8473396b6dc7 — Chris Cannam 5 years ago
Merge from the default branch
5 files changed, 105 insertions(+), 237 deletions(-)

M AudioFactory.cpp
M PulseAudioIO.cpp
M PulseAudioIO.h
M PulseAudioIO.cpp => PulseAudioPlaybackTarget.cpp
M PulseAudioIO.h => PulseAudioPlaybackTarget.h
M AudioFactory.cpp +10 -0
@@ 4,6 4,7 @@ 
 #include "AudioFactory.h"
 
 #include "JACKPlaybackTarget.h"
+#include "PulseAudioPlaybackTarget.h"
 #include "PortAudioPlaybackTarget.h"
 
 #include "JACKRecordSource.h"

          
@@ 31,6 32,15 @@ AudioFactory::createCallbackPlayTarget(A
     }
 #endif
 
+#ifdef HAVE_LIBPULSE
+    target = new PulseAudioPlaybackTarget(source);
+    if (target->isTargetOK()) return target;
+    else {
+	std::cerr << "WARNING: AudioFactory::createCallbackTarget: Failed to open PulseAudio target" << std::endl;
+	delete target;
+    }
+#endif
+
 #ifdef HAVE_PORTAUDIO
     target = new PortAudioPlaybackTarget(source);
     if (target->isTargetOK()) return target;

          
M PulseAudioIO.cpp +11 -10
@@ 21,7 21,7 @@ using std::endl;
 namespace Turbot {
 
 PulseAudioIO::PulseAudioIO(ApplicationRecordTarget *target,
-                                     ApplicationPlaybackSource *source) :
+                           ApplicationPlaybackSource *source) :
     SystemAudioIO(target, source),
     m_mutex(QMutex::Recursive), //!!!???
     m_loop(0),

          
@@ 32,6 32,7 @@ PulseAudioIO::PulseAudioIO(ApplicationRe
     m_loopThread(0),
     m_bufferSize(0),
     m_sampleRate(0),
+    m_paChannels(2),
     m_done(false),
     m_captureReady(false),
     m_playbackReady(false)

          
@@ 56,7 57,7 @@ PulseAudioIO::PulseAudioIO(ApplicationRe
 	m_sampleRate = m_source->getApplicationSampleRate();
     }
     m_spec.rate = m_sampleRate;
-    m_spec.channels = 2;
+    m_spec.channels = m_paChannels;
     m_spec.format = PA_SAMPLE_FLOAT32NE;
 
     m_context = pa_context_new(m_api, "turbot");

          
@@ 206,14 207,14 @@ PulseAudioIO::streamWrite(int requested)
 	    tmpbuf[i] = new float[tmpbufsz];
 	}
 
-        output = new float[tmpbufsz * tmpbufch];
+        output = new float[tmpbufsz * m_paChannels];
     }
 	
     m_source->getSourceSamples(nframes, tmpbuf);
 
     float peakLeft = 0.0, peakRight = 0.0;
 
