summaryrefslogtreecommitdiffstats
path: root/src/plugins
diff options
context:
space:
mode:
authorLing Hu <ling.hu@nokia.com>2011-11-07 11:49:09 +1000
committerQt by Nokia <qt-info@nokia.com>2011-11-09 01:24:14 +0100
commita8be7b6053b836aba27421450161408f2ad7a1e1 (patch)
tree6c7980b66ebf61f0ae7c061f1e25a930f132a2c3 /src/plugins
parent9eeb1389f57bc4c0cfd205c7d1aaaa8fe069f81e (diff)
Fix pullmode data lost problem in QAudioOutput(pulseaudio)
At each userFeed, m_bytesAvailable is not updated properly in pullmode, so the pull data size become irrelevent to the size we can actually write. This problem is fixed by checking the actual writable size each time before pulling the data and limit the size of the pulled and written data. Change-Id: I6f53e6348693ddf4e3c79e90d3c3d0c1ffc713aa Reviewed-by: Jonas Rabbe <jonas.rabbe@nokia.com> Reviewed-by: Michael Goddard <michael.goddard@nokia.com>
Diffstat (limited to 'src/plugins')
-rw-r--r--src/plugins/pulseaudio/qaudiooutput_pulse.cpp76
-rw-r--r--src/plugins/pulseaudio/qaudiooutput_pulse.h2
2 files changed, 36 insertions, 42 deletions
diff --git a/src/plugins/pulseaudio/qaudiooutput_pulse.cpp b/src/plugins/pulseaudio/qaudiooutput_pulse.cpp
index b638d07fe..c068373bf 100644
--- a/src/plugins/pulseaudio/qaudiooutput_pulse.cpp
+++ b/src/plugins/pulseaudio/qaudiooutput_pulse.cpp
@@ -142,7 +142,6 @@ QPulseAudioOutput::QPulseAudioOutput(const QByteArray &device)
, m_pullMode(true)
, m_opened(false)
, m_audioSource(0)
- , m_bytesAvailable(0)
, m_stream(0)
, m_notifyInterval(1000)
, m_periodSize(0)
@@ -292,11 +291,11 @@ bool QPulseAudioOutput::open()
while (pa_stream_get_state(m_stream) != PA_STREAM_READY) {
pa_threaded_mainloop_wait(pulseEngine->mainloop());
}
- pa_threaded_mainloop_unlock(pulseEngine->mainloop());
-
-#ifdef DEBUG_PULSE
const pa_buffer_attr *buffer = pa_stream_get_buffer_attr(m_stream);
-
+ m_periodSize = pa_usec_to_bytes(PeriodTimeMs*1000, &spec);
+ m_bufferSize = buffer->maxlength;
+ m_audioBuffer = new char[buffer->maxlength];
+#ifdef DEBUG_PULSE
qDebug() << "Buffering info:";
qDebug() << "\tMax length: " << buffer->maxlength;
qDebug() << "\tTarget length: " << buffer->tlength;
@@ -305,7 +304,8 @@ bool QPulseAudioOutput::open()
qDebug() << "\tFragment size: " << buffer->fragsize;
#endif
- m_periodSize = pa_usec_to_bytes(PeriodTimeMs*1000, &spec);
+ pa_threaded_mainloop_unlock(pulseEngine->mainloop());
+
m_opened = true;
m_tickTimer->start(PeriodTimeMs);
@@ -316,17 +316,6 @@ bool QPulseAudioOutput::open()
return true;
}
-void QPulseAudioOutput::userFeed()
-{
- if (m_deviceState == QAudio::StoppedState || m_deviceState == QAudio::SuspendedState)
- return;
-
- if (m_deviceState == QAudio::IdleState)
- m_bytesAvailable = bytesFree();
-
- deviceReady();
-}
-
void QPulseAudioOutput::close()
{
m_tickTimer->stop();
@@ -334,15 +323,15 @@ void QPulseAudioOutput::close()
if (m_stream) {
QPulseAudioEngine *pulseEngine = QPulseAudioEngine::instance();
pa_threaded_mainloop_lock(pulseEngine->mainloop());
- pa_operation *o;
pa_stream_set_write_callback(m_stream, NULL, NULL);
- if (!(o = pa_stream_drain(m_stream, outputStreamDrainComplete, NULL))) {
+ pa_operation *o = pa_stream_drain(m_stream, outputStreamDrainComplete, NULL);
+ if (!o) {
qWarning() << QString("pa_stream_drain(): %1").arg(pa_strerror(pa_context_errno(pa_stream_get_context(m_stream))));
- return;
+ } else {
+ pa_operation_unref(o);
}
- pa_operation_unref(o);
pa_stream_disconnect(m_stream);
pa_stream_unref(m_stream);
@@ -356,42 +345,45 @@ void QPulseAudioOutput::close()
m_audioSource = 0;
}
m_opened = false;
+ if (m_audioBuffer) {
+ delete[] m_audioBuffer;
+ m_audioBuffer = 0;
+ }
}
-bool QPulseAudioOutput::deviceReady()
+void QPulseAudioOutput::userFeed()
{
+ if (m_deviceState == QAudio::StoppedState || m_deviceState == QAudio::SuspendedState)
+ return;
+
m_resuming = false;
if (m_pullMode) {
- int l = 0;
- int chunks = m_bytesAvailable/m_periodSize;
- if (chunks==0) {
- m_bytesAvailable = bytesFree();
- return false;
- }
-
- char buffer[m_periodSize];
+ int writableSize = bytesFree();
+ int chunks = writableSize / m_periodSize;
+ if (chunks == 0)
+ return;
- l = m_audioSource->read(buffer, m_periodSize);
- if (l > 0) {
- if (m_deviceState != QAudio::ActiveState)
- return true;
+ int input = m_periodSize * chunks;
+ if (input > m_bufferSize)
+ input = m_bufferSize;
- qint64 bytesWritten = write(buffer, l);
- Q_UNUSED(bytesWritten);
+ int audioBytesPulled = m_audioSource->read(m_audioBuffer, input);
+ Q_ASSERT(audioBytesPulled <= input);
+ if (audioBytesPulled > 0) {
+ qint64 bytesWritten = write(m_audioBuffer, audioBytesPulled);
+ Q_ASSERT(bytesWritten == audioBytesPulled); //unfinished write should not happen since the data provided is less than writableSize
}
}
if (m_deviceState != QAudio::ActiveState)
- return true;
+ return;
if (m_notifyInterval && (m_timeStamp.elapsed() + m_elapsedTimeOffset) > m_notifyInterval) {
emit notify();
m_elapsedTimeOffset = m_timeStamp.elapsed() + m_elapsedTimeOffset - m_notifyInterval;
m_timeStamp.restart();
}
-
- return true;
}
qint64 QPulseAudioOutput::write(const char *data, qint64 len)
@@ -429,7 +421,11 @@ int QPulseAudioOutput::bytesFree() const
if (m_deviceState != QAudio::ActiveState && m_deviceState != QAudio::IdleState)
return 0;
- return pa_stream_writable_size(m_stream);
+ QPulseAudioEngine *pulseEngine = QPulseAudioEngine::instance();
+ pa_threaded_mainloop_lock(pulseEngine->mainloop());
+ int writableSize = pa_stream_writable_size(m_stream);
+ pa_threaded_mainloop_unlock(pulseEngine->mainloop());
+ return writableSize;
}
int QPulseAudioOutput::periodSize() const
diff --git a/src/plugins/pulseaudio/qaudiooutput_pulse.h b/src/plugins/pulseaudio/qaudiooutput_pulse.h
index 884164e3c..d7525c0f5 100644
--- a/src/plugins/pulseaudio/qaudiooutput_pulse.h
+++ b/src/plugins/pulseaudio/qaudiooutput_pulse.h
@@ -107,7 +107,6 @@ private:
qint64 write(const char *data, qint64 len);
private Q_SLOTS:
- bool deviceReady();
void userFeed();
private:
@@ -119,7 +118,6 @@ private:
bool m_pullMode;
bool m_opened;
QIODevice *m_audioSource;
- int m_bytesAvailable;
QTimer m_periodTimer;
pa_stream *m_stream;
int m_notifyInterval;