* Getting rid of goto usage throughout code.
[monky] / src / audacious.c
1 /* $Id$ */
2
3 /* audacious.c:  conky support for audacious music player
4  *
5  * Copyright (C) 2005-2007 Philip Kovacs pkovacs@users.sourceforge.net
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301
20  * USA. */
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <stdio.h>
27 #include <string.h>
28
29 #include <glib.h>
30 #ifndef AUDACIOUS_LEGACY
31 #include <glib-object.h>
32 #include <audacious/audctrl.h>
33 #include <audacious/dbus.h>
34 #else
35 #include <audacious/beepctrl.h>
36 #define audacious_remote_is_running(x)                          \
37         xmms_remote_is_running(x)
38 #define audacious_remote_is_paused(x)                           \
39         xmms_remote_is_paused(x)
40 #define audacious_remote_is_playing(x)                          \
41         xmms_remote_is_playing(x)
42 #define audacious_remote_get_playlist_pos(x)            \
43         xmms_remote_get_playlist_pos(x)
44 #define audacious_remote_get_playlist_title(x, y)       \
45         xmms_remote_get_playlist_title(x, y)
46 #define audacious_remote_get_playlist_time(x, y)        \
47         xmms_remote_get_playlist_time(x, y)
48 #define audacious_remote_get_output_time(x)                     \
49         xmms_remote_get_output_time(x)
50 #define audacious_remote_get_info(w, x, y, z)           \
51         xmms_remote_get_info(w, x, y, z)
52 #define audacious_remote_get_playlist_file(x, y)        \
53         xmms_remote_get_playlist_file(x, y)
54 #define audacious_remote_get_playlist_length(x)         \
55         xmms_remote_get_playlist_length(x)
56 #endif
57
58 #include "config.h"
59 #include "conky.h"
60 #include "audacious.h"
61 #include "timed_thread.h"
62
63 /* access to this item array is synchronized */
64 static audacious_t audacious_items;
65
66 /* -----------------------------------------
67  * Conky update function for audacious data.
68  * ----------------------------------------- */
69 void update_audacious(void)
70 {
71         /* The worker thread is updating audacious_items array asynchronously
72          * to the main conky thread.
73          * We merely copy the audacious_items array into the main thread's info
74          * structure when the main thread's update cycle fires. */
75         if (!info.audacious.p_timed_thread) {
76                 if (create_audacious_thread() != 0) {
77                         CRIT_ERR("unable to create audacious thread!");
78                 }
79                 timed_thread_register(info.audacious.p_timed_thread,
80                         &info.audacious.p_timed_thread);
81         }
82
83         timed_thread_lock(info.audacious.p_timed_thread);
84         memcpy(&info.audacious.items, audacious_items, sizeof(audacious_items));
85         timed_thread_unlock(info.audacious.p_timed_thread);
86 }
87
88 /* ---------------------------------------------------------
89  * Create a worker thread for audacious media player status.
90  *
91  * Returns 0 on success, -1 on error.
92  * --------------------------------------------------------- */
93 int create_audacious_thread(void)
94 {
95         if (!info.audacious.p_timed_thread) {
96                 info.audacious.p_timed_thread =
97                         timed_thread_create(audacious_thread_func, NULL,
98                         info.music_player_interval * 1000000);
99         }
100
101         if (!info.audacious.p_timed_thread
102                         || timed_thread_run(info.audacious.p_timed_thread)) {
103                 return -1;
104         }
105
106         return 0;
107 }
108
109 /* ---------------------------------------
110  * Destroy audacious player status thread.
111  *
112  * Returns 0 on success, -1 on error.
113  * --------------------------------------- */
114 int destroy_audacious_thread(void)
115 {
116         /* Is a worker is thread running? If not, no error. */
117         if (!info.audacious.p_timed_thread) {
118                 return 0;
119         }
120
121         timed_thread_destroy(info.audacious.p_timed_thread,
122                 &info.audacious.p_timed_thread);
123
124         return 0;
125 }
126
127 /* ---------------------------------------------------
128  * Worker thread function for audacious data sampling.
129  * --------------------------------------------------- */
130 void *audacious_thread_func(void *pvoid)
131 {
132         static audacious_t items;
133         gint playpos, frames, length;
134         gint rate, freq, chans;
135         gchar *psong, *pfilename;
136
137 #ifndef AUDACIOUS_LEGACY
138         DBusGProxy *session = NULL;
139         DBusGConnection *connection = NULL;
140 #else
141         gint session;
142 #endif
143
144         pvoid = (void *) pvoid; /* avoid warning */
145         session = 0;
146         psong = NULL;
147         pfilename = NULL;
148
149 #ifndef AUDACIOUS_LEGACY
150         g_type_init();
151         connection = dbus_g_bus_get(DBUS_BUS_SESSION, NULL);
152         if (!connection) {
153                 CRIT_ERR("unable to establish dbus connection");
154         }
155         session = dbus_g_proxy_new_for_name(connection, AUDACIOUS_DBUS_SERVICE,
156                         AUDACIOUS_DBUS_PATH, AUDACIOUS_DBUS_INTERFACE);
157         if (!session) {
158                 CRIT_ERR("unable to create dbus proxy");
159         }
160 #endif /* AUDACIOUS_LEGACY */
161
162         /* Loop until the main thread resets the runnable signal. */
163         while (1) {
164
165                 do {
166                         if (!audacious_remote_is_running(session)) {
167                                 memset(&items, 0, sizeof(items));
168                                 strcpy(items[AUDACIOUS_STATUS], "Not running");
169                                 break;
170                         }
171
172                         /* Player status */
173                         if (audacious_remote_is_paused(session)) {
174                                 strcpy(items[AUDACIOUS_STATUS], "Paused");
175                         } else if (audacious_remote_is_playing(session)) {
176                                 strcpy(items[AUDACIOUS_STATUS], "Playing");
177                         } else {
178                                 strcpy(items[AUDACIOUS_STATUS], "Stopped");
179                         }
180
181                         /* Current song title */
182                         playpos = audacious_remote_get_playlist_pos(session);
183                         psong = audacious_remote_get_playlist_title(session, playpos);
184                         if (psong) {
185                                 strncpy(items[AUDACIOUS_TITLE], psong,
186                                                 sizeof(items[AUDACIOUS_TITLE]) - 1);
187                                 g_free(psong);
188                                 psong = NULL;
189                         }
190
191                         /* Current song length as MM:SS */
192                         frames = audacious_remote_get_playlist_time(session, playpos);
193                         length = frames / 1000;
194                         snprintf(items[AUDACIOUS_LENGTH], sizeof(items[AUDACIOUS_LENGTH]) - 1,
195                                         "%d:%.2d", length / 60, length % 60);
196
197                         /* Current song length in seconds */
198                         snprintf(items[AUDACIOUS_LENGTH_SECONDS],
199                                         sizeof(items[AUDACIOUS_LENGTH_SECONDS]) - 1, "%d", length);
200
201                         /* Current song position as MM:SS */
202                         frames = audacious_remote_get_output_time(session);
203                         length = frames / 1000;
204                         snprintf(items[AUDACIOUS_POSITION],
205                                         sizeof(items[AUDACIOUS_POSITION]) - 1, "%d:%.2d", length / 60,
206                                         length % 60);
207
208                         /* Current song position in seconds */
209                         snprintf(items[AUDACIOUS_POSITION_SECONDS],
210                                         sizeof(items[AUDACIOUS_POSITION_SECONDS]) - 1, "%d", length);
211
212                         /* Current song bitrate */
213                         audacious_remote_get_info(session, &rate, &freq, &chans);
214                         snprintf(items[AUDACIOUS_BITRATE], sizeof(items[AUDACIOUS_BITRATE]) - 1,
215                                         "%d", rate);
216
217                         /* Current song frequency */
218                         snprintf(items[AUDACIOUS_FREQUENCY],
219                                         sizeof(items[AUDACIOUS_FREQUENCY]) - 1, "%d", freq);
220
221                         /* Current song channels */
222                         snprintf(items[AUDACIOUS_CHANNELS],
223                                         sizeof(items[AUDACIOUS_CHANNELS]) - 1, "%d", chans);
224
225                         /* Current song filename */
226                         pfilename = audacious_remote_get_playlist_file(session, playpos);
227                         if (pfilename) {
228                                 strncpy(items[AUDACIOUS_FILENAME], pfilename,
229                                                 sizeof(items[AUDACIOUS_FILENAME]) - 1);
230                                 g_free(pfilename);
231                                 pfilename = NULL;
232                         }
233
234                         /* Length of the Playlist (number of songs) */
235                         length = audacious_remote_get_playlist_length(session);
236                         snprintf(items[AUDACIOUS_PLAYLIST_LENGTH],
237                                         sizeof(items[AUDACIOUS_PLAYLIST_LENGTH]) - 1, "%d", length);
238
239                         /* Playlist position (index of song) */
240                         snprintf(items[AUDACIOUS_PLAYLIST_POSITION],
241                                         sizeof(items[AUDACIOUS_PLAYLIST_POSITION]) - 1, "%d", playpos + 1);
242                 } while (0);
243                 /* Deliver the refreshed items array to audacious_items. */
244                 timed_thread_lock(info.audacious.p_timed_thread);
245                 memcpy(&audacious_items, items, sizeof(items));
246                 timed_thread_unlock(info.audacious.p_timed_thread);
247
248                 if (timed_thread_test(info.audacious.p_timed_thread)) {
249 #ifndef AUDACIOUS_LEGACY
250                         /* release reference to dbus proxy */
251                         g_object_unref(session);
252 #endif
253                         timed_thread_exit(info.audacious.p_timed_thread);
254                 }
255         }
256 }