output: add _get_plugin()
[libmpdclient.git] / src / status.c
blobfe2fd8a848aa97cc12cc15a614a43c040acff510
1 /* libmpdclient
2 (c) 2003-2017 The Music Player Daemon Project
3 This project's homepage is: http://www.musicpd.org
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
9 - Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
12 - Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions and the following disclaimer in the
14 documentation and/or other materials provided with the distribution.
16 - Neither the name of the Music Player Daemon nor the names of its
17 contributors may be used to endorse or promote products derived from
18 this software without specific prior written permission.
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
24 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25 EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28 LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 #include <mpd/status.h>
34 #include <mpd/pair.h>
35 #include <mpd/audio_format.h>
37 #include <stdlib.h>
38 #include <string.h>
40 /**
41 * Information about MPD's current status.
43 struct mpd_status {
44 /** 0-100, or MPD_STATUS_NO_VOLUME when there is no volume support */
45 int volume;
47 /** Queue repeat mode enabled? */
48 bool repeat;
50 /** Random mode enabled? */
51 bool random;
53 /** Single song mode enabled? */
54 bool single;
56 /** Song consume mode enabled? */
57 bool consume;
59 /** Number of songs in the queue */
60 unsigned queue_length;
62 /**
63 * Queue version, use this to determine when the playlist has
64 * changed.
66 unsigned queue_version;
68 /** MPD's current playback state */
69 enum mpd_state state;
71 /** crossfade setting in seconds */
72 unsigned crossfade;
74 /** Mixramp threshold in dB */
75 float mixrampdb;
77 /** Mixramp extra delay in seconds */
78 float mixrampdelay;
80 /**
81 * If a song is currently selected (always the case when state
82 * is PLAY or PAUSE), this is the position of the currently
83 * playing song in the queue, beginning with 0.
85 int song_pos;
87 /** Song ID of the currently selected song */
88 int song_id;
90 /** The same as song_pos, but for the next song to be played */
91 int next_song_pos;
93 /** Song ID of the next song to be played */
94 int next_song_id;
96 /**
97 * Time in seconds that have elapsed in the currently
98 * playing/paused song.
100 unsigned elapsed_time;
103 * Time in milliseconds that have elapsed in the currently
104 * playing/paused song.
106 unsigned elapsed_ms;
108 /** length in seconds of the currently playing/paused song */
109 unsigned total_time;
111 /** current bit rate in kbps */
112 unsigned kbit_rate;
114 /** the current audio format */
115 struct mpd_audio_format audio_format;
117 /** non-zero if MPD is updating, 0 otherwise */
118 unsigned update_id;
120 /** error message */
121 char *error;
124 struct mpd_status *
125 mpd_status_begin(void)
127 struct mpd_status *status = malloc(sizeof(*status));
128 if (status == NULL)
129 return NULL;
131 status->volume = -1;
132 status->repeat = false;
133 status->random = false;
134 status->single = false;
135 status->consume = false;
136 status->queue_version = 0;
137 status->queue_length = 0;
138 status->state = MPD_STATE_UNKNOWN;
139 status->song_pos = -1;
140 status->song_id = -1;
141 status->next_song_pos = -1;
142 status->next_song_id = -1;
143 status->elapsed_time = 0;
144 status->elapsed_ms = 0;
145 status->total_time = 0;
146 status->kbit_rate = 0;
147 memset(&status->audio_format, 0, sizeof(status->audio_format));
148 status->crossfade = 0;
149 status->mixrampdb = 100.0;
150 status->mixrampdelay = -1.0;
151 status->error = NULL;
152 status->update_id = 0;
154 return status;
158 * Parses the fractional part of the "elapsed" response line. Up to
159 * three digits are parsed.
161 static unsigned
162 parse_ms(const char *p)
164 unsigned ms;
166 if (*p >= '0' && *p <= '9')
167 ms = 100 * (*p++ - '0');
168 else
169 return 0;
171 if (*p >= '0' && *p <= '9')
172 ms += 10 * (*p - '0');
173 else
174 return ms;
176 if (*p >= '0' && *p <= '9')
177 ms += *p - '0';
179 return ms;
182 static enum mpd_state
183 parse_mpd_state(const char *p)
185 if (strcmp(p, "play") == 0)
186 return MPD_STATE_PLAY;
187 else if (strcmp(p, "stop") == 0)
188 return MPD_STATE_STOP;
189 else if (strcmp(p, "pause") == 0)
190 return MPD_STATE_PAUSE;
191 else
192 return MPD_STATE_UNKNOWN;
195 static void
196 parse_audio_format(struct mpd_audio_format *audio_format, const char *p)
198 char *endptr;
200 if (strncmp(p, "dsd", 3) == 0) {
201 /* allow format specifications such as "dsd64" which
202 implies the sample rate */
204 unsigned long dsd = strtoul(p + 3, &endptr, 10);
205 if (endptr > p + 3 && *endptr == ':' &&
206 dsd >= 32 && dsd <= 4096 && dsd % 2 == 0) {
207 audio_format->sample_rate = dsd * 44100 / 8;
208 audio_format->bits = MPD_SAMPLE_FORMAT_DSD;
210 p = endptr + 1;
211 audio_format->channels = strtoul(p, NULL, 10);
212 return;
216 audio_format->sample_rate = strtoul(p, &endptr, 10);
217 if (*endptr == ':') {
218 p = endptr + 1;
220 if (p[0] == 'f' && p[1] == ':') {
221 audio_format->bits = MPD_SAMPLE_FORMAT_FLOAT;
222 p += 2;
223 } else if (p[0] == 'd' && p[1] == 's' &&
224 p[2] == 'd' && p[3] == ':') {
225 audio_format->bits = MPD_SAMPLE_FORMAT_DSD;
226 p += 4;
227 } else {
228 audio_format->bits = strtoul(p, &endptr, 10);
229 p = *endptr == ':' ? endptr + 1 : NULL;
232 audio_format->channels = p != NULL
233 ? strtoul(p, NULL, 10)
234 : 0;
235 } else {
236 audio_format->bits = 0;
237 audio_format->channels = 0;
241 void
242 mpd_status_feed(struct mpd_status *status, const struct mpd_pair *pair)
244 if (strcmp(pair->name, "volume") == 0)
245 status->volume = atoi(pair->value);
246 else if (strcmp(pair->name, "repeat") == 0)
247 status->repeat = !!atoi(pair->value);
248 else if (strcmp(pair->name, "random") == 0)
249 status->random = !!atoi(pair->value);
250 else if (strcmp(pair->name, "single") == 0)
251 status->single = !!atoi(pair->value);
252 else if (strcmp(pair->name, "consume") == 0)
253 status->consume = !!atoi(pair->value);
254 else if (strcmp(pair->name, "playlist") == 0)
255 status->queue_version = strtoul(pair->value, NULL, 10);
256 else if (strcmp(pair->name, "playlistlength") == 0)
257 status->queue_length = atoi(pair->value);
258 else if (strcmp(pair->name, "bitrate") == 0)
259 status->kbit_rate = atoi(pair->value);
260 else if (strcmp(pair->name, "state") == 0)
261 status->state = parse_mpd_state(pair->value);
262 else if (strcmp(pair->name, "song") == 0)
263 status->song_pos = atoi(pair->value);
264 else if (strcmp(pair->name, "songid") == 0)
265 status->song_id = atoi(pair->value);
266 else if (strcmp(pair->name, "nextsong") == 0)
267 status->next_song_pos = atoi(pair->value);
268 else if (strcmp(pair->name, "nextsongid") == 0)
269 status->next_song_id = atoi(pair->value);
270 else if (strcmp(pair->name, "time") == 0) {
271 char *endptr;
273 status->elapsed_time = strtoul(pair->value, &endptr, 10);
274 if (*endptr == ':')
275 status->total_time = strtoul(endptr + 1, NULL, 10);
277 if (status->elapsed_ms == 0)
278 status->elapsed_ms = status->elapsed_time * 1000;
279 } else if (strcmp(pair->name, "elapsed") == 0) {
280 char *endptr;
282 status->elapsed_ms = strtoul(pair->value, &endptr, 10) * 1000;
283 if (*endptr == '.')
284 status->elapsed_ms += parse_ms(endptr + 1);
286 if (status->elapsed_time == 0)
287 status->elapsed_time = status->elapsed_ms / 1000;
288 } else if (strcmp(pair->name, "error") == 0) {
289 if (status->error != NULL)
290 free(status->error);
292 status->error = strdup(pair->value);
293 } else if (strcmp(pair->name, "xfade") == 0)
294 status->crossfade = atoi(pair->value);
295 else if (strcmp(pair->name, "mixrampdb") == 0)
296 status->mixrampdb = atof(pair->value);
297 else if (strcmp(pair->name, "mixrampdelay") == 0)
298 status->mixrampdelay = atof(pair->value);
299 else if (strcmp(pair->name, "updating_db") == 0)
300 status->update_id = atoi(pair->value);
301 else if (strcmp(pair->name, "audio") == 0)
302 parse_audio_format(&status->audio_format, pair->value);
305 void mpd_status_free(struct mpd_status * status) {
306 if (status->error) free(status->error);
307 free(status);
310 int mpd_status_get_volume(const struct mpd_status *status)
312 return status->volume;
315 bool
316 mpd_status_get_repeat(const struct mpd_status *status)
318 return status->repeat;
321 bool
322 mpd_status_get_random(const struct mpd_status *status)
324 return status->random;
327 bool
328 mpd_status_get_single(const struct mpd_status *status)
330 return status->single;
333 bool
334 mpd_status_get_consume(const struct mpd_status *status)
336 return status->consume;
339 unsigned
340 mpd_status_get_queue_length(const struct mpd_status *status)
342 return status->queue_length;
345 unsigned
346 mpd_status_get_queue_version(const struct mpd_status *status)
348 return status->queue_version;
351 enum mpd_state
352 mpd_status_get_state(const struct mpd_status *status)
354 return status->state;
357 unsigned
358 mpd_status_get_crossfade(const struct mpd_status *status)
360 return status->crossfade;
363 float
364 mpd_status_get_mixrampdb(const struct mpd_status *status)
366 return status->mixrampdb;
369 float
370 mpd_status_get_mixrampdelay(const struct mpd_status *status)
372 return status->mixrampdelay;
376 mpd_status_get_song_pos(const struct mpd_status *status)
378 return status->song_pos;
382 mpd_status_get_song_id(const struct mpd_status *status)
384 return status->song_id;
388 mpd_status_get_next_song_pos(const struct mpd_status *status)
390 return status->next_song_pos;
394 mpd_status_get_next_song_id(const struct mpd_status *status)
396 return status->next_song_id;
399 unsigned
400 mpd_status_get_elapsed_time(const struct mpd_status *status)
402 return status->elapsed_time;
405 unsigned
406 mpd_status_get_elapsed_ms(const struct mpd_status *status)
408 return status->elapsed_ms;
411 unsigned
412 mpd_status_get_total_time(const struct mpd_status *status)
414 return status->total_time;
417 unsigned
418 mpd_status_get_kbit_rate(const struct mpd_status *status)
420 return status->kbit_rate;
423 const struct mpd_audio_format *
424 mpd_status_get_audio_format(const struct mpd_status *status)
426 return status->audio_format.sample_rate > 0 ||
427 status->audio_format.bits > 0 ||
428 status->audio_format.channels > 0
429 ? &status->audio_format
430 : NULL;
433 unsigned
434 mpd_status_get_update_id(const struct mpd_status *status)
436 return status->update_id;
439 const char *
440 mpd_status_get_error(const struct mpd_status *status)
442 return status->error;