Implement consume, single mode.
[libmpd.git] / src / libmpd-status.c
blobf5c0837e008c22e7bdfd968419c9f1633894ece9
1 /* libmpd (high level libmpdclient library)
2 * Copyright (C) 2004-2009 Qball Cow <qball@sarine.nl>
3 * Project homepage: http://gmpcwiki.sarine.nl/
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <assert.h>
23 #define __USE_GNU
25 #include <string.h>
26 #include <stdarg.h>
27 #include <config.h>
28 #include "debug_printf.h"
29 #include "libmpd.h"
30 #include "libmpd-internal.h"
32 int mpd_stats_update_real(MpdObj *mi, ChangedStatusType* what_changed);
34 int mpd_status_queue_update(MpdObj *mi)
37 if(!mpd_check_connected(mi))
39 debug_printf(DEBUG_INFO,"not connected\n");
40 return MPD_NOT_CONNECTED;
42 if(mi->status != NULL)
44 mpd_freeStatus(mi->status);
45 mi->status = NULL;
47 return MPD_OK;
51 int mpd_status_update(MpdObj *mi)
53 ChangedStatusType what_changed=0;
54 if(!mpd_check_connected(mi))
56 debug_printf(DEBUG_INFO,"not connected\n");
57 return MPD_NOT_CONNECTED;
59 if(mpd_lock_conn(mi))
61 debug_printf(DEBUG_ERROR,"lock failed\n");
62 return MPD_LOCK_FAILED;
67 if(mi->status != NULL)
69 mpd_freeStatus(mi->status);
70 mi->status = NULL;
72 mpd_sendStatusCommand(mi->connection);
73 mi->status = mpd_getStatus(mi->connection);
74 if(mi->status == NULL)
76 debug_printf(DEBUG_ERROR,"Failed to grab status from mpd\n");
77 mpd_unlock_conn(mi);
78 return MPD_STATUS_FAILED;
80 if(mpd_unlock_conn(mi))
82 debug_printf(DEBUG_ERROR, "Failed to unlock");
83 return MPD_LOCK_FAILED;
86 * check for changes
88 /* first save the old status */
89 memcpy(&(mi->OldState), &(mi->CurrentState), sizeof(MpdServerState));
91 /* playlist change */
92 if(mi->CurrentState.playlistid != mi->status->playlist)
94 /* print debug message */
95 debug_printf(DEBUG_INFO, "Playlist has changed!");
97 /* We can't trust the current song anymore. so we remove it */
98 /* tags might have been updated */
99 if(mi->CurrentSong != NULL)
101 mpd_freeSong(mi->CurrentSong);
102 mi->CurrentSong = NULL;
105 /* set MPD_CST_PLAYLIST to be changed */
106 what_changed |= MPD_CST_PLAYLIST;
108 if(mi->CurrentState.playlistLength == mi->status->playlistLength)
110 // what_changed |= MPD_CST_SONGID;
112 /* save new id */
113 mi->CurrentState.playlistid = mi->status->playlist;
116 if(mi->CurrentState.storedplaylistid != mi->status->storedplaylist)
118 /* set MPD_CST_QUEUE to be changed */
119 what_changed |= MPD_CST_STORED_PLAYLIST;
122 /* save new id */
123 mi->CurrentState.storedplaylistid = mi->status->storedplaylist;
127 /* state change */
128 if(mi->CurrentState.state != mi->status->state)
130 what_changed |= MPD_CST_STATE;
131 mi->CurrentState.state = mi->status->state;
134 if(mi->CurrentState.songid != mi->status->songid)
136 /* print debug message */
137 debug_printf(DEBUG_INFO, "Songid has changed %i %i!", mi->OldState.songid, mi->status->songid);
139 what_changed |= MPD_CST_SONGID;
140 /* save new songid */
141 mi->CurrentState.songid = mi->status->songid;
144 if(mi->CurrentState.songpos != mi->status->song)
146 /* print debug message */
147 debug_printf(DEBUG_INFO, "Songpos has changed %i %i!", mi->OldState.songpos, mi->status->song);
149 what_changed |= MPD_CST_SONGPOS;
150 /* save new songid */
151 mi->CurrentState.songpos = mi->status->song;
154 if(mi->CurrentState.nextsongid != mi->status->nextsongid || mi->CurrentState.nextsongpos != mi->status->nextsong)
156 what_changed |= MPD_CST_NEXTSONG;
157 /* save new songid */
158 mi->CurrentState.nextsongpos = mi->status->nextsong;
159 mi->CurrentState.nextsongid = mi->status->nextsongid;
162 if(mi->CurrentState.single != mi->status->single)
164 what_changed |= MPD_CST_SINGLE_MODE;
165 mi->CurrentState.single = mi->status->single;
167 if(mi->CurrentState.consume != mi->status->consume)
169 what_changed |= MPD_CST_CONSUME_MODE;
170 mi->CurrentState.consume = mi->status->consume;
172 if(mi->CurrentState.repeat != mi->status->repeat)
174 what_changed |= MPD_CST_REPEAT;
175 mi->CurrentState.repeat = mi->status->repeat;
177 if(mi->CurrentState.random != mi->status->random)
179 what_changed |= MPD_CST_RANDOM;
180 mi->CurrentState.random = mi->status->random;
182 if(mi->CurrentState.volume != mi->status->volume)
184 what_changed |= MPD_CST_VOLUME;
185 mi->CurrentState.volume = mi->status->volume;
187 if(mi->CurrentState.xfade != mi->status->crossfade)
189 what_changed |= MPD_CST_CROSSFADE;
190 mi->CurrentState.xfade = mi->status->crossfade;
192 if(mi->CurrentState.totaltime != mi->status->totalTime)
194 what_changed |= MPD_CST_TOTAL_TIME;
195 mi->CurrentState.totaltime = mi->status->totalTime;
197 if(mi->CurrentState.elapsedtime != mi->status->elapsedTime)
199 what_changed |= MPD_CST_ELAPSED_TIME;
200 mi->CurrentState.elapsedtime = mi->status->elapsedTime;
203 /* Check if bitrate changed, happens with vbr encodings. */
204 if(mi->CurrentState.bitrate != mi->status->bitRate)
206 what_changed |= MPD_CST_BITRATE;
207 mi->CurrentState.bitrate = mi->status->bitRate;
210 /* The following 3 probly only happen on a song change, or is it possible in one song/stream? */
211 /* Check if the sample rate changed */
212 if(mi->CurrentState.samplerate != mi->status->sampleRate)
214 what_changed |= MPD_CST_AUDIOFORMAT;
215 mi->CurrentState.samplerate = mi->status->sampleRate;
218 /* check if the sampling depth changed */
219 if(mi->CurrentState.bits != mi->status->bits)
221 what_changed |= MPD_CST_AUDIOFORMAT;
222 mi->CurrentState.bits = mi->status->bits;
225 /* Check if the amount of audio channels changed */
226 if(mi->CurrentState.channels != mi->status->channels)
228 what_changed |= MPD_CST_AUDIOFORMAT;
229 mi->CurrentState.channels = mi->status->channels;
232 if(mi->status->error)
234 what_changed |= MPD_CST_SERVER_ERROR;
235 strcpy(mi->CurrentState.error,mi->status->error);
236 mpd_sendClearErrorCommand(mi->connection);
237 mpd_finishCommand(mi->connection);
239 else
241 mi->CurrentState.error[0] ='\0';
244 /* Check if the updating changed,
245 * If it stopped, also update the stats for the new db-time.
247 if(mi->CurrentState.updatingDb != mi->status->updatingDb )
249 what_changed |= MPD_CST_UPDATING;
250 if(!mi->status->updatingDb)
252 mpd_stats_update_real(mi, &what_changed);
254 mi->CurrentState.updatingDb = mi->status->updatingDb;
258 mi->CurrentState.playlistLength = mi->status->playlistLength;
261 /* Detect changed outputs */
262 if(!mi->has_idle)
264 if(mi->num_outputs >0 )
266 mpd_OutputEntity *output = NULL;
267 mpd_sendOutputsCommand(mi->connection);
268 while (( output = mpd_getNextOutput(mi->connection)) != NULL)
270 if(mi->num_outputs < output->id)
272 mi->num_outputs++;
273 mi->output_states = g_realloc(mi->output_states,mi->num_outputs*sizeof(int));
274 mi->output_states[mi->num_outputs] = output->enabled;
275 what_changed |= MPD_CST_OUTPUT;
277 if(mi->output_states[output->id] != output->enabled)
279 mi->output_states[output->id] = output->enabled;
280 what_changed |= MPD_CST_OUTPUT;
282 mpd_freeOutputElement(output);
284 mpd_finishCommand(mi->connection);
286 else
288 /* if no outputs, lets fetch them */
289 mpd_server_update_outputs(mi);
290 if(mi->num_outputs == 0)
292 assert("No outputs defined? that cannot be\n");
294 what_changed |= MPD_CST_OUTPUT;
296 }else {
297 char *name;
298 int update_stats = 0;
299 mpd_sendGetEventsCommand(mi->connection);
300 while((name = mpd_getNextEvent(mi->connection))){
301 if(strcmp(name, "output") == 0){
302 what_changed |= MPD_CST_OUTPUT;
303 }else if (strcmp(name, "database") == 0) {
304 if((what_changed&MPD_CST_DATABASE) == 0)
306 update_stats = 1;
308 what_changed |= MPD_CST_DATABASE;
309 }else if (strcmp(name, "stored_playlist")==0) {
310 what_changed |= MPD_CST_STORED_PLAYLIST;
311 }else if (strcmp(name, "tag") == 0) {
312 what_changed |= MPD_CST_PLAYLIST;
313 }else if (strcmp (name, "sticker") == 0) {
314 what_changed |= MPD_CST_STICKER;
316 free(name);
318 mpd_finishCommand(mi->connection);
319 if(update_stats) {
320 mpd_stats_update_real(mi, &what_changed);
325 /* Run the callback */
326 if((mi->the_status_changed_callback != NULL) && what_changed)
328 mi->the_status_changed_callback( mi, what_changed, mi->the_status_changed_signal_userdata );
331 /* We could have lost connection again during signal handling... so before we return check again if we are connected */
332 if(!mpd_check_connected(mi))
334 return MPD_NOT_CONNECTED;
336 return MPD_OK;
339 /* returns TRUE when status is availible, when not availible and connected it tries to grab it */
340 int mpd_status_check(MpdObj *mi)
342 if(!mpd_check_connected(mi))
344 debug_printf(DEBUG_INFO,"not connected\n");
345 return MPD_NOT_CONNECTED;
347 if(mi->status == NULL)
349 /* try to update */
350 if(mpd_status_update(mi))
352 debug_printf(DEBUG_INFO, "failed to update status\n");
353 return MPD_STATUS_FAILED;
356 return MPD_OK;
360 int mpd_stats_get_total_songs(MpdObj *mi)
362 if(mi == NULL)
364 debug_printf(DEBUG_ERROR, "failed to check mi == NULL\n");
365 return MPD_ARGS_ERROR;
367 if(mpd_stats_check(mi) != MPD_OK)
369 debug_printf(DEBUG_ERROR,"Failed to get status\n");
370 return MPD_STATUS_FAILED;
372 return mi->stats->numberOfSongs;
375 int mpd_stats_get_total_artists(MpdObj *mi)
377 if(mi == NULL)
379 debug_printf(DEBUG_ERROR, "failed to check mi == NULL\n");
380 return MPD_ARGS_ERROR;
382 if(mpd_stats_check(mi) != MPD_OK)
384 debug_printf(DEBUG_ERROR,"Failed to get status\n");
385 return MPD_STATS_FAILED;
387 return mi->stats->numberOfArtists;
390 int mpd_stats_get_total_albums(MpdObj *mi)
392 if(mi == NULL)
394 debug_printf(DEBUG_ERROR,"failed to check mi == NULL\n");
395 return MPD_ARGS_ERROR;
397 if(mpd_stats_check(mi) != MPD_OK)
399 debug_printf(DEBUG_WARNING,"Failed to get status\n");
400 return MPD_STATS_FAILED;
402 return mi->stats->numberOfAlbums;
406 int mpd_stats_get_uptime(MpdObj *mi)
408 if(mi == NULL)
410 debug_printf(DEBUG_ERROR,"failed to check mi == NULL\n");
411 return MPD_ARGS_ERROR;
413 if(mpd_stats_check(mi) != MPD_OK)
415 debug_printf(DEBUG_WARNING,"Failed to get status\n");
416 return MPD_STATS_FAILED;
418 return mi->stats->uptime;
421 int mpd_stats_get_playtime(MpdObj *mi)
423 if(mi == NULL)
425 debug_printf(DEBUG_ERROR, "failed to check mi == NULL\n");
426 return MPD_ARGS_ERROR;
428 if(mpd_stats_check(mi) != MPD_OK)
430 debug_printf(DEBUG_WARNING,"Failed to get status\n");
431 return MPD_STATS_FAILED;
433 return mi->stats->playTime;
436 int mpd_stats_get_db_playtime(MpdObj *mi)
438 if(mi == NULL)
440 debug_printf(DEBUG_ERROR, "failed to check mi == NULL\n");
441 return MPD_ARGS_ERROR;
443 if(mpd_stats_check(mi) != MPD_OK)
445 debug_printf(DEBUG_WARNING,"Failed to get stats\n");
446 return MPD_STATS_FAILED;
448 return mi->stats->dbPlayTime;
467 int mpd_status_get_volume(MpdObj *mi)
469 if(mi == NULL)
471 debug_printf(DEBUG_ERROR, "failed to check mi == NULL\n");
472 return MPD_ARGS_ERROR;
474 if(mpd_status_check(mi) != MPD_OK)
476 debug_printf(DEBUG_WARNING, "Failed to get status\n");
477 return MPD_STATUS_FAILED;
479 return mi->status->volume;
483 int mpd_status_get_bitrate(MpdObj *mi)
485 if(mi == NULL)
487 debug_printf(DEBUG_ERROR,"failed to check mi == NULL\n");
488 return MPD_ARGS_ERROR;
490 if(mpd_status_check(mi) != MPD_OK)
492 debug_printf(DEBUG_WARNING, "Failed to get status\n");
493 return MPD_STATUS_FAILED;
495 return mi->CurrentState.bitrate;
498 int mpd_status_get_channels(MpdObj *mi)
500 if(mi == NULL)
502 debug_printf(DEBUG_ERROR,"failed to check mi == NULL\n");
503 return MPD_ARGS_ERROR;
505 if(mpd_status_check(mi) != MPD_OK)
507 debug_printf(DEBUG_WARNING, "Failed to get status\n");
508 return MPD_STATUS_FAILED;
510 return mi->CurrentState.channels;
513 unsigned int mpd_status_get_samplerate(MpdObj *mi)
515 if(mi == NULL)
517 debug_printf(DEBUG_ERROR,"failed to check mi == NULL\n");
518 return MPD_ARGS_ERROR;
520 if(mpd_status_check(mi) != MPD_OK)
522 debug_printf(DEBUG_WARNING, "Failed to get status\n");
523 return MPD_STATUS_FAILED;
525 return mi->CurrentState.samplerate;
528 int mpd_status_get_bits(MpdObj *mi)
530 if(mi == NULL)
532 debug_printf(DEBUG_WARNING,"failed to check mi == NULL\n");
533 return MPD_ARGS_ERROR;
535 if(mpd_status_check(mi) != MPD_OK)
537 debug_printf(DEBUG_WARNING, "Failed to get status\n");
538 return MPD_STATUS_FAILED;
540 return mi->CurrentState.bits;
543 char * mpd_status_get_mpd_error(MpdObj *mi)
545 if(mi->CurrentState.error[0] != '\0')
547 return strdup(mi->CurrentState.error);
549 return NULL;
552 int mpd_status_db_is_updating(MpdObj *mi)
554 if(!mpd_check_connected(mi))
556 debug_printf(DEBUG_WARNING, "mpd_check_connected failed.\n");
557 return FALSE;
559 return mi->CurrentState.updatingDb;
563 int mpd_status_get_total_song_time(MpdObj *mi)
565 if(!mpd_check_connected(mi))
567 debug_printf(DEBUG_ERROR, "failed to check mi == NULL\n");
568 return MPD_ARGS_ERROR;
570 if(mpd_status_check(mi) != MPD_OK)
572 debug_printf(DEBUG_WARNING, "Failed to get status\n");
573 return MPD_STATUS_FAILED;
575 return mi->status->totalTime;
579 int mpd_status_get_elapsed_song_time(MpdObj *mi)
581 if(!mpd_check_connected(mi))
583 debug_printf(DEBUG_WARNING,"failed to check mi == NULL\n");
584 return MPD_NOT_CONNECTED;
586 if(mpd_status_check(mi) != MPD_OK)
588 debug_printf(DEBUG_WARNING,"Failed to get status\n");
589 return MPD_STATUS_FAILED;
591 return mi->status->elapsedTime;
594 int mpd_status_set_volume(MpdObj *mi,int volume)
596 if(!mpd_check_connected(mi))
598 debug_printf(DEBUG_WARNING,"not connected\n");
599 return MPD_NOT_CONNECTED;
601 /* making sure volume is between 0 and 100 */
602 volume = (volume < 0)? 0:(volume>100)? 100:volume;
604 if(mpd_lock_conn(mi))
606 debug_printf(DEBUG_ERROR,"lock failed\n");
607 return MPD_LOCK_FAILED;
610 /* send the command */
611 mpd_sendSetvolCommand(mi->connection , volume);
612 mpd_finishCommand(mi->connection);
613 /* check for errors */
615 mpd_unlock_conn(mi);
616 /* update status, because we changed it */
617 mpd_status_queue_update(mi);
618 /* return current volume */
619 return mpd_status_get_volume(mi);
622 int mpd_status_get_crossfade(MpdObj *mi)
624 if(!mpd_check_connected(mi))
626 debug_printf(DEBUG_WARNING,"not connected\n");
627 return MPD_NOT_CONNECTED;
629 if(mpd_status_check(mi) != MPD_OK)
631 debug_printf(DEBUG_WARNING,"Failed grabbing status\n");
632 return MPD_NOT_CONNECTED;
634 return mi->status->crossfade;
637 int mpd_status_set_crossfade(MpdObj *mi,int crossfade_time)
639 if(!mpd_check_connected(mi))
641 debug_printf(DEBUG_WARNING,"not connected\n");
642 return MPD_NOT_CONNECTED;
644 if(mpd_lock_conn(mi))
646 debug_printf(DEBUG_ERROR,"lock failed\n");
647 return MPD_LOCK_FAILED;
649 mpd_sendCrossfadeCommand(mi->connection, crossfade_time);
650 mpd_finishCommand(mi->connection);
652 mpd_unlock_conn(mi);
653 mpd_status_queue_update(mi);
654 return MPD_OK;
658 float mpd_status_set_volume_as_float(MpdObj *mi, float fvol)
660 int volume = mpd_status_set_volume(mi, (int)(fvol*100.0));
661 if(volume > -1)
663 return (float)volume/100.0;
665 return (float)volume;
668 int mpd_stats_update(MpdObj *mi)
670 return mpd_stats_update_real(mi, NULL);
673 int mpd_stats_update_real(MpdObj *mi, ChangedStatusType* what_changed)
675 ChangedStatusType what_changed_here = 0;
676 if ( what_changed == NULL ) {
677 /* we need to save the current state, because we're called standalone */
678 memcpy(&(mi->OldState), &(mi->CurrentState), sizeof(MpdServerState));
681 if(!mpd_check_connected(mi))
683 debug_printf(DEBUG_INFO,"not connected\n");
684 return MPD_NOT_CONNECTED;
686 if(mpd_lock_conn(mi))
688 debug_printf(DEBUG_ERROR,"lock failed\n");
689 return MPD_LOCK_FAILED;
692 if(mi->stats != NULL)
694 mpd_freeStats(mi->stats);
696 mpd_sendStatsCommand(mi->connection);
697 mi->stats = mpd_getStats(mi->connection);
698 if(mi->stats == NULL)
700 debug_printf(DEBUG_ERROR,"Failed to grab stats from mpd\n");
702 else if(mi->stats->dbUpdateTime != mi->OldState.dbUpdateTime)
704 debug_printf(DEBUG_INFO, "database updated\n");
705 what_changed_here |= MPD_CST_DATABASE;
707 mi->CurrentState.dbUpdateTime = mi->stats->dbUpdateTime;
710 if (what_changed) {
711 (*what_changed) |= what_changed_here;
712 } else {
713 if((mi->the_status_changed_callback != NULL) & what_changed_here)
715 mi->the_status_changed_callback(mi, what_changed_here, mi->the_status_changed_signal_userdata);
719 if(mpd_unlock_conn(mi))
721 debug_printf(DEBUG_ERROR, "unlock failed");
722 return MPD_LOCK_FAILED;
724 return MPD_OK;
728 int mpd_stats_check(MpdObj *mi)
730 if(!mpd_check_connected(mi))
732 debug_printf(DEBUG_WARNING,"not connected\n");
733 return MPD_NOT_CONNECTED;
735 if(mi->stats == NULL)
737 /* try to update */
738 if(mpd_stats_update(mi))
740 debug_printf(DEBUG_ERROR,"failed to update status\n");
741 return MPD_STATUS_FAILED;
744 return MPD_OK;