From 65d44edd3d06674ec7a0014d7ecabc4f1d0854e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20Str=C3=B8mme?= Date: Wed, 10 Sep 2014 11:52:28 +0200 Subject: OpenSL ES: Be less rigid about tearing down the output device. We where very strict about tearing down the audio device. While this is a good strategy to avoid unnecessary resource usage, it also causes excessive re-allocations, e.g., when transiting from start to stop and back again. This can increase latency, especially in case where a short clip is re-played at a high frequency. This change also decrease the chance of the player ending up in some unknown state where it drops audio clips without any warning. Task-number: QTBUG-40864 Change-Id: I1afad4af0622983f0f0c221d91cf794585d8cad2 Reviewed-by: Yoann Lopes --- src/plugins/opensles/qopenslesaudiooutput.cpp | 65 ++++++++++++++++----------- src/plugins/opensles/qopenslesaudiooutput.h | 3 ++ 2 files changed, 42 insertions(+), 26 deletions(-) (limited to 'src/plugins/opensles') diff --git a/src/plugins/opensles/qopenslesaudiooutput.cpp b/src/plugins/opensles/qopenslesaudiooutput.cpp index f6583e542..06f2261df 100644 --- a/src/plugins/opensles/qopenslesaudiooutput.cpp +++ b/src/plugins/opensles/qopenslesaudiooutput.cpp @@ -71,7 +71,8 @@ QOpenSLESAudioOutput::QOpenSLESAudioOutput(const QByteArray &device) m_elapsedTime(0), m_processedBytes(0), m_availableBuffers(BUFFER_COUNT), - m_eventMask(SL_PLAYEVENT_HEADATEND) + m_eventMask(SL_PLAYEVENT_HEADATEND), + m_startRequiresInit(true) { #ifndef ANDROID m_streamType = -1; @@ -99,13 +100,10 @@ QAudio::State QOpenSLESAudioOutput::state() const void QOpenSLESAudioOutput::start(QIODevice *device) { Q_ASSERT(device); - destroyPlayer(); - - m_pullMode = true; - if (!preparePlayer()) return; + m_pullMode = true; m_audioSource = device; setState(QAudio::ActiveState); setError(QAudio::NoError); @@ -126,29 +124,20 @@ void QOpenSLESAudioOutput::start(QIODevice *device) // Change the state to playing. // We need to do this after filling the buffers or processedBytes might get corrupted. - if (SL_RESULT_SUCCESS != (*m_playItf)->SetPlayState(m_playItf, SL_PLAYSTATE_PLAYING)) { - setError(QAudio::FatalError); - destroyPlayer(); - } + startPlayer(); } QIODevice *QOpenSLESAudioOutput::start() { - destroyPlayer(); - - m_pullMode = false; - if (!preparePlayer()) return Q_NULLPTR; + m_pullMode = false; m_audioSource = new SLIODevicePrivate(this); m_audioSource->open(QIODevice::WriteOnly | QIODevice::Unbuffered); // Change the state to playing - if (SL_RESULT_SUCCESS != (*m_playItf)->SetPlayState(m_playItf, SL_PLAYSTATE_PLAYING)) { - setError(QAudio::FatalError); - destroyPlayer(); - } + startPlayer(); setState(QAudio::IdleState); return m_audioSource; @@ -159,7 +148,7 @@ void QOpenSLESAudioOutput::stop() if (m_state == QAudio::StoppedState) return; - destroyPlayer(); + stopPlayer(); setError(QAudio::NoError); } @@ -181,6 +170,7 @@ void QOpenSLESAudioOutput::setBufferSize(int value) if (m_state != QAudio::StoppedState) return; + m_startRequiresInit = true; m_bufferSize = value; } @@ -254,6 +244,7 @@ void QOpenSLESAudioOutput::resume() void QOpenSLESAudioOutput::setFormat(const QAudioFormat &format) { + m_startRequiresInit = true; m_format = format; } @@ -325,6 +316,7 @@ void QOpenSLESAudioOutput::setCategory(const QString &category) return; } + m_startRequiresInit = true; m_streamType = streamType; m_category = category; #endif // ANDROID @@ -403,6 +395,11 @@ void QOpenSLESAudioOutput::bufferQueueCallback(SLBufferQueueItf bufferQueue, voi bool QOpenSLESAudioOutput::preparePlayer() { + if (m_startRequiresInit) + destroyPlayer(); + else + return true; + SLEngineItf engine = QOpenSLESEngine::instance()->slEngine(); if (!engine) { qWarning() << "No engine"; @@ -543,20 +540,15 @@ bool QOpenSLESAudioOutput::preparePlayer() m_clockStamp.restart(); setError(QAudio::NoError); + m_startRequiresInit = false; return true; } void QOpenSLESAudioOutput::destroyPlayer() { - setState(QAudio::StoppedState); - - // We need to change the state manually... - if (m_playItf) - (*m_playItf)->SetPlayState(m_playItf, SL_PLAYSTATE_STOPPED); - - if (m_bufferQueueItf && SL_RESULT_SUCCESS != (*m_bufferQueueItf)->Clear(m_bufferQueueItf)) - qWarning() << "Unable to clear buffer"; + if (m_state != QAudio::StoppedState) + stopPlayer(); if (m_playerObject) { (*m_playerObject)->Destroy(m_playerObject); @@ -582,6 +574,27 @@ void QOpenSLESAudioOutput::destroyPlayer() m_playItf = Q_NULLPTR; m_volumeItf = Q_NULLPTR; m_bufferQueueItf = Q_NULLPTR; + m_startRequiresInit = true; +} + +void QOpenSLESAudioOutput::stopPlayer() +{ + setState(QAudio::StoppedState); + + // We need to change the state manually... + if (m_playItf) + (*m_playItf)->SetPlayState(m_playItf, SL_PLAYSTATE_STOPPED); + + if (m_bufferQueueItf && SL_RESULT_SUCCESS != (*m_bufferQueueItf)->Clear(m_bufferQueueItf)) + qWarning() << "Unable to clear buffer"; +} + +void QOpenSLESAudioOutput::startPlayer() +{ + if (SL_RESULT_SUCCESS != (*m_playItf)->SetPlayState(m_playItf, SL_PLAYSTATE_PLAYING)) { + setError(QAudio::FatalError); + destroyPlayer(); + } } qint64 QOpenSLESAudioOutput::writeData(const char *data, qint64 len) diff --git a/src/plugins/opensles/qopenslesaudiooutput.h b/src/plugins/opensles/qopenslesaudiooutput.h index d466ea64b..200b4a3cc 100644 --- a/src/plugins/opensles/qopenslesaudiooutput.h +++ b/src/plugins/opensles/qopenslesaudiooutput.h @@ -86,6 +86,8 @@ private: bool preparePlayer(); void destroyPlayer(); + void stopPlayer(); + void startPlayer(); qint64 writeData(const char *data, qint64 len); void setState(QAudio::State state); @@ -113,6 +115,7 @@ private: qint64 m_processedBytes; QAtomicInt m_availableBuffers; SLuint32 m_eventMask; + bool m_startRequiresInit; qint32 m_streamType; QTime m_clockStamp; -- cgit v1.2.3