First public contribution.
1 // Copyright (c) 2002-2009 Nokia Corporation and/or its subsidiary(-ies).
2 // All rights reserved.
3 // This component and the accompanying materials are made available
4 // under the terms of "Eclipse Public License v1.0"
5 // which accompanies this distribution, and is available
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
8 // Initial Contributors:
9 // Nokia Corporation - initial contribution.
16 #include "MmfAudioInput.h"
17 #include <ecom/implementationproxy.h>
18 #include <mmf/server/mmfformat.h>
19 #include <mmf/plugin/mmfaudioiointerfaceuids.hrh>
22 void Panic(TInt aPanicCode)
24 _LIT(KMMFAudioInputPanicCategory, "MMFAudioInput");
25 User::Panic(KMMFAudioInputPanicCategory, aPanicCode);
29 Static standard SymbianOS 2 phase constuction method.
31 Constucts this audio device.
33 @return A pointer to a MDataSource returned on successful construction.
35 MDataSource* CMMFAudioInput::NewSourceL()
37 CMMFAudioInput* self = new (ELeave) CMMFAudioInput ;
38 CleanupStack::PushL(self);
41 return STATIC_CAST( MDataSource*, self );
45 Standard SymbianOS ConstructL.
47 Used to initialise member varibles with device specific behaviour.
49 void CMMFAudioInput::ConstructL()
51 iDataTypeCode = KMMFFourCCCodePCM16;
52 iActiveSchedulerWait = new(ELeave) CActiveSchedulerWait;
56 Standard SymbianOS destructor.
58 CMMFAudioInput::~CMMFAudioInput()
60 delete iActiveSchedulerWait;
70 Overridable constuctor specific to this datasource.
73 The initialisation data.
75 void CMMFAudioInput::ConstructSourceL( const TDesC8& /*aInitData*/ )
82 Gets audio from hardware device abstracted MMFDevsound (not used).
85 The data to read in from a Hardware Device
87 The MDataSink consuming the data contained in aBuffer.
89 void CMMFAudioInput::HWFillBufferL(CMMFBuffer* /*aBuffer*/, MDataSink* /*aConsumer*/)
95 Gets audio from MMFDevsound.
98 iMMFDevSound must be loaded.
101 The data to read in from a Devsound device.
103 The MDataSink consuming the data contained in aBuffer.
105 Type of data supplied - currently ignored.
107 void CMMFAudioInput::FillBufferL(CMMFBuffer* aBuffer, MDataSink* aConsumer, TMediaId /* aMediaId */)
109 iConsumer = aConsumer;
112 Panic(EMMFAudioInputDevSoundNotLoaded);
114 if ((iState == EPaused) && (iPausePending != EFalse) && (iFirstBufferRequested) )
116 User::Leave(KErrNotReady);
119 if ((aBuffer != NULL) && (!CMMFBuffer::IsSupportedDataBuffer(aBuffer->Type())))
120 User::Leave(KErrNotSupported);
122 if (aConsumer == NULL)
123 User::Leave(KErrArgument);
125 //this is a one-shot "prime" funtion for MMFDevSound as first buffer is uninitialised
126 if (!iFirstBufferRequested)
128 iMMFDevSound->RecordInitL();
129 iFirstBufferRequested = ETrue;
133 if (iState != EDevSoundReady && iState != EPaused)
135 User::Leave(KErrNotReady);
138 iMMFDevSound->RecordData();
142 Indicates the data sink has emptied the buffer.
144 Called by the data path's MDataSink when it has emptied the buffer.
146 The default implementation is empty.
149 The data buffer that has been emptied (not used).
151 void CMMFAudioInput::BufferEmptiedL(CMMFBuffer* /*aBuffer*/)
157 Tests whether a source buffer can be created.
159 The default imlpementation returns true.
161 @return A boolean indicating if the buffer can be made. ETrue if the buffer can be created, false
164 TBool CMMFAudioInput::CanCreateSourceBuffer()
170 Creates a source buffer.
172 Intended for asynchronous usage (buffers supplied by Devsound device)
175 The Media ID. Not used in the default implementation.
177 A boolean indicating if MDataSource owns the buffer. ETrue if it does, EFalse if it does
180 @return The buffer created (this will always be NULL when asychronous).
182 CMMFBuffer* CMMFAudioInput::CreateSourceBufferL(TMediaId /*aMediaId*/, TBool &aReference)
184 CMMFDataBuffer* buf = NULL;
186 aReference = ETrue; // This is a reference from DevSound
191 Creates a source buffer.
193 Intended for synchronous usage.
196 The Media ID. Not used in the default implementation.
198 @return The buffer created
200 CMMFBuffer* CMMFAudioInput::CreateSourceBufferL(TMediaId /*aMediaId*/)
202 CMMFDataBuffer* buf = CMMFDataBuffer::NewL(KAudioInputDefaultFrameSize);
210 This is a virtual function that each derived class must implement, but may be left blank for
213 Overridable PrimeL method. Additional Prime method specific to this DataSource.
215 void CMMFAudioInput::SourcePrimeL()
217 iState = EDevSoundReady;
223 This is a virtual function that each derived class must implement, but may be left blank for default
226 Overridable PauseL method. Additional Pause method specific to this DataSource.
228 void CMMFAudioInput::SourcePauseL()
230 if (iState == EDevSoundReady)
231 {//not waiting on a buffer being played so stop devsound now
233 if (iFirstBufferRead)
236 Panic(EMMFAudioInputDevSoundNotLoaded);
238 iMMFDevSound->Pause();
241 iPausePending = ETrue; // Wait for recording to get started.
243 //else if Devsound isn't ready then no point in stopping it
250 This is a virtual function that each derived class must implement, but may be left blank for default
253 Overridable StopL method. Additional Stop method specific to this DataSource.
255 void CMMFAudioInput::SourceStopL()
258 // This is done in Audio Output as well, not sure whether its needed here or not.
259 // Pause will be called before SourceStopL() and pause will take care of closing
261 if (iState == EDevSoundReady || iState == EPaused)
262 {//not waiting on a buffer being played so stop devsound now
264 if (iFirstBufferRequested)
267 Panic(EMMFAudioInputDevSoundNotLoaded);
270 iMMFDevSound->Stop();
273 iFirstBufferRequested = EFalse;
274 iFirstBufferRead = EFalse;
277 //else if Devsound isn't ready then no point in stopping it
283 This is a virtual function that each derived class must implement, but may be left blank for default
286 Overridable PlayL method. Additional Play method specific to this DataSource.
288 void CMMFAudioInput::SourcePlayL()
293 Logs on the source thread.
295 Thread specific initialization procedure for this device. Runs automatically on thread construction.
300 @return An error code indicating if the function call was successful. KErrNone on success, otherwise
301 another of the system-wide error codes.
303 TInt CMMFAudioInput::SourceThreadLogon(MAsyncEventHandler& aEventHandler)
305 iEventHandler = &aEventHandler;
307 if (!iDevSoundLoaded)
313 Logs off the source thread.
315 Thread specific destruction procedure for this device. Runs automatically on thread destruction.
317 void CMMFAudioInput::SourceThreadLogoff()
321 iMMFDevSound->Stop();
325 iDevSoundLoaded = EFalse;
333 dev sound should be created and loaded.
335 void CMMFAudioInput::ConfigDevSoundL()
337 //[precondition dev sound created ]
338 ASSERT( iMMFDevSound );
340 // Query DevSound capabilities and Try to use DevSound sample rate and
341 // mono/stereo capability
342 TMMFCapabilities devSoundCaps = iMMFDevSound->Capabilities();
343 // get current config
344 TMMFCapabilities devSoundConfig = iMMFDevSound->Config();
347 devSoundConfig.iEncoding = EMMFSoundEncoding16BitPCM;
349 // 1 = Monophonic and 2 == Stereo
350 if (((iSinkChannels == 1) && (devSoundCaps.iChannels & EMMFMono)) ||
351 ((iSinkChannels == 2) && (devSoundCaps.iChannels & EMMFStereo)))
352 devSoundConfig.iChannels = iSinkChannels;
355 // Check for std sample rates.
356 if ((iSinkSampleRate == 96000) && (devSoundCaps.iRate & EMMFSampleRate96000Hz))
357 devSoundConfig.iRate = EMMFSampleRate96000Hz;
358 else if ((iSinkSampleRate == 88200) && (devSoundCaps.iRate & EMMFSampleRate88200Hz))
359 devSoundConfig.iRate = EMMFSampleRate88200Hz;
360 else if ((iSinkSampleRate == 64000) && (devSoundCaps.iRate & EMMFSampleRate64000Hz))
361 devSoundConfig.iRate = EMMFSampleRate64000Hz;
362 else if ((iSinkSampleRate == 48000) && (devSoundCaps.iRate & EMMFSampleRate48000Hz))
363 devSoundConfig.iRate = EMMFSampleRate48000Hz;
364 else if ((iSinkSampleRate == 44100) && (devSoundCaps.iRate & EMMFSampleRate44100Hz))
365 devSoundConfig.iRate = EMMFSampleRate44100Hz;
366 else if ((iSinkSampleRate == 32000) && (devSoundCaps.iRate & EMMFSampleRate32000Hz))
367 devSoundConfig.iRate = EMMFSampleRate32000Hz;
368 else if ((iSinkSampleRate == 24000) && (devSoundCaps.iRate & EMMFSampleRate24000Hz))
369 devSoundConfig.iRate = EMMFSampleRate24000Hz;
370 else if ((iSinkSampleRate == 22050) && (devSoundCaps.iRate & EMMFSampleRate22050Hz))
371 devSoundConfig.iRate = EMMFSampleRate22050Hz;
372 else if ((iSinkSampleRate == 16000) && (devSoundCaps.iRate & EMMFSampleRate16000Hz))
373 devSoundConfig.iRate = EMMFSampleRate16000Hz;
374 else if ((iSinkSampleRate == 12000) && (devSoundCaps.iRate & EMMFSampleRate12000Hz))
375 devSoundConfig.iRate = EMMFSampleRate12000Hz;
376 else if ((iSinkSampleRate == 11025) && (devSoundCaps.iRate & EMMFSampleRate11025Hz))
377 devSoundConfig.iRate = EMMFSampleRate11025Hz;
378 else if ((iSinkSampleRate == 8000) && (devSoundCaps.iRate & EMMFSampleRate8000Hz))
379 devSoundConfig.iRate = EMMFSampleRate8000Hz;
382 // pick the maximum sample rate available
383 if (devSoundCaps.iRate & EMMFSampleRate96000Hz)
384 devSoundConfig.iRate = EMMFSampleRate96000Hz;
385 else if (devSoundCaps.iRate & EMMFSampleRate88200Hz)
386 devSoundConfig.iRate = EMMFSampleRate88200Hz;
387 else if (devSoundCaps.iRate & EMMFSampleRate64000Hz)
388 devSoundConfig.iRate = EMMFSampleRate64000Hz;
389 else if (devSoundCaps.iRate & EMMFSampleRate48000Hz)
390 devSoundConfig.iRate = EMMFSampleRate48000Hz;
391 else if (devSoundCaps.iRate & EMMFSampleRate44100Hz)
392 devSoundConfig.iRate = EMMFSampleRate44100Hz;
393 else if (devSoundCaps.iRate & EMMFSampleRate32000Hz)
394 devSoundConfig.iRate = EMMFSampleRate32000Hz;
395 else if (devSoundCaps.iRate & EMMFSampleRate24000Hz)
396 devSoundConfig.iRate = EMMFSampleRate24000Hz;
397 else if (devSoundCaps.iRate & EMMFSampleRate22050Hz)
398 devSoundConfig.iRate = EMMFSampleRate22050Hz;
399 else if (devSoundCaps.iRate & EMMFSampleRate16000Hz)
400 devSoundConfig.iRate = EMMFSampleRate16000Hz;
401 else if (devSoundCaps.iRate & EMMFSampleRate12000Hz)
402 devSoundConfig.iRate = EMMFSampleRate12000Hz;
403 else if (devSoundCaps.iRate & EMMFSampleRate11025Hz)
404 devSoundConfig.iRate = EMMFSampleRate11025Hz;
405 else if (devSoundCaps.iRate & EMMFSampleRate8000Hz)
406 devSoundConfig.iRate = EMMFSampleRate8000Hz;
408 ASSERT(EFalse); // if we don't support any sample rates, there is not much we can do
412 iMMFDevSound->SetConfigL(devSoundConfig);
416 Negotiates with the sink.
418 Called if the source's setup depends on sink.
421 The Data sink. Takes an MDataSink reference so a DataSource can negotiate with this
424 void CMMFAudioInput::NegotiateSourceL(MDataSink& aSink)
426 if (aSink.DataSinkType() == KUidMmfFormatEncode)
427 {//sink is a clip so for now set sink settings to match sink
428 iSinkSampleRate = ((CMMFFormatEncode&)aSink).SampleRate();
429 iSinkChannels = ((CMMFFormatEncode&)aSink).NumChannels();
430 iSinkFourCC.Set(aSink.SinkDataTypeCode(TMediaId(KUidMediaTypeAudio)));
432 // if the sink's sample rate is undefined, try to obtain and use a
433 // default sample rate from the sink. If this is zero, use 8K
434 if (iSinkSampleRate == 0)
436 iSinkSampleRate = ((CMMFFormatEncode&)aSink).GetDefaultSampleRate();
437 if (iSinkSampleRate == 0)
438 iSinkSampleRate = 8000;
443 if (iMMFDevSound == NULL)
444 User::Leave(KErrNotReady);
446 TMMFState prioritySettingsState = iPrioritySettings.iState; //should be EMMFStateRecording
447 //to use the GetSupportedOutputDatatypes but we'll save it just in case it's not
448 iPrioritySettings.iState = EMMFStateRecording; //if playing does not support any output data types
449 RArray<TFourCC> supportedDataTypes;
450 //note Output data types becuase if we are recording audio ie audio input
451 //the data is sent as an output from DevSound
452 TRAPD(err, iMMFDevSound->GetSupportedOutputDataTypesL(supportedDataTypes, iPrioritySettings));
453 iPrioritySettings.iState = prioritySettingsState;
456 if (supportedDataTypes.Find(iSinkFourCC) == KErrNotFound)
457 {//the source fourCC code could not be found in the list of
458 //data types supported by the Devsound therefor default to pcm16
459 iDataTypeCode = KMMFFourCCCodePCM16;
463 //the DevSound does support the same datatype as the source
464 //so set the fourcc to that of the source
465 iDataTypeCode = iSinkFourCC;
468 supportedDataTypes.Close();
469 if (err == KErrNotSupported)
470 {//if the Devsound does not support the GetSupportedOutputDataTypesL method
471 //then assume that the DevSound is pcm16 only
472 iDataTypeCode = KMMFFourCCCodePCM16;
474 else if (err != KErrNone) //we had a real leave error from GetSupportedOuputDataTypesL
479 // Prevent defect when SourcePrimeL is called before NegotiateSourceL()
480 // since characterization is ambiguous
481 if(iState == EDevSoundReady)
486 // moved from LoadL - fix for DEF037168 - AD
487 iMMFDevSound->InitializeL(*this, iDataTypeCode, EMMFStateRecording);
489 // In some implementations InitializeComplete is sent
490 // in context, so check before starting activeSchedulerWait.
491 if (iState != EDevSoundReady)
493 iInitializeState = KRequestPending;
494 iActiveSchedulerWait->Start();
496 User::LeaveIfError(iInitializeState);
498 iMMFDevSound->SetPrioritySettings(iPrioritySettings);
500 // Attempt to configure DevSound to the same settings as the sink.
501 // Need to do this after calling CMMFDevSound::InitializeL() as
502 // this sets up the device capabilities
503 // (returned by iMMFDevSound->Capabilities()).
508 Sets the source's priority settings.
510 @param aPrioritySettings
511 The source priority settings. Takes enumerations to determine audio record priority. Higher
512 numbers mean high priority (can interrupt lower priorities).
514 void CMMFAudioInput::SetSourcePrioritySettings(const TMMFPrioritySettings& aPrioritySettings)
516 iPrioritySettings = aPrioritySettings;
518 Panic(EMMFAudioInputDevSoundNotLoaded);
520 iMMFDevSound->SetPrioritySettings(iPrioritySettings);
525 Gets the data type code for the source specified by the media ID.
528 An optional parameter to specifiy a specific stream when the datasource contains more than
531 @return The 4CC of the data supplied by this source.
533 TFourCC CMMFAudioInput::SourceDataTypeCode(TMediaId /*aMediaId*/)
535 return iDataTypeCode;
539 Sets the data type code for the source.
542 The 4CC of the data supplied by this source.
544 The Media ID. An optional parameter to specifiy specific stream when datasource contains
545 more than one stream of data.
547 @return An error code indicating if the function call was successful. KErrNone on success, otherwise
548 another of the system-wide error codes.
550 TInt CMMFAudioInput::SetSourceDataTypeCode(TFourCC aSourceFourCC, TMediaId /*aMediaId*/)
552 iDataTypeCode = aSourceFourCC;
557 Gets the number of bytes played.
559 @return The number of bytes played. If 16-bit divide this number returned by 2 to get word length.
561 TInt CMMFAudioInput::BytesPlayed()
564 Panic(EMMFAudioInputDevSoundNotLoaded);
565 return iMMFDevSound->SamplesPlayed();
569 Returns the sound device.
572 Dev Sound should be loaded.
574 Accessor function exposing public CMMFDevsound methods.
576 @return A reference to a CMMFDevSound objector.
578 CMMFDevSound& CMMFAudioInput::SoundDevice()
582 Panic(EMMFAudioInputDevSoundNotLoaded);
584 return *iMMFDevSound;
591 This method should not be used - it is provided to maintain SC with v7.0s.
594 The 4CC of the data supplied by this source.
596 void CMMFAudioInput::SetDataTypeL(TFourCC aAudioType)
598 if (aAudioType != KMMFFourCCCodePCM16)
600 User::Leave(KErrNotSupported);
608 This method should not be used - it is provided to maintain SC with v7.0s.
610 @return The 4CC of the data supplied by this source.
612 TFourCC CMMFAudioInput::DataType() const
614 return KMMFFourCCCodePCM16;
619 Loads audio device drivers and initialise this device.
621 void CMMFAudioInput::LoadL()
623 //[ do all the work that can fail first
624 // before we modify the internal state ]
626 iMMFDevSound = CMMFDevSound::NewL();
627 iFirstBufferRequested = EFalse;
628 iFirstBufferRead = EFalse;
629 if (iState != EDevSoundReady)
634 iDevSoundLoaded = ETrue;
636 //[ assert dev sound has been constructed]
637 ASSERT( iMMFDevSound );
638 ASSERT( iDevSoundLoaded );
639 ASSERT( !iFirstBufferRead );
642 void CMMFAudioInput::DeviceMessage(TUid /*aMessageType*/, const TDesC8& /* aMsg */)
646 void CMMFAudioInput::InitializeComplete(TInt aError)
648 if (aError == KErrNone)
650 iState = EDevSoundReady;
653 if(iInitializeState == KRequestPending)
655 iInitializeState = aError;
656 iActiveSchedulerWait->AsyncStop();
662 ToneFinished MMFDevSoundObserver - should never get called.
664 void CMMFAudioInput::ToneFinished(TInt /*aError*/)
666 //we should never get here during a record session!
667 __ASSERT_DEBUG(EFalse,Panic(EMMFAudioInputPanicToneFinishedNotSupported));
672 BuffferToBeEmptied MMFDevSoundObserver
673 Called when stopped due to error.
675 void CMMFAudioInput::BufferToBeEmptied(CMMFBuffer* aBuffer)
677 iDevSoundBuf = aBuffer;
679 if (iFirstBufferRequested)
683 aBuffer->SetLastBuffer(ETrue);
684 iPausePending = EFalse;
688 TRAPD(err, iConsumer->BufferFilledL(aBuffer));
689 __ASSERT_DEBUG(!err, Panic(err));
691 TRAP_IGNORE(iConsumer->BufferFilledL(aBuffer));
694 iFirstBufferRead = ETrue;
700 RecordError MMFDevSoundObserver
701 Called when stopped due to error.
703 void CMMFAudioInput::RecordError(TInt aError)
705 //[ two event categories will be used
706 // which mirrors the datapath response ]
708 //[ record the error ]
709 iMMFDevsoundError = aError;
710 TMMFEvent event( KMMFEventCategoryPlaybackComplete, aError);
712 //[ send the event to the client.
713 SendEventToClient(event);
715 // clear flags if there is an error.
716 iPausePending = EFalse;
718 //[ we are not going to stop devsound ]
723 BufferToBeFilled MMFDevSoundObserver - should never get called.
725 void CMMFAudioInput::BufferToBeFilled(CMMFBuffer* /*aBuffer*/)
727 //we should never get here during a play session!
728 __ASSERT_DEBUG(EFalse, Panic(EMMFAudioInputPanicPlayerDataUsedNotSupported));
733 PlayError MMFDevSoundObserver - should never get called.
735 void CMMFAudioInput::PlayError(TInt /*aError*/)
737 //we should never get here during a record session!
738 __ASSERT_DEBUG(EFalse, Panic(EMMFAudioInputPanicPlayErrorNotSupported));
743 ConvertError MMFDevSoundObserver - should never get called.
745 void CMMFAudioInput::ConvertError(TInt /*aError*/)
750 void CMMFAudioInput::SendEventToClient(const TMMFEvent& aEvent)
752 iEventHandler->SendEventToClient(aEvent);
755 // _________________________________________________________________________
756 // Exported proxy for instantiation method resolution
757 // Define the interface UIDs
759 const TImplementationProxy ImplementationTable[] =
761 IMPLEMENTATION_PROXY_ENTRY(KMmfUidAudioInputInterface, CMMFAudioInput::NewSourceL)
764 EXPORT_C const TImplementationProxy* ImplementationGroupProxy(TInt& aTableCount)
766 aTableCount = sizeof(ImplementationTable) / sizeof(TImplementationProxy);
768 return ImplementationTable;