summaryrefslogtreecommitdiffstats
path: root/src/multimediakit/audio/qaudiooutput_symbian_p.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/multimediakit/audio/qaudiooutput_symbian_p.cpp')
-rw-r--r--src/multimediakit/audio/qaudiooutput_symbian_p.cpp713
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"