9f275ac85af1 — Chris Cannam tip 28 days ago
It turns out pa_mainloop_prepare was treating the msec timeout as usec in PulseAudio versions before 13.0, so the value actually passed to ppoll() was very short indeed. This is fixed in 13.0 and the result was to make it quite hard for the suspend/resume thread to acquire the loop mutex, which was almost always contended. Fix this by adding a couple of yields, and lowering the timeout drastically, since it obviously worked fine with a much lower effective value anyway.
1 files changed, 29 insertions(+), 19 deletions(-)

M src/PulseAudioIO.cpp
M src/PulseAudioIO.cpp +29 -19
@@ 92,7 92,7 @@
 m_playbackReady(false),
     m_suspended(false)
 {
-    log("starting");
+    log("PulseAudioIO: starting");
 
     if (m_mode == Mode::Playback) {
         m_target = 0;

          
@@ 190,7 190,7 @@
  PulseAudioIO::~PulseAudioIO()
 {
-    log("closing");
+    log("PulseAudioIO: closing");
 
     if (m_context) {
 

          
@@ 259,27 259,20 @@
 lock_guard<mutex> lguard(m_loopMutex);
             if (m_done) return;
 
-            //!!! not nice
-            rv = pa_mainloop_prepare(m_loop, 1000);
+            rv = pa_mainloop_prepare(m_loop, 100);
             if (rv < 0) {
                 log("ERROR: threadRun: Failure in pa_mainloop_prepare");
                 return;
             }
+
+            rv = pa_mainloop_poll(m_loop);
+            if (rv < 0) {
+                log("ERROR: threadRun: Failure in pa_mainloop_poll");
+                return;
+            }
         }
 
-        {
-#ifdef DEBUG_PULSE_AUDIO_IO
-//            cerr << "PulseAudioIO::threadRun: locking loop mutex for poll" << endl;
-#endif
-            lock_guard<mutex> lguard(m_loopMutex);
-            if (m_done) return;
-            rv = pa_mainloop_poll(m_loop);
-        }
-
-        if (rv < 0) {
-            log("ERROR: threadRun: Failure in pa_mainloop_poll");
-            return;
-        }
+        this_thread::yield();
 
         {
 #ifdef DEBUG_PULSE_AUDIO_IO

          
@@ 294,6 287,8 @@
 return;
             }
         }
+
+        this_thread::yield();
     }
 }
 

          
@@ 635,7 630,15 @@
 }
 
     lock_guard<mutex> lguard(m_loopMutex);
+#ifdef DEBUG_PULSE_AUDIO_IO
+    cerr << "PulseAudioIO::suspend: loop mutex ok" << endl;
+#endif
+    
     lock_guard<mutex> sguard(m_streamMutex);
+#ifdef DEBUG_PULSE_AUDIO_IO
+    cerr << "PulseAudioIO::suspend: stream mutex ok" << endl;
+#endif
+
     if (m_done) return;
     
     if (m_in) {

          
@@ 651,7 654,7 @@
 m_suspended = true;
     
 #ifdef DEBUG_PULSE_AUDIO_IO
-    cerr << "corked!" << endl;
+    cerr << "PulseAudioIO::suspend: corked!" << endl;
 #endif
 }
 

          
@@ 669,7 672,14 @@
 }
 
     lock_guard<mutex> lguard(m_loopMutex);
+#ifdef DEBUG_PULSE_AUDIO_IO
+    cerr << "PulseAudioIO::suspend: loop mutex ok" << endl;
+#endif
+
     lock_guard<mutex> sguard(m_streamMutex);
+#ifdef DEBUG_PULSE_AUDIO_IO
+    cerr << "PulseAudioIO::suspend: stream mutex ok" << endl;
+#endif
     if (m_done) return;
 
     if (m_in) {

          
@@ 684,7 694,7 @@
 m_suspended = false;
     
 #ifdef DEBUG_PULSE_AUDIO_IO
-    cerr << "uncorked!" << endl;
+    cerr << "PulseAudioIO::resume: uncorked!" << endl;
 #endif
 }