Reformatted all 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                 return;
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                 return 0;
115         }
116
117         timed_thread_destroy(info.audacious.p_timed_thread,
118                 &info.audacious.p_timed_thread);
119
120         return 0;
121 }
122
123 /* ---------------------------------------------------
124  * Worker thread function for audacious data sampling.
125  * --------------------------------------------------- */
126 void *audacious_thread_func(void *pvoid)
127 {
128         static audacious_t items;
129         gint playpos, frames, length;
130         gint rate, freq, chans;
131         gchar *psong, *pfilename;
132
133 #ifndef AUDACIOUS_LEGACY
134         DBusGProxy *session = NULL;
135         DBusGConnection *connection = NULL;
136 #else
137         gint session;
138 #endif
139
140         pvoid = (void *) pvoid; /* avoid warning */
141         session = 0;
142         psong = NULL;
143         pfilename = NULL;
144
145 #ifndef AUDACIOUS_LEGACY
146         g_type_init();
147         connection = dbus_g_bus_get(DBUS_BUS_SESSION, NULL);
148         if (!connection) {
149                 CRIT_ERR("unable to establish dbus connection");
150         }
151         session = dbus_g_proxy_new_for_name(connection, AUDACIOUS_DBUS_SERVICE,
152                 AUDACIOUS_DBUS_PATH, AUDACIOUS_DBUS_INTERFACE);
153         if (!session) {
154                 CRIT_ERR("unable to create dbus proxy");
155         }
156 #endif /* AUDACIOUS_LEGACY */
157
158         /* Loop until the main thread resets the runnable signal. */
159         while (1) {
160
161                 if (!audacious_remote_is_running(session)) {
162                         memset(&items, 0, sizeof(items));
163                         strcpy(items[AUDACIOUS_STATUS], "Not running");
164                         goto bottom;
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
238 bottom:
239
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)) {
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 }