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.
18 #include "MMFBtRoutingSoundDevice.h"
21 _LIT(KPddFileName,"ESDRV.PDD");
22 _LIT(KLddFileName,"ESOUND.LDD");
27 EXPORT_C CRoutingSoundPlayDevice* CRoutingSoundPlayDevice::NewL()
29 CRoutingSoundPlayDevice* self = new(ELeave) CRoutingSoundPlayDevice();
30 CleanupStack::PushL(self);
32 CleanupStack::Pop(self);
36 void CRoutingSoundPlayDevice::ConstructL()
40 CRoutingSoundPlayDevice::CRoutingSoundPlayDevice()
44 EXPORT_C CRoutingSoundPlayDevice::~CRoutingSoundPlayDevice()
46 if (iDeviceUid != KDeviceUidA2dpHeadset)
48 if (iSpeakerDevice.Handle() > 0)
50 iSpeakerDevice.Close();
59 EXPORT_C void CRoutingSoundPlayDevice::Initialize( TUid aDeviceUid,
60 const TDesC8& aDeviceConfig,
61 TRequestStatus& aStatus)
64 iDeviceUid = aDeviceUid;
65 iInitializeStatus = &aStatus;
67 if (iDeviceUid == KDeviceUidA2dpHeadset)
69 // Connect to the Bluetooth client
70 err = iBTDevice.Connect();
73 // Get the Bluetooth device's address using the descriptor
74 iBTAddress = TBTDevAddr(aDeviceConfig);
76 iBTDevice.Initialize(iBTAddress, *iInitializeStatus);
81 User::RequestComplete(iInitializeStatus, err);
85 else if ((iDeviceUid == KDeviceUidSpeaker)||(iDeviceUid == KDeviceUidMic))
87 // aDeviceConfig must be NULL to reach here (see 5.1 of design doc)
89 // Try to load the audio physical driver
90 err = User::LoadPhysicalDevice(KPddFileName);
91 if ((err == KErrNone) || (err == KErrAlreadyExists))
93 // Try to load the audio logical driver
94 err = User::LoadLogicalDevice(KLddFileName);
97 if (err == KErrAlreadyExists)
99 // It's not a problem if the drivers have already
100 // been loaded so reset the error code accordingly
103 // Completed to load the drivers so signal
104 User::RequestComplete(iInitializeStatus, err);
109 User::RequestComplete(iInitializeStatus, KErrNotSupported);
113 EXPORT_C void CRoutingSoundPlayDevice::CancelInitialize(TUid aDeviceUid)
115 if (aDeviceUid == iDeviceUid)
116 {//can only cancel bt headset initialize
117 if (aDeviceUid == KDeviceUidA2dpHeadset)
119 iBTDevice.CancelInitialize();
121 if (iInitializeStatus && *iInitializeStatus == KRequestPending)
123 User::RequestComplete(iInitializeStatus, KErrCancel);
129 * OpenDevice() is used when a specific client needs a handle to the sound
130 * device and is called after permission has been given by the policy server.
131 * TODO - what's the required behaviour when calling OpenDevice repeatedly
132 * (without calling CloseDevice in between) - prevent it (as now by checking the
133 * handle) or just return the KErrInUse code?
135 * Check differences in behaviour: RMdaDevSound must be Opened before any "Set"
136 * calls can be made on it, whereas BT headset's settings can be changed
137 * after it has been initialized but before it's been opened.
139 EXPORT_C void CRoutingSoundPlayDevice::OpenDevice( TUid aDeviceUid,
140 TRequestStatus& aStatus)
142 iOpenDeviceStatus = &aStatus;
143 if (aDeviceUid == KDeviceUidSpeaker)
145 TInt error = KErrNone;
148 error = iSpeakerDevice.Open();
149 if ((!error)||(error == KErrAlreadyExists))
151 error = KErrNone;//swallow KErrAlreadyExists
152 //update the configuration here ignore error
153 //it'll get picked up below if not opened due to error
154 RMdaDevSound::TCurrentSoundFormatBuf soundDeviceSettings;
155 iSpeakerDevice.GetPlayFormat(soundDeviceSettings);
156 soundDeviceSettings().iEncoding = RMdaDevSound::EMdaSoundEncoding16BitPCM;
159 soundDeviceSettings().iRate = iSampleRate;
163 soundDeviceSettings().iChannels = iChannels;
165 //tell sound driver what buffer size to expect
166 //it is up the the implementor to make use the device can support
167 //the required buffer size
170 soundDeviceSettings().iBufferSize = iBufferSize;
172 error = iSpeakerDevice.SetPlayFormat(soundDeviceSettings);
175 iSpeakerDevice.Close();
179 User::RequestComplete(iOpenDeviceStatus, error);
181 else if (aDeviceUid == KDeviceUidA2dpHeadset)
183 iBTDevice.OpenDevice(*iOpenDeviceStatus);
187 User::RequestComplete(iOpenDeviceStatus, KErrNotSupported);
191 EXPORT_C void CRoutingSoundPlayDevice::CancelOpenDevice(TUid aDeviceUid)
193 if (aDeviceUid == iDeviceUid)
195 if (aDeviceUid != KDeviceUidA2dpHeadset)
199 iSpeakerDevice.Close();
204 iBTDevice.CancelOpenDevice();
206 if (iOpenDeviceStatus && *iOpenDeviceStatus == KRequestPending)
208 User::RequestComplete(iOpenDeviceStatus, KErrCancel);
213 EXPORT_C void CRoutingSoundPlayDevice::CloseDevice(TUid aDeviceUid, TRequestStatus& aStatus)
215 if (aDeviceUid != KDeviceUidA2dpHeadset)
217 aStatus = KRequestPending;
220 iSpeakerDevice.Close();
222 TRequestStatus* status = &aStatus;
223 User::RequestComplete(status, KErrNone);
227 iCloseDeviceStatus = &aStatus;
228 iBTDevice.CloseDevice(*iCloseDeviceStatus);
232 EXPORT_C TInt CRoutingSoundPlayDevice::GetSupportedDataTypes(RArray<TFourCC>& aSupportedDataTypes)
235 if (iDeviceUid != KDeviceUidA2dpHeadset)
239 RMdaDevSound::TSoundFormatsSupportedBuf formats;
240 iSpeakerDevice.PlayFormatsSupported(formats);
241 // Only PCM16 is supported (what about unsigned PCM16 and big-endian versions?)
242 err = aSupportedDataTypes.Append(KMMFFourCCCodePCM16);
245 aSupportedDataTypes.Reset();
255 TRAP(err, iBTDevice.GetSupportedDataTypesL(aSupportedDataTypes));
261 EXPORT_C TInt CRoutingSoundPlayDevice::GetSupportedSampleRates(RArray<TUint>& aSupportedDiscreteRates,
262 RArray<TRange>& aSupportedRateRanges)
265 aSupportedDiscreteRates.Reset();
266 aSupportedRateRanges.Reset();
267 if (iDeviceUid != KDeviceUidA2dpHeadset)
271 RMdaDevSound::TSoundFormatsSupportedBuf formatsSupported;
272 iSpeakerDevice.PlayFormatsSupported(formatsSupported);
274 range.iLow = formatsSupported().iMinRate;
275 range.iHigh = formatsSupported().iMaxRate;
276 err = aSupportedRateRanges.Append(range);
279 aSupportedRateRanges.Reset();
289 TRAP(err, iBTDevice.GetSupportedSampleRatesL(aSupportedDiscreteRates,
290 aSupportedRateRanges);)
296 EXPORT_C TInt CRoutingSoundPlayDevice::GetSupportedChannels(RArray<TUint>& aSupportedChannels,
297 TMMFStereoSupport& aStereoSupport)
300 aSupportedChannels.Reset();
301 if (iDeviceUid != KDeviceUidA2dpHeadset)
305 RMdaDevSound::TCurrentSoundFormatBuf soundDeviceSettings;
306 iSpeakerDevice.GetPlayFormat(soundDeviceSettings);
307 //1 = mono 2 = stereo
308 err = aSupportedChannels.Append(soundDeviceSettings().iChannels);
309 if (soundDeviceSettings().iChannels != 2)
312 aStereoSupport = EMMFNone;
316 aStereoSupport = EMMFBothNonAndInterleaved;
326 TRAP(err, iBTDevice.GetSupportedChannelsL(aSupportedChannels, aStereoSupport));
332 EXPORT_C TInt CRoutingSoundPlayDevice::SetDataType(const TFourCC& aDataType)
335 if (iDeviceUid != KDeviceUidA2dpHeadset)
339 if (aDataType == KMMFFourCCCodePCM16)
341 // Section 5 of design doc => only PCM16 is supported
342 RMdaDevSound::TCurrentSoundFormatBuf soundDeviceSettings;
343 iSpeakerDevice.GetPlayFormat(soundDeviceSettings);
344 soundDeviceSettings().iEncoding = RMdaDevSound::EMdaSoundEncoding16BitPCM;
345 err = iSpeakerDevice.SetPlayFormat(soundDeviceSettings);
349 // Trying to set an unsupported data type
350 err = KErrNotSupported;
353 // else actually doesn't really matter - we always set the sound driver to pcm16 anyway
357 err = iBTDevice.SetDataType(aDataType);
363 EXPORT_C TInt CRoutingSoundPlayDevice::SetSampleRate(TUint aSampleRate)
367 if (iDeviceUid != KDeviceUidA2dpHeadset)
371 RMdaDevSound::TCurrentSoundFormatBuf soundDeviceSettings;
372 iSpeakerDevice.GetPlayFormat(soundDeviceSettings);
373 soundDeviceSettings().iRate = aSampleRate;
374 err = iSpeakerDevice.SetPlayFormat(soundDeviceSettings);
376 //should also check whether we support aSampleRate
380 err = iBTDevice.SetSampleRate(aSampleRate);
383 iSampleRate = aSampleRate;
387 EXPORT_C TInt CRoutingSoundPlayDevice::SetChannels( TUint aChannels,
388 TMMFStereoSupport aStereoSupport)
392 if (iDeviceUid != KDeviceUidA2dpHeadset)
396 RMdaDevSound::TCurrentSoundFormatBuf soundDeviceSettings;
397 iSpeakerDevice.GetPlayFormat(soundDeviceSettings);
398 // 1 = mono 2 = stereo
399 soundDeviceSettings().iChannels = aChannels;
400 err = iSpeakerDevice.SetPlayFormat(soundDeviceSettings);
405 err = iBTDevice.SetChannels(aChannels, aStereoSupport);
407 iChannels = aChannels;
408 iStereoSupport = aStereoSupport;
412 EXPORT_C TInt CRoutingSoundPlayDevice::SetBufferSize(TUint aBufferSize)
416 if (iDeviceUid != KDeviceUidA2dpHeadset)
420 RMdaDevSound::TCurrentSoundFormatBuf soundDeviceSettings;
421 iSpeakerDevice.GetPlayFormat(soundDeviceSettings);
422 // 1 = mono 2 = stereo
423 soundDeviceSettings().iBufferSize = aBufferSize;
424 err = iSpeakerDevice.SetPlayFormat(soundDeviceSettings);
427 iBufferSize = aBufferSize;
428 //else we don't need this for bt headset
432 EXPORT_C void CRoutingSoundPlayDevice::FlushBuffer()
434 if (iDeviceUid != KDeviceUidA2dpHeadset)
438 iSpeakerDevice.FlushPlayBuffer();
443 iBTDevice.FlushBuffer();
447 EXPORT_C void CRoutingSoundPlayDevice::NotifyError(TRequestStatus& aStatus)
449 if (iDeviceUid != KDeviceUidA2dpHeadset)
453 iSpeakerDevice.NotifyPlayError(aStatus);
458 iBTDevice.NotifyError(aStatus);
462 EXPORT_C void CRoutingSoundPlayDevice::CancelNotifyError()
464 if (iDeviceUid != KDeviceUidA2dpHeadset)
466 // To avoid a KE0 panic if -ve handle is returned
469 iSpeakerDevice.CancelNotifyPlayError();
474 iBTDevice.CancelNotifyError();
478 EXPORT_C TUint CRoutingSoundPlayDevice::Volume() const
481 if (iDeviceUid != KDeviceUidA2dpHeadset)
485 RMdaDevSound* mutableSpeakerDevice = const_cast<RMdaDevSound*>(&iSpeakerDevice);
486 volume = mutableSpeakerDevice->PlayVolume();
491 volume = iBTDevice.Volume();
496 EXPORT_C TInt CRoutingSoundPlayDevice::SetVolume(TUint aVolume)
499 if (iDeviceUid != KDeviceUidA2dpHeadset)
503 iSpeakerDevice.SetPlayVolume(aVolume);
508 err = iBTDevice.SetVolume(aVolume);
513 EXPORT_C void CRoutingSoundPlayDevice::PlayData(const TDesC8& aData, TRequestStatus& aStatus)
515 if (iDeviceUid != KDeviceUidA2dpHeadset)
519 iSpeakerDevice.PlayData(aStatus, aData);
523 TRequestStatus* status = &aStatus;
524 User::RequestComplete(status, KErrBadHandle);
529 iBTDevice.PlayData(aData, aStatus);
533 EXPORT_C void CRoutingSoundPlayDevice::CancelPlayData()
535 if (iDeviceUid != KDeviceUidA2dpHeadset)
539 iSpeakerDevice.CancelPlayData();
544 iBTDevice.CancelPlayData();
548 EXPORT_C TUint CRoutingSoundPlayDevice::BytesPlayed()
551 if (iDeviceUid != KDeviceUidA2dpHeadset)
555 bytes = iSpeakerDevice.BytesPlayed();
560 bytes = iBTDevice.BytesPlayed();
566 EXPORT_C TInt CRoutingSoundPlayDevice::ResetBytesPlayed()
568 if (iDeviceUid != KDeviceUidA2dpHeadset)
572 iSpeakerDevice.ResetBytesPlayed();
577 iBTDevice.ResetBytesPlayed();
579 return KErrNone; // why are we returing a value?
582 EXPORT_C TInt CRoutingSoundPlayDevice::PauseBuffer()
584 if (iDeviceUid != KDeviceUidA2dpHeadset)
588 iSpeakerDevice.PausePlayBuffer();
593 iBTDevice.PauseBuffer();
598 EXPORT_C TInt CRoutingSoundPlayDevice::ResumePlaying()
600 if (iDeviceUid != KDeviceUidA2dpHeadset)
604 iSpeakerDevice.ResumePlaying();
609 iBTDevice.ResumePlaying();
614 EXPORT_C TInt CRoutingSoundPlayDevice::Handle() const
617 if (iDeviceUid != KDeviceUidA2dpHeadset)
619 handle = iSpeakerDevice.Handle();
623 handle = iBTDevice.Handle();
629 * Implementation of CRoutingSoundRecordDevice.
631 EXPORT_C CRoutingSoundRecordDevice* CRoutingSoundRecordDevice::NewL()
633 CRoutingSoundRecordDevice* self = new(ELeave) CRoutingSoundRecordDevice();
634 CleanupStack::PushL(self);
636 CleanupStack::Pop(self);
640 void CRoutingSoundRecordDevice::ConstructL()
645 CRoutingSoundRecordDevice::CRoutingSoundRecordDevice()
649 EXPORT_C CRoutingSoundRecordDevice::~CRoutingSoundRecordDevice()
651 if (iInputDevice.Handle())
653 iInputDevice.Close();
658 EXPORT_C void CRoutingSoundRecordDevice::Initialize(TUid aDeviceUid,
659 const TDesC8& /*aDeviceConfig*/,
660 TRequestStatus& aStatus)
663 iDeviceUid = aDeviceUid;
664 TRequestStatus* status = &aStatus;
666 if (iDeviceUid == KDeviceUidMic)
669 // Try to load the audio physical driver
670 ret = User::LoadPhysicalDevice(KPddFileName);
671 if ((ret == KErrNone) || (ret == KErrAlreadyExists))
673 // Try to load the audio logical driver
674 ret = User::LoadLogicalDevice(KLddFileName);
677 if (ret == KErrAlreadyExists)
679 // It's not a problem if the drivers have already
680 // been loaded so reset the error code accordingly
686 ret = KErrNotSupported;
689 User::RequestComplete(status, ret);
692 EXPORT_C void CRoutingSoundRecordDevice::CancelInitialize(TUid /*aDeviceUid*/)
697 EXPORT_C void CRoutingSoundRecordDevice::OpenDevice(TUid /*aDeviceUid*/, TRequestStatus& aStatus)
699 iOpenDeviceStatus = &aStatus;
700 TInt error = KErrNone;
701 if (!iInputDevice.Handle())
703 error = iInputDevice.Open();
704 if ((!error)||(error == KErrAlreadyExists))
706 error = KErrNone;//swallow KErrAlreadyExists
707 //update the configuration here ignore error
708 //it'll get picked up below if not opened due to error
709 RMdaDevSound::TCurrentSoundFormatBuf soundDeviceSettings;
710 iInputDevice.GetRecordFormat(soundDeviceSettings);
711 soundDeviceSettings().iEncoding = RMdaDevSound::EMdaSoundEncoding16BitPCM;
714 soundDeviceSettings().iRate = iSampleRate;
718 soundDeviceSettings().iChannels = iChannels;
720 //tell sound driver what buffer size to expect
721 //it is up the the implementor to make use the device can support
722 //the required buffer size
725 soundDeviceSettings().iBufferSize = iBufferSize;
727 error = iInputDevice.SetRecordFormat(soundDeviceSettings);
730 iInputDevice.Close();
734 User::RequestComplete(iOpenDeviceStatus, error);
737 EXPORT_C void CRoutingSoundRecordDevice::CancelOpenDevice(TUid aDeviceUid)
739 if (aDeviceUid == iDeviceUid)
741 if (iDeviceUid != KDeviceUidA2dpHeadset)
745 iInputDevice.Close();
748 if (iOpenDeviceStatus && *iOpenDeviceStatus == KRequestPending)
750 User::RequestComplete(iOpenDeviceStatus, KErrCancel);
755 EXPORT_C void CRoutingSoundRecordDevice::CloseDevice(TUid /*aDeviceUid*/, TRequestStatus& aStatus)
757 aStatus = KRequestPending;//async not really necessary with RMdaDevSound since close is sync
758 if (iInputDevice.Handle())
760 iInputDevice.Close();
762 TRequestStatus* status = &aStatus;
763 User::RequestComplete(status, KErrNone);
766 EXPORT_C TInt CRoutingSoundRecordDevice::GetSupportedSampleRates(RArray<TUint>& aSupportedDiscreteRates,
767 RArray<TRange>& aSupportedRateRanges)
769 aSupportedDiscreteRates.Reset();
770 aSupportedRateRanges.Reset();
774 RMdaDevSound::TSoundFormatsSupportedBuf formatsSupported;
775 iInputDevice.RecordFormatsSupported(formatsSupported);
777 range.iLow = formatsSupported().iMinRate;
778 range.iHigh = formatsSupported().iMaxRate;
779 err = aSupportedRateRanges.Append(range);
782 aSupportedRateRanges.Reset();
793 EXPORT_C TInt CRoutingSoundRecordDevice::GetSupportedChannels( RArray<TUint>& aSupportedChannels,
794 TMMFStereoSupport& aStereoSupport)
799 RMdaDevSound::TSoundFormatsSupportedBuf formatsSupported;
800 iInputDevice.RecordFormatsSupported(formatsSupported);
801 aSupportedChannels.Reset();
802 err = aSupportedChannels.Append(formatsSupported().iChannels);
806 aStereoSupport = EMMFNone; // assume no stereo support for starters
808 if (formatsSupported().iChannels == 2)
810 aStereoSupport = EMMFBothNonAndInterleaved;
822 EXPORT_C TInt CRoutingSoundRecordDevice::SetSampleRate(TUint aSampleRate)
824 // Assume we don't have a handle to the device
828 RMdaDevSound::TCurrentSoundFormatBuf format;
829 iInputDevice.GetRecordFormat(format);
830 format().iRate = aSampleRate;
831 err = iInputDevice.SetRecordFormat(format);
833 iSampleRate = aSampleRate;
837 EXPORT_C TInt CRoutingSoundRecordDevice::SetChannels(TUint aChannels, TMMFStereoSupport aStereoSupport)
843 RMdaDevSound::TCurrentSoundFormatBuf format;
844 iInputDevice.GetRecordFormat(format);
845 format().iChannels = aChannels;
846 err = iInputDevice.SetRecordFormat(format);
848 iChannels = aChannels;
849 iStereoSupport = aStereoSupport;
853 EXPORT_C TInt CRoutingSoundRecordDevice::SetBufferSize(TUint aBufferSize)
857 if (iDeviceUid != KDeviceUidA2dpHeadset)
861 RMdaDevSound::TCurrentSoundFormatBuf format;
862 iInputDevice.GetRecordFormat(format);
863 // 1 = mono 2 = stereo
864 format().iBufferSize = aBufferSize;
865 err = iInputDevice.SetRecordFormat(format);
868 iBufferSize = aBufferSize;
869 //else we don't need this for bt headset
873 EXPORT_C void CRoutingSoundRecordDevice::FlushBuffer()
877 iInputDevice.FlushRecordBuffer();
881 EXPORT_C void CRoutingSoundRecordDevice::NotifyError(TRequestStatus& aStatus)
885 iInputDevice.NotifyRecordError(aStatus);
889 EXPORT_C void CRoutingSoundRecordDevice::CancelNotifyError()
891 // To avoid a KE0 panic if -ve handle is returned
894 iInputDevice.CancelNotifyRecordError();
898 EXPORT_C TUint CRoutingSoundRecordDevice::Gain() const
903 RMdaDevSound* mutableInputDevice = const_cast<RMdaDevSound*>(&iInputDevice);
904 gain = mutableInputDevice->RecordLevel();
909 EXPORT_C TInt CRoutingSoundRecordDevice::SetGain(TUint aGain)
914 iInputDevice.SetRecordLevel(aGain);
923 EXPORT_C void CRoutingSoundRecordDevice::RecordData(TDes8& aData, TRequestStatus& aStatus)
925 //this handle check should really be removed since it impacts performance
926 //, however there do seem to
927 //be cases where a record error occus but the client sends an ack before
928 //it has time to get the RecordError so keep it for now
931 iInputDevice.RecordData(aStatus, aData);
935 TRequestStatus* status = &aStatus;
936 User::RequestComplete(status, KErrBadHandle);
940 EXPORT_C void CRoutingSoundRecordDevice::CancelRecordData()
944 iInputDevice.CancelRecordData();
948 EXPORT_C TUint CRoutingSoundRecordDevice::BytesRecorded()
950 // Is there an equivalent call to bytes played for bytes recorded?
951 // If not, why do we have this method or what should we return?
952 TUint bytesPlayed = 0;
955 bytesPlayed = iInputDevice.BytesPlayed();
960 EXPORT_C TInt CRoutingSoundRecordDevice::Handle() const
962 return iInputDevice.Handle();