Update contrib.
1 // Copyright (c) 2005-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 "mmfbtswcodecwrapper.h"
17 #include "mmfBtSwCodecPlayDataPath.h"
18 #include "mmfBtSwCodecRecordDataPath.h"
19 #include "mmfBtSwCodecConvertDataPath.h"
20 #include <mmfswcodecwrappercustominterfacesuids.hrh>
21 #include "mmfBtswcodecwrapperCustomInterfaces.h"
22 #include "MMFBtRoutingSoundDevice.h"
23 #include <mmfpaniccodes.h>
27 * AO to handle RSD initialisation
30 CRoutingSoundDeviceOpenHandler* CRoutingSoundDeviceOpenHandler::NewL(CMMFSwCodecWrapper* aObserver)
32 CRoutingSoundDeviceOpenHandler* self = new(ELeave) CRoutingSoundDeviceOpenHandler(aObserver);
33 CleanupStack::PushL(self);
35 CleanupStack::Pop(self);
39 CRoutingSoundDeviceOpenHandler::~CRoutingSoundDeviceOpenHandler()
44 void CRoutingSoundDeviceOpenHandler::RunL()
46 TInt err = iStatus.Int();
49 iObserver->OpenComplete(err);
53 void CRoutingSoundDeviceOpenHandler::DoCancel()
57 iObserver->OpenComplete(KErrCancel);
61 CRoutingSoundDeviceOpenHandler::CRoutingSoundDeviceOpenHandler(CMMFSwCodecWrapper* aObserver) :
62 CActive(EPriorityStandard),
66 CActiveScheduler::Add(this);
69 void CRoutingSoundDeviceOpenHandler::ConstructL()
73 void CRoutingSoundDeviceOpenHandler::Start()
86 void Panic(TInt aPanicCode)
88 _LIT(KMMFSwCodecWrapperPanicCategory, "MMFSwCodecWrapper");
89 User::Panic(KMMFSwCodecWrapperPanicCategory, aPanicCode);
94 * This method is not be exported as it is only
95 * intended to be called within this DLL.
96 * It's purpose is to assign an CRoutingSoundPlayDevice to the play
100 void TPlayCustomInterface::SetDevice(CRoutingSoundPlayDevice* aDevice)
105 void TPlayCustomInterface::SetVolume(TUint aVolume)
108 if (iDevice && iDevice->Handle())
110 iDevice->SetVolume(iVolume);
115 * Procedure to get the number of bytes played by the device driver
116 * If there is no handle available to the device driver then the
117 * procedure returns the last known value
119 * @return number of bytes played
121 TUint TPlayCustomInterface::BytesPlayed()
125 if (iDevice->Handle())
127 iBytesPlayed = iDevice->BytesPlayed();
133 TTaskConfig TPlayCustomInterface::Caps()
135 TTaskConfig taskConfig;
136 taskConfig.iRate = 0;
137 taskConfig.iStereoMode = 0;
138 taskConfig.iUid = KUidRefDevSoundTaskConfig;
140 if (iDevice && iDevice->Handle())
142 RArray<TUint> supportedSampleRates;
143 RArray<TRange>supportedRateRanges;
144 iDevice->GetSupportedSampleRates(supportedSampleRates,supportedRateRanges);
145 for (TUint i=0; i<supportedSampleRates.Count(); i++)
147 switch(supportedSampleRates[i])
150 taskConfig.iRate |= ETask8000Hz;
153 taskConfig.iRate |= ETask11025Hz;
156 taskConfig.iRate |= ETask12000Hz;
159 taskConfig.iRate |= ETask16000Hz;
162 taskConfig.iRate |= ETask22050Hz;
165 taskConfig.iRate |= ETask24000Hz;
168 taskConfig.iRate |= ETask32000Hz;
171 taskConfig.iRate |= ETask44100Hz;
174 taskConfig.iRate |= ETask48000Hz;
177 taskConfig.iRate |= ETask88200Hz;
180 taskConfig.iRate |= ETask96000Hz;
182 default: //do nothing
184 }// switch(supportedSampleRates[i])
185 supportedSampleRates.Close();
186 supportedRateRanges.Close();
187 }//for (TUint i=0; i<supportedSampleRates.Count(); i++)
188 RArray<TUint> supportedChannels;
189 TMMFStereoSupport stereoSupport;
190 iDevice->GetSupportedChannels(supportedChannels,stereoSupport);
191 for (TUint i=0; i<supportedChannels.Count(); i++)
192 {//note we don't have a TaskConfig enum for Joint stereo
193 switch(supportedChannels[i])
196 taskConfig.iStereoMode |= ETaskMono;
199 if (stereoSupport == EMMFInterleavedOnly)
201 taskConfig.iStereoMode |= ETaskInterleaved;
203 else if (stereoSupport == EMMFNonInterleavedOnly)
205 taskConfig.iStereoMode |= ETaskNonInterleaved;
207 else if (stereoSupport == EMMFBothNonAndInterleaved)
209 taskConfig.iStereoMode |= (ETaskInterleaved|ETaskNonInterleaved);
214 }//switch(supportedChannels[i])
215 supportedChannels.Close();
216 }// for (TUint i=0; i<supportedChannels.Count(); i++)
217 }//if (iDevice && iDevice->Handle())
222 * Procedure to get the number of bytes recorded by the device
224 * @return number of bytes recorded
226 TUint TRecordCustomInterface::BytesRecorded()
230 iBytesRecorded = iDataPath->RecordedBytesCount();
232 return iBytesRecorded;
238 EXPORT_C CMMFSwCodecWrapper::CMMFSwCodecWrapper()
245 The destructor is called by ECom framework allowing derived classes
246 to clean up implementation specific resources. The sound
247 device drivers are freed.
249 EXPORT_C CMMFSwCodecWrapper::~CMMFSwCodecWrapper()
251 // AO to handle OpenDevice call
252 if (iOpenHandler && iOpenHandler->IsActive())
254 iOpenHandler->Cancel();
257 delete iRecordDevice;
261 delete iPlayCustomInterface;
262 delete iRecordCustomInterface;
266 Initializes the hardware device tasks - in the case of a
267 sw codec wrapper 'hardware device' this consists of loading the
268 sound device drivers and creating the CMMFSwCodec.
271 Device initialization parameters.
272 Only the iHwDeviceObserver is used for CMFSwCodecWrapper
273 derived CMMFHwDevices.
274 @return An error code indicating if the function call was successful. KErrNone on success, otherwise
275 another of the system-wide error codes.
277 EXPORT_C TInt CMMFSwCodecWrapper::Init(THwDeviceInitParams& aDevInfo)
279 TRequestStatus status;
280 Init(aDevInfo,status);
281 User::WaitForRequest(status);
287 Initializes the hardware device tasks - in the case of a
288 sw codec wrapper 'hardware device' this consists of loading the
289 sound device drivers and creating the CMMFSwCodec.
292 Device initialization parameters.
293 Only the iHwDeviceObserver is used for CMFSwCodecWrapper
294 derived CMMFHwDevices.
296 Status flag belonging to an Active Object that will have its
297 RunL() called when this function completes
299 EXPORT_C void CMMFSwCodecWrapper::Init( THwDeviceInitParams &aDevInfo,
300 TRequestStatus& aStatus)
302 aStatus = KRequestPending;
303 TRequestStatus* status = &aStatus;
304 if (!aDevInfo.iHwDeviceObserver)
306 User::RequestComplete(status, KErrArgument);
309 iHwDeviceObserver = aDevInfo.iHwDeviceObserver;
312 if (aDevInfo.iOutStream.iConnection.iId)
314 iDeviceUid = TUid::Uid(aDevInfo.iOutStream.iConnection.iId);
318 TRAP(err, iPlayDevice = CRoutingSoundPlayDevice::NewL());
321 iPlayDevice->Initialize(iDeviceUid,
322 aDevInfo.iOutStream.iDeviceName, *status);
323 if (!iPlayCustomInterface)
325 TRAP(err,iPlayCustomInterface = new(ELeave)TPlayCustomInterface());
330 User::RequestComplete(status, err);
334 static_cast<TPlayCustomInterface*>(iPlayCustomInterface)->SetDevice(iPlayDevice);
337 if (aDevInfo.iInStream.iConnection.iId)
339 iDeviceUid = TUid::Uid(aDevInfo.iInStream.iConnection.iId);
341 TRAP(err, iRecordDevice = CRoutingSoundRecordDevice::NewL());
344 iRecordDevice->Initialize(iDeviceUid, KNullDesC8, *status);
345 if (!iRecordCustomInterface)
347 TRAP(err,iRecordCustomInterface = new(ELeave)TRecordCustomInterface());
350 delete iRecordDevice;
351 iRecordDevice = NULL;
352 User::RequestComplete(status, err);
359 iCodec = &(Codec()); //create codec
361 //[ assert the post condition ]
364 err = KErrNotSupported;
369 User::RequestComplete(status, err);
370 // Cancel initialisation too
371 if (aDevInfo.iOutStream.iConnection.iId)
373 iPlayDevice->CancelInitialize(iDeviceUid);
375 if (aDevInfo.iInStream.iConnection.iId)
377 iRecordDevice->CancelInitialize(iDeviceUid);
380 else if ((!aDevInfo.iOutStream.iConnection.iId)&& (!aDevInfo.iInStream.iConnection.iId))
382 //could be used for conversion so complete the request status
383 User::RequestComplete(status, KErrNone);
389 Starts Encoding or Decoding task(s) based on the parameter specified.
392 The device function specifying the requested service i.e. decode or encode
393 where EDevEncode = Record, EDevDecode = Play and EDevNullFunc = Convert.
395 The device flow directions for requested service.
396 This parameter is ignored for CMMFSwCodecWrapper CMMFHwDevicePlugins
397 @return An error code indicating if the function call was successful. KErrNone on success, otherwise
398 another of the system-wide error codes.
400 EXPORT_C TInt CMMFSwCodecWrapper::Start(TDeviceFunc aFuncCmd, TDeviceFlow /*aFlowCmd*/)
402 TInt error = KErrNone;
404 // [ precondition that aFuncCmd is valid]
405 if (!((aFuncCmd == EDevEncode)|(aFuncCmd == EDevDecode)|(aFuncCmd == EDevNullFunc)))
410 // [ precondition that iCodec is present]
413 return KErrNotReady; //make sure the codec has been added
418 case EDevEncode: // Audio record
420 error = StartEncode();
423 case EDevDecode: // Audio play
425 error = StartDecode();
428 case EDevNullFunc: //Audio Convert
430 error = StartConvert();
434 error = KErrNotSupported;
438 //[ assert the post conditions ]
441 {//only assert if no error otherwise post consitions not valid
442 __ASSERT_DEBUG(iDataPath, Panic(EMMFSwCodecWrapperNoDataPath));
443 if ((aFuncCmd == EDevEncode)||(aFuncCmd == EDevDecode))
445 __ASSERT_DEBUG(iDataPath->Device().Handle(), Panic(EMMFSwCodecWrapperNoDevice));
453 // Use AO to OpenDevice
454 TInt CMMFSwCodecWrapper::StartDecode()
456 TInt error = KErrNone;
458 //[ assert precondition that play custom interface is present]
459 //if there is no play custom interface then the user of the CMMFSwCodecWrapper
460 //cannot have set any of the custom settings such as sample rate.
461 if (!iPlayCustomInterface)
469 TRAP(error,iDataPath = CMMFSwCodecPlayDataPath::NewL(iPlayDevice, iDeviceUid));
470 if ((iDataPath) && (error == KErrNone))
472 iDataPath->SetObserver(*iHwDeviceObserver);
473 error = iDataPath->AddCodec(*iCodec);
474 iDeviceBufferSize = iCodec->SinkBufferSize();
475 static_cast<CMMFSwCodecPlayDataPath*>(iDataPath)->SetPlayCustomInterface(*iPlayCustomInterface);
476 static_cast<CMMFSwCodecPlayDataPath*>(iDataPath)->SetConfigForAudioRamp(iSampleRate, iChannels);
480 if ((error == KErrNone) &&
481 (iDataPath->State() != CMMFSwCodecDataPath::EPlaying))
483 TBool asynchOpen = EFalse; // Ensure we only call OpenPlayComplete once
484 //datapath was created ok and we are not playing
485 if (iDataPath->State() == CMMFSwCodecDataPath::EStopped)
487 //starting from 'fresh so set sound device settings
489 // Create the AO OpenDevice handler
492 TRAP(error, iOpenHandler = CRoutingSoundDeviceOpenHandler::NewL(this));
497 iPlayDevice->SetBufferSize(iDeviceBufferSize);
498 iOpenHandler->Start();
499 static_cast<CMMFSwCodecPlayDataPath*>(iDataPath)->Device()->
500 OpenDevice(iDeviceUid, iOpenHandler->iStatus);
505 error = OpenPlayComplete(error);
508 }//status == KErrNone
513 TInt CMMFSwCodecWrapper::StartEncode()
516 //[ assert precondition that record custom interface is present]
517 //if there is no record custom interface then the user of the CMMFSwCodecWrapper
518 //cannot have set any of the custom settings such as sample rate.
519 if (!iRecordCustomInterface)
524 TInt error = KErrNone;
527 TRAP(error,iDataPath = CMMFSwCodecRecordDataPath::NewL(iRecordDevice));
528 if ((iDataPath)&&(error == KErrNone))
530 iDataPath->SetObserver(*iHwDeviceObserver);
531 error = iDataPath->AddCodec(*iCodec);
532 iDeviceBufferSize = (iCodec->SourceBufferSize());
533 static_cast<TRecordCustomInterface*>(iRecordCustomInterface)->SetDataPath(static_cast<CMMFSwCodecRecordDataPath*>(iDataPath));
536 if ((error == KErrNone)&&
537 (iDataPath->State() != CMMFSwCodecDataPath::EPlaying))
539 TBool asynchOpen = EFalse; // Ensure we only call OpenPlayComplete once
540 if (!(static_cast<CMMFSwCodecRecordDataPath*>(iDataPath))->Device()->Handle())
542 // Create the AO OpenDevice handler
545 TRAP(error, iOpenHandler = CRoutingSoundDeviceOpenHandler::NewL(this));
550 iRecordDevice->SetBufferSize(iDeviceBufferSize);
551 iOpenHandler->Start();
552 static_cast<CMMFSwCodecRecordDataPath*>(iDataPath)->Device()->
553 OpenDevice(iDeviceUid, iOpenHandler->iStatus);
559 error = OpenRecordComplete(error);
566 TInt CMMFSwCodecWrapper::StartConvert()
569 TInt error = KErrNone;
572 TRAP(error,iDataPath = CMMFSwCodecConvertDataPath::NewL());
573 if ((iDataPath)&&(error == KErrNone))
575 iDataPath->SetObserver(*iHwDeviceObserver);
576 error = iDataPath->AddCodec(*iCodec);
579 if (error == KErrNone)
581 error = iDataPath->Start();
587 Temporarily suspends the current task of decoding or encoding.
589 @return An error code indicating if the function call was successful. KErrNone on success, otherwise
590 another of the system-wide error codes.
592 EXPORT_C TInt CMMFSwCodecWrapper::Pause()
594 // [ precondition that datapath exists ]
605 Stops the current on-going task.
607 @return An error code indicating if the function call was successful. KErrNone on success, otherwise
608 another of the system-wide error codes.
610 EXPORT_C TInt CMMFSwCodecWrapper::Stop()
612 // [ precondition that datapath exists ]
623 Stops and deletes the codec.
625 This default implementation simply calls DeleteCodec() and then Stop()
626 but real hardware devices might use this method to free up resources.
628 @return An error code indicating if the function call was successful. KErrNone on success, otherwise
629 another of the system-wide error codes.
631 EXPORT_C TInt CMMFSwCodecWrapper::StopAndDeleteCodec()
633 TInt stopError = Stop();
634 TInt deleteError = DeleteCodec();
636 if (stopError != KErrNone)
648 This default implementation does nothing
649 but real hardware devices might use this method to free up resources.
650 @return Error code. KErrNone if successful
652 EXPORT_C TInt CMMFSwCodecWrapper::DeleteCodec()
658 Call this function to notify hardware device implementation that
659 data is available in aFillBufferPtr for decoding.
661 @param aFillBufferPtr
662 The data buffer filled by the observer.
664 @return An error code indicating if the function call was successful. KErrNone on success, otherwise
665 another of the system-wide error codes.
667 EXPORT_C TInt CMMFSwCodecWrapper::ThisHwBufferFilled(CMMFBuffer& aFillBufferPtr)
669 TRAPD(err,iDataPath->BufferFilledL(STATIC_CAST(CMMFDataBuffer&, aFillBufferPtr)));
674 Call this function to notify hardware device implementation that
675 data in aEmptyBufferPtr from encoding is processed.
678 The data buffer processed by observer.
680 @return An error code indicating if the function call was successful. KErrNone on success, otherwise
681 another of the system-wide error codes.
683 EXPORT_C TInt CMMFSwCodecWrapper::ThisHwBufferEmptied(CMMFBuffer& aBuffer)
685 TRAPD(err,iDataPath->BufferEmptiedL(STATIC_CAST(CMMFDataBuffer&, aBuffer)));
691 Retrieves a custom interface to the device.
692 The reference CMMFSwCodecWrapper supports two standard custom interfaces,
693 TPlayCustomInterface and TRecordCustomInterface.
696 Interface UID, defined with the custom interface.
697 aInterface = KMmfPlayCustomInterface for TPlayCustomInterface,
698 aInterface = KMmfRecordCustomInterface for TRecordCustomInterface.
699 Actual device implementations of CMMFSwCodecWrapper may do this differently however.
700 @return A pointer to the interface implementation, or NULL if the device can not
701 implement the interface requested. The return value must be cast to the
702 correct type by the user.
704 EXPORT_C TAny* CMMFSwCodecWrapper::CustomInterface(TUid aInterface)
708 if (aInterface.iUid == KMmfPlaySettingsCustomInterface)
710 if (!iPlayCustomInterface)
712 TRAP(err,iPlayCustomInterface = new(ELeave)TPlayCustomInterface());
720 ret = static_cast<TAny*>(iPlayCustomInterface);
723 else if (aInterface.iUid == KMmfRecordSettingsCustomInterface)
725 if (!iRecordCustomInterface)
727 TRAP(err,iRecordCustomInterface = new(ELeave)TRecordCustomInterface());
735 ret = static_cast<TAny*>(iRecordCustomInterface);
744 Used to configure the sample rate and stereo mode of a CMMFHwDevice plugin.
746 The configuration of HwDevices is device specific and is not used in any of the reference
747 devices that return KErrNotSupported.
750 The device configuration.
752 EXPORT_C TInt CMMFSwCodecWrapper::SetConfig(TTaskConfig& aConfig)
755 if (aConfig.iUid != KUidRefDevSoundTaskConfig)
757 iSampleRate = aConfig.iRate;//note we're cheating a bit
758 //iRate is actually a bit map enum but an actual value
759 //is more useful here
760 TMMFStereoSupport stereoSupport = EMMFNone;
761 if (aConfig.iStereoMode == ETaskMono)
765 else if (aConfig.iStereoMode == ETaskInterleaved)
768 stereoSupport = EMMFInterleavedOnly;
770 else //don't support non interleaved
772 return KErrNotSupported;
775 //set values on routing sound device
778 err = iPlayDevice->SetChannels(iChannels, stereoSupport);
781 err = iPlayDevice->SetSampleRate(iSampleRate);
784 {//we'll set the data type while were at it for now pcm16 only
785 TFourCC fourCC = KMMFFourCCCodePCM16;
786 err = iPlayDevice->SetDataType(fourCC);
789 if ((iRecordDevice) && (!err))
791 err = iRecordDevice->SetChannels(iChannels, stereoSupport);
794 err = iRecordDevice->SetSampleRate(iSampleRate);
802 Callback once CRoutingSoundPlayDevice or CRoutingSoundRecordDevice::Open has completed or continuation from
803 call to StartDecode / StartEncode, depending on the state.
807 The status of the device.
808 @return A standard Symbian wide error code.
810 TInt CMMFSwCodecWrapper::OpenComplete(TInt aError)
812 TInt err = KErrNotSupported; //
815 err = OpenPlayComplete(aError);
817 else if (iRecordDevice)
819 err = OpenRecordComplete(aError);
825 Callback once CRoutingSoundPlayDevice::Open has completed or continuation from
826 call to StartDecode, depending on the state.
829 The status of the device.
830 @return A standard Symbian wide error code.
832 TInt CMMFSwCodecWrapper::OpenPlayComplete(TInt aError)
836 //datapath was created ok and we are not playing
837 if (error == KErrNone && iDataPath->State() == CMMFSwCodecDataPath::EStopped)
839 //starting from fresh so set sound device settings
840 // static_cast<TPlayCustomInterface*>(iPlayCustomInterface)->SetDevice(
841 // static_cast<CMMFSwCodecPlayDataPath*>(iDataPath)->Device() );
842 static_cast<CMMFSwCodecPlayDataPath*>(iDataPath)->Device()->SetVolume(iPlayCustomInterface->Volume());
845 // resuming from pause or ready to play
846 if ((error == KErrNone) || (error == KErrInUse))
848 error = iDataPath->Start();
855 Callback once CRoutingSoundRecordDevice::Open has completed or continuation from
856 call to StartDecode, depending on the state.
859 The status of the device.
860 @return A standard Symbian wide error code.
862 TInt CMMFSwCodecWrapper::OpenRecordComplete(TInt aError)
866 //datapath was created ok and we are not playing
867 if (error == KErrNone && iDataPath->State() == CMMFSwCodecDataPath::EStopped)
869 //set sound driver settings
870 static_cast<CMMFSwCodecRecordDataPath*>(iDataPath)->Device()
871 ->SetGain(iRecordCustomInterface->Gain());
874 (static_cast<CMMFSwCodecRecordDataPath*>(iDataPath))->Device()->SetSampleRate(iSampleRate);
876 TMMFStereoSupport stereoSupport = EMMFNone; // assume mono
879 // Assume interleaved only
880 stereoSupport = EMMFInterleavedOnly;
882 error = (static_cast<CMMFSwCodecRecordDataPath*>(iDataPath))->Device()->SetChannels(iChannels, stereoSupport);
886 // resuming from pause or ready to play
887 if ((error == KErrNone) || (error == KErrInUse))
889 error = iDataPath->Start();