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
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>
35 #include <mpd/audio_format.h>
41 * Information about MPD's current status.
44 /** 0-100, or MPD_STATUS_NO_VOLUME when there is no volume support */
47 /** Queue repeat mode enabled? */
50 /** Random mode enabled? */
53 /** Single song mode enabled? */
56 /** Song consume mode enabled? */
59 /** Number of songs in the queue */
60 unsigned queue_length
;
63 * Queue version, use this to determine when the playlist has
66 unsigned queue_version
;
68 /** MPD's current playback state */
71 /** crossfade setting in seconds */
74 /** Mixramp threshold in dB */
77 /** Mixramp extra delay in seconds */
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.
87 /** Song ID of the currently selected song */
90 /** The same as song_pos, but for the next song to be played */
93 /** Song ID of the next song to be played */
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.
108 /** length in seconds of the currently playing/paused song */
111 /** current bit rate in kbps */
114 /** the current audio format */
115 struct mpd_audio_format audio_format
;
117 /** non-zero if MPD is updating, 0 otherwise */
125 mpd_status_begin(void)
127 struct mpd_status
*status
= malloc(sizeof(*status
));
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;
158 * Parses the fractional part of the "elapsed" response line. Up to
159 * three digits are parsed.
162 parse_ms(const char *p
)
166 if (*p
>= '0' && *p
<= '9')
167 ms
= 100 * (*p
++ - '0');
171 if (*p
>= '0' && *p
<= '9')
172 ms
+= 10 * (*p
- '0');
176 if (*p
>= '0' && *p
<= '9')
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
;
192 return MPD_STATE_UNKNOWN
;
196 parse_audio_format(struct mpd_audio_format
*audio_format
, const char *p
)
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
;
211 audio_format
->channels
= strtoul(p
, NULL
, 10);
216 audio_format
->sample_rate
= strtoul(p
, &endptr
, 10);
217 if (*endptr
== ':') {
220 if (p
[0] == 'f' && p
[1] == ':') {
221 audio_format
->bits
= MPD_SAMPLE_FORMAT_FLOAT
;
223 } else if (p
[0] == 'd' && p
[1] == 's' &&
224 p
[2] == 'd' && p
[3] == ':') {
225 audio_format
->bits
= MPD_SAMPLE_FORMAT_DSD
;
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)
236 audio_format
->bits
= 0;
237 audio_format
->channels
= 0;
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) {
273 status
->elapsed_time
= strtoul(pair
->value
, &endptr
, 10);
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) {
282 status
->elapsed_ms
= strtoul(pair
->value
, &endptr
, 10) * 1000;
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
)
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
);
310 int mpd_status_get_volume(const struct mpd_status
*status
)
312 return status
->volume
;
316 mpd_status_get_repeat(const struct mpd_status
*status
)
318 return status
->repeat
;
322 mpd_status_get_random(const struct mpd_status
*status
)
324 return status
->random
;
328 mpd_status_get_single(const struct mpd_status
*status
)
330 return status
->single
;
334 mpd_status_get_consume(const struct mpd_status
*status
)
336 return status
->consume
;
340 mpd_status_get_queue_length(const struct mpd_status
*status
)
342 return status
->queue_length
;
346 mpd_status_get_queue_version(const struct mpd_status
*status
)
348 return status
->queue_version
;
352 mpd_status_get_state(const struct mpd_status
*status
)
354 return status
->state
;
358 mpd_status_get_crossfade(const struct mpd_status
*status
)
360 return status
->crossfade
;
364 mpd_status_get_mixrampdb(const struct mpd_status
*status
)
366 return status
->mixrampdb
;
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
;
400 mpd_status_get_elapsed_time(const struct mpd_status
*status
)
402 return status
->elapsed_time
;
406 mpd_status_get_elapsed_ms(const struct mpd_status
*status
)
408 return status
->elapsed_ms
;
412 mpd_status_get_total_time(const struct mpd_status
*status
)
414 return status
->total_time
;
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
434 mpd_status_get_update_id(const struct mpd_status
*status
)
436 return status
->update_id
;
440 mpd_status_get_error(const struct mpd_status
*status
)
442 return status
->error
;