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 <yoann.lopes@theqtcompany.com>
This commit is contained in:
committed by
Christian Stromme
parent
ad929984e3
commit
e92bcbfa4d
@@ -157,7 +157,7 @@ int QOpenSLESAudioOutput::bytesFree() const
|
|||||||
if (m_state != QAudio::ActiveState && m_state != QAudio::IdleState)
|
if (m_state != QAudio::ActiveState && m_state != QAudio::IdleState)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
return m_availableBuffers.load() ? m_bufferSize : 0;
|
return m_availableBuffers.loadAcquire() ? m_bufferSize : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int QOpenSLESAudioOutput::periodSize() const
|
int QOpenSLESAudioOutput::periodSize() const
|
||||||
@@ -343,6 +343,11 @@ void QOpenSLESAudioOutput::onEOSEvent()
|
|||||||
setError(QAudio::UnderrunError);
|
setError(QAudio::UnderrunError);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void QOpenSLESAudioOutput::onBytesProcessed(qint64 bytes)
|
||||||
|
{
|
||||||
|
m_processedBytes += bytes;
|
||||||
|
}
|
||||||
|
|
||||||
void QOpenSLESAudioOutput::bufferAvailable(quint32 count, quint32 playIndex)
|
void QOpenSLESAudioOutput::bufferAvailable(quint32 count, quint32 playIndex)
|
||||||
{
|
{
|
||||||
Q_UNUSED(count);
|
Q_UNUSED(count);
|
||||||
@@ -351,11 +356,13 @@ void QOpenSLESAudioOutput::bufferAvailable(quint32 count, quint32 playIndex)
|
|||||||
if (m_state == QAudio::StoppedState)
|
if (m_state == QAudio::StoppedState)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!m_pullMode) {
|
if (!m_pullMode) { // We're in push mode.
|
||||||
m_availableBuffers.fetchAndAddRelaxed(1);
|
// Signal that there is a new open slot in the buffer and return
|
||||||
|
m_availableBuffers.fetchAndAddRelease(1);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We're in pull mode.
|
||||||
const int index = m_nextBuffer * m_bufferSize;
|
const int index = m_nextBuffer * m_bufferSize;
|
||||||
const qint64 readSize = m_audioSource->read(m_buffers + index, 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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_processedBytes += readSize;
|
|
||||||
m_nextBuffer = (m_nextBuffer + 1) % BUFFER_COUNT;
|
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)
|
void QOpenSLESAudioOutput::playCallback(SLPlayItf player, void *ctx, SLuint32 event)
|
||||||
@@ -570,7 +577,7 @@ void QOpenSLESAudioOutput::destroyPlayer()
|
|||||||
m_buffers = Q_NULLPTR;
|
m_buffers = Q_NULLPTR;
|
||||||
m_processedBytes = 0;
|
m_processedBytes = 0;
|
||||||
m_nextBuffer = 0;
|
m_nextBuffer = 0;
|
||||||
m_availableBuffers = BUFFER_COUNT;
|
m_availableBuffers.storeRelease(BUFFER_COUNT);
|
||||||
m_playItf = Q_NULLPTR;
|
m_playItf = Q_NULLPTR;
|
||||||
m_volumeItf = Q_NULLPTR;
|
m_volumeItf = Q_NULLPTR;
|
||||||
m_bufferQueueItf = Q_NULLPTR;
|
m_bufferQueueItf = Q_NULLPTR;
|
||||||
@@ -599,20 +606,32 @@ void QOpenSLESAudioOutput::startPlayer()
|
|||||||
|
|
||||||
qint64 QOpenSLESAudioOutput::writeData(const char *data, qint64 len)
|
qint64 QOpenSLESAudioOutput::writeData(const char *data, qint64 len)
|
||||||
{
|
{
|
||||||
if (!len || !m_availableBuffers.load())
|
if (!len)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (len > m_bufferSize)
|
if (len > m_bufferSize)
|
||||||
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;
|
const int index = m_nextBuffer * m_bufferSize;
|
||||||
::memcpy(m_buffers + index, data, len);
|
::memcpy(m_buffers + index, data, len);
|
||||||
const SLuint32 res = (*m_bufferQueueItf)->Enqueue(m_bufferQueueItf,
|
const SLuint32 res = (*m_bufferQueueItf)->Enqueue(m_bufferQueueItf,
|
||||||
m_buffers + index,
|
m_buffers + index,
|
||||||
len);
|
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;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (res != SL_RESULT_SUCCESS) {
|
if (res != SL_RESULT_SUCCESS) {
|
||||||
setError(QAudio::FatalError);
|
setError(QAudio::FatalError);
|
||||||
@@ -621,7 +640,6 @@ qint64 QOpenSLESAudioOutput::writeData(const char *data, qint64 len)
|
|||||||
}
|
}
|
||||||
|
|
||||||
m_processedBytes += len;
|
m_processedBytes += len;
|
||||||
m_availableBuffers.fetchAndAddRelaxed(-1);
|
|
||||||
setState(QAudio::ActiveState);
|
setState(QAudio::ActiveState);
|
||||||
setError(QAudio::NoError);
|
setError(QAudio::NoError);
|
||||||
m_nextBuffer = (m_nextBuffer + 1) % BUFFER_COUNT;
|
m_nextBuffer = (m_nextBuffer + 1) % BUFFER_COUNT;
|
||||||
|
|||||||
@@ -79,6 +79,7 @@ private:
|
|||||||
friend class SLIODevicePrivate;
|
friend class SLIODevicePrivate;
|
||||||
|
|
||||||
Q_INVOKABLE void onEOSEvent();
|
Q_INVOKABLE void onEOSEvent();
|
||||||
|
Q_INVOKABLE void onBytesProcessed(qint64 bytes);
|
||||||
void bufferAvailable(quint32 count, quint32 playIndex);
|
void bufferAvailable(quint32 count, quint32 playIndex);
|
||||||
|
|
||||||
static void playCallback(SLPlayItf playItf, void *ctx, SLuint32 event);
|
static void playCallback(SLPlayItf playItf, void *ctx, SLuint32 event);
|
||||||
|
|||||||
Reference in New Issue
Block a user