chiark / gitweb /
Suppress no-collection log message for scratches
[disorder] / lib / uaudio-thread.c
index 3253a1d4f75db199a45684be1e54ba1940205196..e42980c211cd10cc22c95cb6a81c7f7586d3598e 100644 (file)
@@ -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);
 }