typo
[monky] / src / audacious.c
1 /* -------------------------------------------------------------------------
2  * audacious.c:  conky support for audacious music player
3  *
4  * Copyright (C) 2005  Philip Kovacs kovacsp3@comcast.net
5  * 
6  * $Id$
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  USA
21  * --------------------------------------------------------------------------- */
22
23 #include <pthread.h>
24 #include <stdio.h>
25 #include <string.h>
26 #include <unistd.h>
27
28 #include <glib.h>
29 #include <audacious/beepctrl.h>
30
31 #include "config.h"
32 #include "conky.h"
33 #include "audacious.h"
34
35 /* access to this item array is synchronized */
36 static audacious_t audacious_items;
37
38 /* -----------------------------------------
39  * Conky update function for audacious data.
40  * ----------------------------------------- */
41 void update_audacious(void)
42 {
43     /* 
44       The worker thread is updating audacious_items array asynchronously to the main 
45       conky thread.  We merely copy the audacious_items array into the main thread's 
46       info structure when the main thread's update cycle fires. 
47     */
48     pthread_mutex_lock(&info.audacious.item_mutex);
49     memcpy(&info.audacious.items,audacious_items,sizeof(audacious_items));
50     pthread_mutex_unlock(&info.audacious.item_mutex);
51 }
52
53
54 /* ------------------------------------------------------------
55  * Create a worker thread for audacious media player status.
56  *
57  * Returns 0 on success, -1 on error. 
58  * ------------------------------------------------------------*/
59 int create_audacious_thread(void)
60 {
61     /* Is a worker is thread already running? */
62     if (info.audacious.thread)
63         return(-1);
64
65     /* Joinable thread for audacious activity */
66     pthread_attr_init(&info.audacious.thread_attr);
67     pthread_attr_setdetachstate(&info.audacious.thread_attr, PTHREAD_CREATE_JOINABLE);
68     /* Init mutexes */
69     pthread_mutex_init(&info.audacious.item_mutex, NULL);
70     pthread_mutex_init(&info.audacious.runnable_mutex, NULL);
71     /* Init runnable condition for worker thread */
72     pthread_mutex_lock(&info.audacious.runnable_mutex);
73     info.audacious.runnable=1;
74     pthread_mutex_unlock(&info.audacious.runnable_mutex);
75     if (pthread_create(&info.audacious.thread, &info.audacious.thread_attr, audacious_thread_func, NULL))
76         return(-1);
77
78     return 0;
79 }
80
81 /* ------------------------------------------------
82  * Destroy audacious player status thread. 
83  *
84  * Returns 0 on success, -1 on error.
85  * ------------------------------------------------ */
86 int destroy_audacious_thread(void)
87 {
88     /* Is a worker is thread running? If not, no error. */
89     if (!info.audacious.thread)
90         return(0);
91
92     /* Signal audacious thread to terminate */
93     pthread_mutex_lock(&info.audacious.runnable_mutex);
94     info.audacious.runnable=0;
95     pthread_mutex_unlock(&info.audacious.runnable_mutex);
96     /* Destroy thread attribute and wait for thread */
97     pthread_attr_destroy(&info.audacious.thread_attr);
98     if (pthread_join(info.audacious.thread, NULL))
99         return(-1);
100     /* Destroy mutexes */
101     pthread_mutex_destroy(&info.audacious.item_mutex);
102     pthread_mutex_destroy(&info.audacious.runnable_mutex);
103
104     info.audacious.thread=(pthread_t)0;
105     return 0;
106 }
107
108 /* ---------------------------------------------------
109  * Worker thread function for audacious data sampling.
110  * --------------------------------------------------- */ 
111 void *audacious_thread_func(void *pvoid)
112 {
113     int runnable;
114     static audacious_t items;
115     gint session,playpos,frames,length;
116     gint rate,freq,chans;
117     gchar *psong,*pfilename;
118
119     pvoid=(void *)pvoid;  /* avoid warning */
120     session=0;
121     psong=NULL;
122     pfilename=NULL;
123
124     /* Grab the runnable signal.  Should be non-zero here or we do nothing. */
125     pthread_mutex_lock(&info.audacious.runnable_mutex);
126     runnable=info.audacious.runnable;
127     pthread_mutex_unlock(&info.audacious.runnable_mutex );
128
129     /* Loop until the main thread sets the runnable signal to 0. */
130     while(runnable) {
131
132         for (;;) {  /* convenience loop so we can break below */
133
134             if (!xmms_remote_is_running (session)) {
135                 memset(&items,0,sizeof(items));
136                 strcpy(items[AUDACIOUS_STATUS],"Not running");
137                 break;
138             }
139
140             /* Player status */
141             if (xmms_remote_is_paused (session))
142                 strcpy(items[AUDACIOUS_STATUS],"Paused");
143             else if (xmms_remote_is_playing (session))
144                  strcpy(items[AUDACIOUS_STATUS],"Playing");
145             else
146                  strcpy(items[AUDACIOUS_STATUS],"Stopped");
147
148             /* Current song title */
149             playpos = xmms_remote_get_playlist_pos (session);
150             psong = xmms_remote_get_playlist_title (session, playpos);
151             if (psong) {
152                 strncpy(items[AUDACIOUS_TITLE],psong,sizeof(items[AUDACIOUS_TITLE])-1);
153                 g_free (psong);
154                 psong=NULL;
155             }
156
157             /* Current song length as MM:SS */
158             frames = xmms_remote_get_playlist_time (session,playpos);
159             length = frames / 1000;
160             snprintf(items[AUDACIOUS_LENGTH],sizeof(items[AUDACIOUS_LENGTH])-1,
161                      "%d:%.2d", length / 60, length % 60);
162
163             /* Current song length in seconds */
164             snprintf(items[AUDACIOUS_LENGTH_SECONDS],sizeof(items[AUDACIOUS_LENGTH_SECONDS])-1,
165                      "%d", length);
166
167             /* Current song position as MM:SS */
168             frames = xmms_remote_get_output_time (session);
169             length = frames / 1000;
170             snprintf(items[AUDACIOUS_POSITION],sizeof(items[AUDACIOUS_POSITION])-1,
171                      "%d:%.2d", length / 60, length % 60);
172
173             /* Current song position in seconds */
174             snprintf(items[AUDACIOUS_POSITION_SECONDS],sizeof(items[AUDACIOUS_POSITION_SECONDS])-1,
175                      "%d", length);
176
177             /* Current song bitrate */
178             xmms_remote_get_info (session, &rate, &freq, &chans);
179             snprintf(items[AUDACIOUS_BITRATE],sizeof(items[AUDACIOUS_BITRATE])-1, "%d", rate);
180
181             /* Current song frequency */
182             snprintf(items[AUDACIOUS_FREQUENCY],sizeof(items[AUDACIOUS_FREQUENCY])-1, "%d", freq);
183
184             /* Current song channels */
185             snprintf(items[AUDACIOUS_CHANNELS],sizeof(items[AUDACIOUS_CHANNELS])-1, "%d", chans);
186
187             /* Current song filename */
188             pfilename = xmms_remote_get_playlist_file (session,playpos);
189             if (pfilename) {
190                 strncpy(items[AUDACIOUS_FILENAME],pfilename,sizeof(items[AUDACIOUS_FILENAME])-1);
191                 g_free (pfilename);
192                 pfilename=NULL;
193             }
194
195             /* Length of the Playlist (number of songs) */
196             length = xmms_remote_get_playlist_length (session);
197             snprintf(items[AUDACIOUS_PLAYLIST_LENGTH],sizeof(items[AUDACIOUS_PLAYLIST_LENGTH])-1, "%d", length);
198
199             /* Playlist position (index of song) */
200             snprintf(items[AUDACIOUS_PLAYLIST_POSITION],sizeof(items[AUDACIOUS_PLAYLIST_POSITION])-1, "%d", playpos+1);
201
202             break;
203         }
204
205         /* Deliver the refreshed items array to audacious_items. */
206         pthread_mutex_lock(&info.audacious.item_mutex);
207         memcpy(&audacious_items,items,sizeof(items));
208         pthread_mutex_unlock(&info.audacious.item_mutex);
209
210         /* Grab the runnable signal for next loop. */
211         pthread_mutex_lock(&info.audacious.runnable_mutex);
212         runnable=info.audacious.runnable;
213         pthread_mutex_unlock(&info.audacious.runnable_mutex);
214
215         sleep(1);
216     }
217
218     pthread_exit(NULL);
219 }