-/* -------------------------------------------------------------------------
- * audacious.c: conky support for Audacious media player
+/* -*- mode: c; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: t -*-
+ * vim: ts=4 sw=4 noet ai cindent syntax=c
*
- * http://audacious-media-player.org
+ * audacious.c: conky support for audacious music player
*
- * Copyright (C) 2005 Philip Kovacs kovacsp3@comcast.net
- *
- * $Id$
+ * Copyright (C) 2005-2007 Philip Kovacs pkovacs@users.sourceforge.net
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- * --------------------------------------------------------------------------- */
-
-#include <pthread.h>
-/*#include <glib.h>*/
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-#include <audacious/beepctrl.h>
-#include "audacious.h"
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+ * USA.
+ *
+ */
+
+#include "config.h"
#include "conky.h"
+#include "logging.h"
+#include "audacious.h"
+
+#include <glib.h>
+#ifndef AUDACIOUS_LEGACY
+#include <glib-object.h>
+#include <audacious/audctrl.h>
+#include <audacious/dbus.h>
+#else
+#include <audacious/beepctrl.h>
+#define audacious_remote_is_running(x) \
+ xmms_remote_is_running(x)
+#define audacious_remote_is_paused(x) \
+ xmms_remote_is_paused(x)
+#define audacious_remote_is_playing(x) \
+ xmms_remote_is_playing(x)
+#define audacious_remote_get_playlist_pos(x) \
+ xmms_remote_get_playlist_pos(x)
+#define audacious_remote_get_playlist_title(x, y) \
+ xmms_remote_get_playlist_title(x, y)
+#define audacious_remote_get_playlist_time(x, y) \
+ xmms_remote_get_playlist_time(x, y)
+#define audacious_remote_get_output_time(x) \
+ xmms_remote_get_output_time(x)
+#define audacious_remote_get_info(w, x, y, z) \
+ xmms_remote_get_info(w, x, y, z)
+#define audacious_remote_get_playlist_file(x, y) \
+ xmms_remote_get_playlist_file(x, y)
+#define audacious_remote_get_playlist_length(x) \
+ xmms_remote_get_playlist_length(x)
+#endif
+
+/* access to this item array is synchronized */
+static audacious_t audacious_items;
+
+/* -----------------------------------------
+ * Conky update function for audacious data.
+ * ----------------------------------------- */
+int update_audacious(void)
+{
+ /* The worker thread is updating audacious_items array asynchronously
+ * to the main conky thread.
+ * We merely copy the audacious_items array into the main thread's info
+ * structure when the main thread's update cycle fires. */
+ if (!info.audacious.p_timed_thread) {
+ if (create_audacious_thread() != 0) {
+ CRIT_ERR(NULL, NULL, "unable to create audacious thread!");
+ }
+ timed_thread_register(info.audacious.p_timed_thread,
+ &info.audacious.p_timed_thread);
+ }
-/* access to this item array is synchronized with mutexes */
-static audacious_t g_items;
+ timed_thread_lock(info.audacious.p_timed_thread);
+ memcpy(&info.audacious.items, audacious_items, sizeof(audacious_items));
+ timed_thread_unlock(info.audacious.p_timed_thread);
+ return 0;
+}
-/* ----------------------------------------
- * Conky update function for Audacious data.
- * ---------------------------------------- */
-void update_audacious(void)
+/* ---------------------------------------------------------
+ * Create a worker thread for audacious media player status.
+ *
+ * Returns 0 on success, -1 on error.
+ * --------------------------------------------------------- */
+int create_audacious_thread(void)
{
- /*
- The worker thread is updating ihe g_items array asynchronously to the main
- conky thread. We merely copy the g_items array into the main thread's info
- structure when the main thread's update cycle fires. Note that using the
- mutexes here makes it easier since we won't have to do any sync in conky.c.
- */
- pthread_mutex_lock(&info.audacious.item_mutex);
- memcpy(&info.audacious.items,g_items,sizeof(g_items));
- pthread_mutex_unlock(&info.audacious.item_mutex);
+ if (!info.audacious.p_timed_thread) {
+ info.audacious.p_timed_thread =
+ timed_thread_create(audacious_thread_func, NULL,
+ info.music_player_interval * 1000000);
+ }
+
+ if (!info.audacious.p_timed_thread
+ || timed_thread_run(info.audacious.p_timed_thread)) {
+ return -1;
+ }
+
+ return 0;
}
+/* ---------------------------------------
+ * Destroy audacious player status thread.
+ *
+ * Returns 0 on success, -1 on error.
+ * --------------------------------------- */
+int destroy_audacious_thread(void)
+{
+ /* Is a worker is thread running? If not, no error. */
+ if (info.audacious.p_timed_thread) {
+ timed_thread_destroy(info.audacious.p_timed_thread,
+ &info.audacious.p_timed_thread);
+ }
-/* --------------------------------------------------
- * Worker thread function for Audacious data sampling.
- * -------------------------------------------------- */
+ return 0;
+}
+
+/* ---------------------------------------------------
+ * Worker thread function for audacious data sampling.
+ * --------------------------------------------------- */
+__attribute((noreturn))
void *audacious_thread_func(void *pvoid)
{
- int runnable;
- static audacious_t items;
- int session,playpos,frames,length;
- int rate,freq,chans;
- char *psong;
-
- pvoid=(void*)pvoid; /* useless cast to avoid unused var warning */
- session=0;
-
- /* Grab the runnable signal. Should be non-zero here or we do nothing. */
- pthread_mutex_lock(&info.audacious.runnable_mutex);
- runnable=info.audacious.runnable;
- pthread_mutex_unlock(&info.audacious.runnable_mutex );
-
- /* Loop until the main thread sets the runnable signal to 0. */
- while(runnable) {
-
- for (;;) { /* convenience loop so we can break below */
-
- if (!xmms_remote_is_running(session)) {
- memset(&items,0,sizeof(items));
- strcpy(items[AUDACIOUS_STATUS],"Not running");
- break;
- }
-
- /* Player status */
- if (xmms_remote_is_paused(session))
- strcpy(items[AUDACIOUS_STATUS],"Paused");
- else if (xmms_remote_is_playing(session))
- strcpy(items[AUDACIOUS_STATUS],"Playing");
- else
- strcpy(items[AUDACIOUS_STATUS],"Stopped");
-
- /* Current song title */
- playpos = (int) xmms_remote_get_playlist_pos(session);
- psong = (char *) xmms_remote_get_playlist_title(session, playpos);
- if (psong)
- strncpy(items[AUDACIOUS_SONG],psong,sizeof(items[AUDACIOUS_SONG]));
-
- /* Current song length as MM:SS */
- frames = xmms_remote_get_playlist_time(session,playpos);
- length = frames / 1000;
- snprintf(items[AUDACIOUS_SONG_LENGTH],sizeof(items[AUDACIOUS_SONG_LENGTH]),
- "%d:%.2d", length / 60, length % 60);
-
- /* Current song length in seconds */
- snprintf(items[AUDACIOUS_SONG_LENGTH_SECONDS],sizeof(items[AUDACIOUS_SONG_LENGTH_SECONDS]),
- "%d", length);
-
- /* Current song length in frames */
- snprintf(items[AUDACIOUS_SONG_LENGTH_FRAMES],sizeof(items[AUDACIOUS_SONG_LENGTH_FRAMES]),
- "%d", frames);
-
- /* Current song output length as MM:SS */
- frames = xmms_remote_get_output_time(session);
- length = frames / 1000;
- snprintf(items[AUDACIOUS_SONG_OUTPUT_LENGTH],sizeof(items[AUDACIOUS_SONG_OUTPUT_LENGTH]),
- "%d:%.2d", length / 60, length % 60);
-
- /* Current song output length in seconds */
- snprintf(items[AUDACIOUS_SONG_OUTPUT_LENGTH_SECONDS],sizeof(items[AUDACIOUS_SONG_OUTPUT_LENGTH_SECONDS]),
- "%d", length);
-
- /* Current song output length in frames */
- snprintf(items[AUDACIOUS_SONG_OUTPUT_LENGTH_FRAMES],sizeof(items[AUDACIOUS_SONG_OUTPUT_LENGTH_FRAMES]),
- "%d", frames);
-
- /* Current song bitrate */
- xmms_remote_get_info(session, &rate, &freq, &chans);
- snprintf(items[AUDACIOUS_SONG_BITRATE],sizeof(items[AUDACIOUS_SONG_BITRATE]), "%d", rate);
-
- /* Current song frequency */
- snprintf(items[AUDACIOUS_SONG_FREQUENCY],sizeof(items[AUDACIOUS_SONG_FREQUENCY]), "%d", freq);
-
- /* Current song channels */
- snprintf(items[AUDACIOUS_SONG_CHANNELS],sizeof(items[AUDACIOUS_SONG_CHANNELS]), "%d", chans);
-
-
- break;
+ static audacious_t items;
+ gint playpos, frames, length;
+ gint rate, freq, chans, vol;
+ gchar *psong, *pfilename;
+
+#ifndef AUDACIOUS_LEGACY
+ DBusGProxy *session = NULL;
+ DBusGConnection *connection = NULL;
+#else
+ gint session;
+#endif
+
+ pvoid = (void *) pvoid; /* avoid warning */
+ session = 0;
+ psong = NULL;
+ pfilename = NULL;
+
+#ifndef AUDACIOUS_LEGACY
+ g_type_init();
+ connection = dbus_g_bus_get(DBUS_BUS_SESSION, NULL);
+ if (!connection) {
+ CRIT_ERR(NULL, NULL, "unable to establish dbus connection");
}
+ session = dbus_g_proxy_new_for_name(connection, AUDACIOUS_DBUS_SERVICE,
+ AUDACIOUS_DBUS_PATH, AUDACIOUS_DBUS_INTERFACE);
+ if (!session) {
+ CRIT_ERR(NULL, NULL, "unable to create dbus proxy");
+ }
+#endif /* AUDACIOUS_LEGACY */
+
+ /* Loop until the main thread resets the runnable signal. */
+ while (1) {
+
+ do {
+ if (!audacious_remote_is_running(session)) {
+ memset(&items, 0, sizeof(items));
+ strcpy(items[AUDACIOUS_STATUS], "Not running");
+ break;
+ }
+
+ /* Player status */
+ if (audacious_remote_is_paused(session)) {
+ strcpy(items[AUDACIOUS_STATUS], "Paused");
+ } else if (audacious_remote_is_playing(session)) {
+ strcpy(items[AUDACIOUS_STATUS], "Playing");
+ } else {
+ strcpy(items[AUDACIOUS_STATUS], "Stopped");
+ }
+
+ /* Current song title */
+ playpos = audacious_remote_get_playlist_pos(session);
+ psong = audacious_remote_get_playlist_title(session, playpos);
+ if (psong) {
+ strncpy(items[AUDACIOUS_TITLE], psong,
+ sizeof(items[AUDACIOUS_TITLE]) - 1);
+ g_free(psong);
+ psong = NULL;
+ }
- /* Deliver the refreshed items array to g_items. */
- pthread_mutex_lock(&info.audacious.item_mutex);
- memcpy(&g_items,items,sizeof(items));
- pthread_mutex_unlock(&info.audacious.item_mutex);
+ /* Current song length as MM:SS */
+ frames = audacious_remote_get_playlist_time(session, playpos);
+ length = frames / 1000;
+ snprintf(items[AUDACIOUS_LENGTH], sizeof(items[AUDACIOUS_LENGTH]) - 1,
+ "%d:%.2d", length / 60, length % 60);
- /* Grab the runnable signal for next loop. */
- pthread_mutex_lock(&info.audacious.runnable_mutex);
- runnable=info.audacious.runnable;
- pthread_mutex_unlock(&info.audacious.runnable_mutex);
+ /* Current song length in seconds */
+ snprintf(items[AUDACIOUS_LENGTH_SECONDS],
+ sizeof(items[AUDACIOUS_LENGTH_SECONDS]) - 1, "%d", length);
- sleep(1);
- }
+ /* Current song position as MM:SS */
+ frames = audacious_remote_get_output_time(session);
+ length = frames / 1000;
+ snprintf(items[AUDACIOUS_POSITION],
+ sizeof(items[AUDACIOUS_POSITION]) - 1, "%d:%.2d", length / 60,
+ length % 60);
- pthread_exit(NULL);
+ /* Current song position in seconds */
+ snprintf(items[AUDACIOUS_POSITION_SECONDS],
+ sizeof(items[AUDACIOUS_POSITION_SECONDS]) - 1, "%d", length);
+
+ /* Current song bitrate */
+ audacious_remote_get_info(session, &rate, &freq, &chans);
+ snprintf(items[AUDACIOUS_BITRATE], sizeof(items[AUDACIOUS_BITRATE]) - 1,
+ "%d", rate);
+
+ /* Current song frequency */
+ snprintf(items[AUDACIOUS_FREQUENCY],
+ sizeof(items[AUDACIOUS_FREQUENCY]) - 1, "%d", freq);
+
+ /* Current song channels */
+ snprintf(items[AUDACIOUS_CHANNELS],
+ sizeof(items[AUDACIOUS_CHANNELS]) - 1, "%d", chans);
+
+ /* Current song filename */
+ pfilename = audacious_remote_get_playlist_file(session, playpos);
+ if (pfilename) {
+ strncpy(items[AUDACIOUS_FILENAME], pfilename,
+ sizeof(items[AUDACIOUS_FILENAME]) - 1);
+ g_free(pfilename);
+ pfilename = NULL;
+ }
+
+ /* Length of the Playlist (number of songs) */
+ length = audacious_remote_get_playlist_length(session);
+ snprintf(items[AUDACIOUS_PLAYLIST_LENGTH],
+ sizeof(items[AUDACIOUS_PLAYLIST_LENGTH]) - 1, "%d", length);
+
+ /* Playlist position (index of song) */
+ snprintf(items[AUDACIOUS_PLAYLIST_POSITION],
+ sizeof(items[AUDACIOUS_PLAYLIST_POSITION]) - 1, "%d", playpos + 1);
+ /* Main volume */
+ vol = audacious_remote_get_main_volume(session);
+ snprintf(items[AUDACIOUS_MAIN_VOLUME],
+ sizeof(items[AUDACIOUS_MAIN_VOLUME]) - 1, "%d", vol);
+
+ } while (0);
+ /* Deliver the refreshed items array to audacious_items. */
+ timed_thread_lock(info.audacious.p_timed_thread);
+ memcpy(&audacious_items, items, sizeof(items));
+ timed_thread_unlock(info.audacious.p_timed_thread);
+
+ if (timed_thread_test(info.audacious.p_timed_thread, 0)) {
+#ifndef AUDACIOUS_LEGACY
+ /* release reference to dbus proxy */
+ g_object_unref(session);
+#endif
+ timed_thread_exit(info.audacious.p_timed_thread);
+ }
+ }
}