X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~mdw/git/disorder/blobdiff_plain/4fd3886810d93a7d3d2c2505e8b9ac38df2430d1..c7a422cbe672d7ec8ef9572f00d8230e0e69f23a:/lib/uaudio-thread.c diff --git a/lib/uaudio-thread.c b/lib/uaudio-thread.c index 3253a1d..e42980c 100644 --- a/lib/uaudio-thread.c +++ b/lib/uaudio-thread.c @@ -68,11 +68,13 @@ static pthread_t uaudio_collect_thread; /** @brief Playing thread ID */ static pthread_t uaudio_play_thread; +/** @brief Flags */ +static unsigned uaudio_thread_flags; + static uaudio_callback *uaudio_thread_collect_callback; static uaudio_playcallback *uaudio_thread_play_callback; static void *uaudio_thread_userdata; static int uaudio_thread_started; -static int uaudio_thread_activated; static int uaudio_thread_collecting; static pthread_mutex_t uaudio_thread_lock = PTHREAD_MUTEX_INITIALIZER; static pthread_cond_t uaudio_thread_cond = PTHREAD_COND_INITIALIZER; @@ -83,6 +85,9 @@ static size_t uaudio_thread_min; /** @brief Maximum number of samples per chunk */ static size_t uaudio_thread_max; +/** @brief Set when activated, clear when paused */ +static int uaudio_thread_activated; + /** @brief Return number of buffers currently in use */ static int uaudio_buffers_used(void) { return (uaudio_collect_buffer - uaudio_play_buffer) % UAUDIO_THREAD_BUFFERS; @@ -115,12 +120,14 @@ static void *uaudio_collect_thread_fn(void attribute((unused)) *arg) { /* Keep on trying until we get the minimum required amount of data */ b->nsamples = 0; - while(b->nsamples < uaudio_thread_min) { - b->nsamples += uaudio_thread_collect_callback - ((char *)b->samples - + b->nsamples * uaudio_sample_size, - uaudio_thread_max - b->nsamples, - uaudio_thread_userdata); + if(uaudio_thread_activated) { + while(b->nsamples < uaudio_thread_min) { + b->nsamples += uaudio_thread_collect_callback + ((char *)b->samples + + b->nsamples * uaudio_sample_size, + uaudio_thread_max - b->nsamples, + uaudio_thread_userdata); + } } pthread_mutex_lock(&uaudio_thread_lock); /* Advance to next buffer */ @@ -145,9 +152,23 @@ static void *uaudio_collect_thread_fn(void attribute((unused)) *arg) { */ static void *uaudio_play_thread_fn(void attribute((unused)) *arg) { int resync = 1; + unsigned last_flags = 0; + unsigned char zero[uaudio_thread_max * uaudio_sample_size]; + memset(zero, 0, sizeof zero); - pthread_mutex_lock(&uaudio_thread_lock); while(uaudio_thread_started) { + // If we're paused then just play silence + if(!uaudio_thread_activated) { + pthread_mutex_unlock(&uaudio_thread_lock); + unsigned flags = UAUDIO_PAUSED; + if(last_flags & UAUDIO_PLAYING) + flags |= UAUDIO_PAUSE; + uaudio_thread_play_callback(zero, uaudio_thread_max, + last_flags = flags); + /* We expect the play callback to block for a reasonable period */ + pthread_mutex_lock(&uaudio_thread_lock); + continue; + } const int used = uaudio_buffers_used(); int go; @@ -162,10 +183,15 @@ static void *uaudio_play_thread_fn(void attribute((unused)) *arg) { pthread_mutex_unlock(&uaudio_thread_lock); //fprintf(stderr, "P%d.", uaudio_play_buffer); size_t played = 0; - while(played < b->nsamples) + while(played < b->nsamples) { + unsigned flags = UAUDIO_PLAYING; + if(last_flags & UAUDIO_PAUSED) + flags |= UAUDIO_RESUME; played += uaudio_thread_play_callback((char *)b->samples + played * uaudio_sample_size, - b->nsamples - played); + b->nsamples - played, + last_flags = flags); + } pthread_mutex_lock(&uaudio_thread_lock); /* Move to next buffer */ uaudio_play_buffer = (1 + uaudio_play_buffer) % UAUDIO_THREAD_BUFFERS; @@ -189,6 +215,7 @@ static void *uaudio_play_thread_fn(void attribute((unused)) *arg) { * @param playcallback Callback to play audio data * @param min Minimum number of samples to play in a chunk * @param max Maximum number of samples to play in a chunk + * @param flags Flags (not currently used) * * @p callback will be called multiple times in quick succession if necessary * to gather at least @p min samples. Equally @p playcallback may be called @@ -199,27 +226,31 @@ void uaudio_thread_start(uaudio_callback *callback, void *userdata, uaudio_playcallback *playcallback, size_t min, - size_t max) { + size_t max, + unsigned flags) { int e; uaudio_thread_collect_callback = callback; uaudio_thread_userdata = userdata; uaudio_thread_play_callback = playcallback; uaudio_thread_min = min; uaudio_thread_max = max; + uaudio_thread_flags = flags; uaudio_thread_started = 1; + uaudio_thread_activated = 0; for(int n = 0; n < UAUDIO_THREAD_BUFFERS; ++n) - uaudio_buffers[n].samples = xcalloc(uaudio_thread_max, uaudio_sample_size); + uaudio_buffers[n].samples = xcalloc_noptr(uaudio_thread_max, + uaudio_sample_size); uaudio_collect_buffer = uaudio_play_buffer = 0; if((e = pthread_create(&uaudio_collect_thread, NULL, uaudio_collect_thread_fn, NULL))) - fatal(e, "pthread_create"); + disorder_fatal(e, "pthread_create"); if((e = pthread_create(&uaudio_play_thread, NULL, uaudio_play_thread_fn, NULL))) - fatal(e, "pthread_create"); + disorder_fatal(e, "pthread_create"); } /** @brief Shut down background threads for audio processing */ @@ -242,19 +273,14 @@ void uaudio_thread_activate(void) { pthread_mutex_lock(&uaudio_thread_lock); uaudio_thread_activated = 1; pthread_cond_broadcast(&uaudio_thread_cond); - while(!uaudio_thread_collecting) - pthread_cond_wait(&uaudio_thread_cond, &uaudio_thread_lock); pthread_mutex_unlock(&uaudio_thread_lock); } /** @brief Deactivate audio output */ void uaudio_thread_deactivate(void) { pthread_mutex_lock(&uaudio_thread_lock); - uaudio_thread_activated = 0; + uaudio_thread_activated = 0; pthread_cond_broadcast(&uaudio_thread_cond); - - while(uaudio_thread_collecting || uaudio_buffers_used()) - pthread_cond_wait(&uaudio_thread_cond, &uaudio_thread_lock); pthread_mutex_unlock(&uaudio_thread_lock); }