change to const
[libmpd.git] / src / libmpd-status.c
blob5a976a1b149a22f5573ba2bee93e371574ae25a9
1 /*
2 *Copyright (C) 2004-2007 Qball Cow <Qball@qballcow.nl>
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
14 * You should have received a copy of the GNU General Public
15 * License along with this program; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, 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,"Where 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,"Where 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;
155 if(mi->CurrentState.repeat != mi->status->repeat)
157 what_changed |= MPD_CST_REPEAT;
158 mi->CurrentState.repeat = mi->status->repeat;
160 if(mi->CurrentState.random != mi->status->random)
162 what_changed |= MPD_CST_RANDOM;
163 mi->CurrentState.random = mi->status->random;
165 if(mi->CurrentState.volume != mi->status->volume)
167 what_changed |= MPD_CST_VOLUME;
168 mi->CurrentState.volume = mi->status->volume;
170 if(mi->CurrentState.xfade != mi->status->crossfade)
172 what_changed |= MPD_CST_CROSSFADE;
173 mi->CurrentState.xfade = mi->status->crossfade;
175 if(mi->CurrentState.totaltime != mi->status->totalTime)
177 what_changed |= MPD_CST_TOTAL_TIME;
178 mi->CurrentState.totaltime = mi->status->totalTime;
180 if(mi->CurrentState.elapsedtime != mi->status->elapsedTime)
182 what_changed |= MPD_CST_ELAPSED_TIME;
183 mi->CurrentState.elapsedtime = mi->status->elapsedTime;
186 /* Check if bitrate changed, happens with vbr encodings. */
187 if(mi->CurrentState.bitrate != mi->status->bitRate)
189 what_changed |= MPD_CST_BITRATE;
190 mi->CurrentState.bitrate = mi->status->bitRate;
193 /* The following 3 probly only happen on a song change, or is it possible in one song/stream? */
194 /* Check if the sample rate changed */
195 if(mi->CurrentState.samplerate != mi->status->sampleRate)
197 what_changed |= MPD_CST_AUDIOFORMAT;
198 mi->CurrentState.samplerate = mi->status->sampleRate;
201 /* check if the sampling depth changed */
202 if(mi->CurrentState.bits != mi->status->bits)
204 what_changed |= MPD_CST_AUDIOFORMAT;
205 mi->CurrentState.bits = mi->status->bits;
208 /* Check if the amount of audio channels changed */
209 if(mi->CurrentState.channels != mi->status->channels)
211 what_changed |= MPD_CST_AUDIOFORMAT;
212 mi->CurrentState.channels = mi->status->channels;
215 if(mi->status->error)
217 what_changed |= MPD_CST_SERVER_ERROR;
218 strcpy(mi->CurrentState.error,mi->status->error);
219 mpd_sendClearErrorCommand(mi->connection);
220 mpd_finishCommand(mi->connection);
222 else
224 mi->CurrentState.error[0] ='\0';
227 /* Check if the updating changed,
228 * If it stopped, also update the stats for the new db-time.
230 if(mi->CurrentState.updatingDb != mi->status->updatingDb )
232 what_changed |= MPD_CST_UPDATING;
233 if(!mi->status->updatingDb)
235 mpd_stats_update_real(mi, &what_changed);
237 mi->CurrentState.updatingDb = mi->status->updatingDb;
241 mi->CurrentState.playlistLength = mi->status->playlistLength;
244 /* Detect changed outputs */
245 if(!mi->has_idle)
247 if(mi->num_outputs >0 )
249 mpd_OutputEntity *output = NULL;
250 mpd_sendOutputsCommand(mi->connection);
251 while (( output = mpd_getNextOutput(mi->connection)) != NULL)
253 if(mi->output_states[output->id] != output->enabled)
255 mi->output_states[output->id] = output->enabled;
256 what_changed |= MPD_CST_OUTPUT;
258 mpd_freeOutputElement(output);
260 mpd_finishCommand(mi->connection);
262 else
264 /* if no outputs, lets fetch them */
265 mpd_server_update_outputs(mi);
266 if(mi->num_outputs == 0)
268 assert("No outputs defined? that cannot be\n");
270 what_changed |= MPD_CST_OUTPUT;
272 }else {
273 char *name;
274 mpd_sendGetEventsCommand(mi->connection);
275 while((name = mpd_getNextEvent(mi->connection))){
276 printf("name: %s\n", name);
277 if(strcmp(name, "output") == 0){
278 what_changed |= MPD_CST_OUTPUT;
279 }else if (strcmp(name, "stored_playlist")==0) {
280 what_changed |= MPD_CST_STORED_PLAYLIST;
283 free(name);
285 mpd_finishCommand(mi->connection);
289 /* Run the callback */
290 if((mi->the_status_changed_callback != NULL) && what_changed)
292 mi->the_status_changed_callback( mi, what_changed, mi->the_status_changed_signal_userdata );
295 /* We could have lost connection again during signal handling... so before we return check again if we are connected */
296 if(!mpd_check_connected(mi))
298 return MPD_NOT_CONNECTED;
300 return MPD_OK;
303 /* returns TRUE when status is availible, when not availible and connected it tries to grab it */
304 int mpd_status_check(MpdObj *mi)
306 if(!mpd_check_connected(mi))
308 debug_printf(DEBUG_INFO,"not connected\n");
309 return MPD_NOT_CONNECTED;
311 if(mi->status == NULL)
313 /* try to update */
314 if(mpd_status_update(mi))
316 debug_printf(DEBUG_INFO, "failed to update status\n");
317 return MPD_STATUS_FAILED;
320 return MPD_OK;
324 int mpd_stats_get_total_songs(MpdObj *mi)
326 if(mi == NULL)
328 debug_printf(DEBUG_ERROR, "failed to check mi == NULL\n");
329 return MPD_ARGS_ERROR;
331 if(mpd_stats_check(mi) != MPD_OK)
333 debug_printf(DEBUG_ERROR,"Failed to get status\n");
334 return MPD_STATUS_FAILED;
336 return mi->stats->numberOfSongs;
339 int mpd_stats_get_total_artists(MpdObj *mi)
341 if(mi == NULL)
343 debug_printf(DEBUG_ERROR, "failed to check mi == NULL\n");
344 return MPD_ARGS_ERROR;
346 if(mpd_stats_check(mi) != MPD_OK)
348 debug_printf(DEBUG_ERROR,"Failed to get status\n");
349 return MPD_STATS_FAILED;
351 return mi->stats->numberOfArtists;
354 int mpd_stats_get_total_albums(MpdObj *mi)
356 if(mi == NULL)
358 debug_printf(DEBUG_ERROR,"failed to check mi == NULL\n");
359 return MPD_ARGS_ERROR;
361 if(mpd_stats_check(mi) != MPD_OK)
363 debug_printf(DEBUG_WARNING,"Failed to get status\n");
364 return MPD_STATS_FAILED;
366 return mi->stats->numberOfAlbums;
370 int mpd_stats_get_uptime(MpdObj *mi)
372 if(mi == NULL)
374 debug_printf(DEBUG_ERROR,"failed to check mi == NULL\n");
375 return MPD_ARGS_ERROR;
377 if(mpd_stats_check(mi) != MPD_OK)
379 debug_printf(DEBUG_WARNING,"Failed to get status\n");
380 return MPD_STATS_FAILED;
382 return mi->stats->uptime;
385 int mpd_stats_get_playtime(MpdObj *mi)
387 if(mi == NULL)
389 debug_printf(DEBUG_ERROR, "failed to check mi == NULL\n");
390 return MPD_ARGS_ERROR;
392 if(mpd_stats_check(mi) != MPD_OK)
394 debug_printf(DEBUG_WARNING,"Failed to get status\n");
395 return MPD_STATS_FAILED;
397 return mi->stats->playTime;
400 int mpd_stats_get_db_playtime(MpdObj *mi)
402 if(mi == NULL)
404 debug_printf(DEBUG_ERROR, "failed to check mi == NULL\n");
405 return MPD_ARGS_ERROR;
407 if(mpd_stats_check(mi) != MPD_OK)
409 debug_printf(DEBUG_WARNING,"Failed to get stats\n");
410 return MPD_STATS_FAILED;
412 return mi->stats->dbPlayTime;
431 int mpd_status_get_volume(MpdObj *mi)
433 if(mi == NULL)
435 debug_printf(DEBUG_ERROR, "failed to check mi == NULL\n");
436 return MPD_ARGS_ERROR;
438 if(mpd_status_check(mi) != MPD_OK)
440 debug_printf(DEBUG_WARNING, "Failed to get status\n");
441 return MPD_STATUS_FAILED;
443 return mi->status->volume;
447 int mpd_status_get_bitrate(MpdObj *mi)
449 if(mi == NULL)
451 debug_printf(DEBUG_ERROR,"failed to check mi == NULL\n");
452 return MPD_ARGS_ERROR;
454 if(mpd_status_check(mi) != MPD_OK)
456 debug_printf(DEBUG_WARNING, "Failed to get status\n");
457 return MPD_STATUS_FAILED;
459 return mi->CurrentState.bitrate;
462 int mpd_status_get_channels(MpdObj *mi)
464 if(mi == NULL)
466 debug_printf(DEBUG_ERROR,"failed to check mi == NULL\n");
467 return MPD_ARGS_ERROR;
469 if(mpd_status_check(mi) != MPD_OK)
471 debug_printf(DEBUG_WARNING, "Failed to get status\n");
472 return MPD_STATUS_FAILED;
474 return mi->CurrentState.channels;
477 unsigned int mpd_status_get_samplerate(MpdObj *mi)
479 if(mi == NULL)
481 debug_printf(DEBUG_ERROR,"failed to check mi == NULL\n");
482 return MPD_ARGS_ERROR;
484 if(mpd_status_check(mi) != MPD_OK)
486 debug_printf(DEBUG_WARNING, "Failed to get status\n");
487 return MPD_STATUS_FAILED;
489 return mi->CurrentState.samplerate;
492 int mpd_status_get_bits(MpdObj *mi)
494 if(mi == NULL)
496 debug_printf(DEBUG_WARNING,"failed to check mi == NULL\n");
497 return MPD_ARGS_ERROR;
499 if(mpd_status_check(mi) != MPD_OK)
501 debug_printf(DEBUG_WARNING, "Failed to get status\n");
502 return MPD_STATUS_FAILED;
504 return mi->CurrentState.bits;
507 char * mpd_status_get_mpd_error(MpdObj *mi)
509 if(mi->CurrentState.error[0] != '\0')
511 return strdup(mi->CurrentState.error);
513 return NULL;
516 /* TODO: error checking might be nice? */
517 int mpd_status_db_is_updating(MpdObj *mi)
519 return mi->CurrentState.updatingDb;
523 int mpd_status_get_total_song_time(MpdObj *mi)
525 if(!mpd_check_connected(mi))
527 debug_printf(DEBUG_ERROR, "failed to check mi == NULL\n");
528 return MPD_ARGS_ERROR;
530 if(mpd_status_check(mi) != MPD_OK)
532 debug_printf(DEBUG_WARNING, "Failed to get status\n");
533 return MPD_STATUS_FAILED;
535 return mi->status->totalTime;
539 int mpd_status_get_elapsed_song_time(MpdObj *mi)
541 if(!mpd_check_connected(mi))
543 debug_printf(DEBUG_WARNING,"failed to check mi == NULL\n");
544 return MPD_NOT_CONNECTED;
546 if(mpd_status_check(mi) != MPD_OK)
548 debug_printf(DEBUG_WARNING,"Failed to get status\n");
549 return MPD_STATUS_FAILED;
551 return mi->status->elapsedTime;
554 int mpd_status_set_volume(MpdObj *mi,int volume)
556 if(!mpd_check_connected(mi))
558 debug_printf(DEBUG_WARNING,"not connected\n");
559 return MPD_NOT_CONNECTED;
561 /* making sure volume is between 0 and 100 */
562 volume = (volume < 0)? 0:(volume>100)? 100:volume;
564 if(mpd_lock_conn(mi))
566 debug_printf(DEBUG_ERROR,"lock failed\n");
567 return MPD_LOCK_FAILED;
570 /* send the command */
571 mpd_sendSetvolCommand(mi->connection , volume);
572 mpd_finishCommand(mi->connection);
573 /* check for errors */
575 mpd_unlock_conn(mi);
576 /* update status, because we changed it */
577 mpd_status_queue_update(mi);
578 /* return current volume */
579 return mpd_status_get_volume(mi);
582 int mpd_status_get_crossfade(MpdObj *mi)
584 if(!mpd_check_connected(mi))
586 debug_printf(DEBUG_WARNING,"not connected\n");
587 return MPD_NOT_CONNECTED;
589 if(mpd_status_check(mi) != MPD_OK)
591 debug_printf(DEBUG_WARNING,"Failed grabbing status\n");
592 return MPD_NOT_CONNECTED;
594 return mi->status->crossfade;
597 int mpd_status_set_crossfade(MpdObj *mi,int crossfade_time)
599 if(!mpd_check_connected(mi))
601 debug_printf(DEBUG_WARNING,"not connected\n");
602 return MPD_NOT_CONNECTED;
604 if(mpd_lock_conn(mi))
606 debug_printf(DEBUG_ERROR,"lock failed\n");
607 return MPD_LOCK_FAILED;
609 mpd_sendCrossfadeCommand(mi->connection, crossfade_time);
610 mpd_finishCommand(mi->connection);
612 mpd_unlock_conn(mi);
613 mpd_status_queue_update(mi);
614 return MPD_OK;
618 float mpd_status_set_volume_as_float(MpdObj *mi, float fvol)
620 int volume = mpd_status_set_volume(mi, (int)(fvol*100.0));
621 if(volume > -1)
623 return (float)volume/100.0;
625 return (float)volume;
628 int mpd_stats_update(MpdObj *mi)
630 return mpd_stats_update_real(mi, NULL);
633 int mpd_stats_update_real(MpdObj *mi, ChangedStatusType* what_changed)
635 ChangedStatusType what_changed_here = 0;
636 if ( what_changed == NULL ) {
637 /* we need to save the current state, because we're called standalone */
638 memcpy(&(mi->OldState), &(mi->CurrentState), sizeof(MpdServerState));
641 if(!mpd_check_connected(mi))
643 debug_printf(DEBUG_INFO,"Where not connected\n");
644 return MPD_NOT_CONNECTED;
646 if(mpd_lock_conn(mi))
648 debug_printf(DEBUG_ERROR,"lock failed\n");
649 return MPD_LOCK_FAILED;
652 if(mi->stats != NULL)
654 mpd_freeStats(mi->stats);
656 mpd_sendStatsCommand(mi->connection);
657 mi->stats = mpd_getStats(mi->connection);
658 if(mi->stats == NULL)
660 debug_printf(DEBUG_ERROR,"Failed to grab stats from mpd\n");
662 else if(mi->stats->dbUpdateTime != mi->OldState.dbUpdateTime)
664 debug_printf(DEBUG_INFO, "database updated\n");
665 what_changed_here |= MPD_CST_DATABASE;
667 mi->CurrentState.dbUpdateTime = mi->stats->dbUpdateTime;
670 if (what_changed) {
671 (*what_changed) |= what_changed_here;
672 } else {
673 if((mi->the_status_changed_callback != NULL) & what_changed_here)
675 mi->the_status_changed_callback(mi, what_changed_here, mi->the_status_changed_signal_userdata);
679 if(mpd_unlock_conn(mi))
681 debug_printf(DEBUG_ERROR, "unlock failed");
682 return MPD_LOCK_FAILED;
684 return MPD_OK;
688 int mpd_stats_check(MpdObj *mi)
690 if(!mpd_check_connected(mi))
692 debug_printf(DEBUG_WARNING,"not connected\n");
693 return MPD_NOT_CONNECTED;
695 if(mi->stats == NULL)
697 /* try to update */
698 if(mpd_stats_update(mi))
700 debug_printf(DEBUG_ERROR,"failed to update status\n");
701 return MPD_STATUS_FAILED;
704 return MPD_OK;