* Fixed potential issue on FreeBSD when nprocs < 10 (thanks zotrix)
[monky] / src / xmms2.c
1 /*
2 * xmms2.c: xmms2 stuff for Conky
3 *
4 *
5 */
6
7 #include "conky.h"
8 #include <stdio.h>
9 #include <string.h>
10 #include <stdlib.h>
11 #include <xmmsclient/xmmsclient.h>
12
13 #define CONN_INIT    0
14 #define CONN_OK      1
15 #define CONN_NO      2
16
17 /* callbacks */
18
19 static void xmms_alloc(struct information *ptr)
20 {
21         if (ptr->xmms2.status == NULL) {
22                 ptr->xmms2.status = malloc(TEXT_BUFFER_SIZE);
23                 ptr->xmms2.status[0] = '\0';
24         }
25
26         if (ptr->xmms2.artist == NULL) {
27                 ptr->xmms2.artist = malloc(TEXT_BUFFER_SIZE);
28                 ptr->xmms2.artist[0] = '\0';
29         }
30
31         if (ptr->xmms2.album == NULL) {
32                 ptr->xmms2.album = malloc(TEXT_BUFFER_SIZE);
33                 ptr->xmms2.album[0] = '\0';
34         }
35
36         if (ptr->xmms2.title == NULL) {
37                 ptr->xmms2.title = malloc(TEXT_BUFFER_SIZE);
38                 ptr->xmms2.title[0] = '\0';
39         }
40
41         if (ptr->xmms2.genre == NULL) {
42                 ptr->xmms2.genre = malloc(TEXT_BUFFER_SIZE);
43                 ptr->xmms2.genre[0] = '\0';
44         }
45
46         if (ptr->xmms2.comment == NULL) {
47                 ptr->xmms2.comment = malloc(TEXT_BUFFER_SIZE);
48                 ptr->xmms2.comment[0] = '\0';
49         }
50
51         if (ptr->xmms2.decoder == NULL) {
52                 ptr->xmms2.decoder = malloc(TEXT_BUFFER_SIZE);
53                 ptr->xmms2.decoder[0] = '\0';
54         }
55
56         if (ptr->xmms2.transport == NULL) {
57                 ptr->xmms2.transport = malloc(TEXT_BUFFER_SIZE);
58                 ptr->xmms2.transport[0] = '\0';
59         }
60
61         if (ptr->xmms2.url == NULL) {
62                 ptr->xmms2.url = malloc(TEXT_BUFFER_SIZE);
63                 ptr->xmms2.url[0] = '\0';
64         }
65
66         if (ptr->xmms2.date == NULL) {
67                 ptr->xmms2.date = malloc(TEXT_BUFFER_SIZE);
68                 ptr->xmms2.date[0] = '\0';
69         }
70 }
71
72 static void xmms_clear(struct information *ptr) {
73         xmms_alloc(ptr);
74         ptr->xmms2.status[0] = '\0';
75         ptr->xmms2.artist[0] = '\0';
76         ptr->xmms2.album[0] = '\0';
77         ptr->xmms2.title[0] = '\0';
78         ptr->xmms2.genre[0] = '\0';
79         ptr->xmms2.comment[0] = '\0';
80         ptr->xmms2.decoder[0] = '\0';
81         ptr->xmms2.transport[0] = '\0';
82         ptr->xmms2.url[0] = '\0';
83         ptr->xmms2.date[0] = '\0';
84 }
85
86 void connection_lost(void *p)
87 {
88         struct information *ptr = p;
89         ptr->xmms2_conn_state = CONN_NO;
90
91         xmms_clear(ptr);
92         ptr->xmms2.tracknr = 0;
93         ptr->xmms2.id = 0;
94         ptr->xmms2.bitrate = 0;
95         ptr->xmms2.duration = 0;
96         ptr->xmms2.elapsed = 0;
97         ptr->xmms2.size = 0;
98         ptr->xmms2.progress = 0;
99 }
100
101 void handle_curent_id(xmmsc_result_t *res, void *p)
102 {
103     uint current_id;
104     struct information *ptr = p;
105
106     if ( xmmsc_result_get_uint( res, &current_id ) ) {
107
108         xmmsc_result_t *res2;
109         res2 = xmmsc_medialib_get_info(ptr->xmms2_conn, current_id);
110         xmmsc_result_wait( res2 );
111                 
112         xmms_clear(ptr);
113
114         ptr->xmms2.id = current_id;
115
116         char *temp;
117         xmmsc_result_get_dict_entry_string( res2, "artist", &temp );
118         if ( temp != NULL ) {
119             strncpy(ptr->xmms2.artist, temp, TEXT_BUFFER_SIZE - 1);
120         } else {
121             strncpy(ptr->xmms2.artist, "[Unknown]", TEXT_BUFFER_SIZE - 1);
122         }
123
124
125         xmmsc_result_get_dict_entry_string( res2, "title", &temp );
126         if ( temp != NULL ) {
127             strncpy(ptr->xmms2.title, temp, TEXT_BUFFER_SIZE - 1);
128         } else {
129             strncpy(ptr->xmms2.title, "[Unknown]", TEXT_BUFFER_SIZE - 1);
130         }
131
132         xmmsc_result_get_dict_entry_string( res2, "album", &temp );
133         if ( temp != NULL ) {
134             strncpy(ptr->xmms2.album, temp, TEXT_BUFFER_SIZE - 1);
135         } else {
136             strncpy(ptr->xmms2.album, "[Unknown]", TEXT_BUFFER_SIZE - 1);
137         }
138
139
140         xmmsc_result_get_dict_entry_string( res2, "genre", &temp );
141         if ( temp != NULL ) {
142
143             strncpy(ptr->xmms2.genre, temp, TEXT_BUFFER_SIZE - 1);
144         } else {
145             strncpy(ptr->xmms2.genre, "[Unknown]", TEXT_BUFFER_SIZE - 1);
146         }
147
148
149         xmmsc_result_get_dict_entry_string( res2, "comment", &temp );
150         if ( temp != NULL ) {
151             strncpy(ptr->xmms2.comment, temp, TEXT_BUFFER_SIZE - 1);
152         } else {
153             strncpy(ptr->xmms2.comment, "", TEXT_BUFFER_SIZE - 1);
154         }
155
156
157         xmmsc_result_get_dict_entry_string( res2, "decoder", &temp );
158         if ( temp != NULL ) {
159             strncpy(ptr->xmms2.decoder, temp, TEXT_BUFFER_SIZE - 1);
160         } else {
161             strncpy(ptr->xmms2.decoder, "[Unknown]", TEXT_BUFFER_SIZE - 1);
162         }
163
164
165         xmmsc_result_get_dict_entry_string( res2, "transport", &temp );
166         if ( temp != NULL ) {
167             strncpy(ptr->xmms2.transport, temp, TEXT_BUFFER_SIZE - 1);
168         } else {
169             strncpy(ptr->xmms2.transport, "[Unknown]", TEXT_BUFFER_SIZE - 1);
170         }
171
172
173         xmmsc_result_get_dict_entry_string( res2, "url", &temp );
174         if ( temp != NULL ) {
175             strncpy(ptr->xmms2.url, temp, TEXT_BUFFER_SIZE - 1);
176         } else {
177             strncpy(ptr->xmms2.url, "[Unknown]", TEXT_BUFFER_SIZE - 1);
178         }
179
180
181         xmmsc_result_get_dict_entry_string( res2, "date", &temp );
182         if ( temp != NULL ) {
183             strncpy(ptr->xmms2.date, temp, TEXT_BUFFER_SIZE - 1);
184         } else {
185             strncpy(ptr->xmms2.date, "????", TEXT_BUFFER_SIZE - 1);
186         }
187
188
189         int itemp;
190         xmmsc_result_get_dict_entry_int( res2, "tracknr", &itemp );
191         ptr->xmms2.tracknr = itemp;
192
193         xmmsc_result_get_dict_entry_int( res2, "duration", &itemp );
194         ptr->xmms2.duration = itemp;
195
196         xmmsc_result_get_dict_entry_int( res2, "bitrate", &itemp );
197         ptr->xmms2.bitrate = itemp / 1000;
198
199         xmmsc_result_get_dict_entry_int( res2, "size", &itemp );
200         ptr->xmms2.size = (float)itemp / 1048576;
201
202         xmmsc_result_unref( res2 );
203     }
204 }
205
206 void handle_playtime(xmmsc_result_t *res, void *p) {
207         struct information *ptr = p;
208     xmmsc_result_t * res2;
209     uint play_time;
210
211     if ( xmmsc_result_iserror( res ) )
212         return;
213
214     if ( !xmmsc_result_get_uint( res, &play_time ) )
215         return;
216
217     res2 = xmmsc_result_restart( res );
218     xmmsc_result_unref( res2 );
219
220     ptr->xmms2.elapsed = play_time;
221     ptr->xmms2.progress = (float) play_time / ptr->xmms2.duration;
222 }
223
224 void handle_playback_state_change(xmmsc_result_t *res, void *p) {
225         struct information *ptr = p;
226     uint pb_state = 0;
227     if ( xmmsc_result_iserror( res ) )
228         return;
229
230     if ( !xmmsc_result_get_uint( res, &pb_state ) )
231         return;
232
233     switch (pb_state) {
234     case XMMS_PLAYBACK_STATUS_PLAY:
235         strncpy(ptr->xmms2.status, "Playing", TEXT_BUFFER_SIZE - 1);
236         break;
237     case XMMS_PLAYBACK_STATUS_PAUSE:
238         strncpy(ptr->xmms2.status, "Paused", TEXT_BUFFER_SIZE - 1);
239         break;
240     case XMMS_PLAYBACK_STATUS_STOP:
241         strncpy(ptr->xmms2.status, "Stopped", TEXT_BUFFER_SIZE - 1);
242         break;
243     default:
244         strncpy(ptr->xmms2.status, "Unknown", TEXT_BUFFER_SIZE - 1);
245     }
246 }
247
248
249 void update_xmms2() {
250     struct information * current_info = &info;
251
252     /* initialize connection */
253     if ( current_info->xmms2_conn_state == CONN_INIT ) {
254
255         if ( current_info->xmms2_conn == NULL ) {
256             current_info->xmms2_conn = xmmsc_init( "conky" );
257         }
258
259         /* did init fail? */
260         if ( current_info->xmms2_conn == NULL ) {
261             fprintf(stderr,"Conky: xmms2 init failed. %s\n", xmmsc_get_last_error ( current_info->xmms2_conn ));
262             fflush(stderr);
263             return;
264         }
265
266         /* init ok but not connected yet.. */
267         current_info->xmms2_conn_state = CONN_NO;
268
269         /* clear all values */
270                 xmms_clear(current_info);
271
272         current_info->xmms2.tracknr = 0;
273         current_info->xmms2.id = 0;
274         current_info->xmms2.bitrate = 0;
275         current_info->xmms2.duration = 0;
276         current_info->xmms2.elapsed = 0;
277         current_info->xmms2.size = 0;
278         current_info->xmms2.progress = 0;
279
280         /*    fprintf(stderr,"Conky: xmms2 init ok.\n");
281             fflush(stderr); */
282     }
283
284     /* connect */
285     if ( current_info->xmms2_conn_state == CONN_NO ) {
286
287         char *path = getenv ( "XMMS_PATH" );
288         if ( !xmmsc_connect( current_info->xmms2_conn, path ) ) {
289             fprintf(stderr,"Conky: xmms2 connection failed. %s\n",
290                     xmmsc_get_last_error ( current_info->xmms2_conn ));
291             fflush(stderr);
292             current_info->xmms2_conn_state = CONN_NO;
293             return;
294         }
295
296         /* set callbacks */
297         xmmsc_disconnect_callback_set( current_info->xmms2_conn, connection_lost, current_info );
298         XMMS_CALLBACK_SET( current_info->xmms2_conn, xmmsc_playback_current_id, handle_curent_id, current_info );
299         XMMS_CALLBACK_SET( current_info->xmms2_conn, xmmsc_broadcast_playback_current_id, handle_curent_id, current_info );
300         XMMS_CALLBACK_SET( current_info->xmms2_conn, xmmsc_signal_playback_playtime, handle_playtime, current_info );
301         XMMS_CALLBACK_SET( current_info->xmms2_conn, xmmsc_broadcast_playback_status, handle_playback_state_change, current_info );
302
303         /* get playback status, it wont be broadcasted untill it chages */
304         xmmsc_result_t * res = xmmsc_playback_status( current_info->xmms2_conn );
305         xmmsc_result_wait ( res );
306         unsigned int pb_state;
307
308         xmmsc_result_get_uint( res, &pb_state );
309         switch (pb_state) {
310         case XMMS_PLAYBACK_STATUS_PLAY:
311             strncpy(current_info->xmms2.status,
312                      "Playing", TEXT_BUFFER_SIZE - 1 );
313             break;
314         case XMMS_PLAYBACK_STATUS_PAUSE:
315             strncpy( current_info->xmms2.status,
316                      "Paused", TEXT_BUFFER_SIZE - 1 );
317             break;
318         case XMMS_PLAYBACK_STATUS_STOP:
319             strncpy( current_info->xmms2.status,
320                      "Stopped", TEXT_BUFFER_SIZE - 1 );
321             break;
322         default:
323             strncpy( current_info->xmms2.status,
324                      "Unknown", TEXT_BUFFER_SIZE - 1 );
325         }
326         xmmsc_result_unref ( res );
327         
328         /* everything seems to be ok */
329         current_info->xmms2_conn_state = CONN_OK;
330
331         /*   fprintf(stderr,"Conky: xmms2 connected.\n");
332               fflush(stderr);  */
333     }
334
335
336     /* handle callbacks */
337     if ( current_info->xmms2_conn_state == CONN_OK ) {
338         struct timeval tmout;
339         tmout.tv_sec = 0;
340         tmout.tv_usec = 100;
341
342         select( current_info->xmms2_fd + 1, &current_info->xmms2_fdset, NULL, NULL, &tmout );
343
344         xmmsc_io_in_handle(current_info->xmms2_conn);
345         if (xmmsc_io_want_out(current_info->xmms2_conn)) {
346             xmmsc_io_out_handle(current_info->xmms2_conn);
347         }
348     }
349 }