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