-    for (int ch = 0; ch < 2; ++ch) {
+    for (int ch = 0; ch < m_paChannels; ++ch) {
 	
 	float peak = 0.0;
 

          
@@ 221,22 222,22 @@ PulseAudioIO::streamWrite(int requested)
 
 	    // PulseAudio samples are interleaved
 	    for (int i = 0; i < nframes; ++i) {
-                output[i * 2 + ch] = tmpbuf[ch][i] * m_outputGain;
-                float sample = fabsf(output[i * 2 + ch]);
+                output[i * m_paChannels + ch] = tmpbuf[ch][i] * m_outputGain;
+                float sample = fabsf(output[i * m_paChannels + ch]);
                 if (sample > peak) peak = sample;
 	    }
 
 	} else if (ch == 1 && sourceChannels == 1) {
 
 	    for (int i = 0; i < nframes; ++i) {
-                output[i * 2 + ch] = tmpbuf[0][i] * m_outputGain;
-                float sample = fabsf(output[i * 2 + ch]);
+                output[i * m_paChannels + ch] = tmpbuf[0][i] * m_outputGain;
+                float sample = fabsf(output[i * m_paChannels + ch]);
                 if (sample > peak) peak = sample;
 	    }
 
 	} else {
 	    for (int i = 0; i < nframes; ++i) {
-		output[i * 2 + ch] = 0;
+		output[i * m_paChannels + ch] = 0;
 	    }
 	}
 

          
@@ 381,7 382,7 @@ PulseAudioIO::streamStateChanged(pa_stre
     cerr << "PulseAudioIO::streamStateChanged" << endl;
 #endif
 
-    assert(stream == m_in || stream == m_out);
+    assert(stream == m_out);
 
     QMutexLocker locker(&m_mutex);
 

          
M PulseAudioIO.h +1 -0
@@ 72,6 72,7 @@ protected:
 
     int m_bufferSize;
     int m_sampleRate;
+    int m_paChannels;
     bool m_done;
 
     bool m_captureReady;

          
M PulseAudioIO.cpp => PulseAudioPlaybackTarget.cpp +76 -212
@@ 3,9 3,8 @@ 
 
 #ifdef HAVE_LIBPULSE
 
-#include "PulseAudioIO.h"
+#include "PulseAudioPlaybackTarget.h"
 #include "ApplicationPlaybackSource.h"
-#include "ApplicationRecordTarget.h"
 
 #include "VectorOps.h"
 

          
@@ 16,33 15,31 @@ using std::cerr;
 using std::cout;
 using std::endl;
 
-//#define DEBUG_AUDIO_PULSE_AUDIO_IO 1
+//#define DEBUG_PULSE_AUDIO_PLAYBACK_TARGET 1
 
 namespace Turbot {
 
-PulseAudioIO::PulseAudioIO(ApplicationRecordTarget *target,
-                                     ApplicationPlaybackSource *source) :
-    SystemAudioIO(target, source),
+PulseAudioPlaybackTarget::PulseAudioPlaybackTarget(ApplicationPlaybackSource *source) :
+    SystemPlaybackTarget(source),
     m_mutex(QMutex::Recursive), //!!!???
     m_loop(0),
     m_api(0),
     m_context(0),
-    m_in(0), 
     m_out(0),
     m_loopThread(0),
     m_bufferSize(0),
     m_sampleRate(0),
+    m_paChannels(2),
     m_done(false),
-    m_captureReady(false),
     m_playbackReady(false)
 {
-#ifdef DEBUG_AUDIO_PULSE_AUDIO_IO
-    cerr << "PulseAudioIO: Initialising for PulseAudio" << endl;
+#ifdef DEBUG_PULSE_AUDIO_PLAYBACK_TARGET
+    cerr << "PulseAudioPlaybackTarget: Initialising for PulseAudio" << endl;
 #endif
 
     m_loop = pa_mainloop_new();
     if (!m_loop) {
-        cerr << "ERROR: PulseAudioIO: Failed to create main loop" << endl;
+        cerr << "ERROR: PulseAudioPlaybackTarget: Failed to create main loop" << endl;
         return;
     }
 

          
@@ 56,12 53,12 @@ PulseAudioIO::PulseAudioIO(ApplicationRe
 	m_sampleRate = m_source->getApplicationSampleRate();
     }
     m_spec.rate = m_sampleRate;
-    m_spec.channels = 2;
+    m_spec.channels = m_paChannels;
     m_spec.format = PA_SAMPLE_FLOAT32NE;
 
     m_context = pa_context_new(m_api, "turbot");
     if (!m_context) {
-        cerr << "ERROR: PulseAudioIO: Failed to create context object" << endl;
+        cerr << "ERROR: PulseAudioPlaybackTarget: Failed to create context object" << endl;
         return;
     }
 

          
@@ 72,14 69,14 @@ PulseAudioIO::PulseAudioIO(ApplicationRe
     m_loopThread = new MainLoopThread(m_loop);
     m_loopThread->start();
 
-#ifdef DEBUG_PULSE_AUDIO_IO
-    cerr << "PulseAudioIO: initialised OK" << endl;
+#ifdef DEBUG_PULSE_AUDIO_PLAYBACK_TARGET
+    cerr << "PulseAudioPlaybackTarget: initialised OK" << endl;
 #endif
 }
 
-PulseAudioIO::~PulseAudioIO()
+PulseAudioPlaybackTarget::~PulseAudioPlaybackTarget()
 {
-    cerr << "PulseAudioIO::~PulseAudioIO()" << endl;
+    cerr << "PulseAudioPlaybackTarget::~PulseAudioPlaybackTarget()" << endl;
 
 //!!!    if (m_source) {
 //        m_source->setTarget(0, m_bufferSize);

          
@@ 89,7 86,6 @@ PulseAudioIO::~PulseAudioIO()
 
     QMutexLocker locker(&m_mutex);
 
-    if (m_in) pa_stream_unref(m_in);
     if (m_out) pa_stream_unref(m_out);
 
     if (m_context) pa_context_unref(m_context);

          
@@ 99,35 95,17 @@ PulseAudioIO::~PulseAudioIO()
         pa_mainloop_free(m_loop);
     }
 
-    cerr << "PulseAudioIO::~PulseAudioIO() done" << endl;
+    cerr << "PulseAudioPlaybackTarget::~PulseAudioPlaybackTarget() done" << endl;
 }
 
 bool
-PulseAudioIO::isSourceOK() const
-{
-    return (m_context != 0);
-}
-
-bool
-PulseAudioIO::isTargetOK() const
+PulseAudioPlaybackTarget::isTargetOK() const
 {
     return (m_context != 0);
 }
 
-bool
-PulseAudioIO::isSourceReady() const
-{
-    return m_captureReady;
-}
-
-bool
-PulseAudioIO::isTargetReady() const
-{
-    return m_playbackReady;
-}
-
 double
-PulseAudioIO::getCurrentTime() const
+PulseAudioPlaybackTarget::getCurrentTime() const
 {
     if (!m_out) return 0.0;
     

          
@@ 137,11 115,11 @@ PulseAudioIO::getCurrentTime() const
 }
 
 void
-PulseAudioIO::streamWriteStatic(pa_stream *stream,
-                                size_t length,
-                                void *data)
+PulseAudioPlaybackTarget::streamWriteStatic(pa_stream *stream,
+                                            size_t length,
+                                            void *data)
 {
-    PulseAudioIO *target = (PulseAudioIO *)data;
+    PulseAudioPlaybackTarget *target = (PulseAudioPlaybackTarget *)data;
     
     assert(stream == target->m_out);
 

          
@@ 149,13 127,16 @@ PulseAudioIO::streamWriteStatic(pa_strea
 }
 
 void
-PulseAudioIO::streamWrite(int requested)
+PulseAudioPlaybackTarget::streamWrite(int requested)
 {
-#ifdef DEBUG_AUDIO_PULSE_AUDIO_IO    
-    cout << "PulseAudioIO::streamWrite(" << requested << ")" << endl;
+#ifdef DEBUG_PULSE_AUDIO_PLAYBACK_TARGET    
+    cout << "PulseAudioPlaybackTarget::streamWrite(" << requested << ")" << endl;
 #endif
     if (m_done) return;
 
+    // requested is a byte count for an interleaved buffer, so number
+    // of frames = requested / (channels * sizeof(float))
+
     QMutexLocker locker(&m_mutex);
 
     pa_usec_t latency = 0;

          
@@ 172,17 153,28 @@ PulseAudioIO::streamWrite(int requested)
 
     int sourceChannels = m_source->getApplicationChannelCount();
     if (sourceChannels == 0) {
+        //!!! but this is incredibly cpu-intensive and poor for
+        //!!! battery life, because it happens all the time when not
+        //!!! playing. should pause and resume the stream somehow
+        int samples = requested / sizeof(float);
+        output = new float[samples];
+        for (int i = 0; i < samples; ++i) {
+            output[i] = 0.f;
+        }
+        pa_stream_write(m_out, output, samples * sizeof(float),
+                        0, 0, PA_SEEK_RELATIVE);
+        m_source->setOutputLevels(0.f, 0.f);
         return;
     }
 
     int nframes = requested / (sourceChannels * sizeof(float)); //!!! this should be dividing by how many channels PA thinks it has!
 
     if (nframes > m_bufferSize) {
-        cerr << "WARNING: PulseAudioIO::streamWrite: nframes " << nframes << " > m_bufferSize " << m_bufferSize << endl;
+        cerr << "WARNING: PulseAudioPlaybackTarget::streamWrite: nframes " << nframes << " > m_bufferSize " << m_bufferSize << endl;
     }
 
-#ifdef DEBUG_AUDIO_PULSE_AUDIO_IO
-    cout << "PulseAudioIO::streamWrite: nframes = " << nframes << endl;
+#ifdef DEBUG_PULSE_AUDIO_PLAYBACK_TARGET
+    cerr << "PulseAudioPlaybackTarget::streamWrite: nframes = " << nframes << endl;
 #endif
 
     if (!tmpbuf || tmpbufch != sourceChannels || int(tmpbufsz) < nframes) {

          
@@ 206,14 198,14 @@ PulseAudioIO::streamWrite(int requested)
 	    tmpbuf[i] = new float[tmpbufsz];
 	}
 
-        output = new float[tmpbufsz * tmpbufch];
+        output = new float[tmpbufsz * m_paChannels];
     }
 	
     m_source->getSourceSamples(nframes, tmpbuf);
 
     float peakLeft = 0.0, peakRight = 0.0;
 
-    for (int ch = 0; ch < 2; ++ch) {
+    for (int ch = 0; ch < m_paChannels; ++ch) {
 	
 	float peak = 0.0;
 

          
@@ 221,22 213,22 @@ PulseAudioIO::streamWrite(int requested)
 
 	    // PulseAudio samples are interleaved
 	    for (int i = 0; i < nframes; ++i) {
-                output[i * 2 + ch] = tmpbuf[ch][i] * m_outputGain;
-                float sample = fabsf(output[i * 2 + ch]);
+                output[i * m_paChannels + ch] = tmpbuf[ch][i] * m_outputGain;
+                float sample = fabsf(output[i * m_paChannels + ch]);
                 if (sample > peak) peak = sample;
 	    }
 
 	} else if (ch == 1 && sourceChannels == 1) {
 
 	    for (int i = 0; i < nframes; ++i) {
-                output[i * 2 + ch] = tmpbuf[0][i] * m_outputGain;
-                float sample = fabsf(output[i * 2 + ch]);
+                output[i * m_paChannels + ch] = tmpbuf[0][i] * m_outputGain;
+                float sample = fabsf(output[i * m_paChannels + ch]);
                 if (sample > peak) peak = sample;
 	    }
 
 	} else {
 	    for (int i = 0; i < nframes; ++i) {
-		output[i * 2 + ch] = 0;
+		output[i * m_paChannels + ch] = 0;
 	    }
 	}
 

          
@@ 244,7 236,7 @@ PulseAudioIO::streamWrite(int requested)
 	if (ch > 0 || sourceChannels == 1) peakRight = peak;
     }
 
-#ifdef DEBUG_AUDIO_PULSE_AUDIO_IO
+#ifdef DEBUG_PULSE_AUDIO_PLAYBACK_TARGET
     cerr << "calling pa_stream_write with "
               << nframes * tmpbufch * sizeof(float) << " bytes" << endl;
 #endif

          
@@ 252,136 244,32 @@ PulseAudioIO::streamWrite(int requested)
     pa_stream_write(m_out, output, nframes * tmpbufch * sizeof(float),
                     0, 0, PA_SEEK_RELATIVE);
 
+//    cerr << "peaks: " << peakLeft << ", " << peakRight << endl;
+
     m_source->setOutputLevels(peakLeft, peakRight);
 
     return;
 }
 
 void
-PulseAudioIO::streamReadStatic(pa_stream *stream,
-                               size_t length,
-                               void *data)
-{
-    PulseAudioIO *target = (PulseAudioIO *)data;
-    
-    assert(stream == target->m_in);
-
-    target->streamRead(length);
-}
-
-void
-PulseAudioIO::streamRead(int available)
-{
-#ifdef DEBUG_AUDIO_PULSE_AUDIO_IO
-    cerr << "PulseAudioIO::streamRead(" << available << ")" << endl;
-#endif
-
-    QMutexLocker locker(&m_mutex);
-
-    pa_usec_t latency = 0;
-    int negative = 0;
-    if (!pa_stream_get_latency(m_in, &latency, &negative)) {
-        int latframes = (latency / 1000000.f) * float(m_sampleRate);
-        if (latframes > 0) m_target->setSystemRecordLatency(latframes);
-    }
-
-    int sz = pa_stream_readable_size(m_in);
-
-    static const void *input = 0;
-    static float **tmpbuf = 0;
-    static int tmpbufch = 0;
-    static int tmpbufsz = 0;
-
-    int targetChannels = m_target->getApplicationChannelCount();
-
-    //!!! need to handle mismatches between our and PA's expectations!
-
-    if (targetChannels < 2) targetChannels = 2;
-
-    int nframes = available / (targetChannels * sizeof(float)); //!!! this should be dividing by how many channels PA thinks it has!
-
-    if (nframes > m_bufferSize) {
-        cerr << "WARNING: PulseAudioIO::streamRead: nframes " << nframes << " > m_bufferSize " << m_bufferSize << endl;
-    }
-
-#ifdef DEBUG_AUDIO_PULSE_AUDIO_IO
-    cout << "PulseAudioIO::streamRead: nframes = " << nframes << endl;
-#endif
-
-    if (!tmpbuf || tmpbufch != targetChannels || int(tmpbufsz) < nframes) {
-
-	if (tmpbuf) {
-	    for (int i = 0; i < tmpbufch; ++i) {
-		delete[] tmpbuf[i];
-	    }
-	    delete[] tmpbuf;
-	}
-
-	tmpbufch = targetChannels;
-	tmpbufsz = nframes;
-	tmpbuf = new float *[tmpbufch];
-
-	for (int i = 0; i < tmpbufch; ++i) {
-	    tmpbuf[i] = new float[tmpbufsz];
-	}
-    }
-	
-    float peakLeft = 0.0, peakRight = 0.0;
-
-    size_t actual = available;
-
-    pa_stream_peek(m_in, &input, &actual);
-
-    int actualFrames = actual / (targetChannels * sizeof(float)); //!!! this should be dividing by how many channels PA thinks it has!
-
-    if (actualFrames < nframes) {
-        cerr << "WARNING: streamRead: read " << actualFrames << " frames, expected " << nframes << endl;
-    }
-    
-    const float *finput = (const float *)input;
-
-    for (int ch = 0; ch < targetChannels; ++ch) {
-	
-	float peak = 0.0;
-
-        // PulseAudio samples are interleaved
-        for (int i = 0; i < nframes; ++i) {
-            tmpbuf[ch][i] = finput[i * 2 + ch];
-            float sample = fabsf(finput[i * 2 + ch]);
-            if (sample > peak) peak = sample;
-        }
-
-	if (ch == 0) peakLeft = peak;
-	if (ch > 0 || targetChannels == 1) peakRight = peak;
-    }
-
-    m_target->putSamples(nframes, tmpbuf);
-    m_target->setInputLevels(peakLeft, peakRight);
-
-    pa_stream_drop(m_in);
-
-    return;
-}
-
-void
-PulseAudioIO::streamStateChangedStatic(pa_stream *stream,
+PulseAudioPlaybackTarget::streamStateChangedStatic(pa_stream *stream,
                                             void *data)
 {
-    PulseAudioIO *target = (PulseAudioIO *)data;
+    PulseAudioPlaybackTarget *target = (PulseAudioPlaybackTarget *)data;
     
-    assert(stream == target->m_in || stream == target->m_out);
+    assert(stream == target->m_out);
 
     target->streamStateChanged(stream);
 }
 
 void
-PulseAudioIO::streamStateChanged(pa_stream *stream)
+PulseAudioPlaybackTarget::streamStateChanged(pa_stream *stream)
 {
-#ifdef DEBUG_AUDIO_PULSE_AUDIO_IO
-    cerr << "PulseAudioIO::streamStateChanged" << endl;
+#ifdef DEBUG_PULSE_AUDIO_PLAYBACK_TARGET
+    cerr << "PulseAudioPlaybackTarget::streamStateChanged" << endl;
 #endif
 
-    assert(stream == m_in || stream == m_out);
+    assert(stream == m_out);
 
     QMutexLocker locker(&m_mutex);
 

          
@@ 393,18 281,12 @@ PulseAudioIO::streamStateChanged(pa_stre
 
         case PA_STREAM_READY:
         {
-            if (stream == m_in) {
-                cerr << "PulseAudioIO::streamStateChanged: Capture ready" << endl;
-                m_captureReady = true;
-            } else {
-                cerr << "PulseAudioIO::streamStateChanged: Playback ready" << endl;
-                m_playbackReady = true;
-            }                
+            m_playbackReady = true;
 
             pa_usec_t latency = 0;
             int negative = 0;
             if (pa_stream_get_latency(m_out, &latency, &negative)) {
-                cerr << "PulseAudioIO::contextStateChanged: Failed to query latency" << endl;
+                cerr << "PulseAudioPlaybackTarget::contextStateChanged: Failed to query latency" << endl;
             }
             cerr << "Latency = " << latency << " usec" << endl;
             int latframes = (latency / 1000000.f) * float(m_sampleRate);

          
@@ 412,12 294,12 @@ PulseAudioIO::streamStateChanged(pa_stre
 
             const pa_buffer_attr *attr;
             if (!(attr = pa_stream_get_buffer_attr(m_out))) {
-                cerr << "PulseAudioIO::streamStateChanged: Cannot query stream buffer attributes" << endl;
+                cerr << "PulseAudioPlaybackTarget::streamStateChanged: Cannot query stream buffer attributes" << endl;
                 m_source->setSystemPlaybackBlockSize(4096);
                 m_source->setSystemPlaybackSampleRate(m_sampleRate);
                 m_source->setSystemPlaybackLatency(latframes);
             } else {
-                cerr << "PulseAudioIO::streamStateChanged: stream max length = " << attr->maxlength << endl;
+                cerr << "PulseAudioPlaybackTarget::streamStateChanged: stream max length = " << attr->maxlength << endl;
                 int latency = attr->tlength;
                 cerr << "latency = " << latency << endl;
                 m_source->setSystemPlaybackBlockSize(attr->maxlength);

          
@@ 425,15 307,12 @@ PulseAudioIO::streamStateChanged(pa_stre
                 m_source->setSystemPlaybackLatency(latframes);
             }
 
-            cerr << "PulseAudioIO: setting system record sample rate to " << m_sampleRate << endl;
-            m_target->setSystemRecordSampleRate(m_sampleRate);
-
             break;
         }
 
         case PA_STREAM_FAILED:
         default:
-            cerr << "PulseAudioIO::streamStateChanged: Error: "
+            cerr << "PulseAudioPlaybackTarget::streamStateChanged: Error: "
                       << pa_strerror(pa_context_errno(m_context)) << endl;
             //!!! do something...
             break;

          
@@ 441,10 320,10 @@ PulseAudioIO::streamStateChanged(pa_stre
 }
 
 void
-PulseAudioIO::contextStateChangedStatic(pa_context *context,
+PulseAudioPlaybackTarget::contextStateChangedStatic(pa_context *context,
                                                  void *data)
 {
-    PulseAudioIO *target = (PulseAudioIO *)data;
+    PulseAudioPlaybackTarget *target = (PulseAudioPlaybackTarget *)data;
     
     assert(context == target->m_context);
 

          
@@ 452,10 331,10 @@ PulseAudioIO::contextStateChangedStatic(
 }
 
 void
-PulseAudioIO::contextStateChanged()
+PulseAudioPlaybackTarget::contextStateChanged()
 {
-#ifdef DEBUG_AUDIO_PULSE_AUDIO_IO
-    cerr << "PulseAudioIO::contextStateChanged" << endl;
+#ifdef DEBUG_PULSE_AUDIO_PLAYBACK_TARGET
+    cerr << "PulseAudioPlaybackTarget::contextStateChanged" << endl;
 #endif
     QMutexLocker locker(&m_mutex);
 

          
@@ 468,24 347,9 @@ PulseAudioIO::contextStateChanged()
 
         case PA_CONTEXT_READY:
         {
-            cerr << "PulseAudioIO::contextStateChanged: Ready"
+            cerr << "PulseAudioPlaybackTarget::contextStateChanged: Ready"
                       << endl;
 
-            m_in = pa_stream_new(m_context, "Turbot capture", &m_spec, 0);
-            assert(m_in); //!!!
-            
-            pa_stream_set_state_callback(m_in, streamStateChangedStatic, this);
-            pa_stream_set_read_callback(m_in, streamReadStatic, this);
-            pa_stream_set_overflow_callback(m_in, streamOverflowStatic, this);
-            pa_stream_set_underflow_callback(m_in, streamUnderflowStatic, this);
-
-            if (pa_stream_connect_record
-                (m_in, 0, 0,
-                 pa_stream_flags_t(PA_STREAM_INTERPOLATE_TIMING |
-                                   PA_STREAM_AUTO_TIMING_UPDATE))) { //??? return value
-                cerr << "PulseAudioIO: Failed to connect record stream" << endl;
-            }
-
             m_out = pa_stream_new(m_context, "Turbot playback", &m_spec, 0);
             assert(m_out); //!!!
             

          
@@ 499,20 363,20 @@ PulseAudioIO::contextStateChanged()
                  pa_stream_flags_t(PA_STREAM_INTERPOLATE_TIMING |
                                    PA_STREAM_AUTO_TIMING_UPDATE),
                  0, 0)) { //??? return value
-                cerr << "PulseAudioIO: Failed to connect playback stream" << endl;
+                cerr << "PulseAudioPlaybackTarget: Failed to connect playback stream" << endl;
             }
 
             break;
         }
 
         case PA_CONTEXT_TERMINATED:
-            cerr << "PulseAudioIO::contextStateChanged: Terminated" << endl;
+            cerr << "PulseAudioPlaybackTarget::contextStateChanged: Terminated" << endl;
             //!!! do something...
             break;
 
         case PA_CONTEXT_FAILED:
         default:
-            cerr << "PulseAudioIO::contextStateChanged: Error: "
+            cerr << "PulseAudioPlaybackTarget::contextStateChanged: Error: "
                       << pa_strerror(pa_context_errno(m_context)) << endl;
             //!!! do something...
             break;

          
@@ 520,15 384,15 @@ PulseAudioIO::contextStateChanged()
 }
 
 void
-PulseAudioIO::streamOverflowStatic(pa_stream *, void *)
+PulseAudioPlaybackTarget::streamOverflowStatic(pa_stream *, void *)
 {
-    cerr << "PulseAudioIO::streamOverflowStatic: Overflow!" << endl;
+    cerr << "PulseAudioPlaybackTarget::streamOverflowStatic: Overflow!" << endl;
 }
 
 void
-PulseAudioIO::streamUnderflowStatic(pa_stream *, void *)
+PulseAudioPlaybackTarget::streamUnderflowStatic(pa_stream *, void *)
 {
-    cerr << "PulseAudioIO::streamUnderflowStatic: Underflow!" << endl;
+    cerr << "PulseAudioPlaybackTarget::streamUnderflowStatic: Underflow!" << endl;
 }
 
 

          
M PulseAudioIO.h => PulseAudioPlaybackTarget.h +7 -15
@@ 1,14 1,14 @@ 
 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
 /* Copyright Chris Cannam - All Rights Reserved */
 
-#ifndef _AUDIO_PULSE_AUDIO_IO_H_
-#define _AUDIO_PULSE_AUDIO_IO_H_
+#ifndef _AUDIO_PULSE_AUDIO_PLAYBACK_TARGET_H_
+#define _AUDIO_PULSE_AUDIO_PLAYBACK_TARGET_H_
 
 #ifdef HAVE_LIBPULSE
 
 #include <pulse/pulseaudio.h>
 
-#include "SystemAudioIO.h"
+#include "SystemPlaybackTarget.h"
 
 #include "system/Thread.h"
 

          
@@ 16,31 16,24 @@ 
 
 namespace Turbot {
 
-class ApplicationRecordTarget;
 class ApplicationPlaybackSource;
 
-class PulseAudioIO : public SystemAudioIO
+class PulseAudioPlaybackTarget : public SystemPlaybackTarget
 {
 public:
-    PulseAudioIO(ApplicationRecordTarget *recordTarget,
-		      ApplicationPlaybackSource *playSource);
-    virtual ~PulseAudioIO();
+    PulseAudioPlaybackTarget(ApplicationPlaybackSource *playSource);
+    virtual ~PulseAudioPlaybackTarget();
 
-    virtual bool isSourceOK() const;
-    virtual bool isSourceReady() const;
     virtual bool isTargetOK() const;
-    virtual bool isTargetReady() const;
 
     virtual double getCurrentTime() const;
 
 protected:
     void streamWrite(int);
-    void streamRead(int);
     void streamStateChanged(pa_stream *);
     void contextStateChanged();
 
     static void streamWriteStatic(pa_stream *, size_t, void *);
-    static void streamReadStatic(pa_stream *, size_t, void *);
     static void streamStateChangedStatic(pa_stream *, void *);
     static void streamOverflowStatic(pa_stream *, void *);
     static void streamUnderflowStatic(pa_stream *, void *);

          
@@ 64,7 57,6 @@ protected:
     pa_mainloop *m_loop;
     pa_mainloop_api *m_api;
     pa_context *m_context;
-    pa_stream *m_in;
     pa_stream *m_out;
     pa_sample_spec m_spec;
 

          
@@ 72,9 64,9 @@ protected:
 
     int m_bufferSize;
     int m_sampleRate;
+    int m_paChannels;
     bool m_done;
 
-    bool m_captureReady;
     bool m_playbackReady;
 };