1 /* libmpd (high level libmpdclient library)
2  * Copyright (C) 2004-2009 Qball Cow <qball@sarine.nl>
3  * Project homepage: http://gmpcwiki.sarine.nl/
4 
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.
9 
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.
14 
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.
18 */
19 
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <assert.h>
23 #define __USE_GNU
24 
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"
31 
32 int mpd_stats_update_real(MpdObj *mi, ChangedStatusType* what_changed);
33 
mpd_status_queue_update(MpdObj * mi)34 int mpd_status_queue_update(MpdObj *mi)
35 {
36 
37 	if(!mpd_check_connected(mi))
38 	{
39 		debug_printf(DEBUG_INFO,"not connected\n");
40 		return MPD_NOT_CONNECTED;
41 	}
42 	if(mi->status != NULL)
43 	{
44 		mpd_freeStatus(mi->status);
45 		mi->status = NULL;
46 	}
47 	return MPD_OK;
48 }
49 
50 
mpd_status_update(MpdObj * mi)51 int mpd_status_update(MpdObj *mi)
52 {
53 	ChangedStatusType what_changed=0;
54 	if(!mpd_check_connected(mi))
55 	{
56 		debug_printf(DEBUG_INFO,"not connected\n");
57 		return MPD_NOT_CONNECTED;
58 	}
59 	if(mpd_lock_conn(mi))
60 	{
61 		debug_printf(DEBUG_ERROR,"lock failed\n");
62 		return MPD_LOCK_FAILED;
63 	}
64 
65 
66 
67 	if(mi->status != NULL)
68 	{
69 		mpd_freeStatus(mi->status);
70 		mi->status = NULL;
71 	}
72 	mpd_sendStatusCommand(mi->connection);
73 	mi->status = mpd_getStatus(mi->connection);
74 	if(mi->status == NULL)
75 	{
76 		debug_printf(DEBUG_ERROR,"Failed to grab status from mpd\n");
77 		mpd_unlock_conn(mi);
78 		return MPD_STATUS_FAILED;
79 	}
80 	if(mpd_unlock_conn(mi))
81 	{
82 		debug_printf(DEBUG_ERROR, "Failed to unlock");
83 		return MPD_LOCK_FAILED;
84 	}
85 	/*
86 	 * check for changes
87 	 */
88 	/* first save the old status */
89 	memcpy(&(mi->OldState), &(mi->CurrentState), sizeof(MpdServerState));
90 
91 	/* playlist change */
92 	if(mi->CurrentState.playlistid != mi->status->playlist)
93 	{
94 		/* print debug message */
95 		debug_printf(DEBUG_INFO, "Playlist has changed!");
96 
97 		/* We can't trust the current song anymore. so we remove it */
98 		/* tags might have been updated */
99 		if(mi->CurrentSong != NULL)
100 		{
101 			mpd_freeSong(mi->CurrentSong);
102 			mi->CurrentSong = NULL;
103 		}
104 
105 		/* set MPD_CST_PLAYLIST to be changed */
106 		what_changed |= MPD_CST_PLAYLIST;
107 
108         if(mi->CurrentState.playlistLength == mi->status->playlistLength)
109         {
110 //            what_changed |= MPD_CST_SONGID;
111         }
112 		/* save new id */
113 		mi->CurrentState.playlistid = mi->status->playlist;
114 	}
115 
116 	if(mi->CurrentState.storedplaylistid != mi->status->storedplaylist)
117 	{
118 		/* set MPD_CST_QUEUE to be changed */
119 		what_changed |= MPD_CST_STORED_PLAYLIST;
120 
121 
122 		/* save new id */
123 		mi->CurrentState.storedplaylistid = mi->status->storedplaylist;
124 	}
125 
126 
127 	/* state change */
128 	if(mi->CurrentState.state != mi->status->state)
129 	{
130 		what_changed |= MPD_CST_STATE;
131 		mi->CurrentState.state = mi->status->state;
132 	}
133 
134 	if(mi->CurrentState.songid != mi->status->songid)
135 	{
136 		/* print debug message */
137 		debug_printf(DEBUG_INFO, "Songid has changed %i %i!", mi->OldState.songid, mi->status->songid);
138 
139 		what_changed |= MPD_CST_SONGID;
140 		/* save new songid */
141 		mi->CurrentState.songid = mi->status->songid;
142 
143 	}
144 	if(mi->CurrentState.songpos != mi->status->song)
145 	{
146 		/* print debug message */
147 		debug_printf(DEBUG_INFO, "Songpos has changed %i %i!", mi->OldState.songpos, mi->status->song);
148 
149 		what_changed |= MPD_CST_SONGPOS;
150 		/* save new songid */
151 		mi->CurrentState.songpos = mi->status->song;
152 
153 	}
154     if(mi->CurrentState.nextsongid != mi->status->nextsongid || mi->CurrentState.nextsongpos != mi->status->nextsong)
155     {
156 		what_changed |= MPD_CST_NEXTSONG;
157 		/* save new songid */
158 		mi->CurrentState.nextsongpos = mi->status->nextsong;
159         mi->CurrentState.nextsongid = mi->status->nextsongid;
160     }
161 
162 	if(mi->CurrentState.single != mi->status->single)
163 	{
164 		what_changed |= MPD_CST_SINGLE_MODE;
165 		mi->CurrentState.single = mi->status->single;
166 	}
167 	if(mi->CurrentState.consume != mi->status->consume)
168 	{
169 		what_changed |= MPD_CST_CONSUME_MODE;
170 		mi->CurrentState.consume = mi->status->consume;
171 	}
172 	if(mi->CurrentState.repeat != mi->status->repeat)
173 	{
174 		what_changed |= MPD_CST_REPEAT;
175 		mi->CurrentState.repeat = mi->status->repeat;
176 	}
177 	if(mi->CurrentState.random != mi->status->random)
178 	{
179 		what_changed |= MPD_CST_RANDOM;
180 		mi->CurrentState.random = mi->status->random;
181 	}
182 	if(mi->CurrentState.volume != mi->status->volume)
183 	{
184 		what_changed |= MPD_CST_VOLUME;
185 		mi->CurrentState.volume = mi->status->volume;
186 	}
187 	if(mi->CurrentState.xfade != mi->status->crossfade)
188 	{
189 		what_changed |= MPD_CST_CROSSFADE;
190 		mi->CurrentState.xfade = mi->status->crossfade;
191 	}
192 	if(mi->CurrentState.totaltime != mi->status->totalTime)
193 	{
194 		what_changed |= MPD_CST_TOTAL_TIME;
195 		mi->CurrentState.totaltime = mi->status->totalTime;
196 	}
197 	if(mi->CurrentState.elapsedtime != mi->status->elapsedTime)
198 	{
199 		what_changed |= MPD_CST_ELAPSED_TIME;
200 		mi->CurrentState.elapsedtime = mi->status->elapsedTime;
201 	}
202 
203 	/* Check if bitrate changed, happens with vbr encodings. */
204 	if(mi->CurrentState.bitrate != mi->status->bitRate)
205 	{
206 		what_changed |= MPD_CST_BITRATE;
207 		mi->CurrentState.bitrate = mi->status->bitRate;
208 	}
209 
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)
213 	{
214 		what_changed |= MPD_CST_AUDIOFORMAT;
215 		mi->CurrentState.samplerate = mi->status->sampleRate;
216 	}
217 
218 	/* check if the sampling depth changed */
219 	if(mi->CurrentState.bits != mi->status->bits)
220 	{
221 		what_changed |= MPD_CST_AUDIOFORMAT;
222 		mi->CurrentState.bits = mi->status->bits;
223 	}
224 
225 	/* Check if the amount of audio channels changed */
226 	if(mi->CurrentState.channels != mi->status->channels)
227 	{
228 		what_changed |= MPD_CST_AUDIOFORMAT;
229 		mi->CurrentState.channels = mi->status->channels;
230 	}
231 
232     if(mi->status->error)
233     {
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);
238     }
239     else
240     {
241         mi->CurrentState.error[0] ='\0';
242     }
243 
244 	/* Check if the updating changed,
245 	 * If it stopped, also update the stats for the new db-time.
246 	 */
247 	if(mi->CurrentState.updatingDb != mi->status->updatingDb )
248 	{
249 		what_changed |= MPD_CST_UPDATING;
250 		if(!mi->status->updatingDb)
251 		{
252 			mpd_stats_update_real(mi, &what_changed);
253 		}
254 		mi->CurrentState.updatingDb = mi->status->updatingDb;
255 	}
256 
257 
258     mi->CurrentState.playlistLength = mi->status->playlistLength;
259 
260 
261     /* Detect changed outputs */
262     if(!mi->has_idle)
263     {
264         if(mi->num_outputs >0 )
265         {
266             mpd_OutputEntity *output = NULL;
267             mpd_sendOutputsCommand(mi->connection);
268             while (( output = mpd_getNextOutput(mi->connection)) != NULL)
269             {
270                 if(mi->num_outputs < output->id)
271                 {
272                     mi->num_outputs++;
273                     mi->output_states = realloc(mi->output_states,mi->num_outputs*sizeof(int));
274                     mi->output_states[mi->num_outputs] = output->enabled;
275                     what_changed |= MPD_CST_OUTPUT;
276                 }
277                 if(mi->output_states[output->id] != output->enabled)
278                 {
279                     mi->output_states[output->id] = output->enabled;
280                     what_changed |= MPD_CST_OUTPUT;
281                 }
282                 mpd_freeOutputElement(output);
283             }
284             mpd_finishCommand(mi->connection);
285         }
286         else
287         {
288             /* if no outputs, lets fetch them */
289             mpd_server_update_outputs(mi);
290             if(mi->num_outputs == 0)
291             {
292                 assert("No outputs defined? that cannot be\n");
293             }
294             what_changed |= MPD_CST_OUTPUT;
295         }
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)
305                 {
306                     update_stats = 1;
307                 }
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;
315                 /* This means repeat,random, replaygain or crossface changed */
316             }else if (strcmp (name, "options") == 0) {
317                 what_changed |= MPD_CST_REPLAYGAIN;
318             }
319 
320             free(name);
321        }
322        mpd_finishCommand(mi->connection);
323        if(update_stats) {
324            mpd_stats_update_real(mi, &what_changed);
325        }
326     }
327 
328 
329 	/* Run the callback */
330 	if((mi->the_status_changed_callback != NULL) && what_changed)
331 	{
332 		mi->the_status_changed_callback( mi, what_changed, mi->the_status_changed_signal_userdata );
333 	}
334 
335         /* We could have lost connection again during signal handling... so before we return check again if we are connected */
336 	if(!mpd_check_connected(mi))
337 	{
338 		return MPD_NOT_CONNECTED;
339 	}
340 	return MPD_OK;
341 }
342 
343 /* returns TRUE when status is availible, when not availible and connected it tries to grab it */
mpd_status_check(MpdObj * mi)344 int mpd_status_check(MpdObj *mi)
345 {
346 	if(!mpd_check_connected(mi))
347 	{
348 		debug_printf(DEBUG_INFO,"not connected\n");
349 		return MPD_NOT_CONNECTED;
350 	}
351 	if(mi->status == NULL)
352 	{
353 		/* try to update */
354 		if(mpd_status_update(mi))
355 		{
356 			debug_printf(DEBUG_INFO, "failed to update status\n");
357 			return MPD_STATUS_FAILED;
358 		}
359 	}
360 	return MPD_OK;
361 }
362 
363 
mpd_stats_get_total_songs(MpdObj * mi)364 int mpd_stats_get_total_songs(MpdObj *mi)
365 {
366 	if(mi == NULL)
367 	{
368 		debug_printf(DEBUG_ERROR, "failed to check mi == NULL\n");
369 		return MPD_ARGS_ERROR;
370 	}
371 	if(mpd_stats_check(mi) != MPD_OK)
372 	{
373 		debug_printf(DEBUG_ERROR,"Failed to get status\n");
374 		return MPD_STATUS_FAILED;
375 	}
376 	return mi->stats->numberOfSongs;
377 }
378 
mpd_stats_get_total_artists(MpdObj * mi)379 int mpd_stats_get_total_artists(MpdObj *mi)
380 {
381 	if(mi == NULL)
382 	{
383 		debug_printf(DEBUG_ERROR, "failed to check mi == NULL\n");
384 		return MPD_ARGS_ERROR;
385 	}
386 	if(mpd_stats_check(mi) != MPD_OK)
387 	{
388 		debug_printf(DEBUG_ERROR,"Failed to get status\n");
389 		return MPD_STATS_FAILED;
390 	}
391 	return mi->stats->numberOfArtists;
392 }
393 
mpd_stats_get_total_albums(MpdObj * mi)394 int mpd_stats_get_total_albums(MpdObj *mi)
395 {
396 	if(mi == NULL)
397 	{
398 		debug_printf(DEBUG_ERROR,"failed to check mi == NULL\n");
399 		return MPD_ARGS_ERROR;
400 	}
401 	if(mpd_stats_check(mi) != MPD_OK)
402 	{
403 		debug_printf(DEBUG_WARNING,"Failed to get status\n");
404 		return MPD_STATS_FAILED;
405 	}
406 	return mi->stats->numberOfAlbums;
407 }
408 
409 
mpd_stats_get_uptime(MpdObj * mi)410 int mpd_stats_get_uptime(MpdObj *mi)
411 {
412 	if(mi == NULL)
413 	{
414 		debug_printf(DEBUG_ERROR,"failed to check mi == NULL\n");
415 		return MPD_ARGS_ERROR;
416 	}
417 	if(mpd_stats_check(mi) != MPD_OK)
418 	{
419 		debug_printf(DEBUG_WARNING,"Failed to get status\n");
420 		return MPD_STATS_FAILED;
421 	}
422 	return mi->stats->uptime;
423 }
424 
mpd_stats_get_playtime(MpdObj * mi)425 int mpd_stats_get_playtime(MpdObj *mi)
426 {
427 	if(mi == NULL)
428 	{
429 		debug_printf(DEBUG_ERROR, "failed to check mi == NULL\n");
430 		return MPD_ARGS_ERROR;
431 	}
432 	if(mpd_stats_check(mi) != MPD_OK)
433 	{
434 		debug_printf(DEBUG_WARNING,"Failed to get status\n");
435 		return MPD_STATS_FAILED;
436 	}
437 	return mi->stats->playTime;
438 }
439 
mpd_stats_get_db_playtime(MpdObj * mi)440 int mpd_stats_get_db_playtime(MpdObj *mi)
441 {
442 	if(mi == NULL)
443 	{
444 		debug_printf(DEBUG_ERROR, "failed to check mi == NULL\n");
445 		return MPD_ARGS_ERROR;
446 	}
447 	if(mpd_stats_check(mi) != MPD_OK)
448 	{
449 		debug_printf(DEBUG_WARNING,"Failed to get stats\n");
450 		return MPD_STATS_FAILED;
451 	}
452 	return mi->stats->dbPlayTime;
453 }
454 
455 
456 
457 
458 
459 
460 
461 
462 
463 
464 
465 
466 
467 
468 
469 
470 
mpd_status_get_volume(MpdObj * mi)471 int mpd_status_get_volume(MpdObj *mi)
472 {
473 	if(mi == NULL)
474 	{
475 		debug_printf(DEBUG_ERROR, "failed to check mi == NULL\n");
476 		return MPD_ARGS_ERROR;
477 	}
478 	if(mpd_status_check(mi) != MPD_OK)
479 	{
480 		debug_printf(DEBUG_WARNING, "Failed to get status\n");
481 		return MPD_STATUS_FAILED;
482 	}
483 	return mi->status->volume;
484 }
485 
486 
mpd_status_get_bitrate(MpdObj * mi)487 int mpd_status_get_bitrate(MpdObj *mi)
488 {
489 	if(mi == NULL)
490 	{
491 		debug_printf(DEBUG_ERROR,"failed to check mi == NULL\n");
492 		return MPD_ARGS_ERROR;
493 	}
494 	if(mpd_status_check(mi) != MPD_OK)
495 	{
496 		debug_printf(DEBUG_WARNING, "Failed to get status\n");
497 		return MPD_STATUS_FAILED;
498 	}
499 	return mi->CurrentState.bitrate;
500 }
501 
mpd_status_get_channels(MpdObj * mi)502 int mpd_status_get_channels(MpdObj *mi)
503 {
504 	if(mi == NULL)
505 	{
506 		debug_printf(DEBUG_ERROR,"failed to check mi == NULL\n");
507 		return MPD_ARGS_ERROR;
508 	}
509 	if(mpd_status_check(mi) != MPD_OK)
510 	{
511 		debug_printf(DEBUG_WARNING, "Failed to get status\n");
512 		return MPD_STATUS_FAILED;
513 	}
514 	return mi->CurrentState.channels;
515 }
516 
mpd_status_get_samplerate(MpdObj * mi)517 unsigned int mpd_status_get_samplerate(MpdObj *mi)
518 {
519 	if(mi == NULL)
520 	{
521 		debug_printf(DEBUG_ERROR,"failed to check mi == NULL\n");
522 		return MPD_ARGS_ERROR;
523 	}
524 	if(mpd_status_check(mi) != MPD_OK)
525 	{
526 		debug_printf(DEBUG_WARNING, "Failed to get status\n");
527 		return MPD_STATUS_FAILED;
528 	}
529 	return mi->CurrentState.samplerate;
530 }
531 
mpd_status_get_bits(MpdObj * mi)532 int mpd_status_get_bits(MpdObj *mi)
533 {
534 	if(mi == NULL)
535 	{
536 		debug_printf(DEBUG_WARNING,"failed to check mi == NULL\n");
537 		return MPD_ARGS_ERROR;
538 	}
539 	if(mpd_status_check(mi) != MPD_OK)
540 	{
541 		debug_printf(DEBUG_WARNING, "Failed to get status\n");
542 		return MPD_STATUS_FAILED;
543 	}
544 	return mi->CurrentState.bits;
545 }
546 
mpd_status_get_mpd_error(MpdObj * mi)547 char * mpd_status_get_mpd_error(MpdObj *mi)
548 {
549     if(mi->CurrentState.error[0] != '\0')
550     {
551         return strdup(mi->CurrentState.error);
552     }
553     return NULL;
554 }
555 
mpd_status_db_is_updating(MpdObj * mi)556 int mpd_status_db_is_updating(MpdObj *mi)
557 {
558 	if(!mpd_check_connected(mi))
559 	{
560 		debug_printf(DEBUG_WARNING, "mpd_check_connected failed.\n");
561 		return FALSE;
562 	}
563 	return mi->CurrentState.updatingDb;
564 }
565 
566 
mpd_status_get_total_song_time(MpdObj * mi)567 int mpd_status_get_total_song_time(MpdObj *mi)
568 {
569 	if(!mpd_check_connected(mi))
570 	{
571 		debug_printf(DEBUG_ERROR, "failed to check mi == NULL\n");
572 		return MPD_ARGS_ERROR;
573 	}
574 	if(mpd_status_check(mi) != MPD_OK)
575 	{
576 		debug_printf(DEBUG_WARNING, "Failed to get status\n");
577 		return MPD_STATUS_FAILED;
578 	}
579 	return mi->status->totalTime;
580 }
581 
582 
mpd_status_get_elapsed_song_time(MpdObj * mi)583 int mpd_status_get_elapsed_song_time(MpdObj *mi)
584 {
585 	if(!mpd_check_connected(mi))
586 	{
587 		debug_printf(DEBUG_WARNING,"failed to check mi == NULL\n");
588 		return MPD_NOT_CONNECTED;
589 	}
590 	if(mpd_status_check(mi) != MPD_OK)
591 	{
592 		debug_printf(DEBUG_WARNING,"Failed to get status\n");
593 		return MPD_STATUS_FAILED;
594 	}
595 	return mi->status->elapsedTime;
596 }
597 
mpd_status_set_volume(MpdObj * mi,int volume)598 int mpd_status_set_volume(MpdObj *mi,int volume)
599 {
600 	if(!mpd_check_connected(mi))
601 	{
602 		debug_printf(DEBUG_WARNING,"not connected\n");
603 		return MPD_NOT_CONNECTED;
604 	}
605 	/* making sure volume is between 0 and 100 */
606 	volume = (volume < 0)? 0:(volume>100)? 100:volume;
607 
608 	if(mpd_lock_conn(mi))
609 	{
610 		debug_printf(DEBUG_ERROR,"lock failed\n");
611 		return MPD_LOCK_FAILED;
612 	}
613 
614 	/* send the command */
615 	mpd_sendSetvolCommand(mi->connection , volume);
616 	mpd_finishCommand(mi->connection);
617 	/* check for errors */
618 
619 	mpd_unlock_conn(mi);
620 	/* update status, because we changed it */
621 	mpd_status_queue_update(mi);
622 	/* return current volume */
623 	return mpd_status_get_volume(mi);
624 }
625 
mpd_status_get_crossfade(MpdObj * mi)626 int mpd_status_get_crossfade(MpdObj *mi)
627 {
628 	if(!mpd_check_connected(mi))
629 	{
630 		debug_printf(DEBUG_WARNING,"not connected\n");
631 		return MPD_NOT_CONNECTED;
632 	}
633 	if(mpd_status_check(mi) != MPD_OK)
634 	{
635 		debug_printf(DEBUG_WARNING,"Failed grabbing status\n");
636 		return MPD_NOT_CONNECTED;
637 	}
638 	return mi->status->crossfade;
639 }
640 
mpd_status_set_crossfade(MpdObj * mi,int crossfade_time)641 int mpd_status_set_crossfade(MpdObj *mi,int crossfade_time)
642 {
643 	if(!mpd_check_connected(mi))
644 	{
645 		debug_printf(DEBUG_WARNING,"not connected\n");
646 		return MPD_NOT_CONNECTED;
647 	}
648 	if(mpd_lock_conn(mi))
649 	{
650 		debug_printf(DEBUG_ERROR,"lock failed\n");
651 		return MPD_LOCK_FAILED;
652 	}
653 	mpd_sendCrossfadeCommand(mi->connection, crossfade_time);
654 	mpd_finishCommand(mi->connection);
655 
656 	mpd_unlock_conn(mi);
657 	mpd_status_queue_update(mi);
658 	return MPD_OK;
659 }
660 
661 
mpd_status_set_volume_as_float(MpdObj * mi,float fvol)662 float mpd_status_set_volume_as_float(MpdObj *mi, float fvol)
663 {
664 	int volume = mpd_status_set_volume(mi, (int)(fvol*100.0));
665 	if(volume > -1)
666 	{
667 		return (float)volume/100.0;
668 	}
669 	return (float)volume;
670 }
671 
mpd_stats_update(MpdObj * mi)672 int mpd_stats_update(MpdObj *mi)
673 {
674 	return mpd_stats_update_real(mi, NULL);
675 }
676 
mpd_stats_update_real(MpdObj * mi,ChangedStatusType * what_changed)677 int mpd_stats_update_real(MpdObj *mi, ChangedStatusType* what_changed)
678 {
679 	ChangedStatusType what_changed_here = 0;
680 	if ( what_changed == NULL ) {
681 		/* we need to save the current state, because we're called standalone */
682 		memcpy(&(mi->OldState), &(mi->CurrentState), sizeof(MpdServerState));
683 	}
684 
685 	if(!mpd_check_connected(mi))
686 	{
687 		debug_printf(DEBUG_INFO,"not connected\n");
688 		return MPD_NOT_CONNECTED;
689 	}
690 	if(mpd_lock_conn(mi))
691 	{
692 		debug_printf(DEBUG_ERROR,"lock failed\n");
693 		return MPD_LOCK_FAILED;
694 	}
695 
696 	if(mi->stats != NULL)
697 	{
698 		mpd_freeStats(mi->stats);
699 	}
700 	mpd_sendStatsCommand(mi->connection);
701 	mi->stats = mpd_getStats(mi->connection);
702 	if(mi->stats == NULL)
703 	{
704 		debug_printf(DEBUG_ERROR,"Failed to grab stats from mpd\n");
705 	}
706 	else if(mi->stats->dbUpdateTime != mi->OldState.dbUpdateTime)
707 	{
708 		debug_printf(DEBUG_INFO, "database updated\n");
709 		what_changed_here |= MPD_CST_DATABASE;
710 
711 		mi->CurrentState.dbUpdateTime = mi->stats->dbUpdateTime;
712 	}
713 
714 	if (what_changed) {
715 		(*what_changed) |= what_changed_here;
716 	} else {
717 		if((mi->the_status_changed_callback != NULL) & what_changed_here)
718 		{
719 			mi->the_status_changed_callback(mi, what_changed_here, mi->the_status_changed_signal_userdata);
720 		}
721 	}
722 
723 	if(mpd_unlock_conn(mi))
724 	{
725 		debug_printf(DEBUG_ERROR, "unlock failed");
726 		return MPD_LOCK_FAILED;
727 	}
728 	return MPD_OK;
729 }
730 
731 
mpd_stats_check(MpdObj * mi)732 int mpd_stats_check(MpdObj *mi)
733 {
734 	if(!mpd_check_connected(mi))
735 	{
736 		debug_printf(DEBUG_WARNING,"not connected\n");
737 		return MPD_NOT_CONNECTED;
738 	}
739 	if(mi->stats == NULL)
740 	{
741 		/* try to update */
742 		if(mpd_stats_update(mi))
743 		{
744 			debug_printf(DEBUG_ERROR,"failed to update status\n");
745 			return MPD_STATUS_FAILED;
746 		}
747 	}
748 	return MPD_OK;
749 }
750