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