chiark / gitweb /
uaudio: more sophisticated choice of default playback API
[disorder] / lib / uaudio-thread.c
1 /*
2  * This file is part of DisOrder.
3  * Copyright (C) 2009, 2013 Richard Kettlewell
4  *
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  * 
15  * You should have received a copy of the GNU General Public License
16  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
17  */
18 /** @file lib/uaudio-thread.c
19  * @brief Background thread for audio processing */
20 #include "common.h"
21
22 #include <pthread.h>
23 #include <unistd.h>
24
25 #include "uaudio.h"
26 #include "log.h"
27 #include "mem.h"
28 #include "syscalls.h"
29 #include "timeval.h"
30
31 /** @brief Number of buffers
32  *
33  * Must be at least 2 and should normally be at least 3.  We maintain multiple
34  * buffers so that we can read new data into one while the previous is being
35  * played.
36  */
37 #define UAUDIO_THREAD_BUFFERS 4
38
39 /** @brief Buffer data structure */
40 struct uaudio_buffer {
41   /** @brief Pointer to sample data */
42   void *samples;
43
44   /** @brief Count of samples */
45   size_t nsamples;
46 };
47
48 /** @brief Input buffers
49  *
50  * This is actually a ring buffer, managed by @ref uaudio_collect_buffer and
51  * @ref uaudio_play_buffer.
52  *
53  * Initially both pointers are 0.  Whenever the pointers are equal, we
54  * interpreted this as meaning that there is no data stored at all.  A
55  * consequence of this is that maximal occupancy is when the collect point is
56  * just before the play point, so at least one buffer is always empty (hence it
57  * being good for @ref UAUDIO_THREAD_BUFFERS to be at least 3).
58  */
59 static struct uaudio_buffer uaudio_buffers[UAUDIO_THREAD_BUFFERS];
60
61 /** @brief Buffer to read into */
62 static unsigned uaudio_collect_buffer;
63
64 /** @brief Buffer to play from */
65 static unsigned uaudio_play_buffer;
66
67 /** @brief Collection thread ID */
68 static pthread_t uaudio_collect_thread;
69
70 /** @brief Playing thread ID */
71 static pthread_t uaudio_play_thread;
72
73 /** @brief Flags */
74 static unsigned uaudio_thread_flags;
75
76 static uaudio_callback *uaudio_thread_collect_callback;
77 static uaudio_playcallback *uaudio_thread_play_callback;
78 static void *uaudio_thread_userdata;
79 static int uaudio_thread_started;
80 static int uaudio_thread_collecting;
81 static pthread_mutex_t uaudio_thread_lock = PTHREAD_MUTEX_INITIALIZER;
82 static pthread_cond_t uaudio_thread_cond = PTHREAD_COND_INITIALIZER;
83
84 /** @brief Minimum number of samples per chunk */
85 static size_t uaudio_thread_min;
86
87 /** @brief Maximum number of samples per chunk */
88 static size_t uaudio_thread_max;
89
90 /** @brief Set when activated, clear when paused */
91 static int uaudio_thread_activated;
92
93 /** @brief Return number of buffers currently in use */
94 static int uaudio_buffers_used(void) {
95   return (uaudio_collect_buffer - uaudio_play_buffer) % UAUDIO_THREAD_BUFFERS;
96 }
97
98 /** @brief Background thread for audio collection
99  *
100  * Collects data while activated and communicates its status via @ref
101  * uaudio_thread_collecting.
102  */
103 static void *uaudio_collect_thread_fn(void attribute((unused)) *arg) {
104   pthread_mutex_lock(&uaudio_thread_lock);
105   while(uaudio_thread_started) {
106     /* Wait until we're activatd */
107     if(!uaudio_thread_activated) {
108       pthread_cond_wait(&uaudio_thread_cond, &uaudio_thread_lock);
109       continue;
110     }
111     /* We are definitely active now */
112     uaudio_thread_collecting = 1;
113     pthread_cond_broadcast(&uaudio_thread_cond);
114     while(uaudio_thread_activated) {
115       if(uaudio_buffers_used() < UAUDIO_THREAD_BUFFERS - 1) {
116         /* At least one buffer is available.  We release the lock while
117          * collecting data so that other already-filled buffers can be played
118          * without delay.  */
119         struct uaudio_buffer *const b = &uaudio_buffers[uaudio_collect_buffer];
120         pthread_mutex_unlock(&uaudio_thread_lock);
121         //fprintf(stderr, "C%d.", uaudio_collect_buffer);
122         
123         /* Keep on trying until we get the minimum required amount of data */
124         b->nsamples = 0;
125         if(uaudio_thread_activated) {
126           while(b->nsamples < uaudio_thread_min) {
127             b->nsamples += uaudio_thread_collect_callback
128               ((char *)b->samples
129                + b->nsamples * uaudio_sample_size,
130                uaudio_thread_max - b->nsamples,
131                uaudio_thread_userdata);
132           }
133         }
134         pthread_mutex_lock(&uaudio_thread_lock);
135         /* Advance to next buffer */
136         uaudio_collect_buffer = (1 + uaudio_collect_buffer) % UAUDIO_THREAD_BUFFERS;
137         /* Awaken player */
138         pthread_cond_broadcast(&uaudio_thread_cond);
139       } else
140         /* No space, wait for player */
141         pthread_cond_wait(&uaudio_thread_cond, &uaudio_thread_lock);
142     }
143     uaudio_thread_collecting = 0;
144     pthread_cond_broadcast(&uaudio_thread_cond);
145   }
146   pthread_mutex_unlock(&uaudio_thread_lock);
147   return NULL;
148 }
149
150 static size_t uaudio_play_samples(void *buffer, size_t samples, unsigned flags) {
151   static struct timespec base;
152   static int64_t frames_supplied;
153   struct timespec now;
154   struct timespec delay_ts;
155   double target, delay;
156
157   if(!base.tv_sec)
158     xgettime(CLOCK_MONOTONIC, &base);
159   samples = uaudio_thread_play_callback(buffer, samples, flags);
160   frames_supplied += samples / uaudio_channels;
161   /* Set target to the approximate point at which we run out of buffered audio.
162    * If no buffer size has been specified, use 1/16th of a second. */
163   target = (frames_supplied - (uaudio_buffer ? uaudio_buffer : uaudio_rate / 16))
164     / (double)uaudio_rate + ts_to_double(base);
165   for(;;) {
166     xgettime(CLOCK_MONOTONIC, &now);
167     delay = target - ts_to_double(now);
168     if(delay <= 0) {
169       //putc('.', stderr);
170       break;
171     }
172     //putc('!', stderr);
173     /*
174     fprintf(stderr, "frames supplied %ld (%lds) base %f target %f now %f want delay %g\n", 
175             frames_supplied,
176             frames_supplied / uaudio_rate,
177             ts_to_double(base),
178             target, 
179             ts_to_double(now),
180             delay);
181     */
182     delay_ts = double_to_ts(delay);
183     xnanosleep(&delay_ts, NULL);
184   }
185   return samples;
186 }
187
188 /** @brief Background thread for audio playing 
189  *
190  * This thread plays data as long as there is something to play.  So the
191  * buffers will drain to empty before deactivation completes.
192  */
193 static void *uaudio_play_thread_fn(void attribute((unused)) *arg) {
194   int resync = 1;
195   unsigned last_flags = 0;
196   unsigned char zero[uaudio_thread_max * uaudio_sample_size];
197   memset(zero, 0, sizeof zero);
198
199   while(uaudio_thread_started) {
200     // If we're paused then just play silence
201     if(!uaudio_thread_activated) {
202       pthread_mutex_unlock(&uaudio_thread_lock);
203       unsigned flags = UAUDIO_PAUSED;
204       if(last_flags & UAUDIO_PLAYING)
205         flags |= UAUDIO_PAUSE;
206       uaudio_play_samples(zero, uaudio_thread_max, last_flags = flags);
207       /* We expect the play callback to block for a reasonable period */
208       pthread_mutex_lock(&uaudio_thread_lock);
209       continue;
210     }
211     const int used = uaudio_buffers_used();
212     int go;
213
214     if(resync)
215       go = (used == UAUDIO_THREAD_BUFFERS - 1);
216     else
217       go = (used > 0);
218     if(go) {
219       /* At least one buffer is filled.  We release the lock while playing so
220        * that more collection can go on. */
221       struct uaudio_buffer *const b = &uaudio_buffers[uaudio_play_buffer];
222       pthread_mutex_unlock(&uaudio_thread_lock);
223       //fprintf(stderr, "P%d.", uaudio_play_buffer);
224       size_t played = 0;
225       while(played < b->nsamples) {
226         unsigned flags = UAUDIO_PLAYING;
227         if(last_flags & UAUDIO_PAUSED)
228           flags |= UAUDIO_RESUME;
229         played += uaudio_play_samples((char *)b->samples
230                                       + played * uaudio_sample_size,
231                                       b->nsamples - played,
232                                       last_flags = flags);
233       }
234       pthread_mutex_lock(&uaudio_thread_lock);
235       /* Move to next buffer */
236       uaudio_play_buffer = (1 + uaudio_play_buffer) % UAUDIO_THREAD_BUFFERS;
237       /* Awaken collector */
238       pthread_cond_broadcast(&uaudio_thread_cond);
239       resync = 0;
240     } else {
241       /* Insufficient data to play, wait for collector */
242       pthread_cond_wait(&uaudio_thread_cond, &uaudio_thread_lock);
243       /* (Still) re-synchronizing */
244       resync = 1;
245     }
246   }
247   pthread_mutex_unlock(&uaudio_thread_lock);
248   return NULL;
249 }
250
251 /** @brief Create background threads for audio processing 
252  * @param callback Callback to collect audio data
253  * @param userdata Passed to @p callback
254  * @param playcallback Callback to play audio data
255  * @param min Minimum number of samples to play in a chunk
256  * @param max Maximum number of samples to play in a chunk
257  * @param flags Flags (not currently used)
258  *
259  * @p callback will be called multiple times in quick succession if necessary
260  * to gather at least @p min samples.  Equally @p playcallback may be called
261  * repeatedly in quick succession to play however much was received in a single
262  * chunk.
263  */
264 void uaudio_thread_start(uaudio_callback *callback,
265                          void *userdata,
266                          uaudio_playcallback *playcallback,
267                          size_t min,
268                          size_t max,
269                          unsigned flags) {
270   int e;
271   uaudio_thread_collect_callback = callback;
272   uaudio_thread_userdata = userdata;
273   uaudio_thread_play_callback = playcallback;
274   uaudio_thread_min = min;
275   uaudio_thread_max = max;
276   uaudio_thread_flags = flags;
277   uaudio_thread_started = 1;
278   uaudio_thread_activated = 0;
279   for(int n = 0; n < UAUDIO_THREAD_BUFFERS; ++n)
280     uaudio_buffers[n].samples = xcalloc_noptr(uaudio_thread_max,
281                                               uaudio_sample_size);
282   uaudio_collect_buffer = uaudio_play_buffer = 0;
283   if((e = pthread_create(&uaudio_collect_thread,
284                          NULL,
285                          uaudio_collect_thread_fn,
286                          NULL)))
287     disorder_fatal(e, "pthread_create");
288   if((e = pthread_create(&uaudio_play_thread,
289                          NULL,
290                          uaudio_play_thread_fn,
291                          NULL)))
292     disorder_fatal(e, "pthread_create");
293 }
294
295 /** @brief Shut down background threads for audio processing */
296 void uaudio_thread_stop(void) {
297   void *result;
298
299   pthread_mutex_lock(&uaudio_thread_lock);
300   uaudio_thread_activated = 0;
301   uaudio_thread_started = 0;
302   pthread_cond_broadcast(&uaudio_thread_cond);
303   pthread_mutex_unlock(&uaudio_thread_lock);
304   pthread_join(uaudio_collect_thread, &result);
305   pthread_join(uaudio_play_thread, &result);
306   for(int n = 0; n < UAUDIO_THREAD_BUFFERS; ++n)
307     xfree(uaudio_buffers[n].samples);
308 }
309
310 /** @brief Activate audio output */
311 void uaudio_thread_activate(void) {
312   pthread_mutex_lock(&uaudio_thread_lock);
313   uaudio_thread_activated = 1;
314   pthread_cond_broadcast(&uaudio_thread_cond);
315   pthread_mutex_unlock(&uaudio_thread_lock);
316 }
317
318 /** @brief Deactivate audio output */
319 void uaudio_thread_deactivate(void) {
320   pthread_mutex_lock(&uaudio_thread_lock);
321   uaudio_thread_activated = 0; 
322   pthread_cond_broadcast(&uaudio_thread_cond);
323   pthread_mutex_unlock(&uaudio_thread_lock);
324 }
325
326 /*
327 Local Variables:
328 c-basic-offset:2
329 comment-column:40
330 fill-column:79
331 indent-tabs-mode:nil
332 End:
333 */