2 * This file is part of DisOrder.
3 * Copyright (C) 2009 Richard Kettlewell
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.
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.
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/>.
18 /** @file lib/uaudio-thread.c
19 * @brief Background thread for audio processing */
29 /** @brief Number of buffers
31 * Must be at least 2 and should normally be at least 3. We maintain multiple
32 * buffers so that we can read new data into one while the previous is being
35 #define UAUDIO_THREAD_BUFFERS 4
37 /** @brief Buffer data structure */
38 struct uaudio_buffer {
39 /** @brief Pointer to sample data */
42 /** @brief Count of samples */
46 /** @brief Input buffers
48 * This is actually a ring buffer, managed by @ref uaudio_collect_buffer and
49 * @ref uaudio_play_buffer.
51 * Initially both pointers are 0. Whenever the pointers are equal, we
52 * interpreted this as meaning that there is no data stored at all. A
53 * consequence of this is that maximal occupancy is when the collect point is
54 * just before the play point, so at least one buffer is always empty (hence it
55 * being good for @ref UAUDIO_THREAD_BUFFERS to be at least 3).
57 static struct uaudio_buffer uaudio_buffers[UAUDIO_THREAD_BUFFERS];
59 /** @brief Buffer to read into */
60 static unsigned uaudio_collect_buffer;
62 /** @brief Buffer to play from */
63 static unsigned uaudio_play_buffer;
65 /** @brief Collection thread ID */
66 static pthread_t uaudio_collect_thread;
68 /** @brief Playing thread ID */
69 static pthread_t uaudio_play_thread;
72 static unsigned uaudio_thread_flags;
74 static uaudio_callback *uaudio_thread_collect_callback;
75 static uaudio_playcallback *uaudio_thread_play_callback;
76 static void *uaudio_thread_userdata;
77 static int uaudio_thread_started;
78 static int uaudio_thread_collecting;
79 static pthread_mutex_t uaudio_thread_lock = PTHREAD_MUTEX_INITIALIZER;
80 static pthread_cond_t uaudio_thread_cond = PTHREAD_COND_INITIALIZER;
82 /** @brief Minimum number of samples per chunk */
83 static size_t uaudio_thread_min;
85 /** @brief Maximum number of samples per chunk */
86 static size_t uaudio_thread_max;
88 /** @brief Set when activated, clear when paused */
89 static int uaudio_thread_activated;
91 /** @brief Return number of buffers currently in use */
92 static int uaudio_buffers_used(void) {
93 return (uaudio_collect_buffer - uaudio_play_buffer) % UAUDIO_THREAD_BUFFERS;
96 /** @brief Background thread for audio collection
98 * Collects data while activated and communicates its status via @ref
99 * uaudio_thread_collecting.
101 static void *uaudio_collect_thread_fn(void attribute((unused)) *arg) {
102 pthread_mutex_lock(&uaudio_thread_lock);
103 while(uaudio_thread_started) {
104 /* Wait until we're activatd */
105 if(!uaudio_thread_activated) {
106 pthread_cond_wait(&uaudio_thread_cond, &uaudio_thread_lock);
109 /* We are definitely active now */
110 uaudio_thread_collecting = 1;
111 pthread_cond_broadcast(&uaudio_thread_cond);
112 while(uaudio_thread_activated) {
113 if(uaudio_buffers_used() < UAUDIO_THREAD_BUFFERS - 1) {
114 /* At least one buffer is available. We release the lock while
115 * collecting data so that other already-filled buffers can be played
117 struct uaudio_buffer *const b = &uaudio_buffers[uaudio_collect_buffer];
118 pthread_mutex_unlock(&uaudio_thread_lock);
119 //fprintf(stderr, "C%d.", uaudio_collect_buffer);
121 /* Keep on trying until we get the minimum required amount of data */
123 if(uaudio_thread_activated) {
124 while(b->nsamples < uaudio_thread_min) {
125 b->nsamples += uaudio_thread_collect_callback
127 + b->nsamples * uaudio_sample_size,
128 uaudio_thread_max - b->nsamples,
129 uaudio_thread_userdata);
132 pthread_mutex_lock(&uaudio_thread_lock);
133 /* Advance to next buffer */
134 uaudio_collect_buffer = (1 + uaudio_collect_buffer) % UAUDIO_THREAD_BUFFERS;
136 pthread_cond_broadcast(&uaudio_thread_cond);
138 /* No space, wait for player */
139 pthread_cond_wait(&uaudio_thread_cond, &uaudio_thread_lock);
141 uaudio_thread_collecting = 0;
142 pthread_cond_broadcast(&uaudio_thread_cond);
144 pthread_mutex_unlock(&uaudio_thread_lock);
148 /** @brief Background thread for audio playing
150 * This thread plays data as long as there is something to play. So the
151 * buffers will drain to empty before deactivation completes.
153 static void *uaudio_play_thread_fn(void attribute((unused)) *arg) {
155 unsigned last_flags = 0;
156 unsigned char zero[uaudio_thread_max * uaudio_sample_size];
157 memset(zero, 0, sizeof zero);
159 while(uaudio_thread_started) {
160 // If we're paused then just play silence
161 if(!uaudio_thread_activated) {
162 pthread_mutex_unlock(&uaudio_thread_lock);
163 unsigned flags = UAUDIO_PAUSED;
164 if(last_flags & UAUDIO_PLAYING)
165 flags |= UAUDIO_PAUSE;
166 uaudio_thread_play_callback(zero, uaudio_thread_max,
168 /* We expect the play callback to block for a reasonable period */
169 pthread_mutex_lock(&uaudio_thread_lock);
172 const int used = uaudio_buffers_used();
176 go = (used == UAUDIO_THREAD_BUFFERS - 1);
180 /* At least one buffer is filled. We release the lock while playing so
181 * that more collection can go on. */
182 struct uaudio_buffer *const b = &uaudio_buffers[uaudio_play_buffer];
183 pthread_mutex_unlock(&uaudio_thread_lock);
184 //fprintf(stderr, "P%d.", uaudio_play_buffer);
186 while(played < b->nsamples) {
187 unsigned flags = UAUDIO_PLAYING;
188 if(last_flags & UAUDIO_PAUSED)
189 flags |= UAUDIO_RESUME;
190 played += uaudio_thread_play_callback((char *)b->samples
191 + played * uaudio_sample_size,
192 b->nsamples - played,
195 pthread_mutex_lock(&uaudio_thread_lock);
196 /* Move to next buffer */
197 uaudio_play_buffer = (1 + uaudio_play_buffer) % UAUDIO_THREAD_BUFFERS;
198 /* Awaken collector */
199 pthread_cond_broadcast(&uaudio_thread_cond);
202 /* Insufficient data to play, wait for collector */
203 pthread_cond_wait(&uaudio_thread_cond, &uaudio_thread_lock);
204 /* (Still) re-synchronizing */
208 pthread_mutex_unlock(&uaudio_thread_lock);
212 /** @brief Create background threads for audio processing
213 * @param callback Callback to collect audio data
214 * @param userdata Passed to @p callback
215 * @param playcallback Callback to play audio data
216 * @param min Minimum number of samples to play in a chunk
217 * @param max Maximum number of samples to play in a chunk
218 * @param flags Flags (not currently used)
220 * @p callback will be called multiple times in quick succession if necessary
221 * to gather at least @p min samples. Equally @p playcallback may be called
222 * repeatedly in quick succession to play however much was received in a single
225 void uaudio_thread_start(uaudio_callback *callback,
227 uaudio_playcallback *playcallback,
232 uaudio_thread_collect_callback = callback;
233 uaudio_thread_userdata = userdata;
234 uaudio_thread_play_callback = playcallback;
235 uaudio_thread_min = min;
236 uaudio_thread_max = max;
237 uaudio_thread_flags = flags;
238 uaudio_thread_started = 1;
239 uaudio_thread_activated = 0;
240 for(int n = 0; n < UAUDIO_THREAD_BUFFERS; ++n)
241 uaudio_buffers[n].samples = xcalloc_noptr(uaudio_thread_max,
243 uaudio_collect_buffer = uaudio_play_buffer = 0;
244 if((e = pthread_create(&uaudio_collect_thread,
246 uaudio_collect_thread_fn,
248 disorder_fatal(e, "pthread_create");
249 if((e = pthread_create(&uaudio_play_thread,
251 uaudio_play_thread_fn,
253 disorder_fatal(e, "pthread_create");
256 /** @brief Shut down background threads for audio processing */
257 void uaudio_thread_stop(void) {
260 pthread_mutex_lock(&uaudio_thread_lock);
261 uaudio_thread_activated = 0;
262 uaudio_thread_started = 0;
263 pthread_cond_broadcast(&uaudio_thread_cond);
264 pthread_mutex_unlock(&uaudio_thread_lock);
265 pthread_join(uaudio_collect_thread, &result);
266 pthread_join(uaudio_play_thread, &result);
267 for(int n = 0; n < UAUDIO_THREAD_BUFFERS; ++n)
268 xfree(uaudio_buffers[n].samples);
271 /** @brief Activate audio output */
272 void uaudio_thread_activate(void) {
273 pthread_mutex_lock(&uaudio_thread_lock);
274 uaudio_thread_activated = 1;
275 pthread_cond_broadcast(&uaudio_thread_cond);
276 pthread_mutex_unlock(&uaudio_thread_lock);
279 /** @brief Deactivate audio output */
280 void uaudio_thread_deactivate(void) {
281 pthread_mutex_lock(&uaudio_thread_lock);
282 uaudio_thread_activated = 0;
283 pthread_cond_broadcast(&uaudio_thread_cond);
284 pthread_mutex_unlock(&uaudio_thread_lock);