src/multimedia/audio/qaudiooutput_symbian_p.cpp
changeset 25 e24348a560a6
parent 19 fcece45ef507
equal deleted inserted replaced
23:89e065397ea6 25:e24348a560a6
   108     ,   m_error(QAudio::NoError)
   108     ,   m_error(QAudio::NoError)
   109     ,   m_internalState(SymbianAudio::ClosedState)
   109     ,   m_internalState(SymbianAudio::ClosedState)
   110     ,   m_externalState(QAudio::StoppedState)
   110     ,   m_externalState(QAudio::StoppedState)
   111     ,   m_pullMode(false)
   111     ,   m_pullMode(false)
   112     ,   m_source(0)
   112     ,   m_source(0)
       
   113     ,   m_devSound(0)
   113     ,   m_devSoundBuffer(0)
   114     ,   m_devSoundBuffer(0)
   114     ,   m_devSoundBufferSize(0)
   115     ,   m_devSoundBufferSize(0)
   115     ,   m_bytesWritten(0)
   116     ,   m_bytesWritten(0)
   116     ,   m_pushDataReady(false)
   117     ,   m_pushDataReady(false)
   117     ,   m_bytesPadding(0)
   118     ,   m_bytesPadding(0)
   119     ,   m_lastBuffer(false)
   120     ,   m_lastBuffer(false)
   120     ,   m_underflowTimer(new QTimer(this))
   121     ,   m_underflowTimer(new QTimer(this))
   121     ,   m_samplesPlayed(0)
   122     ,   m_samplesPlayed(0)
   122     ,   m_totalSamplesPlayed(0)
   123     ,   m_totalSamplesPlayed(0)
   123 {
   124 {
       
   125     qRegisterMetaType<CMMFBuffer *>("CMMFBuffer *");
       
   126 
   124     connect(m_notifyTimer.data(), SIGNAL(timeout()), this, SIGNAL(notify()));
   127     connect(m_notifyTimer.data(), SIGNAL(timeout()), this, SIGNAL(notify()));
   125 
       
   126     SymbianAudio::Utils::formatQtToNative(m_format, m_nativeFourCC,
       
   127                                           m_nativeFormat);
       
   128 
   128 
   129     m_underflowTimer->setInterval(UnderflowTimerInterval);
   129     m_underflowTimer->setInterval(UnderflowTimerInterval);
   130     connect(m_underflowTimer.data(), SIGNAL(timeout()), this,
   130     connect(m_underflowTimer.data(), SIGNAL(timeout()), this,
   131             SLOT(underflowTimerExpired()));
   131             SLOT(underflowTimerExpired()));
   132 }
   132 }
   138 
   138 
   139 QIODevice* QAudioOutputPrivate::start(QIODevice *device)
   139 QIODevice* QAudioOutputPrivate::start(QIODevice *device)
   140 {
   140 {
   141     stop();
   141     stop();
   142 
   142 
   143     // We have to set these before the call to open() because of the
       
   144     // logic in initializingState()
       
   145     if (device) {
   143     if (device) {
   146         m_pullMode = true;
   144         m_pullMode = true;
   147         m_source = device;
   145         m_source = device;
   148     }
   146     }
   149 
   147 
   169 }
   167 }
   170 
   168 
   171 void QAudioOutputPrivate::reset()
   169 void QAudioOutputPrivate::reset()
   172 {
   170 {
   173     m_totalSamplesPlayed += getSamplesPlayed();
   171     m_totalSamplesPlayed += getSamplesPlayed();
   174     m_devSound->Stop();
   172     m_devSound->stop();
   175     m_bytesPadding = 0;
   173     m_bytesPadding = 0;
   176     startPlayback();
   174     startPlayback();
   177 }
   175 }
   178 
   176 
   179 void QAudioOutputPrivate::suspend()
   177 void QAudioOutputPrivate::suspend()
   194         // implementations, for play-mode DevSound sessions.  We therefore
   192         // implementations, for play-mode DevSound sessions.  We therefore
   195         // have to implement suspend() by calling CMMFDevSound::Stop().
   193         // have to implement suspend() by calling CMMFDevSound::Stop().
   196         // Because this causes buffered data to be dropped, we replace the
   194         // Because this causes buffered data to be dropped, we replace the
   197         // lost data with silence following a call to resume(), in order to
   195         // lost data with silence following a call to resume(), in order to
   198         // ensure that processedUSecs() returns the correct value.
   196         // ensure that processedUSecs() returns the correct value.
   199         m_devSound->Stop();
   197         m_devSound->stop();
   200         m_totalSamplesPlayed += samplesPlayed;
   198         m_totalSamplesPlayed += samplesPlayed;
   201 
   199 
   202         // Calculate the amount of data dropped
   200         // Calculate the amount of data dropped
   203         const qint64 paddingSamples = samplesWritten - samplesPlayed;
   201         const qint64 paddingSamples = samplesWritten - samplesPlayed;
       
   202         Q_ASSERT(paddingSamples >= 0);
   204         m_bytesPadding = SymbianAudio::Utils::samplesToBytes(m_format,
   203         m_bytesPadding = SymbianAudio::Utils::samplesToBytes(m_format,
   205                                                              paddingSamples);
   204                                                              paddingSamples);
   206 
   205 
   207         setState(SymbianAudio::SuspendedState);
   206         setState(SymbianAudio::SuspendedState);
   208     }
   207     }
   209 }
   208 }
   210 
   209 
   211 void QAudioOutputPrivate::resume()
   210 void QAudioOutputPrivate::resume()
   212 {
   211 {
   213     if (SymbianAudio::SuspendedState == m_internalState)
   212     if (SymbianAudio::SuspendedState == m_internalState) {
       
   213         if (!m_pullMode && m_devSoundBuffer && m_devSoundBuffer->Data().Length())
       
   214             bufferFilled();
   214         startPlayback();
   215         startPlayback();
       
   216     }
   215 }
   217 }
   216 
   218 
   217 int QAudioOutputPrivate::bytesFree() const
   219 int QAudioOutputPrivate::bytesFree() const
   218 {
   220 {
   219     int result = 0;
   221     int result = 0;
   247     return m_devSoundBufferSize ? m_devSoundBufferSize : m_clientBufferSize;
   249     return m_devSoundBufferSize ? m_devSoundBufferSize : m_clientBufferSize;
   248 }
   250 }
   249 
   251 
   250 void QAudioOutputPrivate::setNotifyInterval(int ms)
   252 void QAudioOutputPrivate::setNotifyInterval(int ms)
   251 {
   253 {
   252     if (ms > 0) {
   254     if (ms >= 0) {
   253         const int oldNotifyInterval = m_notifyInterval;
   255         const int oldNotifyInterval = m_notifyInterval;
   254         m_notifyInterval = ms;
   256         m_notifyInterval = ms;
   255         if (m_notifyTimer->isActive() && ms != oldNotifyInterval)
   257         if (m_notifyInterval && (SymbianAudio::ActiveState == m_internalState ||
       
   258                                  SymbianAudio::IdleState == m_internalState))
   256             m_notifyTimer->start(m_notifyInterval);
   259             m_notifyTimer->start(m_notifyInterval);
       
   260         else
       
   261             m_notifyTimer->stop();
   257     }
   262     }
   258 }
   263 }
   259 
   264 
   260 int QAudioOutputPrivate::notifyInterval() const
   265 int QAudioOutputPrivate::notifyInterval() const
   261 {
   266 {
   298 QAudioFormat QAudioOutputPrivate::format() const
   303 QAudioFormat QAudioOutputPrivate::format() const
   299 {
   304 {
   300     return m_format;
   305     return m_format;
   301 }
   306 }
   302 
   307 
   303 //-----------------------------------------------------------------------------
   308 
   304 // MDevSoundObserver implementation
   309 //-----------------------------------------------------------------------------
   305 //-----------------------------------------------------------------------------
   310 // Private functions
   306 
   311 //-----------------------------------------------------------------------------
   307 void QAudioOutputPrivate::InitializeComplete(TInt aError)
   312 
       
   313 void QAudioOutputPrivate::dataReady()
       
   314 {
       
   315     // Client-provided QIODevice has data ready to read.
       
   316 
       
   317     Q_ASSERT_X(m_source->bytesAvailable(), Q_FUNC_INFO,
       
   318         "readyRead signal received, but no data available");
       
   319 
       
   320     if (!m_bytesPadding)
       
   321         pullData();
       
   322 }
       
   323 
       
   324 void QAudioOutputPrivate::underflowTimerExpired()
       
   325 {
       
   326     const TInt samplesPlayed = getSamplesPlayed();
       
   327     if (m_samplesPlayed && (samplesPlayed == m_samplesPlayed)) {
       
   328         setError(QAudio::UnderrunError);
       
   329     } else {
       
   330         m_samplesPlayed = samplesPlayed;
       
   331         m_underflowTimer->start();
       
   332     }
       
   333 }
       
   334 
       
   335 void QAudioOutputPrivate::devsoundInitializeComplete(int err)
   308 {
   336 {
   309     Q_ASSERT_X(SymbianAudio::InitializingState == m_internalState,
   337     Q_ASSERT_X(SymbianAudio::InitializingState == m_internalState,
   310         Q_FUNC_INFO, "Invalid state");
   338         Q_FUNC_INFO, "Invalid state");
   311 
   339 
   312     if (KErrNone == aError)
   340     if (!err && m_devSound->isFormatSupported(m_format))
   313         startPlayback();
   341         startPlayback();
   314 }
   342     else
   315 
   343         setError(QAudio::OpenError);
   316 void QAudioOutputPrivate::ToneFinished(TInt aError)
   344 }
   317 {
   345 
   318     Q_UNUSED(aError)
   346 void QAudioOutputPrivate::devsoundBufferToBeFilled(CMMFBuffer *bufferBase)
   319     // This class doesn't use DevSound's tone playback functions, so should
   347 {
   320     // never receive this callback.
   348     // Following receipt of this signal, DevSound should not provide another
   321     Q_ASSERT_X(false, Q_FUNC_INFO, "Unexpected callback");
       
   322 }
       
   323 
       
   324 void QAudioOutputPrivate::BufferToBeFilled(CMMFBuffer *aBuffer)
       
   325 {
       
   326     // Following receipt of this callback, DevSound should not provide another
       
   327     // buffer until we have returned the current one.
   349     // buffer until we have returned the current one.
   328     Q_ASSERT_X(!m_devSoundBuffer, Q_FUNC_INFO, "Buffer already held");
   350     Q_ASSERT_X(!m_devSoundBuffer, Q_FUNC_INFO, "Buffer already held");
   329 
   351 
   330     // Will be returned to DevSound by bufferFilled().
   352     // Will be returned to DevSoundWrapper by bufferProcessed().
   331     m_devSoundBuffer = static_cast<CMMFDataBuffer*>(aBuffer);
   353     m_devSoundBuffer = static_cast<CMMFDataBuffer*>(bufferBase);
   332 
   354 
   333     if (!m_devSoundBufferSize)
   355     if (!m_devSoundBufferSize)
   334         m_devSoundBufferSize = m_devSoundBuffer->Data().MaxLength();
   356         m_devSoundBufferSize = m_devSoundBuffer->Data().MaxLength();
   335 
   357 
   336     writePaddingData();
   358     writePaddingData();
   337 
   359 
   338     if (m_pullMode && isDataReady() && !m_bytesPadding)
   360     if (m_pullMode && isDataReady() && !m_bytesPadding)
   339         pullData();
   361         pullData();
   340 }
   362 }
   341 
   363 
   342 void QAudioOutputPrivate::PlayError(TInt aError)
   364 void QAudioOutputPrivate::devsoundPlayError(int err)
   343 {
   365 {
   344     switch (aError) {
   366     switch (err) {
   345     case KErrUnderflow:
   367     case KErrUnderflow:
   346         m_underflow = true;
   368         m_underflow = true;
   347         if (m_pullMode && !m_lastBuffer)
   369         if (m_pullMode && !m_lastBuffer)
   348             setError(QAudio::UnderrunError);
   370             setError(QAudio::UnderrunError);
   349         else
   371         else
   353         setError(QAudio::IOError);
   375         setError(QAudio::IOError);
   354         break;
   376         break;
   355     }
   377     }
   356 }
   378 }
   357 
   379 
   358 void QAudioOutputPrivate::BufferToBeEmptied(CMMFBuffer *aBuffer)
       
   359 {
       
   360     Q_UNUSED(aBuffer)
       
   361     // This class doesn't use DevSound in record mode, so should never receive
       
   362     // this callback.
       
   363     Q_ASSERT_X(false, Q_FUNC_INFO, "Unexpected callback");
       
   364 }
       
   365 
       
   366 void QAudioOutputPrivate::RecordError(TInt aError)
       
   367 {
       
   368     Q_UNUSED(aError)
       
   369     // This class doesn't use DevSound in record mode, so should never receive
       
   370     // this callback.
       
   371     Q_ASSERT_X(false, Q_FUNC_INFO, "Unexpected callback");
       
   372 }
       
   373 
       
   374 void QAudioOutputPrivate::ConvertError(TInt aError)
       
   375 {
       
   376     Q_UNUSED(aError)
       
   377     // This class doesn't use DevSound's format conversion functions, so
       
   378     // should never receive this callback.
       
   379     Q_ASSERT_X(false, Q_FUNC_INFO, "Unexpected callback");
       
   380 }
       
   381 
       
   382 void QAudioOutputPrivate::DeviceMessage(TUid aMessageType, const TDesC8 &aMsg)
       
   383 {
       
   384     Q_UNUSED(aMessageType)
       
   385     Q_UNUSED(aMsg)
       
   386     // Ignore this callback.
       
   387 }
       
   388 
       
   389 //-----------------------------------------------------------------------------
       
   390 // Private functions
       
   391 //-----------------------------------------------------------------------------
       
   392 
       
   393 void QAudioOutputPrivate::dataReady()
       
   394 {
       
   395     // Client-provided QIODevice has data ready to read.
       
   396 
       
   397     Q_ASSERT_X(m_source->bytesAvailable(), Q_FUNC_INFO,
       
   398         "readyRead signal received, but no data available");
       
   399 
       
   400     if (!m_bytesPadding)
       
   401         pullData();
       
   402 }
       
   403 
       
   404 void QAudioOutputPrivate::underflowTimerExpired()
       
   405 {
       
   406     const TInt samplesPlayed = getSamplesPlayed();
       
   407     if (m_samplesPlayed && (samplesPlayed == m_samplesPlayed)) {
       
   408         setError(QAudio::UnderrunError);
       
   409     } else {
       
   410         m_samplesPlayed = samplesPlayed;
       
   411         m_underflowTimer->start();
       
   412     }
       
   413 }
       
   414 
       
   415 void QAudioOutputPrivate::open()
   380 void QAudioOutputPrivate::open()
   416 {
   381 {
   417     Q_ASSERT_X(SymbianAudio::ClosedState == m_internalState,
   382     Q_ASSERT_X(SymbianAudio::ClosedState == m_internalState,
   418         Q_FUNC_INFO, "DevSound already opened");
   383         Q_FUNC_INFO, "DevSound already opened");
   419 
   384 
   420     QT_TRAP_THROWING( m_devSound.reset(CMMFDevSound::NewL()) )
   385     Q_ASSERT(!m_devSound);
   421 
   386     m_devSound = new SymbianAudio::DevSoundWrapper(QAudio::AudioOutput, this);
   422     QScopedPointer<SymbianAudio::DevSoundCapabilities> caps(
   387 
   423         new SymbianAudio::DevSoundCapabilities(*m_devSound,
   388     connect(m_devSound, SIGNAL(initializeComplete(int)),
   424                                                QAudio::AudioOutput));
   389             this, SLOT(devsoundInitializeComplete(int)));
   425 
   390     connect(m_devSound, SIGNAL(bufferToBeProcessed(CMMFBuffer *)),
   426     int err = SymbianAudio::Utils::isFormatSupported(m_format, *caps) ?
   391             this, SLOT(devsoundBufferToBeFilled(CMMFBuffer *)));
   427                   KErrNone : KErrNotSupported;
   392     connect(m_devSound, SIGNAL(processingError(int)),
   428 
   393             this, SLOT(devsoundPlayError(int)));
   429     if (KErrNone == err) {
   394 
   430         setState(SymbianAudio::InitializingState);
   395     setState(SymbianAudio::InitializingState);
   431         TRAP(err, m_devSound->InitializeL(*this, m_nativeFourCC,
   396     m_devSound->initialize(m_format.codec());
   432                                           EMMFStatePlaying));
       
   433     }
       
   434 
       
   435     if (KErrNone != err) {
       
   436         setError(QAudio::OpenError);
       
   437         m_devSound.reset();
       
   438     }
       
   439 }
   397 }
   440 
   398 
   441 void QAudioOutputPrivate::startPlayback()
   399 void QAudioOutputPrivate::startPlayback()
   442 {
   400 {
   443     TRAPD(err, startDevSoundL());
   401     bool ok = m_devSound->setFormat(m_format);
   444     if (KErrNone == err) {
   402     if (ok)
       
   403         ok = m_devSound->start();
       
   404 
       
   405     if (ok) {
   445         if (isDataReady())
   406         if (isDataReady())
   446             setState(SymbianAudio::ActiveState);
   407             setState(SymbianAudio::ActiveState);
   447         else
   408         else
   448             setState(SymbianAudio::IdleState);
   409             setState(SymbianAudio::IdleState);
   449 
   410 
   450         m_notifyTimer->start(m_notifyInterval);
   411         if (m_notifyInterval)
       
   412             m_notifyTimer->start(m_notifyInterval);
   451         m_underflow = false;
   413         m_underflow = false;
   452 
   414 
   453         Q_ASSERT(m_devSound->SamplesPlayed() == 0);
   415         Q_ASSERT(m_devSound->samplesProcessed() == 0);
   454 
   416 
   455         writePaddingData();
   417         writePaddingData();
   456 
   418 
   457         if (m_pullMode && m_source->bytesAvailable() && !m_bytesPadding)
   419         if (m_pullMode && m_source->bytesAvailable() && !m_bytesPadding)
   458             dataReady();
   420             dataReady();
   459     } else {
   421     } else {
   460         setError(QAudio::OpenError);
   422         setError(QAudio::OpenError);
   461         close();
   423         close();
   462     }
   424     }
   463 }
       
   464 
       
   465 void QAudioOutputPrivate::startDevSoundL()
       
   466 {
       
   467     TMMFCapabilities nativeFormat = m_devSound->Config();
       
   468     m_nativeFormat.iBufferSize = nativeFormat.iBufferSize;
       
   469     m_devSound->SetConfigL(m_nativeFormat);
       
   470     m_devSound->PlayInitL();
       
   471 }
   425 }
   472 
   426 
   473 void QAudioOutputPrivate::writePaddingData()
   427 void QAudioOutputPrivate::writePaddingData()
   474 {
   428 {
   475     // See comments in suspend()
   429     // See comments in suspend()
   484                                         outputBytes : m_bytesPadding;
   438                                         outputBytes : m_bytesPadding;
   485         unsigned char *ptr = const_cast<unsigned char*>(outputBuffer.Ptr());
   439         unsigned char *ptr = const_cast<unsigned char*>(outputBuffer.Ptr());
   486         Mem::FillZ(ptr, paddingBytes);
   440         Mem::FillZ(ptr, paddingBytes);
   487         outputBuffer.SetLength(outputBuffer.Length() + paddingBytes);
   441         outputBuffer.SetLength(outputBuffer.Length() + paddingBytes);
   488         m_bytesPadding -= paddingBytes;
   442         m_bytesPadding -= paddingBytes;
       
   443         Q_ASSERT(m_bytesPadding >= 0);
   489 
   444 
   490         if (m_pullMode && m_source->atEnd())
   445         if (m_pullMode && m_source->atEnd())
   491             lastBufferFilled();
   446             lastBufferFilled();
   492         if (paddingBytes == outputBytes)
   447         if ((paddingBytes == outputBytes) || !m_bytesPadding)
   493             bufferFilled();
   448             bufferFilled();
   494     }
   449     }
   495 }
   450 }
   496 
   451 
   497 qint64 QAudioOutputPrivate::pushData(const char *data, qint64 len)
   452 qint64 QAudioOutputPrivate::pushData(const char *data, qint64 len)
   541 void QAudioOutputPrivate::pullData()
   496 void QAudioOutputPrivate::pullData()
   542 {
   497 {
   543     Q_ASSERT_X(m_pullMode, Q_FUNC_INFO,
   498     Q_ASSERT_X(m_pullMode, Q_FUNC_INFO,
   544         "pullData called when in push mode");
   499         "pullData called when in push mode");
   545 
   500 
   546     if (m_bytesPadding)
       
   547         m_bytesPadding = 1;
       
   548 
       
   549     // writePaddingData() is called by BufferToBeFilled() before pullData(),
   501     // writePaddingData() is called by BufferToBeFilled() before pullData(),
   550     // so we should never have any padding data left at this point.
   502     // so we should never have any padding data left at this point.
   551     Q_ASSERT_X(0 == m_bytesPadding, Q_FUNC_INFO,
   503     Q_ASSERT_X(0 == m_bytesPadding, Q_FUNC_INFO,
   552         "Padding bytes remaining in pullData");
   504         "Padding bytes remaining in pullData");
   553 
   505 
   588     m_underflowTimer->start();
   540     m_underflowTimer->start();
   589 
   541 
   590     if (QAudio::UnderrunError == m_error)
   542     if (QAudio::UnderrunError == m_error)
   591         m_error = QAudio::NoError;
   543         m_error = QAudio::NoError;
   592 
   544 
   593     m_devSound->PlayData();
   545     m_devSound->bufferProcessed();
   594 }
   546 }
   595 
   547 
   596 void QAudioOutputPrivate::lastBufferFilled()
   548 void QAudioOutputPrivate::lastBufferFilled()
   597 {
   549 {
   598     Q_ASSERT_X(m_devSoundBuffer, Q_FUNC_INFO, "No buffer to fill");
   550     Q_ASSERT_X(m_devSoundBuffer, Q_FUNC_INFO, "No buffer to fill");
   608     m_underflowTimer->stop();
   560     m_underflowTimer->stop();
   609 
   561 
   610     m_error = QAudio::NoError;
   562     m_error = QAudio::NoError;
   611 
   563 
   612     if (m_devSound)
   564     if (m_devSound)
   613         m_devSound->Stop();
   565         m_devSound->stop();
   614     m_devSound.reset();
   566     delete m_devSound;
       
   567     m_devSound = 0;
       
   568 
   615     m_devSoundBuffer = 0;
   569     m_devSoundBuffer = 0;
   616     m_devSoundBufferSize = 0;
   570     m_devSoundBufferSize = 0;
   617 
   571 
   618     if (!m_pullMode) // m_source is owned
   572     if (!m_pullMode) // m_source is owned
   619         delete m_source;
   573         delete m_source;
   642             result = samplesWritten;
   596             result = samplesWritten;
   643         } else {
   597         } else {
   644             // This is necessary because some DevSound implementations report
   598             // This is necessary because some DevSound implementations report
   645             // that they have played more data than has actually been provided to them
   599             // that they have played more data than has actually been provided to them
   646             // by the client.
   600             // by the client.
   647             const qint64 devSoundSamplesPlayed(m_devSound->SamplesPlayed());
   601             const qint64 devSoundSamplesPlayed(m_devSound->samplesProcessed());
   648             result = qMin(devSoundSamplesPlayed, samplesWritten);
   602             result = qMin(devSoundSamplesPlayed, samplesWritten);
   649         }
   603         }
   650     }
   604     }
   651     return result;
   605     return result;
   652 }
   606 }
   656     m_error = error;
   610     m_error = error;
   657 
   611 
   658     // Although no state transition actually occurs here, a stateChanged event
   612     // Although no state transition actually occurs here, a stateChanged event
   659     // must be emitted to inform the client that the call to start() was
   613     // must be emitted to inform the client that the call to start() was
   660     // unsuccessful.
   614     // unsuccessful.
   661     if (QAudio::OpenError == error)
   615     if (QAudio::OpenError == error) {
   662         emit stateChanged(QAudio::StoppedState);
   616         emit stateChanged(QAudio::StoppedState);
   663 
   617     } else {
   664     if (QAudio::UnderrunError == error)
   618         if (QAudio::UnderrunError == error)
   665         setState(SymbianAudio::IdleState);
   619             setState(SymbianAudio::IdleState);
   666     else
   620         else
   667         // Close the DevSound instance.  This causes a transition to
   621             // Close the DevSound instance.  This causes a transition to
   668         // StoppedState.  This must be done asynchronously in case the
   622             // StoppedState.  This must be done asynchronously in case the
   669         // current function was called from a DevSound event handler, in which
   623             // current function was called from a DevSound event handler, in which
   670         // case deleting the DevSound instance may cause an exception.
   624             // case deleting the DevSound instance may cause an exception.
   671         QMetaObject::invokeMethod(this, "close", Qt::QueuedConnection);
   625             QMetaObject::invokeMethod(this, "close", Qt::QueuedConnection);
       
   626     }
   672 }
   627 }
   673 
   628 
   674 void QAudioOutputPrivate::setState(SymbianAudio::State newInternalState)
   629 void QAudioOutputPrivate::setState(SymbianAudio::State newInternalState)
   675 {
   630 {
   676     const QAudio::State oldExternalState = m_externalState;
   631     const QAudio::State oldExternalState = m_externalState;
   677     m_internalState = newInternalState;
   632     m_internalState = newInternalState;
   678     m_externalState = SymbianAudio::Utils::stateNativeToQt(
   633     m_externalState = SymbianAudio::Utils::stateNativeToQt(m_internalState);
   679                             m_internalState, initializingState());
       
   680 
   634 
   681     if (m_externalState != oldExternalState)
   635     if (m_externalState != oldExternalState)
   682         emit stateChanged(m_externalState);
   636         emit stateChanged(m_externalState);
   683 }
   637 }
   684 
   638 
   687     return (m_source && m_source->bytesAvailable())
   641     return (m_source && m_source->bytesAvailable())
   688         ||  m_bytesPadding
   642         ||  m_bytesPadding
   689         ||  m_pushDataReady;
   643         ||  m_pushDataReady;
   690 }
   644 }
   691 
   645 
   692 QAudio::State QAudioOutputPrivate::initializingState() const
       
   693 {
       
   694     return isDataReady() ? QAudio::ActiveState : QAudio::IdleState;
       
   695 }
       
   696 
       
   697 QT_END_NAMESPACE
   646 QT_END_NAMESPACE