changeset 193:0b3aa9b702bb

* Fix problems playing back when the target block size is close to, or greater than, the default ring-buffer size
author Chris Cannam
date Tue, 22 Jun 2010 13:48:00 +0000
parents 2b1869fccec1
children 302dae1f6016
files audioio/AudioCallbackPlaySource.cpp audioio/AudioCallbackPlaySource.h audioio/AudioPulseAudioTarget.cpp
diffstat 3 files changed, 49 insertions(+), 27 deletions(-) [+]
line wrap: on
line diff
--- a/audioio/AudioCallbackPlaySource.cpp	Tue Jun 22 09:45:19 2010 +0000
+++ b/audioio/AudioCallbackPlaySource.cpp	Tue Jun 22 13:48:00 2010 +0000
@@ -37,7 +37,7 @@
 //#define DEBUG_AUDIO_PLAY_SOURCE 1
 //#define DEBUG_AUDIO_PLAY_SOURCE_PLAYING 1
 
-const size_t AudioCallbackPlaySource::m_ringBufferSize = 131071;
+static const size_t DEFAULT_RING_BUFFER_SIZE = 131071;
 
 AudioCallbackPlaySource::AudioCallbackPlaySource(ViewManagerBase *manager,
                                                  QString clientName) :
@@ -62,6 +62,7 @@
     m_playing(false),
     m_exiting(false),
     m_lastModelEndFrame(0),
+    m_ringBufferSize(DEFAULT_RING_BUFFER_SIZE),
     m_outputLeft(0.0),
     m_outputRight(0.0),
     m_auditioningPlugin(0),
@@ -529,9 +530,20 @@
 AudioCallbackPlaySource::setTarget(AudioCallbackPlayTarget *target, size_t size)
 {
     m_target = target;
-//    std::cout << "AudioCallbackPlaySource::setTargetBlockSize() -> " << size << std::endl;
-    assert(size < m_ringBufferSize);
-    m_blockSize = size;
+    std::cout << "AudioCallbackPlaySource::setTarget: Block size -> " << size << std::endl;
+    if (size != 0) {
+        m_blockSize = size;
+    }
+    if (size * 4 > m_ringBufferSize) {
+        std::cerr << "AudioCallbackPlaySource::setTarget: Buffer size "
+                  << size << " > a quarter of ring buffer size "
+                  << m_ringBufferSize << ", calling for more ring buffer"
+                  << std::endl;
+        m_ringBufferSize = size * 4;
+        if (m_writeBuffers && !m_writeBuffers->empty()) {
+            clearRingBuffers();
+        }
+    }
 }
 
 size_t
@@ -684,6 +696,7 @@
         RealTime playing_t = bufferedto_t
             - latency_t - stretchlat_t - lastretrieved_t - inbuffer_t
             + sincerequest_t;
+        if (playing_t < RealTime::zeroTime) playing_t = RealTime::zeroTime;
         size_t frame = RealTime::realTime2Frame(playing_t, sourceRate);
         return m_viewManager->alignPlaybackFrameToReference(frame);
     }
@@ -1033,6 +1046,9 @@
     int count = ucount;
 
     if (!m_playing) {
+#ifdef DEBUG_AUDIO_PLAY_SOURCE_PLAYING
+        std::cerr << "AudioCallbackPlaySource::getSourceSamples: Not playing" << std::endl;
+#endif
 	for (size_t ch = 0; ch < getTargetChannelCount(); ++ch) {
 	    for (int i = 0; i < count; ++i) {
 		buffer[ch][i] = 0.0;
@@ -1061,7 +1077,9 @@
 #ifdef DEBUG_AUDIO_PLAY_SOURCE
             std::cerr << "WARNING: AudioCallbackPlaySource::getSourceSamples: "
                       << "Ring buffer for channel " << ch << " has only "
-                      << rs << " (of " << count << ") samples available, "
+                      << rs << " (of " << count << ") samples available ("
+                      << "ring buffer size is " << rb->getSize() << ", write "
+                      << "space " << rb->getWriteSpace() << "), "
                       << "reducing request size" << std::endl;
 #endif
             count = rs;
@@ -1297,6 +1315,9 @@
     bool readWriteEqual = (m_readBuffers == m_writeBuffers);
 
 #ifdef DEBUG_AUDIO_PLAY_SOURCE
+    if (!readWriteEqual) {
+        std::cout << "AudioCallbackPlaySourceFillThread: note read buffers != write buffers" << std::endl;
+    }
     std::cout << "AudioCallbackPlaySourceFillThread: filling " << space << " frames" << std::endl;
 #endif
 
@@ -1665,6 +1686,9 @@
 		    m_lastModelEndFrame) {
 		    // OK, we don't have enough and there's more to
 		    // read -- don't unify until we can do better
+#ifdef DEBUG_AUDIO_PLAY_SOURCE_PLAYING
+                    std::cerr << "AudioCallbackPlaySource::unifyRingBuffers: Not unifying: write buffer has less (" << wb->getReadSpace() << ") than " << m_blockSize*2 << " to read and write buffer fill (" << m_writeBufferFill << ") is not close to end frame (" << m_lastModelEndFrame << ")" << std::endl;
+#endif
 		    return;
 		}
 	    }
@@ -1682,7 +1706,9 @@
 	else rf = 0;
     }
     
