1 /*
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  */
23 
24 #include <config.h>
25 
26 #include <cmath>
27 
28 #include <mutex>
29 #include "audacious.h"
30 #include "conky.h"
31 #include "logging.h"
32 #include "update-cb.hh"
33 
34 #include <glib.h>
35 #ifdef NEW_AUDACIOUS_FOUND
36 #include <audacious/audctrl.h>
37 #include <audacious/dbus.h>
38 #include <glib-object.h>
39 #else /* NEW_AUDACIOUS_FOUND */
40 #include <audacious/beepctrl.h>
41 #define audacious_remote_is_running(x) xmms_remote_is_running(x)
42 #define audacious_remote_is_paused(x) xmms_remote_is_paused(x)
43 #define audacious_remote_is_playing(x) xmms_remote_is_playing(x)
44 #define audacious_remote_get_playlist_pos(x) 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) xmms_remote_get_output_time(x)
50 #define audacious_remote_get_info(w, x, y, z) xmms_remote_get_info(w, x, y, z)
51 #define audacious_remote_get_playlist_file(x, y) \
52   xmms_remote_get_playlist_file(x, y)
53 #define audacious_remote_get_playlist_length(x) \
54   xmms_remote_get_playlist_length(x)
55 #endif /* NEW_AUDACIOUS_FOUND */
56 
57 namespace {
58 
59 enum aud_status { AS_NOT_RUNNING, AS_PAUSED, AS_PLAYING, AS_STOPPED };
60 const char *const as_message[] = {"Not running", "Paused", "Playing",
61                                   "Stopped"};
62 
63 struct aud_result {
64   std::string title;
65   std::string filename;
66   int length;    // in ms
67   int position;  // in ms
68   int bitrate;
69   int frequency;
70   int channels;
71   int playlist_length;
72   int playlist_position;
73   int main_volume;
74   aud_status status;
75 
aud_result__anon28330d850111::aud_result76   aud_result()
77       : length(0),
78         position(0),
79         bitrate(0),
80         frequency(0),
81         channels(0),
82         playlist_length(0),
83         playlist_position(0),
84         main_volume(0),
85         status(AS_NOT_RUNNING) {}
86 };
87 
88 class audacious_cb : public conky::callback<aud_result> {
89   typedef conky::callback<aud_result> Base;
90 
91 #ifdef NEW_AUDACIOUS_FOUND
92   DBusGProxy *session;
93 #else
94   gint session;
95 #endif
96 
97  protected:
98   virtual void work();
99 
100  public:
audacious_cb(uint32_t period)101   audacious_cb(uint32_t period) : Base(period, false, Tuple()) {
102 #ifdef NEW_AUDACIOUS_FOUND
103     DBusGConnection *connection = dbus_g_bus_get(DBUS_BUS_SESSION, nullptr);
104     if (!connection)
105       throw std::runtime_error("unable to establish dbus connection");
106 
107     session = dbus_g_proxy_new_for_name(connection, AUDACIOUS_DBUS_SERVICE,
108                                         AUDACIOUS_DBUS_PATH,
109                                         AUDACIOUS_DBUS_INTERFACE);
110     if (!session) throw std::runtime_error("unable to create dbus proxy");
111 #else
112     session = 0;
113 #endif /* NEW_AUDACIOUS_FOUND */
114   }
115 
116 #ifdef NEW_AUDACIOUS_FOUND
~audacious_cb()117   ~audacious_cb() {
118     /* release reference to dbus proxy */
119     g_object_unref(session);
120   }
121 #endif
122 };
123 
124 /* ---------------------------------------------------
125  * Worker thread function for audacious data sampling.
126  * --------------------------------------------------- */
work()127 void audacious_cb::work() {
128   aud_result tmp;
129   gchar *psong, *pfilename;
130   psong = nullptr;
131   pfilename = nullptr;
132 
133   do {
134     if (!audacious_remote_is_running(session)) {
135       tmp.status = AS_NOT_RUNNING;
136       break;
137     }
138 
139     /* Player status */
140     if (audacious_remote_is_paused(session)) {
141       tmp.status = AS_PAUSED;
142     } else if (audacious_remote_is_playing(session)) {
143       tmp.status = AS_PLAYING;
144     } else {
145       tmp.status = AS_STOPPED;
146     }
147 
148     /* Current song title */
149     tmp.playlist_position = audacious_remote_get_playlist_pos(session);
150     psong = audacious_remote_get_playlist_title(session, tmp.playlist_position);
151     if (psong) {
152       tmp.title = psong;
153       g_free(psong);
154     }
155 
156     /* Current song length */
157     tmp.length =
158         audacious_remote_get_playlist_time(session, tmp.playlist_position);
159 
160     /* Current song position */
161     tmp.position = audacious_remote_get_output_time(session);
162 
163     /* Current song bitrate, frequency, channels */
164     audacious_remote_get_info(session, &tmp.bitrate, &tmp.frequency,
165                               &tmp.channels);
166 
167     /* Current song filename */
168     pfilename =
169         audacious_remote_get_playlist_file(session, tmp.playlist_position);
170     if (pfilename) {
171       tmp.filename = pfilename;
172       g_free(pfilename);
173     }
174 
175     /* Length of the Playlist (number of songs) */
176     tmp.playlist_length = audacious_remote_get_playlist_length(session);
177 
178     /* Main volume */
179     tmp.main_volume = audacious_remote_get_main_volume(session);
180   } while (0);
181   {
182     /* Deliver the refreshed items array to audacious_items. */
183     std::lock_guard<std::mutex> lock(result_mutex);
184     result = tmp;
185   }
186 }
187 
get_res()188 aud_result get_res() {
189   uint32_t period = std::max(
190       lround(music_player_interval.get(*state) / active_update_interval()), 1l);
191   return conky::register_cb<audacious_cb>(period)->get_result_copy();
192 }
193 }  // namespace
194 
print_audacious_status(struct text_object *,char * p,unsigned int p_max_size)195 void print_audacious_status(struct text_object *, char *p,
196                             unsigned int p_max_size) {
197   const aud_result &res = get_res();
198   snprintf(p, p_max_size, "%s", as_message[res.status]);
199 }
200 
print_audacious_title(struct text_object * obj,char * p,unsigned int p_max_size)201 void print_audacious_title(struct text_object *obj, char *p,
202                            unsigned int p_max_size) {
203   snprintf(p, std::min((unsigned int)obj->data.i, p_max_size), "%s",
204            get_res().title.c_str());
205 }
206 
print_audacious_filename(struct text_object * obj,char * p,unsigned int p_max_size)207 void print_audacious_filename(struct text_object *obj, char *p,
208                               unsigned int p_max_size) {
209   snprintf(p, std::min((unsigned int)obj->data.i, p_max_size), "%s",
210            get_res().filename.c_str());
211 }
212 
audacious_barval(struct text_object *)213 double audacious_barval(struct text_object *) {
214   const aud_result &res = get_res();
215   return (double)res.position / res.length;
216 }
217 
print_audacious_length(struct text_object *,char * p,unsigned int p_max_size)218 void print_audacious_length(struct text_object *, char *p,
219                             unsigned int p_max_size) {
220   const aud_result &res = get_res();
221   int sec = res.length / 1000;
222   snprintf(p, p_max_size, "%d:%.2d", sec / 60, sec % 60);
223 }
224 
print_audacious_length_seconds(struct text_object *,char * p,unsigned int p_max_size)225 void print_audacious_length_seconds(struct text_object *, char *p,
226                                     unsigned int p_max_size) {
227   snprintf(p, p_max_size, "%d", get_res().length);
228 }
229 
print_audacious_position(struct text_object *,char * p,unsigned int p_max_size)230 void print_audacious_position(struct text_object *, char *p,
231                               unsigned int p_max_size) {
232   const aud_result &res = get_res();
233   int sec = res.position / 1000;
234   snprintf(p, p_max_size, "%d:%.2d", sec / 60, sec % 60);
235 }
236 
print_audacious_position_seconds(struct text_object *,char * p,unsigned int p_max_size)237 void print_audacious_position_seconds(struct text_object *, char *p,
238                                       unsigned int p_max_size) {
239   snprintf(p, p_max_size, "%d", get_res().position);
240 }
241 
print_audacious_bitrate(struct text_object *,char * p,unsigned int p_max_size)242 void print_audacious_bitrate(struct text_object *, char *p,
243                              unsigned int p_max_size) {
244   snprintf(p, p_max_size, "%d", get_res().bitrate);
245 }
246 
print_audacious_frequency(struct text_object *,char * p,unsigned int p_max_size)247 void print_audacious_frequency(struct text_object *, char *p,
248                                unsigned int p_max_size) {
249   snprintf(p, p_max_size, "%d", get_res().frequency);
250 }
251 
print_audacious_channels(struct text_object *,char * p,unsigned int p_max_size)252 void print_audacious_channels(struct text_object *, char *p,
253                               unsigned int p_max_size) {
254   snprintf(p, p_max_size, "%d", get_res().channels);
255 }
256 
print_audacious_playlist_length(struct text_object *,char * p,unsigned int p_max_size)257 void print_audacious_playlist_length(struct text_object *, char *p,
258                                      unsigned int p_max_size) {
259   snprintf(p, p_max_size, "%d", get_res().playlist_length);
260 }
261 
print_audacious_playlist_position(struct text_object *,char * p,unsigned int p_max_size)262 void print_audacious_playlist_position(struct text_object *, char *p,
263                                        unsigned int p_max_size) {
264   snprintf(p, p_max_size, "%d", get_res().playlist_position + 1);
265 }
266 
print_audacious_main_volume(struct text_object *,char * p,unsigned int p_max_size)267 void print_audacious_main_volume(struct text_object *, char *p,
268                                  unsigned int p_max_size) {
269   snprintf(p, p_max_size, "%d", get_res().main_volume);
270 }
271