3 * $Id: ausys-win32.c,v 1.1 2002/02/02 19:16:28 mdw Exp $
5 * Unix-specific (SDL) audio handling
7 * (c) 2002 Mark Wooding
10 /*----- Licensing notice --------------------------------------------------*
12 * This file is part of Jog: Programming for a jogging machine.
14 * Jog is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
19 * Jog is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
24 * You should have received a copy of the GNU General Public License
25 * along with Jog; if not, write to the Free Software Foundation,
26 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
29 /*----- Revision history --------------------------------------------------*
31 * $Log: ausys-win32.c,v $
32 * Revision 1.1 2002/02/02 19:16:28 mdw
33 * New audio subsystem.
37 /*----- Header files ------------------------------------------------------*/
47 #include <sys/types.h>
54 #include <mLib/alloc.h>
55 #include <mLib/bits.h>
57 #include <mLib/trace.h>
64 /*----- Data structures ---------------------------------------------------*/
66 /* --- Queue of samples to play --- */
68 typedef struct qnode {
69 struct qnode *next; /* Next item in the queue */
70 au_data *a; /* Pointer to sample data */
73 /*----- Global variables --------------------------------------------------*/
75 const char *const ausys_suffix = "wav";
77 /*----- Static data -------------------------------------------------------*/
79 static qnode *qhead = 0, *qtail = 0; /* Queue of samples to play */
80 static qnode *qfree = 0; /* Queue of samples to free */
82 static pthread_t tid_play; /* The sample-playing thread */
83 static pthread_mutex_t mx_queue; /* Mutex for @qhead@ */
84 static pthread_cond_t cv_play; /* More samples to play */
86 static pthread_t tid_free; /* The sample-freeing thread */
87 static pthread_mutex_t mx_free; /* Mutex for @qfree@ */
88 static pthread_cond_t cv_free; /* More sample data to free */
90 static pthread_mutex_t mx_sub; /* Protects mLib @sub@ functions */
92 /*----- Thread structure --------------------------------------------------*
94 * In order to ensure that samples don't overlap each other, we play them
95 * synchronously in a separate thread. The @play@ function reads samples to
96 * play from the queue at @qhead@. Hence @qhead@ must be locked when it's
97 * modified, using @mx_queue@.
99 * In order to keep latency down when new sample data is wanted, we don't do
100 * potentially tedious things like freeing sample data blocks in the @play@
101 * thread. Instead, there's a queue of sample blocks which need freeing, and
102 * a separate thread @dofree@ which processes the queue. The queue, @qfree@
103 * is locked by @mx_free@. When new nodes are added to @qfree@, the
104 * condition @cv_free@ is signalled.
106 * Finally, the mLib `sub' module isn't thread-safe, so it's locked
107 * separately by @mx_sub@.
109 * There's an ordering on mutexes. If you want more than one mutex at a
110 * time, you must lock the greatest first. The ordering is:
115 /*----- Main code ---------------------------------------------------------*/
117 /* --- @dofree@ --- *
119 * Arguments: @void *u@ = unused pointer
121 * Returns: An unused pointer.
123 * Use: Frees unwanted sample queue nodes.
126 static void *play(void *u)
132 /* --- If we have nothing to do locally, fetch the external queue --- */
135 pthread_mutex_lock(&mx_queue);
137 T( trace(T_AUSYS, "ausys: waiting for samples to play"); )
138 pthread_cond_wait(&cv_play, &mx_queue);
142 pthread_mutex_unlock(&mx_queue);
145 /* --- Play the next sample --- */
148 T( trace(T_AUSYS, "ausys: playing `%s'", SYM_NAME(q->a->s)); )
149 PlaySound((const void *)q->a->p, 0, SND_SYNC | SND_MEMORY);
151 /* --- Put it on the free list --- */
153 pthread_mutex_lock(&mx_free);
156 pthread_mutex_unlock(&mx_free);
157 pthread_cond_signal(&cv_free);
161 /* --- @dofree@ --- *
163 * Arguments: @void *u@ = unused pointer
165 * Returns: An unused pointer.
167 * Use: Frees unwanted sample queue nodes.
170 static void *dofree(void *u)
174 pthread_mutex_lock(&mx_free);
176 T( trace(T_AUSYS, "ausys: dofree sleeping"); )
177 pthread_cond_wait(&cv_free, &mx_free);
178 T( trace(T_AUSYS, "ausys: dofree woken: work to do"); )
183 pthread_mutex_lock(&mx_sub);
186 T( trace(T_AUSYS, "ausys: freeing `%s'", SYM_NAME(q->a->s)); )
187 au_free_unlocked(q->a);
191 pthread_mutex_unlock(&mx_sub);
196 /* --- @ausys_init@ --- *
202 * Use: Does any initialization required by the system-specific audio
206 void ausys_init(void)
211 if ((e = pthread_mutex_init(&mx_free, 0)) != 0 ||
212 (e = pthread_mutex_init(&mx_sub, 0)) != 0 ||
213 (e = pthread_mutex_init(&mx_queue, 0)) != 0 ||
214 (e = pthread_cond_init(&cv_play, 0)) != 0 ||
215 (e = pthread_cond_init(&cv_free, 0)) != 0 ||
216 (e = pthread_attr_init(&ta)) != 0 ||
217 (e = pthread_attr_setdetachstate(&ta, PTHREAD_CREATE_DETACHED)) != 0 ||
218 (e = pthread_create(&tid_free, &ta, play, 0)) != 0 ||
219 (e = pthread_create(&tid_free, &ta, dofree, 0)) != 0) {
220 err_report(ERR_AUDIO, ERRAU_INIT, e,
221 "couldn't create audio threads: %s", strerror(errno));
224 pthread_attr_destroy(&ta);
226 T( trace(T_AUSYS, "ausys: initalized ok"); )
229 /* --- @ausys_shutdown@ --- *
235 * Use: Does any tidying up required.
238 void ausys_shutdown(void)
240 pthread_cancel(tid_free);
241 pthread_cancel(tid_play);
242 T( trace(T_AUSYS, "ausys: shut down ok"); )
245 /* --- @ausys_lock@, @ausys_unlock@ --- *
251 * Use: Locks or unlocks the audio subsystem. This protects the
252 * audio queue from becoming corrupted during all the tedious
253 * asynchronous stuff.
256 void ausys_lock(void)
258 pthread_mutex_lock(&mx_free);
259 pthread_mutex_lock(&mx_sub);
260 T( trace(T_AUSYS, "ausys: acquired lock"); )
263 void ausys_unlock(void)
265 pthread_mutex_unlock(&mx_sub);
266 pthread_mutex_unlock(&mx_free);
267 T( trace(T_AUSYS, "ausys: released lock"); )
270 /* --- @ausys_decode@ --- *
272 * Arguments: @au_sample *s@ = pointer to sample block
273 * @const void *p@ = pointer to sample file contents
274 * @size_t sz@ = size of sample file contents
276 * Returns: Pointer to a sample data structure.
278 * Use: Decodes a WAV file into something the system-specific layer
279 * actually wants to deal with.
282 au_data *ausys_decode(au_sample *s, const void *p, size_t sz)
286 pthread_mutex_lock(&mx_sub);
288 pthread_mutex_unlock(&mx_sub);
293 T( trace(T_AUSYS, "ausys: decoded `%s' ok", SYM_NAME(s)); )
297 /* --- @ausys_queue@ --- *
299 * Arguments: @au_data *a@ = an audio thingy to play
303 * Use: Queues an audio sample to be played. The sample should be
304 * freed (with @au_free@) when it's no longer wanted.
307 void ausys_queue(au_data *a)
311 pthread_mutex_lock(&mx_sub);
313 pthread_mutex_unlock(&mx_sub);
316 pthread_mutex_lock(&mx_queue);
322 pthread_mutex_unlock(&mx_queue);
323 pthread_cond_signal(&cv_play);
324 T( trace(T_AUSYS, "ausys: queuing `%s'", SYM_NAME(a->s)); )
327 /* --- @ausys_free@ --- *
329 * Arguments: @au_data *a@ = an audio thingy to free
333 * Use: Frees a decoded audio sample.
336 void ausys_free(au_data *a)
340 T( trace(T_AUSYS, "ausys: freeing data for `%s' ok", SYM_NAME(a->s)); )
343 /*----- That's all, folks -------------------------------------------------*/