-    //std::cout << "m_readBufferFill = " << m_readBufferFill << ", rf = " << rf << ", m_writeBufferFill = " << m_writeBufferFill << std::endl;
+#ifdef DEBUG_AUDIO_PLAY_SOURCE_PLAYING
+    std::cerr << "AudioCallbackPlaySource::unifyRingBuffers: m_readBufferFill = " << m_readBufferFill << ", rf = " << rf << ", m_writeBufferFill = " << m_writeBufferFill << std::endl;
+#endif
 
     size_t wf = m_writeBufferFill;
     size_t skip = 0;
@@ -1710,7 +1736,9 @@
     m_bufferScavenger.claim(m_readBuffers);
     m_readBuffers = m_writeBuffers;
     m_readBufferFill = m_writeBufferFill;
-//    std::cout << "unified" << std::endl;
+#ifdef DEBUG_AUDIO_PLAY_SOURCE_PLAYING
+    std::cerr << "unified" << std::endl;
+#endif
 }
 
 void
@@ -1746,7 +1774,8 @@
 	    
 	    float ms = 100;
 	    if (s.getSourceSampleRate() > 0) {
-		ms = float(m_ringBufferSize) / float(s.getSourceSampleRate()) * 1000.0;
+		ms = float(s.m_ringBufferSize) /
+                    float(s.getSourceSampleRate()) * 1000.0;
 	    }
 	    
 	    if (s.m_playing) ms /= 10;
--- a/audioio/AudioCallbackPlaySource.h	Tue Jun 22 09:45:19 2010 +0000
+++ b/audioio/AudioCallbackPlaySource.h	Tue Jun 22 13:48:00 2010 +0000
@@ -296,7 +296,7 @@
     bool                              m_playing;
     bool                              m_exiting;
     size_t                            m_lastModelEndFrame;
-    static const size_t               m_ringBufferSize;
+    size_t                            m_ringBufferSize;
     float                             m_outputLeft;
     float                             m_outputRight;
     RealTimePluginInstance           *m_auditioningPlugin;
--- a/audioio/AudioPulseAudioTarget.cpp	Tue Jun 22 09:45:19 2010 +0000
+++ b/audioio/AudioPulseAudioTarget.cpp	Tue Jun 22 13:48:00 2010 +0000
@@ -158,19 +158,11 @@
 
     QMutexLocker locker(&m_mutex);
 
-    if (m_source->getTargetPlayLatency() == 0) { //!!! need better test
-            //!!!
-            pa_usec_t latency = 0;
-            int negative = 0;
-            if (pa_stream_get_latency(m_stream, &latency, &negative)) {
-                std::cerr << "AudioPulseAudioTarget::streamWrite: Failed to query latency" << std::endl;
-            }
-//            std::cerr << "Latency = " << latency << " usec" << std::endl;
-            int latframes = (latency / 1000000.f) * float(m_sampleRate);
-//            std::cerr << "that's " << latframes << " frames" << std::endl;
-            if (latframes > 0) {
-                m_source->setTargetPlayLatency(latframes); //!!! buh
-            }
+    pa_usec_t latency = 0;
+    int negative = 0;
+    if (!pa_stream_get_latency(m_stream, &latency, &negative)) {
+        int latframes = (latency / 1000000.f) * float(m_sampleRate);
+        if (latframes > 0) m_source->setTargetPlayLatency(latframes);
     }
 
     static float *output = 0;
@@ -324,13 +316,14 @@
                 std::cerr << "AudioPulseAudioTarget::streamStateChanged: Cannot query stream buffer attributes" << std::endl;
                 m_source->setTarget(this, m_bufferSize);
                 m_source->setTargetSampleRate(m_sampleRate);
-                m_source->setTargetPlayLatency(latframes);
+                if (latframes != 0) m_source->setTargetPlayLatency(latframes);
             } else {
-                std::cerr << "AudioPulseAudioTarget::streamStateChanged: stream max length = " << attr->maxlength << std::endl;
-                int latency = attr->tlength;
-                std::cerr << "latency = " << latency << std::endl;
-                m_source->setTarget(this, attr->maxlength);
+                int targetLength = attr->tlength;
+                std::cerr << "AudioPulseAudioTarget::streamStateChanged: stream target length = " << targetLength << std::endl;
+                m_source->setTarget(this, targetLength);
                 m_source->setTargetSampleRate(m_sampleRate);
+                if (latframes == 0) latframes = targetLength;
+                std::cerr << "latency = " << latframes << std::endl;
                 m_source->setTargetPlayLatency(latframes);
             }
         }