* Applied 2 patches:
[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                 if (!audacious_remote_is_running(session)) {
166                         memset(&items, 0, sizeof(items));
167                         strcpy(items[AUDACIOUS_STATUS], "Not running");
168                         goto bottom;
169                 }
170
171                 /* Player status */
172                 if (audacious_remote_is_paused(session)) {
173                         strcpy(items[AUDACIOUS_STATUS], "Paused");
174                 } else if (audacious_remote_is_playing(session)) {
175                         strcpy(items[AUDACIOUS_STATUS], "Playing");
176                 } else {
177                         strcpy(items[AUDACIOUS_STATUS], "Stopped");
178                 }
179
180                 /* Current song title */
181                 playpos = audacious_remote_get_playlist_pos(session);
182                 psong = audacious_remote_get_playlist_title(session, playpos);
183                 if (psong) {
184                         strncpy(items[AUDACIOUS_TITLE], psong,
185                                 sizeof(items[AUDACIOUS_TITLE]) - 1);
186                         g_free(psong);
187                         psong = NULL;
188                 }
189
190                 /* Current song length as MM:SS */
191                 frames = audacious_remote_get_playlist_time(session, playpos);
192                 length = frames / 1000;
193                 snprintf(items[AUDACIOUS_LENGTH], sizeof(items[AUDACIOUS_LENGTH]) - 1,
194                         "%d:%.2d", length / 60, length % 60);
195
196                 /* Current song length in seconds */
197                 snprintf(items[AUDACIOUS_LENGTH_SECONDS],
198                         sizeof(items[AUDACIOUS_LENGTH_SECONDS]) - 1, "%d", length);
199
200                 /* Current song position as MM:SS */
201                 frames = audacious_remote_get_output_time(session);
202                 length = frames / 1000;
203                 snprintf(items[AUDACIOUS_POSITION],
204                         sizeof(items[AUDACIOUS_POSITION]) - 1, "%d:%.2d", length / 60,
205                         length % 60);
206
207                 /* Current song position in seconds */
208                 snprintf(items[AUDACIOUS_POSITION_SECONDS],
209                         sizeof(items[AUDACIOUS_POSITION_SECONDS]) - 1, "%d", length);
210
211                 /* Current song bitrate */
212                 audacious_remote_get_info(session, &rate, &freq, &chans);
213                 snprintf(items[AUDACIOUS_BITRATE], sizeof(items[AUDACIOUS_BITRATE]) - 1,
214                         "%d", rate);
215
216                 /* Current song frequency */
217                 snprintf(items[AUDACIOUS_FREQUENCY],
218                         sizeof(items[AUDACIOUS_FREQUENCY]) - 1, "%d", freq);
219
220                 /* Current song channels */
221                 snprintf(items[AUDACIOUS_CHANNELS],
222                         sizeof(items[AUDACIOUS_CHANNELS]) - 1, "%d", chans);
223
224                 /* Current song filename */
225                 pfilename = audacious_remote_get_playlist_file(session, playpos);
226                 if (pfilename) {
227                         strncpy(items[AUDACIOUS_FILENAME], pfilename,
228                                 sizeof(items[AUDACIOUS_FILENAME]) - 1);
229                         g_free(pfilename);
230                         pfilename = NULL;
231                 }
232
233                 /* Length of the Playlist (number of songs) */
234                 length = audacious_remote_get_playlist_length(session);
235                 snprintf(items[AUDACIOUS_PLAYLIST_LENGTH],
236                         sizeof(items[AUDACIOUS_PLAYLIST_LENGTH]) - 1, "%d", length);
237
238                 /* Playlist position (index of song) */
239                 snprintf(items[AUDACIOUS_PLAYLIST_POSITION],
240                         sizeof(items[AUDACIOUS_PLAYLIST_POSITION]) - 1, "%d", playpos + 1);
241
242 bottom:
243
244                 /* Deliver the refreshed items array to audacious_items. */
245                 timed_thread_lock(info.audacious.p_timed_thread);
246                 memcpy(&audacious_items, items, sizeof(items));
247                 timed_thread_unlock(info.audacious.p_timed_thread);
248
249                 if (timed_thread_test(info.audacious.p_timed_thread)) {
250 #ifndef AUDACIOUS_LEGACY
251                         /* release reference to dbus proxy */
252                         g_object_unref(session);
253 #endif
254                         timed_thread_exit(info.audacious.p_timed_thread);
255                 }
256         }
257 }