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