Switch to side-by-side view

--- a/sc2src/alsadirect.cpp
+++ b/sc2src/alsadirect.cpp
@@ -33,6 +33,7 @@
 
 #include <iostream>
 #include <queue>
+#include <mutex>
 #include <alsa/asoundlib.h>
 
 #include <samplerate.h>
@@ -62,13 +63,14 @@
    started */
 static bool qinit = false;
 
-static snd_pcm_t *pcm = nullptr;
+/* Alsa. Locked while we work with it */
+static std::mutex alsa_mutex;
+static snd_pcm_t *pcm;
 static string alsadevice("default");
-
-static bool alsa_init(const string& dev, AudioMessage *tsk);
-static void alsa_close();
-
-// From MPD recovery code
+static snd_pcm_sframes_t alsa_delay;
+
+// From MPD recovery code.
+// Note: no locking: we're called from alsawriter holding the lock.
 static int alsa_recover(snd_pcm_t *pcm, int err)
 {
     if (err == -EPIPE) {
@@ -124,6 +126,8 @@
 static snd_pcm_uframes_t periodframes;
 static snd_pcm_uframes_t bufferframes;
 
+static bool alsa_init(const string& dev, AudioMessage *tsk);
+
 static void *alsawriter(void *p)
 {
     while (true) {
@@ -142,9 +146,9 @@
             return (void*)1;
         }
 
+        std::unique_lock<std::mutex> lock(alsa_mutex);
         if (pcm == nullptr) {
             if (!alsa_init(alsadevice, tsk)) {
-                LOGERR("alsawriter: error alsa init\n");
                 alsaqueue.workerExit();
                 return (void*)1;
             }
@@ -156,6 +160,12 @@
         // be necessary, in synchronous mode, alsa is supposed to
         // perform complete writes except for errors or interrupts
         while (frames > 0) {
+            if (g_quitrequest) {
+                break;
+            }
+            if (snd_pcm_delay(pcm, &alsa_delay) < 0) {
+                alsa_delay = 0;
+            }
 //            LOGDEB("alsawriter: avail frames " << snd_pcm_avail(pcm) <<
 //                   " writing " << frames << endl);
             snd_pcm_sframes_t ret =  snd_pcm_writei(pcm, tsk->m_buf, frames);
@@ -313,28 +323,19 @@
 
 error:
     LOGERR("alsa_init: " << cmd << " error:" << snd_strerror(err) << endl);
+    alsa_close();
     return false;
 }
 
-static void alsa_close()
+void alsa_close()
 {
     LOGDEB("alsawriter: alsa close\n");
+    std::unique_lock<std::mutex> lock(alsa_mutex);
+    alsa_delay = 0;
     if (pcm != nullptr) {
         snd_pcm_close(pcm);
         pcm = nullptr;
     }
-}
-
-// Current in-driver delay in samples
-static int alsadelay()
-{
-    snd_pcm_sframes_t delay;
-    if (pcm != nullptr) {
-        if (snd_pcm_delay(pcm, &delay) >= 0) {
-            return delay;
-        }
-    }
-    return 0;
 }
 
 class Filter {
@@ -415,7 +416,7 @@
     
     if (qinit) {
         // Qsize in frames. This is the variable to control
-        qs = alsaqueue.qsize() * bufframes + alsadelay();
+        qs = alsaqueue.qsize() * bufframes + alsa_delay;
         // Error term
         double qstargframes = qstarg * bufframes;
         double et =  ((qstargframes - qs) / qstargframes);
@@ -723,12 +724,17 @@
     alsaqueue.start(1, alsawriter, 0);
 
     while (true) {
+        if (g_quitrequest) {
+            goto done;
+        }
         AudioMessage *tsk = 0;
         // Get new data
         if (!queue->take(&tsk)) {
             LOGDEB("audioEater: alsadirect: queue take failed\n");
             goto done;
         }
+        alsaAudioEater.pktcounter++;
+        
         if (tsk->m_bytes == 0 || tsk->m_chans == 0 || tsk->m_bits == 0) {
             LOGDEB("Zero buf\n");
             continue;