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