diff options
Diffstat (limited to 'src/multimediakit/audio/qaudiooutput_symbian_p.cpp')
-rw-r--r-- | src/multimediakit/audio/qaudiooutput_symbian_p.cpp | 713 |
1 files changed, 0 insertions, 713 deletions
diff --git a/src/multimediakit/audio/qaudiooutput_symbian_p.cpp b/src/multimediakit/audio/qaudiooutput_symbian_p.cpp deleted file mode 100644 index 3a1bc2424..000000000 --- a/src/multimediakit/audio/qaudiooutput_symbian_p.cpp +++ /dev/null @@ -1,713 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the Qt Mobility Components. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** This file may be used under the terms of the GNU Lesser General Public -** License version 2.1 as published by the Free Software Foundation and -** appearing in the file LICENSE.LGPL included in the packaging of this -** file. Please review the following information to ensure the GNU Lesser -** General Public License version 2.1 requirements will be met: -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qaudiooutput_symbian_p.h" - -QT_BEGIN_NAMESPACE - -//----------------------------------------------------------------------------- -// Constants -//----------------------------------------------------------------------------- - -const int UnderflowTimerInterval = 50; // ms - - -//----------------------------------------------------------------------------- -// Private class -//----------------------------------------------------------------------------- - -SymbianAudioOutputPrivate::SymbianAudioOutputPrivate( - QAudioOutputPrivate *audioDevice) - : m_audioDevice(audioDevice) -{ - -} - -SymbianAudioOutputPrivate::~SymbianAudioOutputPrivate() -{ - -} - -qint64 SymbianAudioOutputPrivate::readData(char *data, qint64 len) -{ - Q_UNUSED(data) - Q_UNUSED(len) - return 0; -} - -qint64 SymbianAudioOutputPrivate::writeData(const char *data, qint64 len) -{ - qint64 totalWritten = 0; - - if (m_audioDevice->state() == QAudio::ActiveState || - m_audioDevice->state() == QAudio::IdleState) { - - while (totalWritten < len) { - const qint64 written = m_audioDevice->pushData(data + totalWritten, - len - totalWritten); - if (written > 0) - totalWritten += written; - else - break; - } - } - - return totalWritten; -} - - -//----------------------------------------------------------------------------- -// Public functions -//----------------------------------------------------------------------------- - -QAudioOutputPrivate::QAudioOutputPrivate(const QByteArray &device) - : m_device(device) - , m_clientBufferSize(SymbianAudio::DefaultBufferSize) - , m_notifyInterval(SymbianAudio::DefaultNotifyInterval) - , m_notifyTimer(new QTimer(this)) - , m_lastNotifyPosition(0) - , m_error(QAudio::NoError) - , m_internalState(SymbianAudio::ClosedState) - , m_externalState(QAudio::StoppedState) - , m_pullMode(false) - , m_source(0) - , m_devSound(0) - , m_devSoundBuffer(0) - , m_devSoundBufferSize(0) - , m_bytesWritten(0) - , m_pushDataReady(false) - , m_bytesPadding(0) - , m_underflow(false) - , m_lastBuffer(false) - , m_underflowTimer(new QTimer(this)) - , m_samplesPlayed(0) - , m_totalSamplesPlayed(0) -{ - connect(m_notifyTimer.data(), SIGNAL(timeout()), - this, SLOT(notifyTimerExpired())); - - m_underflowTimer->setInterval(UnderflowTimerInterval); - - connect(m_underflowTimer.data(), SIGNAL(timeout()), this, - SLOT(underflowTimerExpired())); -} - -QAudioOutputPrivate::~QAudioOutputPrivate() -{ - close(); -} - -void QAudioOutputPrivate::setFormat(const QAudioFormat& fmt) -{ - m_format = fmt; -} - -void QAudioOutputPrivate::start(QIODevice *device) -{ - stop(); - - // We have to set these before the call to open() because of the - // logic in initializingState() - m_pullMode = true; - m_source = device; - - open(); - - if (SymbianAudio::ClosedState != m_internalState) { - connect(m_source, SIGNAL(readyRead()), this, SLOT(dataReady())); - m_elapsed.restart(); - } -} - -QIODevice* QAudioOutputPrivate::start() -{ - stop(); - - open(); - - if (SymbianAudio::ClosedState != m_internalState) { - m_source = new SymbianAudioOutputPrivate(this); - m_source->open(QIODevice::WriteOnly | QIODevice::Unbuffered); - m_elapsed.restart(); - } - - return m_source; -} - -void QAudioOutputPrivate::stop() -{ - close(); -} - -void QAudioOutputPrivate::reset() -{ -#ifndef PRE_S60_52_PLATFORM - int err = m_devSound->flush(); - if (err != 0) - setError(QAudio::FatalError); -#else - m_totalSamplesPlayed += getSamplesPlayed(); - m_devSound->stop(); - m_bytesPadding = 0; - startPlayback(); -#endif -} - -void QAudioOutputPrivate::suspend() -{ - if (SymbianAudio::ActiveState == m_internalState - || SymbianAudio::IdleState == m_internalState) { - m_underflowTimer->stop(); - const qint64 samplesWritten = SymbianAudio::Utils::bytesToSamples( - m_format, m_bytesWritten); - const qint64 samplesPlayed = getSamplesPlayed(); -#ifdef PRE_S60_52_PLATFORM - m_totalSamplesPlayed += samplesPlayed; - m_bytesWritten = 0; -#endif - const bool paused = m_devSound->pause(); - if (paused) { - setState(SymbianAudio::SuspendedPausedState); - } else { - m_devSoundBuffer = 0; - // Calculate the amount of data dropped - const qint64 paddingSamples = samplesWritten - samplesPlayed; - Q_ASSERT(paddingSamples >= 0); - m_bytesPadding = SymbianAudio::Utils::samplesToBytes(m_format, - paddingSamples); - setState(SymbianAudio::SuspendedStoppedState); - } - } -} - -void QAudioOutputPrivate::resume() -{ - if (QAudio::SuspendedState == m_externalState) { - if (SymbianAudio::SuspendedPausedState == m_internalState) { -#ifndef PRE_S60_52_PLATFORM - setState(SymbianAudio::ActiveState); - if (m_devSoundBuffer != 0) - devsoundBufferToBeFilled(m_devSoundBuffer); - m_devSound->start(); -#else -//defined in else part of macro to enable compatibility of previous code - m_devSound->resume(); -#endif - } else { - startPlayback(); - } - } -} - -int QAudioOutputPrivate::bytesFree() const -{ - int result = 0; - if (m_devSoundBuffer) { - const TDes8 &outputBuffer = m_devSoundBuffer->Data(); - result = outputBuffer.MaxLength() - outputBuffer.Length(); - } - return result; -} - -int QAudioOutputPrivate::periodSize() const -{ - return bufferSize(); -} - -void QAudioOutputPrivate::setBufferSize(int value) -{ - // Note that DevSound does not allow its client to specify the buffer size. - // This functionality is available via custom interfaces, but since these - // cannot be guaranteed to work across all DevSound implementations, we - // do not use them here. - // In order to comply with the expected bevahiour of QAudioOutput, we store - // the value and return it from bufferSize(), but the underlying DevSound - // buffer size remains unchanged. - if (value > 0) - m_clientBufferSize = value; -} - -int QAudioOutputPrivate::bufferSize() const -{ - return m_devSoundBufferSize ? m_devSoundBufferSize : m_clientBufferSize; -} - -void QAudioOutputPrivate::setNotifyInterval(int ms) -{ - if (ms >= 0) { - //const int oldNotifyInterval = m_notifyInterval; - m_notifyInterval = ms; - if (m_notifyInterval && (SymbianAudio::ActiveState == m_internalState || - SymbianAudio::IdleState == m_internalState)) - m_notifyTimer->start(m_notifyInterval); - else - m_notifyTimer->stop(); - } -} - -int QAudioOutputPrivate::notifyInterval() const -{ - return m_notifyInterval; -} - -qint64 QAudioOutputPrivate::processedUSecs() const -{ - int samplesPlayed = 0; - - if (!m_devSound) - return samplesPlayed; - - if (QAudio::SuspendedState != m_externalState) - samplesPlayed = getSamplesPlayed(); - - // Protect against division by zero - Q_ASSERT_X(m_format.frequency() > 0, Q_FUNC_INFO, "Invalid frequency"); - -#ifndef PRE_S60_52_PLATFORM - const qint64 devSoundSamplesPlayed(m_devSound->samplesProcessed()); - const qint64 result = qint64(1000000) * - (devSoundSamplesPlayed) - / m_format.frequency(); -#else - const qint64 result = qint64(1000000) * - (samplesPlayed + m_totalSamplesPlayed) - / m_format.frequency(); -#endif - return result; -} - -qint64 QAudioOutputPrivate::elapsedUSecs() const -{ - const qint64 result = (QAudio::StoppedState == state()) ? - 0 : m_elapsed.elapsed() * 1000; - return result; -} - -QAudio::Error QAudioOutputPrivate::error() const -{ - return m_error; -} - -QAudio::State QAudioOutputPrivate::state() const -{ - return m_externalState; -} - -QAudioFormat QAudioOutputPrivate::format() const -{ - return m_format; -} - - -//----------------------------------------------------------------------------- -// Private functions -//----------------------------------------------------------------------------- - -void QAudioOutputPrivate::notifyTimerExpired() -{ - const qint64 pos = processedUSecs(); - if (pos > m_lastNotifyPosition) { - int count = (pos - m_lastNotifyPosition) / (m_notifyInterval * 1000); - while (count--) { - emit notify(); - m_lastNotifyPosition += m_notifyInterval * 1000; - } - } -} - -void QAudioOutputPrivate::dataReady() -{ - // Client-provided QIODevice has data ready to read. - - Q_ASSERT_X(m_source->bytesAvailable(), Q_FUNC_INFO, - "readyRead signal received, but no data available"); - - if (!m_bytesPadding) - pullData(); -} - -void QAudioOutputPrivate::underflowTimerExpired() -{ - const TInt samplesPlayed = getSamplesPlayed(); - if (m_samplesPlayed && (samplesPlayed == m_samplesPlayed)) { - setError(QAudio::UnderrunError); -#ifndef PRE_S60_52_PLATFORM - m_underflowTimer->stop(); -#endif - } else { - m_samplesPlayed = samplesPlayed; - m_underflowTimer->start(); - } -} - -void QAudioOutputPrivate::devsoundInitializeComplete(int err) -{ - Q_ASSERT_X(SymbianAudio::InitializingState == m_internalState, - Q_FUNC_INFO, "Invalid state"); - - if (!err && m_devSound->isFormatSupported(m_format)) - startPlayback(); - else - setError(QAudio::OpenError); -} - -void QAudioOutputPrivate::devsoundBufferToBeFilled(CMMFBuffer *bufferBase) -{ - // Following receipt of this signal, DevSound should not provide another - // buffer until we have returned the current one. - Q_ASSERT_X(!m_devSoundBuffer, Q_FUNC_INFO, "Buffer already held"); - - // Will be returned to DevSoundWrapper by bufferProcessed(). - m_devSoundBuffer = static_cast<CMMFDataBuffer*>(bufferBase); -#ifndef PRE_S60_52_PLATFORM - if (m_externalState == QAudio::SuspendedState) { - // This condition occurs when buffertobefilled callback is received after - // pause command is processed. - return; - } -#endif - - if (!m_devSoundBufferSize) - m_devSoundBufferSize = m_devSoundBuffer->Data().MaxLength(); - - writePaddingData(); - - if (m_pullMode && isDataReady() && !m_bytesPadding) - pullData(); -} - -void QAudioOutputPrivate::devsoundPlayError(int err) -{ - switch (err) { - case KErrUnderflow: - m_underflow = true; - if (m_pullMode && !m_lastBuffer) - setError(QAudio::UnderrunError); - else - setState(SymbianAudio::IdleState); - break; - case KErrOverflow: - // Silently consume this error when in playback mode - break; - default: - setError(QAudio::IOError); - break; - } -} - -void QAudioOutputPrivate::open() -{ - Q_ASSERT_X(SymbianAudio::ClosedState == m_internalState, - Q_FUNC_INFO, "DevSound already opened"); - - Q_ASSERT(!m_devSound); - m_devSound = new SymbianAudio::DevSoundWrapper(QAudio::AudioOutput, this); - - connect(m_devSound, SIGNAL(initializeComplete(int)), - this, SLOT(devsoundInitializeComplete(int))); - connect(m_devSound, SIGNAL(bufferToBeProcessed(CMMFBuffer *)), - this, SLOT(devsoundBufferToBeFilled(CMMFBuffer *))); - connect(m_devSound, SIGNAL(processingError(int)), - this, SLOT(devsoundPlayError(int))); - - setState(SymbianAudio::InitializingState); - m_devSound->initialize(m_format.codec()); -} - -void QAudioOutputPrivate::startPlayback() -{ - bool ok = m_devSound->setFormat(m_format); - if (ok) - ok = m_devSound->start(); - - if (ok) { - if (isDataReady()) - setState(SymbianAudio::ActiveState); - else - setState(SymbianAudio::IdleState); - - if (m_notifyInterval) - m_notifyTimer->start(m_notifyInterval); - m_underflow = false; - - Q_ASSERT(m_devSound->samplesProcessed() == 0); - - writePaddingData(); - - if (m_pullMode && m_source->bytesAvailable() && !m_bytesPadding) - dataReady(); - } else { - setError(QAudio::OpenError); - close(); - } -} - -void QAudioOutputPrivate::writePaddingData() -{ - // See comments in suspend() - - while (m_devSoundBuffer && m_bytesPadding) { - if (SymbianAudio::IdleState == m_internalState) - setState(SymbianAudio::ActiveState); - - TDes8 &outputBuffer = m_devSoundBuffer->Data(); - const qint64 outputBytes = bytesFree(); - const qint64 paddingBytes = outputBytes < m_bytesPadding ? - outputBytes : m_bytesPadding; - unsigned char *ptr = const_cast<unsigned char*>(outputBuffer.Ptr()); - Mem::FillZ(ptr, paddingBytes); - outputBuffer.SetLength(outputBuffer.Length() + paddingBytes); - m_bytesPadding -= paddingBytes; - Q_ASSERT(m_bytesPadding >= 0); - - if (m_pullMode && m_source->atEnd()) - lastBufferFilled(); - if ((paddingBytes == outputBytes) || !m_bytesPadding) - bufferFilled(); - } -} - -qint64 QAudioOutputPrivate::pushData(const char *data, qint64 len) -{ - // Data has been written to SymbianAudioOutputPrivate - - Q_ASSERT_X(!m_pullMode, Q_FUNC_INFO, - "pushData called when in pull mode"); - - const unsigned char *const inputPtr = - reinterpret_cast<const unsigned char*>(data); - qint64 bytesWritten = 0; - - if (SymbianAudio::IdleState == m_internalState) - setState(SymbianAudio::ActiveState); - - while (m_devSoundBuffer && (bytesWritten < len)) { - // writePaddingData() is called from BufferToBeFilled(), so we should - // never have any padding data left at this point. - Q_ASSERT_X(0 == m_bytesPadding, Q_FUNC_INFO, - "Padding bytes remaining in pushData"); - - TDes8 &outputBuffer = m_devSoundBuffer->Data(); - - const qint64 outputBytes = bytesFree(); - const qint64 inputBytes = len - bytesWritten; - const qint64 copyBytes = outputBytes < inputBytes ? - outputBytes : inputBytes; - - outputBuffer.Append(inputPtr + bytesWritten, copyBytes); - bytesWritten += copyBytes; - - bufferFilled(); - } - - m_pushDataReady = (bytesWritten < len); - - // If DevSound is still initializing (m_internalState == InitializingState), - // we cannot transition m_internalState to ActiveState, but we must emit - // an (external) state change from IdleState to ActiveState. The following - // call triggers this signal. - setState(m_internalState); - - return bytesWritten; -} - -void QAudioOutputPrivate::pullData() -{ - Q_ASSERT_X(m_pullMode, Q_FUNC_INFO, - "pullData called when in push mode"); - - // writePaddingData() is called by BufferToBeFilled() before pullData(), - // so we should never have any padding data left at this point. - Q_ASSERT_X(0 == m_bytesPadding, Q_FUNC_INFO, - "Padding bytes remaining in pullData"); - - qint64 inputBytes = m_source->bytesAvailable(); - while (m_devSoundBuffer && inputBytes) { - if (SymbianAudio::IdleState == m_internalState) - setState(SymbianAudio::ActiveState); - - TDes8 &outputBuffer = m_devSoundBuffer->Data(); - - const qint64 outputBytes = bytesFree(); - const qint64 copyBytes = outputBytes < inputBytes ? - outputBytes : inputBytes; - - char *outputPtr = (char*)(outputBuffer.Ptr() + outputBuffer.Length()); - const qint64 bytesCopied = m_source->read(outputPtr, copyBytes); - - //Partial buffers can be sent to DevSound. This assert not required. - //Q_ASSERT(bytesCopied == copyBytes); - outputBuffer.SetLength(outputBuffer.Length() + bytesCopied); - inputBytes -= bytesCopied; - - if(bytesCopied == 0) - return; - - if (m_source->atEnd()) - lastBufferFilled(); - else - bufferFilled(); - } -} - -void QAudioOutputPrivate::bufferFilled() -{ - Q_ASSERT_X(m_devSoundBuffer, Q_FUNC_INFO, "No buffer to return"); - - const TDes8 &outputBuffer = m_devSoundBuffer->Data(); - m_bytesWritten += outputBuffer.Length(); - - m_devSoundBuffer = 0; - - m_samplesPlayed = getSamplesPlayed(); - m_underflowTimer->start(); - - if (QAudio::UnderrunError == m_error) - m_error = QAudio::NoError; - - m_devSound->bufferProcessed(); -} - -void QAudioOutputPrivate::lastBufferFilled() -{ - Q_ASSERT_X(m_devSoundBuffer, Q_FUNC_INFO, "No buffer to fill"); - Q_ASSERT_X(!m_lastBuffer, Q_FUNC_INFO, "Last buffer already sent"); - m_lastBuffer = true; - m_devSoundBuffer->SetLastBuffer(ETrue); - bufferFilled(); -} - -void QAudioOutputPrivate::close() -{ - m_lastNotifyPosition = 0; - m_underflowTimer->stop(); - - m_error = QAudio::NoError; - - if (m_devSound) - m_devSound->stop(); - delete m_devSound; - m_devSound = 0; - - m_devSoundBuffer = 0; - m_devSoundBufferSize = 0; - - if (!m_pullMode) // m_source is owned - delete m_source; - m_pullMode = false; - m_source = 0; - - m_bytesWritten = 0; - m_pushDataReady = false; - m_bytesPadding = 0; - m_underflow = false; - m_lastBuffer = false; - m_samplesPlayed = 0; - m_totalSamplesPlayed = 0; - - setState(SymbianAudio::ClosedState); -} - -qint64 QAudioOutputPrivate::getSamplesPlayed() const -{ - qint64 result = 0; - if (m_devSound) { - const qint64 samplesWritten = SymbianAudio::Utils::bytesToSamples( - m_format, m_bytesWritten); - - if (m_underflow) { - result = samplesWritten; - } else { - // This is necessary because some DevSound implementations report - // that they have played more data than has actually been provided to them - // by the client. - const qint64 devSoundSamplesPlayed(m_devSound->samplesProcessed()); - result = qMin(devSoundSamplesPlayed, samplesWritten); - } - } - return result; -} - -void QAudioOutputPrivate::setError(QAudio::Error error) -{ - m_error = error; - - // Although no state transition actually occurs here, a stateChanged event - // must be emitted to inform the client that the call to start() was - // unsuccessful. - if (QAudio::OpenError == error) { - emit stateChanged(QAudio::StoppedState); - } else { - if (QAudio::UnderrunError == error) - setState(SymbianAudio::IdleState); - else - // Close the DevSound instance. This causes a transition to - // StoppedState. This must be done asynchronously in case the - // current function was called from a DevSound event handler, in which - // case deleting the DevSound instance may cause an exception. - QMetaObject::invokeMethod(this, "close", Qt::QueuedConnection); - } -} - -void QAudioOutputPrivate::setState(SymbianAudio::State newInternalState) -{ - const QAudio::State oldExternalState = m_externalState; - m_internalState = newInternalState; - m_externalState = SymbianAudio::Utils::stateNativeToQt(m_internalState); - - if (m_externalState != QAudio::ActiveState && - m_externalState != QAudio::IdleState) - m_notifyTimer->stop(); - - if (m_externalState != oldExternalState) - emit stateChanged(m_externalState); -} - -bool QAudioOutputPrivate::isDataReady() const -{ - return (m_source && m_source->bytesAvailable()) - || m_bytesPadding - || m_pushDataReady; -} - -QT_END_NAMESPACE - -#include "moc_qaudiooutput_symbian_p.cpp" |