src/multimedia/audio/qaudioinput_symbian_p.cpp
changeset 25 e24348a560a6
parent 19 fcece45ef507
equal deleted inserted replaced
23:89e065397ea6 25:e24348a560a6
   114     ,   m_internalState(SymbianAudio::ClosedState)
   114     ,   m_internalState(SymbianAudio::ClosedState)
   115     ,   m_externalState(QAudio::StoppedState)
   115     ,   m_externalState(QAudio::StoppedState)
   116     ,   m_pullMode(false)
   116     ,   m_pullMode(false)
   117     ,   m_sink(0)
   117     ,   m_sink(0)
   118     ,   m_pullTimer(new QTimer(this))
   118     ,   m_pullTimer(new QTimer(this))
       
   119     ,   m_devSound(0)
   119     ,   m_devSoundBuffer(0)
   120     ,   m_devSoundBuffer(0)
   120     ,   m_devSoundBufferSize(0)
   121     ,   m_devSoundBufferSize(0)
   121     ,   m_totalBytesReady(0)
   122     ,   m_totalBytesReady(0)
   122     ,   m_devSoundBufferPos(0)
   123     ,   m_devSoundBufferPos(0)
   123     ,   m_totalSamplesRecorded(0)
   124     ,   m_totalSamplesRecorded(0)
   124 {
   125 {
       
   126     qRegisterMetaType<CMMFBuffer *>("CMMFBuffer *");
       
   127 
   125     connect(m_notifyTimer.data(), SIGNAL(timeout()), this, SIGNAL(notify()));
   128     connect(m_notifyTimer.data(), SIGNAL(timeout()), this, SIGNAL(notify()));
   126 
       
   127     SymbianAudio::Utils::formatQtToNative(m_format, m_nativeFourCC,
       
   128                                           m_nativeFormat);
       
   129 
   129 
   130     m_pullTimer->setInterval(PushInterval);
   130     m_pullTimer->setInterval(PushInterval);
   131     connect(m_pullTimer.data(), SIGNAL(timeout()), this, SLOT(pullData()));
   131     connect(m_pullTimer.data(), SIGNAL(timeout()), this, SLOT(pullData()));
   132 }
   132 }
   133 
   133 
   162 }
   162 }
   163 
   163 
   164 void QAudioInputPrivate::reset()
   164 void QAudioInputPrivate::reset()
   165 {
   165 {
   166     m_totalSamplesRecorded += getSamplesRecorded();
   166     m_totalSamplesRecorded += getSamplesRecorded();
   167     m_devSound->Stop();
   167     m_devSound->stop();
   168     startRecording();
   168     startRecording();
   169 }
   169 }
   170 
   170 
   171 void QAudioInputPrivate::suspend()
   171 void QAudioInputPrivate::suspend()
   172 {
   172 {
   173     if (SymbianAudio::ActiveState == m_internalState
   173     if (SymbianAudio::ActiveState == m_internalState
   174         || SymbianAudio::IdleState == m_internalState) {
   174         || SymbianAudio::IdleState == m_internalState) {
   175         m_notifyTimer->stop();
   175         m_notifyTimer->stop();
   176         m_pullTimer->stop();
   176         m_pullTimer->stop();
   177         m_devSound->Pause();
   177         m_devSound->pause();
   178         const qint64 samplesRecorded = getSamplesRecorded();
   178         const qint64 samplesRecorded = getSamplesRecorded();
   179         m_totalSamplesRecorded += samplesRecorded;
   179         m_totalSamplesRecorded += samplesRecorded;
   180 
   180 
   181         if (m_devSoundBuffer) {
   181         if (m_devSoundBuffer) {
   182             m_devSoundBufferQ.append(m_devSoundBuffer);
   182             m_devSoundBufferQ.append(m_devSoundBuffer);
   187     }
   187     }
   188 }
   188 }
   189 
   189 
   190 void QAudioInputPrivate::resume()
   190 void QAudioInputPrivate::resume()
   191 {
   191 {
   192     if (SymbianAudio::SuspendedState == m_internalState)
   192     if (SymbianAudio::SuspendedState == m_internalState) {
       
   193         if (!m_pullMode && !bytesReady())
       
   194             m_devSound->start();
   193         startDataTransfer();
   195         startDataTransfer();
       
   196     }
   194 }
   197 }
   195 
   198 
   196 int QAudioInputPrivate::bytesReady() const
   199 int QAudioInputPrivate::bytesReady() const
   197 {
   200 {
   198     Q_ASSERT(m_devSoundBufferPos <= m_totalBytesReady);
   201     Q_ASSERT(m_devSoundBufferPos <= m_totalBytesReady);
   222     return m_devSoundBufferSize ? m_devSoundBufferSize : m_clientBufferSize;
   225     return m_devSoundBufferSize ? m_devSoundBufferSize : m_clientBufferSize;
   223 }
   226 }
   224 
   227 
   225 void QAudioInputPrivate::setNotifyInterval(int ms)
   228 void QAudioInputPrivate::setNotifyInterval(int ms)
   226 {
   229 {
   227     if (ms > 0) {
   230     if (ms >= 0) {
   228         const int oldNotifyInterval = m_notifyInterval;
   231         const int oldNotifyInterval = m_notifyInterval;
   229         m_notifyInterval = ms;
   232         m_notifyInterval = ms;
   230         if (m_notifyTimer->isActive() && ms != oldNotifyInterval)
   233         if (m_notifyInterval && (SymbianAudio::ActiveState == m_internalState ||
       
   234                                  SymbianAudio::IdleState == m_internalState))
   231             m_notifyTimer->start(m_notifyInterval);
   235             m_notifyTimer->start(m_notifyInterval);
       
   236         else
       
   237             m_notifyTimer->stop();
   232     }
   238     }
   233 }
   239 }
   234 
   240 
   235 int QAudioInputPrivate::notifyInterval() const
   241 int QAudioInputPrivate::notifyInterval() const
   236 {
   242 {
   273 QAudioFormat QAudioInputPrivate::format() const
   279 QAudioFormat QAudioInputPrivate::format() const
   274 {
   280 {
   275     return m_format;
   281     return m_format;
   276 }
   282 }
   277 
   283 
   278 //-----------------------------------------------------------------------------
       
   279 // MDevSoundObserver implementation
       
   280 //-----------------------------------------------------------------------------
       
   281 
       
   282 void QAudioInputPrivate::InitializeComplete(TInt aError)
       
   283 {
       
   284     Q_ASSERT_X(SymbianAudio::InitializingState == m_internalState,
       
   285         Q_FUNC_INFO, "Invalid state");
       
   286 
       
   287     if (KErrNone == aError)
       
   288         startRecording();
       
   289 }
       
   290 
       
   291 void QAudioInputPrivate::ToneFinished(TInt aError)
       
   292 {
       
   293     Q_UNUSED(aError)
       
   294     // This class doesn't use DevSound's tone playback functions, so should
       
   295     // never receive this callback.
       
   296     Q_ASSERT_X(false, Q_FUNC_INFO, "Unexpected callback");
       
   297 }
       
   298 
       
   299 void QAudioInputPrivate::BufferToBeFilled(CMMFBuffer *aBuffer)
       
   300 {
       
   301     Q_UNUSED(aBuffer)
       
   302     // This class doesn't use DevSound in play mode, so should never receive
       
   303     // this callback.
       
   304     Q_ASSERT_X(false, Q_FUNC_INFO, "Unexpected callback");
       
   305 }
       
   306 
       
   307 void QAudioInputPrivate::PlayError(TInt aError)
       
   308 {
       
   309     Q_UNUSED(aError)
       
   310     // This class doesn't use DevSound in play mode, so should never receive
       
   311     // this callback.
       
   312     Q_ASSERT_X(false, Q_FUNC_INFO, "Unexpected callback");
       
   313 }
       
   314 
       
   315 void QAudioInputPrivate::BufferToBeEmptied(CMMFBuffer *aBuffer)
       
   316 {
       
   317     // Following receipt of this callback, DevSound should not provide another
       
   318     // buffer until we have returned the current one.
       
   319     Q_ASSERT_X(!m_devSoundBuffer, Q_FUNC_INFO, "Buffer already held");
       
   320 
       
   321     CMMFDataBuffer *const buffer = static_cast<CMMFDataBuffer*>(aBuffer);
       
   322 
       
   323     if (!m_devSoundBufferSize)
       
   324         m_devSoundBufferSize = buffer->Data().MaxLength();
       
   325 
       
   326     m_totalBytesReady += buffer->Data().Length();
       
   327 
       
   328     if (SymbianAudio::SuspendedState == m_internalState) {
       
   329         m_devSoundBufferQ.append(buffer);
       
   330     } else {
       
   331         // Will be returned to DevSound by bufferEmptied().
       
   332         m_devSoundBuffer = buffer;
       
   333         m_devSoundBufferPos = 0;
       
   334 
       
   335         if (bytesReady() && !m_pullMode)
       
   336             pushData();
       
   337     }
       
   338 }
       
   339 
       
   340 void QAudioInputPrivate::RecordError(TInt aError)
       
   341 {
       
   342     Q_UNUSED(aError)
       
   343     setError(QAudio::IOError);
       
   344 }
       
   345 
       
   346 void QAudioInputPrivate::ConvertError(TInt aError)
       
   347 {
       
   348     Q_UNUSED(aError)
       
   349     // This class doesn't use DevSound's format conversion functions, so
       
   350     // should never receive this callback.
       
   351     Q_ASSERT_X(false, Q_FUNC_INFO, "Unexpected callback");
       
   352 }
       
   353 
       
   354 void QAudioInputPrivate::DeviceMessage(TUid aMessageType, const TDesC8 &aMsg)
       
   355 {
       
   356     Q_UNUSED(aMessageType)
       
   357     Q_UNUSED(aMsg)
       
   358     // Ignore this callback.
       
   359 }
       
   360 
   284 
   361 //-----------------------------------------------------------------------------
   285 //-----------------------------------------------------------------------------
   362 // Private functions
   286 // Private functions
   363 //-----------------------------------------------------------------------------
   287 //-----------------------------------------------------------------------------
   364 
   288 
   365 void QAudioInputPrivate::open()
   289 void QAudioInputPrivate::open()
   366 {
   290 {
   367     Q_ASSERT_X(SymbianAudio::ClosedState == m_internalState,
   291     Q_ASSERT_X(SymbianAudio::ClosedState == m_internalState,
   368         Q_FUNC_INFO, "DevSound already opened");
   292         Q_FUNC_INFO, "DevSound already opened");
   369 
   293 
   370     QT_TRAP_THROWING( m_devSound.reset(CMMFDevSound::NewL()) )
   294     Q_ASSERT(!m_devSound);
   371 
   295     m_devSound = new SymbianAudio::DevSoundWrapper(QAudio::AudioInput, this);
   372     QScopedPointer<SymbianAudio::DevSoundCapabilities> caps(
   296 
   373         new SymbianAudio::DevSoundCapabilities(*m_devSound, QAudio::AudioInput));
   297     connect(m_devSound, SIGNAL(initializeComplete(int)),
   374 
   298             this, SLOT(devsoundInitializeComplete(int)));
   375     int err = SymbianAudio::Utils::isFormatSupported(m_format, *caps) ?
   299     connect(m_devSound, SIGNAL(bufferToBeProcessed(CMMFBuffer *)),
   376                   KErrNone : KErrNotSupported;
   300             this, SLOT(devsoundBufferToBeEmptied(CMMFBuffer *)));
   377 
   301     connect(m_devSound, SIGNAL(processingError(int)),
   378     if (KErrNone == err) {
   302             this, SLOT(devsoundRecordError(int)));
   379         setState(SymbianAudio::InitializingState);
   303 
   380         TRAP(err, m_devSound->InitializeL(*this, m_nativeFourCC,
   304     setState(SymbianAudio::InitializingState);
   381                                           EMMFStateRecording));
   305     m_devSound->initialize(m_format.codec());
   382     }
       
   383 
       
   384     if (KErrNone != err) {
       
   385         setError(QAudio::OpenError);
       
   386         m_devSound.reset();
       
   387     }
       
   388 }
   306 }
   389 
   307 
   390 void QAudioInputPrivate::startRecording()
   308 void QAudioInputPrivate::startRecording()
   391 {
   309 {
   392     const int samplesRecorded = m_devSound->SamplesRecorded();
   310     const int samplesRecorded = m_devSound->samplesProcessed();
   393     Q_ASSERT(samplesRecorded == 0);
   311     Q_ASSERT(samplesRecorded == 0);
   394 
   312 
   395     TRAPD(err, startDevSoundL());
   313     bool ok = m_devSound->setFormat(m_format);
   396     if (KErrNone == err) {
   314     if (ok)
       
   315         ok = m_devSound->start();
       
   316 
       
   317     if (ok) {
   397         startDataTransfer();
   318         startDataTransfer();
   398     } else {
   319     } else {
   399         setError(QAudio::OpenError);
   320         setError(QAudio::OpenError);
   400         close();
   321         close();
   401     }
   322     }
   402 }
   323 }
   403 
   324 
   404 void QAudioInputPrivate::startDevSoundL()
       
   405 {
       
   406     TMMFCapabilities nativeFormat = m_devSound->Config();
       
   407     m_nativeFormat.iBufferSize = nativeFormat.iBufferSize;
       
   408     m_devSound->SetConfigL(m_nativeFormat);
       
   409     m_devSound->RecordInitL();
       
   410 }
       
   411 
       
   412 void QAudioInputPrivate::startDataTransfer()
   325 void QAudioInputPrivate::startDataTransfer()
   413 {
   326 {
   414     m_notifyTimer->start(m_notifyInterval);
   327     if (m_notifyInterval)
       
   328         m_notifyTimer->start(m_notifyInterval);
   415 
   329 
   416     if (m_pullMode)
   330     if (m_pullMode)
   417         m_pullTimer->start();
   331         m_pullTimer->start();
   418 
   332 
   419     if (bytesReady()) {
   333     if (bytesReady()) {
   501         if (!bytesPushed)
   415         if (!bytesPushed)
   502             break;
   416             break;
   503     }
   417     }
   504 }
   418 }
   505 
   419 
       
   420 void QAudioInputPrivate::devsoundInitializeComplete(int err)
       
   421 {
       
   422     Q_ASSERT_X(SymbianAudio::InitializingState == m_internalState,
       
   423         Q_FUNC_INFO, "Invalid state");
       
   424 
       
   425     if (!err && m_devSound->isFormatSupported(m_format))
       
   426         startRecording();
       
   427     else
       
   428         setError(QAudio::OpenError);
       
   429 }
       
   430 
       
   431 void QAudioInputPrivate::devsoundBufferToBeEmptied(CMMFBuffer *baseBuffer)
       
   432 {
       
   433     // Following receipt of this signal, DevSound should not provide another
       
   434     // buffer until we have returned the current one.
       
   435     Q_ASSERT_X(!m_devSoundBuffer, Q_FUNC_INFO, "Buffer already held");
       
   436 
       
   437     CMMFDataBuffer *const buffer = static_cast<CMMFDataBuffer*>(baseBuffer);
       
   438 
       
   439     if (!m_devSoundBufferSize)
       
   440         m_devSoundBufferSize = buffer->Data().MaxLength();
       
   441 
       
   442     m_totalBytesReady += buffer->Data().Length();
       
   443 
       
   444     if (SymbianAudio::SuspendedState == m_internalState) {
       
   445         m_devSoundBufferQ.append(buffer);
       
   446     } else {
       
   447         // Will be returned to DevSoundWrapper by bufferProcessed().
       
   448         m_devSoundBuffer = buffer;
       
   449         m_devSoundBufferPos = 0;
       
   450 
       
   451         if (bytesReady() && !m_pullMode)
       
   452             pushData();
       
   453     }
       
   454 }
       
   455 
       
   456 void QAudioInputPrivate::devsoundRecordError(int err)
       
   457 {
       
   458     Q_UNUSED(err)
       
   459     setError(QAudio::IOError);
       
   460 }
       
   461 
   506 void QAudioInputPrivate::bufferEmptied()
   462 void QAudioInputPrivate::bufferEmptied()
   507 {
   463 {
   508     m_devSoundBufferPos = 0;
   464     m_devSoundBufferPos = 0;
   509 
   465 
   510     if (m_devSoundBuffer) {
   466     if (m_devSoundBuffer) {
   511         m_totalBytesReady -= m_devSoundBuffer->Data().Length();
   467         m_totalBytesReady -= m_devSoundBuffer->Data().Length();
   512         m_devSoundBuffer = 0;
   468         m_devSoundBuffer = 0;
   513         m_devSound->RecordData();
   469         m_devSound->bufferProcessed();
   514     } else {
   470     } else {
   515         Q_ASSERT(!m_devSoundBufferQ.empty());
   471         Q_ASSERT(!m_devSoundBufferQ.empty());
   516         m_totalBytesReady -= m_devSoundBufferQ.front()->Data().Length();
   472         m_totalBytesReady -= m_devSoundBufferQ.front()->Data().Length();
   517         m_devSoundBufferQ.erase(m_devSoundBufferQ.begin());
   473         m_devSoundBufferQ.erase(m_devSoundBufferQ.begin());
   518 
   474 
   519         // If the queue has been emptied, resume transfer from the hardware
   475         // If the queue has been emptied, resume transfer from the hardware
   520         if (m_devSoundBufferQ.empty())
   476         if (m_devSoundBufferQ.empty())
   521             m_devSound->RecordInitL();
   477             if (!m_devSound->start())
       
   478                 setError(QAudio::IOError);
   522     }
   479     }
   523 
   480 
   524     Q_ASSERT(m_totalBytesReady >= 0);
   481     Q_ASSERT(m_totalBytesReady >= 0);
   525 }
   482 }
   526 
   483 
   530     m_pullTimer->stop();
   487     m_pullTimer->stop();
   531 
   488 
   532     m_error = QAudio::NoError;
   489     m_error = QAudio::NoError;
   533 
   490 
   534     if (m_devSound)
   491     if (m_devSound)
   535         m_devSound->Stop();
   492         m_devSound->stop();
   536     m_devSound.reset();
   493     delete m_devSound;
       
   494     m_devSound = 0;
       
   495 
   537     m_devSoundBuffer = 0;
   496     m_devSoundBuffer = 0;
   538     m_devSoundBufferSize = 0;
   497     m_devSoundBufferSize = 0;
   539     m_totalBytesReady = 0;
   498     m_totalBytesReady = 0;
   540 
   499 
   541     if (!m_pullMode) // m_sink is owned
   500     if (!m_pullMode) // m_sink is owned
   552 
   511 
   553 qint64 QAudioInputPrivate::getSamplesRecorded() const
   512 qint64 QAudioInputPrivate::getSamplesRecorded() const
   554 {
   513 {
   555     qint64 result = 0;
   514     qint64 result = 0;
   556     if (m_devSound)
   515     if (m_devSound)
   557         result = qint64(m_devSound->SamplesRecorded());
   516         result = qint64(m_devSound->samplesProcessed());
   558     return result;
   517     return result;
   559 }
   518 }
   560 
   519 
   561 void QAudioInputPrivate::setError(QAudio::Error error)
   520 void QAudioInputPrivate::setError(QAudio::Error error)
   562 {
   521 {
   563     m_error = error;
   522     m_error = error;
   564 
   523 
   565     // Although no state transition actually occurs here, a stateChanged event
   524     // Although no state transition actually occurs here, a stateChanged event
   566     // must be emitted to inform the client that the call to start() was
   525     // must be emitted to inform the client that the call to start() was
   567     // unsuccessful.
   526     // unsuccessful.
   568     if (QAudio::OpenError == error)
   527     if (QAudio::OpenError == error) {
   569         emit stateChanged(QAudio::StoppedState);
   528         emit stateChanged(QAudio::StoppedState);
   570 
   529     } else {
   571     // Close the DevSound instance.  This causes a transition to StoppedState.
   530         if (QAudio::UnderrunError == error)
   572     // This must be done asynchronously in case the current function was called
   531             setState(SymbianAudio::IdleState);
   573     // from a DevSound event handler, in which case deleting the DevSound
   532         else
   574     // instance may cause an exception.
   533             // Close the DevSound instance.  This causes a transition to
   575     QMetaObject::invokeMethod(this, "close", Qt::QueuedConnection);
   534             // StoppedState.  This must be done asynchronously in case the
       
   535             // current function was called from a DevSound event handler, in which
       
   536             // case deleting the DevSound instance may cause an exception.
       
   537             QMetaObject::invokeMethod(this, "close", Qt::QueuedConnection);
       
   538     }
   576 }
   539 }
   577 
   540 
   578 void QAudioInputPrivate::setState(SymbianAudio::State newInternalState)
   541 void QAudioInputPrivate::setState(SymbianAudio::State newInternalState)
   579 {
   542 {
   580     const QAudio::State oldExternalState = m_externalState;
   543     const QAudio::State oldExternalState = m_externalState;
   581     m_internalState = newInternalState;
   544     m_internalState = newInternalState;
   582     m_externalState = SymbianAudio::Utils::stateNativeToQt(
   545     m_externalState = SymbianAudio::Utils::stateNativeToQt(m_internalState);
   583                             m_internalState, initializingState());
       
   584 
   546 
   585     if (m_externalState != oldExternalState)
   547     if (m_externalState != oldExternalState)
   586         emit stateChanged(m_externalState);
   548         emit stateChanged(m_externalState);
   587 }
   549 }
   588 
   550 
   589 QAudio::State QAudioInputPrivate::initializingState() const
       
   590 {
       
   591     return QAudio::IdleState;
       
   592 }
       
   593 
       
   594 QT_END_NAMESPACE
   551 QT_END_NAMESPACE