From e92bcbfa4dc8ea5e78e4c1712fffc9be0104a73e Mon Sep 17 00:00:00 2001 From: =?utf8?q?Christian=20Str=C3=B8mme?= Date: Thu, 30 Oct 2014 18:29:38 +0100 Subject: [PATCH] OpenSL ES: improve buffer logic Don't use relaxed load and stores, we need to be stricter to avoid problems with high frequency re-fills of the buffer. If we don't enforce ordering we might end-up spending more time trying to acquire an open slot in the buffer. Updating processes bytes is also moved off the "OpenSL" thread. Added some comments for improved readability. Change-Id: Ie27965fc6bf4b8394081ae6419f4933522ada98e Reviewed-by: Yoann Lopes --- src/plugins/opensles/qopenslesaudiooutput.cpp | 34 ++++++++++++++++++++------- src/plugins/opensles/qopenslesaudiooutput.h | 1 + 2 files changed, 27 insertions(+), 8 deletions(-) diff --git a/src/plugins/opensles/qopenslesaudiooutput.cpp b/src/plugins/opensles/qopenslesaudiooutput.cpp index c45fbd3..b89d8b9 100644 --- a/src/plugins/opensles/qopenslesaudiooutput.cpp +++ b/src/plugins/opensles/qopenslesaudiooutput.cpp @@ -157,7 +157,7 @@ int QOpenSLESAudioOutput::bytesFree() const if (m_state != QAudio::ActiveState && m_state != QAudio::IdleState) return 0; - return m_availableBuffers.load() ? m_bufferSize : 0; + return m_availableBuffers.loadAcquire() ? m_bufferSize : 0; } int QOpenSLESAudioOutput::periodSize() const @@ -343,6 +343,11 @@ void QOpenSLESAudioOutput::onEOSEvent() setError(QAudio::UnderrunError); } +void QOpenSLESAudioOutput::onBytesProcessed(qint64 bytes) +{ + m_processedBytes += bytes; +} + void QOpenSLESAudioOutput::bufferAvailable(quint32 count, quint32 playIndex) { Q_UNUSED(count); @@ -351,11 +356,13 @@ void QOpenSLESAudioOutput::bufferAvailable(quint32 count, quint32 playIndex) if (m_state == QAudio::StoppedState) return; - if (!m_pullMode) { - m_availableBuffers.fetchAndAddRelaxed(1); + if (!m_pullMode) { // We're in push mode. + // Signal that there is a new open slot in the buffer and return + m_availableBuffers.fetchAndAddRelease(1); return; } + // We're in pull mode. const int index = m_nextBuffer * m_bufferSize; const qint64 readSize = m_audioSource->read(m_buffers + index, m_bufferSize); @@ -370,8 +377,8 @@ void QOpenSLESAudioOutput::bufferAvailable(quint32 count, quint32 playIndex) return; } - m_processedBytes += readSize; m_nextBuffer = (m_nextBuffer + 1) % BUFFER_COUNT; + QMetaObject::invokeMethod(this, "onBytesProcessed", Qt::QueuedConnection, Q_ARG(qint64, readSize)); } void QOpenSLESAudioOutput::playCallback(SLPlayItf player, void *ctx, SLuint32 event) @@ -570,7 +577,7 @@ void QOpenSLESAudioOutput::destroyPlayer() m_buffers = Q_NULLPTR; m_processedBytes = 0; m_nextBuffer = 0; - m_availableBuffers = BUFFER_COUNT; + m_availableBuffers.storeRelease(BUFFER_COUNT); m_playItf = Q_NULLPTR; m_volumeItf = Q_NULLPTR; m_bufferQueueItf = Q_NULLPTR; @@ -599,20 +606,32 @@ void QOpenSLESAudioOutput::startPlayer() qint64 QOpenSLESAudioOutput::writeData(const char *data, qint64 len) { - if (!len || !m_availableBuffers.load()) + if (!len) return 0; if (len > m_bufferSize) len = m_bufferSize; + // Acquire one slot in the buffer + const int before = m_availableBuffers.fetchAndAddAcquire(-1); + + // If there where no vacant slots, then we just overdrew the buffer account... + if (before < 1) { + m_availableBuffers.fetchAndAddRelease(1); + return 0; + } + const int index = m_nextBuffer * m_bufferSize; ::memcpy(m_buffers + index, data, len); const SLuint32 res = (*m_bufferQueueItf)->Enqueue(m_bufferQueueItf, m_buffers + index, len); - if (res == SL_RESULT_BUFFER_INSUFFICIENT) + // If we where unable to enqueue a new buffer, give back the acquired slot. + if (res == SL_RESULT_BUFFER_INSUFFICIENT) { + m_availableBuffers.fetchAndAddRelease(1); return 0; + } if (res != SL_RESULT_SUCCESS) { setError(QAudio::FatalError); @@ -621,7 +640,6 @@ qint64 QOpenSLESAudioOutput::writeData(const char *data, qint64 len) } m_processedBytes += len; - m_availableBuffers.fetchAndAddRelaxed(-1); setState(QAudio::ActiveState); setError(QAudio::NoError); m_nextBuffer = (m_nextBuffer + 1) % BUFFER_COUNT; diff --git a/src/plugins/opensles/qopenslesaudiooutput.h b/src/plugins/opensles/qopenslesaudiooutput.h index 200b4a3..f36a5bf 100644 --- a/src/plugins/opensles/qopenslesaudiooutput.h +++ b/src/plugins/opensles/qopenslesaudiooutput.h @@ -79,6 +79,7 @@ private: friend class SLIODevicePrivate; Q_INVOKABLE void onEOSEvent(); + Q_INVOKABLE void onBytesProcessed(qint64 bytes); void bufferAvailable(quint32 count, quint32 playIndex); static void playCallback(SLPlayItf playItf, void *ctx, SLuint32 event); -- 2.7.4