sl@0: // Copyright (c) 2005-2009 Nokia Corporation and/or its subsidiary(-ies). sl@0: // All rights reserved. sl@0: // This component and the accompanying materials are made available sl@0: // under the terms of "Eclipse Public License v1.0" sl@0: // which accompanies this distribution, and is available sl@0: // at the URL "http://www.eclipse.org/legal/epl-v10.html". sl@0: // sl@0: // Initial Contributors: sl@0: // Nokia Corporation - initial contribution. sl@0: // sl@0: // Contributors: sl@0: // sl@0: // Description: sl@0: // sl@0: sl@0: #include sl@0: #include sl@0: #include "MMFBtRoutingSoundDevice.h" sl@0: sl@0: // Sound drivers sl@0: _LIT(KPddFileName,"ESDRV.PDD"); sl@0: _LIT(KLddFileName,"ESOUND.LDD"); sl@0: sl@0: sl@0: sl@0: sl@0: EXPORT_C CRoutingSoundPlayDevice* CRoutingSoundPlayDevice::NewL() sl@0: { sl@0: CRoutingSoundPlayDevice* self = new(ELeave) CRoutingSoundPlayDevice(); sl@0: CleanupStack::PushL(self); sl@0: self->ConstructL(); sl@0: CleanupStack::Pop(self); sl@0: return self; sl@0: } sl@0: sl@0: void CRoutingSoundPlayDevice::ConstructL() sl@0: { sl@0: } sl@0: sl@0: CRoutingSoundPlayDevice::CRoutingSoundPlayDevice() sl@0: { sl@0: } sl@0: sl@0: EXPORT_C CRoutingSoundPlayDevice::~CRoutingSoundPlayDevice() sl@0: { sl@0: if (iDeviceUid != KDeviceUidA2dpHeadset) sl@0: { sl@0: if (iSpeakerDevice.Handle() > 0) sl@0: { sl@0: iSpeakerDevice.Close(); sl@0: } sl@0: } sl@0: else sl@0: { sl@0: iBTDevice.Close(); sl@0: } sl@0: } sl@0: sl@0: EXPORT_C void CRoutingSoundPlayDevice::Initialize( TUid aDeviceUid, sl@0: const TDesC8& aDeviceConfig, sl@0: TRequestStatus& aStatus) sl@0: { sl@0: TInt err = KErrNone; sl@0: iDeviceUid = aDeviceUid; sl@0: iInitializeStatus = &aStatus; sl@0: sl@0: if (iDeviceUid == KDeviceUidA2dpHeadset) sl@0: { sl@0: // Connect to the Bluetooth client sl@0: err = iBTDevice.Connect(); sl@0: if (!err) sl@0: { sl@0: // Get the Bluetooth device's address using the descriptor sl@0: iBTAddress = TBTDevAddr(aDeviceConfig); sl@0: // Initialize sl@0: iBTDevice.Initialize(iBTAddress, *iInitializeStatus); sl@0: } sl@0: else sl@0: { sl@0: // Failed to connect sl@0: User::RequestComplete(iInitializeStatus, err); sl@0: } sl@0: } sl@0: sl@0: else if ((iDeviceUid == KDeviceUidSpeaker)||(iDeviceUid == KDeviceUidMic)) sl@0: { sl@0: // aDeviceConfig must be NULL to reach here (see 5.1 of design doc) sl@0: // Load the drivers sl@0: // Try to load the audio physical driver sl@0: err = User::LoadPhysicalDevice(KPddFileName); sl@0: if ((err == KErrNone) || (err == KErrAlreadyExists)) sl@0: { sl@0: // Try to load the audio logical driver sl@0: err = User::LoadLogicalDevice(KLddFileName); sl@0: } sl@0: sl@0: if (err == KErrAlreadyExists) sl@0: { sl@0: // It's not a problem if the drivers have already sl@0: // been loaded so reset the error code accordingly sl@0: err = KErrNone; sl@0: } sl@0: // Completed to load the drivers so signal sl@0: User::RequestComplete(iInitializeStatus, err); sl@0: } sl@0: else sl@0: { sl@0: // Unexpected Uid sl@0: User::RequestComplete(iInitializeStatus, KErrNotSupported); sl@0: } sl@0: } sl@0: sl@0: EXPORT_C void CRoutingSoundPlayDevice::CancelInitialize(TUid aDeviceUid) sl@0: { sl@0: if (aDeviceUid == iDeviceUid) sl@0: {//can only cancel bt headset initialize sl@0: if (aDeviceUid == KDeviceUidA2dpHeadset) sl@0: { sl@0: iBTDevice.CancelInitialize(); sl@0: } sl@0: if (iInitializeStatus && *iInitializeStatus == KRequestPending) sl@0: { sl@0: User::RequestComplete(iInitializeStatus, KErrCancel); sl@0: } sl@0: } sl@0: } sl@0: sl@0: /** sl@0: * OpenDevice() is used when a specific client needs a handle to the sound sl@0: * device and is called after permission has been given by the policy server. sl@0: * TODO - what's the required behaviour when calling OpenDevice repeatedly sl@0: * (without calling CloseDevice in between) - prevent it (as now by checking the sl@0: * handle) or just return the KErrInUse code? sl@0: * TODO: sl@0: * Check differences in behaviour: RMdaDevSound must be Opened before any "Set" sl@0: * calls can be made on it, whereas BT headset's settings can be changed sl@0: * after it has been initialized but before it's been opened. sl@0: */ sl@0: EXPORT_C void CRoutingSoundPlayDevice::OpenDevice( TUid aDeviceUid, sl@0: TRequestStatus& aStatus) sl@0: { sl@0: iOpenDeviceStatus = &aStatus; sl@0: if (aDeviceUid == KDeviceUidSpeaker) sl@0: { sl@0: TInt error = KErrNone; sl@0: if (!Handle()) sl@0: { sl@0: error = iSpeakerDevice.Open(); sl@0: if ((!error)||(error == KErrAlreadyExists)) sl@0: { sl@0: error = KErrNone;//swallow KErrAlreadyExists sl@0: //update the configuration here ignore error sl@0: //it'll get picked up below if not opened due to error sl@0: RMdaDevSound::TCurrentSoundFormatBuf soundDeviceSettings; sl@0: iSpeakerDevice.GetPlayFormat(soundDeviceSettings); sl@0: soundDeviceSettings().iEncoding = RMdaDevSound::EMdaSoundEncoding16BitPCM; sl@0: if (iSampleRate) sl@0: { sl@0: soundDeviceSettings().iRate = iSampleRate; sl@0: } sl@0: if (iChannels) sl@0: { sl@0: soundDeviceSettings().iChannels = iChannels; sl@0: } sl@0: //tell sound driver what buffer size to expect sl@0: //it is up the the implementor to make use the device can support sl@0: //the required buffer size sl@0: if (iBufferSize) sl@0: { sl@0: soundDeviceSettings().iBufferSize = iBufferSize; sl@0: } sl@0: error = iSpeakerDevice.SetPlayFormat(soundDeviceSettings); sl@0: if (error) sl@0: { sl@0: iSpeakerDevice.Close(); sl@0: } sl@0: } sl@0: } sl@0: User::RequestComplete(iOpenDeviceStatus, error); sl@0: } sl@0: else if (aDeviceUid == KDeviceUidA2dpHeadset) sl@0: { sl@0: iBTDevice.OpenDevice(*iOpenDeviceStatus); sl@0: } sl@0: else sl@0: { sl@0: User::RequestComplete(iOpenDeviceStatus, KErrNotSupported); sl@0: } sl@0: } sl@0: sl@0: EXPORT_C void CRoutingSoundPlayDevice::CancelOpenDevice(TUid aDeviceUid) sl@0: { sl@0: if (aDeviceUid == iDeviceUid) sl@0: { sl@0: if (aDeviceUid != KDeviceUidA2dpHeadset) sl@0: { sl@0: if(Handle() > 0) sl@0: { sl@0: iSpeakerDevice.Close(); sl@0: } sl@0: } sl@0: else sl@0: { sl@0: iBTDevice.CancelOpenDevice(); sl@0: } sl@0: if (iOpenDeviceStatus && *iOpenDeviceStatus == KRequestPending) sl@0: { sl@0: User::RequestComplete(iOpenDeviceStatus, KErrCancel); sl@0: } sl@0: } sl@0: } sl@0: sl@0: EXPORT_C void CRoutingSoundPlayDevice::CloseDevice(TUid aDeviceUid, TRequestStatus& aStatus) sl@0: { sl@0: if (aDeviceUid != KDeviceUidA2dpHeadset) sl@0: { sl@0: aStatus = KRequestPending; sl@0: if (Handle() > 0) sl@0: { sl@0: iSpeakerDevice.Close(); sl@0: } sl@0: TRequestStatus* status = &aStatus; sl@0: User::RequestComplete(status, KErrNone); sl@0: } sl@0: else sl@0: { sl@0: iCloseDeviceStatus = &aStatus; sl@0: iBTDevice.CloseDevice(*iCloseDeviceStatus); sl@0: } sl@0: } sl@0: sl@0: EXPORT_C TInt CRoutingSoundPlayDevice::GetSupportedDataTypes(RArray& aSupportedDataTypes) sl@0: { sl@0: TInt err = KErrNone; sl@0: if (iDeviceUid != KDeviceUidA2dpHeadset) sl@0: { sl@0: if (Handle() > 0) sl@0: { sl@0: RMdaDevSound::TSoundFormatsSupportedBuf formats; sl@0: iSpeakerDevice.PlayFormatsSupported(formats); sl@0: // Only PCM16 is supported (what about unsigned PCM16 and big-endian versions?) sl@0: err = aSupportedDataTypes.Append(KMMFFourCCCodePCM16); sl@0: if (!err) sl@0: { sl@0: aSupportedDataTypes.Reset(); sl@0: } sl@0: } sl@0: else sl@0: { sl@0: err = KErrNotReady; sl@0: } sl@0: } sl@0: else sl@0: { sl@0: TRAP(err, iBTDevice.GetSupportedDataTypesL(aSupportedDataTypes)); sl@0: } sl@0: sl@0: return err; sl@0: } sl@0: sl@0: EXPORT_C TInt CRoutingSoundPlayDevice::GetSupportedSampleRates(RArray& aSupportedDiscreteRates, sl@0: RArray& aSupportedRateRanges) sl@0: { sl@0: TInt err = KErrNone; sl@0: aSupportedDiscreteRates.Reset(); sl@0: aSupportedRateRanges.Reset(); sl@0: if (iDeviceUid != KDeviceUidA2dpHeadset) sl@0: { sl@0: if (Handle() > 0) sl@0: { sl@0: RMdaDevSound::TSoundFormatsSupportedBuf formatsSupported; sl@0: iSpeakerDevice.PlayFormatsSupported(formatsSupported); sl@0: TRange range; sl@0: range.iLow = formatsSupported().iMinRate; sl@0: range.iHigh = formatsSupported().iMaxRate; sl@0: err = aSupportedRateRanges.Append(range); sl@0: if (err != KErrNone) sl@0: { sl@0: aSupportedRateRanges.Reset(); sl@0: } sl@0: } sl@0: else sl@0: { sl@0: err = KErrNotReady; sl@0: } sl@0: } sl@0: else sl@0: { sl@0: TRAP(err, iBTDevice.GetSupportedSampleRatesL(aSupportedDiscreteRates, sl@0: aSupportedRateRanges);) sl@0: } sl@0: sl@0: return err; sl@0: } sl@0: sl@0: EXPORT_C TInt CRoutingSoundPlayDevice::GetSupportedChannels(RArray& aSupportedChannels, sl@0: TMMFStereoSupport& aStereoSupport) sl@0: { sl@0: TInt err = KErrNone; sl@0: aSupportedChannels.Reset(); sl@0: if (iDeviceUid != KDeviceUidA2dpHeadset) sl@0: { sl@0: if (Handle() > 0) sl@0: { sl@0: RMdaDevSound::TCurrentSoundFormatBuf soundDeviceSettings; sl@0: iSpeakerDevice.GetPlayFormat(soundDeviceSettings); sl@0: //1 = mono 2 = stereo sl@0: err = aSupportedChannels.Append(soundDeviceSettings().iChannels); sl@0: if (soundDeviceSettings().iChannels != 2) sl@0: { sl@0: // No stereo support sl@0: aStereoSupport = EMMFNone; sl@0: } sl@0: else sl@0: { sl@0: aStereoSupport = EMMFBothNonAndInterleaved; sl@0: } sl@0: } sl@0: else sl@0: { sl@0: err = KErrNotReady; sl@0: } sl@0: } sl@0: else sl@0: { sl@0: TRAP(err, iBTDevice.GetSupportedChannelsL(aSupportedChannels, aStereoSupport)); sl@0: } sl@0: sl@0: return err; sl@0: } sl@0: sl@0: EXPORT_C TInt CRoutingSoundPlayDevice::SetDataType(const TFourCC& aDataType) sl@0: { sl@0: TInt err = KErrNone; sl@0: if (iDeviceUid != KDeviceUidA2dpHeadset) sl@0: { sl@0: if (Handle() > 0) sl@0: { sl@0: if (aDataType == KMMFFourCCCodePCM16) sl@0: { sl@0: // Section 5 of design doc => only PCM16 is supported sl@0: RMdaDevSound::TCurrentSoundFormatBuf soundDeviceSettings; sl@0: iSpeakerDevice.GetPlayFormat(soundDeviceSettings); sl@0: soundDeviceSettings().iEncoding = RMdaDevSound::EMdaSoundEncoding16BitPCM; sl@0: err = iSpeakerDevice.SetPlayFormat(soundDeviceSettings); sl@0: } sl@0: else sl@0: { sl@0: // Trying to set an unsupported data type sl@0: err = KErrNotSupported; sl@0: } sl@0: } sl@0: // else actually doesn't really matter - we always set the sound driver to pcm16 anyway sl@0: } sl@0: else sl@0: { sl@0: err = iBTDevice.SetDataType(aDataType); sl@0: } sl@0: sl@0: return err; sl@0: } sl@0: sl@0: EXPORT_C TInt CRoutingSoundPlayDevice::SetSampleRate(TUint aSampleRate) sl@0: { sl@0: TInt err = KErrNone; sl@0: sl@0: if (iDeviceUid != KDeviceUidA2dpHeadset) sl@0: { sl@0: if (Handle()) sl@0: { sl@0: RMdaDevSound::TCurrentSoundFormatBuf soundDeviceSettings; sl@0: iSpeakerDevice.GetPlayFormat(soundDeviceSettings); sl@0: soundDeviceSettings().iRate = aSampleRate; sl@0: err = iSpeakerDevice.SetPlayFormat(soundDeviceSettings); sl@0: } sl@0: //should also check whether we support aSampleRate sl@0: } sl@0: else sl@0: { sl@0: err = iBTDevice.SetSampleRate(aSampleRate); sl@0: } sl@0: sl@0: iSampleRate = aSampleRate; sl@0: return err; sl@0: } sl@0: sl@0: EXPORT_C TInt CRoutingSoundPlayDevice::SetChannels( TUint aChannels, sl@0: TMMFStereoSupport aStereoSupport) sl@0: { sl@0: TInt err = KErrNone; sl@0: sl@0: if (iDeviceUid != KDeviceUidA2dpHeadset) sl@0: { sl@0: if (Handle() > 0) sl@0: { sl@0: RMdaDevSound::TCurrentSoundFormatBuf soundDeviceSettings; sl@0: iSpeakerDevice.GetPlayFormat(soundDeviceSettings); sl@0: // 1 = mono 2 = stereo sl@0: soundDeviceSettings().iChannels = aChannels; sl@0: err = iSpeakerDevice.SetPlayFormat(soundDeviceSettings); sl@0: } sl@0: } sl@0: else sl@0: { sl@0: err = iBTDevice.SetChannels(aChannels, aStereoSupport); sl@0: } sl@0: iChannels = aChannels; sl@0: iStereoSupport = aStereoSupport; sl@0: return err; sl@0: } sl@0: sl@0: EXPORT_C TInt CRoutingSoundPlayDevice::SetBufferSize(TUint aBufferSize) sl@0: { sl@0: TInt err = KErrNone; sl@0: sl@0: if (iDeviceUid != KDeviceUidA2dpHeadset) sl@0: { sl@0: if (Handle() > 0) sl@0: { sl@0: RMdaDevSound::TCurrentSoundFormatBuf soundDeviceSettings; sl@0: iSpeakerDevice.GetPlayFormat(soundDeviceSettings); sl@0: // 1 = mono 2 = stereo sl@0: soundDeviceSettings().iBufferSize = aBufferSize; sl@0: err = iSpeakerDevice.SetPlayFormat(soundDeviceSettings); sl@0: } sl@0: } sl@0: iBufferSize = aBufferSize; sl@0: //else we don't need this for bt headset sl@0: return err; sl@0: } sl@0: sl@0: EXPORT_C void CRoutingSoundPlayDevice::FlushBuffer() sl@0: { sl@0: if (iDeviceUid != KDeviceUidA2dpHeadset) sl@0: { sl@0: if (Handle() > 0) sl@0: { sl@0: iSpeakerDevice.FlushPlayBuffer(); sl@0: } sl@0: } sl@0: else sl@0: { sl@0: iBTDevice.FlushBuffer(); sl@0: } sl@0: } sl@0: sl@0: EXPORT_C void CRoutingSoundPlayDevice::NotifyError(TRequestStatus& aStatus) sl@0: { sl@0: if (iDeviceUid != KDeviceUidA2dpHeadset) sl@0: { sl@0: if (Handle() > 0) sl@0: { sl@0: iSpeakerDevice.NotifyPlayError(aStatus); sl@0: } sl@0: } sl@0: else sl@0: { sl@0: iBTDevice.NotifyError(aStatus); sl@0: } sl@0: } sl@0: sl@0: EXPORT_C void CRoutingSoundPlayDevice::CancelNotifyError() sl@0: { sl@0: if (iDeviceUid != KDeviceUidA2dpHeadset) sl@0: { sl@0: // To avoid a KE0 panic if -ve handle is returned sl@0: if (Handle() > 0) sl@0: { sl@0: iSpeakerDevice.CancelNotifyPlayError(); sl@0: } sl@0: } sl@0: else sl@0: { sl@0: iBTDevice.CancelNotifyError(); sl@0: } sl@0: } sl@0: sl@0: EXPORT_C TUint CRoutingSoundPlayDevice::Volume() const sl@0: { sl@0: TUint volume = 0; sl@0: if (iDeviceUid != KDeviceUidA2dpHeadset) sl@0: { sl@0: if (Handle() > 0) sl@0: { sl@0: RMdaDevSound* mutableSpeakerDevice = const_cast(&iSpeakerDevice); sl@0: volume = mutableSpeakerDevice->PlayVolume(); sl@0: } sl@0: } sl@0: else sl@0: { sl@0: volume = iBTDevice.Volume(); sl@0: } sl@0: return volume; sl@0: } sl@0: sl@0: EXPORT_C TInt CRoutingSoundPlayDevice::SetVolume(TUint aVolume) sl@0: { sl@0: TInt err = KErrNone; sl@0: if (iDeviceUid != KDeviceUidA2dpHeadset) sl@0: { sl@0: if (Handle() > 0) sl@0: { sl@0: iSpeakerDevice.SetPlayVolume(aVolume); sl@0: } sl@0: } sl@0: else sl@0: { sl@0: err = iBTDevice.SetVolume(aVolume); sl@0: } sl@0: return err; sl@0: } sl@0: sl@0: EXPORT_C void CRoutingSoundPlayDevice::PlayData(const TDesC8& aData, TRequestStatus& aStatus) sl@0: { sl@0: if (iDeviceUid != KDeviceUidA2dpHeadset) sl@0: { sl@0: if (Handle() > 0) sl@0: { sl@0: iSpeakerDevice.PlayData(aStatus, aData); sl@0: } sl@0: else sl@0: { sl@0: TRequestStatus* status = &aStatus; sl@0: User::RequestComplete(status, KErrBadHandle); sl@0: } sl@0: } sl@0: else sl@0: { sl@0: iBTDevice.PlayData(aData, aStatus); sl@0: } sl@0: } sl@0: sl@0: EXPORT_C void CRoutingSoundPlayDevice::CancelPlayData() sl@0: { sl@0: if (iDeviceUid != KDeviceUidA2dpHeadset) sl@0: { sl@0: if (Handle() > 0) sl@0: { sl@0: iSpeakerDevice.CancelPlayData(); sl@0: } sl@0: } sl@0: else sl@0: { sl@0: iBTDevice.CancelPlayData(); sl@0: } sl@0: } sl@0: sl@0: EXPORT_C TUint CRoutingSoundPlayDevice::BytesPlayed() sl@0: { sl@0: TUint bytes = 0; sl@0: if (iDeviceUid != KDeviceUidA2dpHeadset) sl@0: { sl@0: if (Handle() > 0) sl@0: { sl@0: bytes = iSpeakerDevice.BytesPlayed(); sl@0: } sl@0: } sl@0: else sl@0: { sl@0: bytes = iBTDevice.BytesPlayed(); sl@0: } sl@0: sl@0: return bytes; sl@0: } sl@0: sl@0: EXPORT_C TInt CRoutingSoundPlayDevice::ResetBytesPlayed() sl@0: { sl@0: if (iDeviceUid != KDeviceUidA2dpHeadset) sl@0: { sl@0: if (Handle() > 0) sl@0: { sl@0: iSpeakerDevice.ResetBytesPlayed(); sl@0: } sl@0: } sl@0: else sl@0: { sl@0: iBTDevice.ResetBytesPlayed(); sl@0: } sl@0: return KErrNone; // why are we returing a value? sl@0: } sl@0: sl@0: EXPORT_C TInt CRoutingSoundPlayDevice::PauseBuffer() sl@0: { sl@0: if (iDeviceUid != KDeviceUidA2dpHeadset) sl@0: { sl@0: if (Handle() > 0) sl@0: { sl@0: iSpeakerDevice.PausePlayBuffer(); sl@0: } sl@0: } sl@0: else sl@0: { sl@0: iBTDevice.PauseBuffer(); sl@0: } sl@0: return KErrNone; sl@0: } sl@0: sl@0: EXPORT_C TInt CRoutingSoundPlayDevice::ResumePlaying() sl@0: { sl@0: if (iDeviceUid != KDeviceUidA2dpHeadset) sl@0: { sl@0: if (Handle() > 0) sl@0: { sl@0: iSpeakerDevice.ResumePlaying(); sl@0: } sl@0: } sl@0: else sl@0: { sl@0: iBTDevice.ResumePlaying(); sl@0: } sl@0: return KErrNone; sl@0: } sl@0: sl@0: EXPORT_C TInt CRoutingSoundPlayDevice::Handle() const sl@0: { sl@0: TInt handle; sl@0: if (iDeviceUid != KDeviceUidA2dpHeadset) sl@0: { sl@0: handle = iSpeakerDevice.Handle(); sl@0: } sl@0: else sl@0: { sl@0: handle = iBTDevice.Handle(); sl@0: } sl@0: return handle; sl@0: } sl@0: sl@0: /** sl@0: * Implementation of CRoutingSoundRecordDevice. sl@0: */ sl@0: EXPORT_C CRoutingSoundRecordDevice* CRoutingSoundRecordDevice::NewL() sl@0: { sl@0: CRoutingSoundRecordDevice* self = new(ELeave) CRoutingSoundRecordDevice(); sl@0: CleanupStack::PushL(self); sl@0: self->ConstructL(); sl@0: CleanupStack::Pop(self); sl@0: return self; sl@0: } sl@0: sl@0: void CRoutingSoundRecordDevice::ConstructL() sl@0: { sl@0: //... sl@0: } sl@0: sl@0: CRoutingSoundRecordDevice::CRoutingSoundRecordDevice() sl@0: { sl@0: } sl@0: sl@0: EXPORT_C CRoutingSoundRecordDevice::~CRoutingSoundRecordDevice() sl@0: { sl@0: if (iInputDevice.Handle()) sl@0: { sl@0: iInputDevice.Close(); sl@0: } sl@0: } sl@0: sl@0: sl@0: EXPORT_C void CRoutingSoundRecordDevice::Initialize(TUid aDeviceUid, sl@0: const TDesC8& /*aDeviceConfig*/, sl@0: TRequestStatus& aStatus) sl@0: sl@0: { sl@0: iDeviceUid = aDeviceUid; sl@0: TRequestStatus* status = &aStatus; sl@0: TInt ret = KErrNone; sl@0: if (iDeviceUid == KDeviceUidMic) sl@0: { sl@0: // Load the drivers sl@0: // Try to load the audio physical driver sl@0: ret = User::LoadPhysicalDevice(KPddFileName); sl@0: if ((ret == KErrNone) || (ret == KErrAlreadyExists)) sl@0: { sl@0: // Try to load the audio logical driver sl@0: ret = User::LoadLogicalDevice(KLddFileName); sl@0: } sl@0: sl@0: if (ret == KErrAlreadyExists) sl@0: { sl@0: // It's not a problem if the drivers have already sl@0: // been loaded so reset the error code accordingly sl@0: ret = KErrNone; sl@0: } sl@0: } sl@0: else sl@0: { sl@0: ret = KErrNotSupported; sl@0: } sl@0: sl@0: User::RequestComplete(status, ret); sl@0: } sl@0: sl@0: EXPORT_C void CRoutingSoundRecordDevice::CancelInitialize(TUid /*aDeviceUid*/) sl@0: { sl@0: // Nothing to do sl@0: } sl@0: sl@0: EXPORT_C void CRoutingSoundRecordDevice::OpenDevice(TUid /*aDeviceUid*/, TRequestStatus& aStatus) sl@0: { sl@0: iOpenDeviceStatus = &aStatus; sl@0: TInt error = KErrNone; sl@0: if (!iInputDevice.Handle()) sl@0: { sl@0: error = iInputDevice.Open(); sl@0: if ((!error)||(error == KErrAlreadyExists)) sl@0: { sl@0: error = KErrNone;//swallow KErrAlreadyExists sl@0: //update the configuration here ignore error sl@0: //it'll get picked up below if not opened due to error sl@0: RMdaDevSound::TCurrentSoundFormatBuf soundDeviceSettings; sl@0: iInputDevice.GetRecordFormat(soundDeviceSettings); sl@0: soundDeviceSettings().iEncoding = RMdaDevSound::EMdaSoundEncoding16BitPCM; sl@0: if (iSampleRate) sl@0: { sl@0: soundDeviceSettings().iRate = iSampleRate; sl@0: } sl@0: if (iChannels) sl@0: { sl@0: soundDeviceSettings().iChannels = iChannels; sl@0: } sl@0: //tell sound driver what buffer size to expect sl@0: //it is up the the implementor to make use the device can support sl@0: //the required buffer size sl@0: if (iBufferSize) sl@0: { sl@0: soundDeviceSettings().iBufferSize = iBufferSize; sl@0: } sl@0: error = iInputDevice.SetRecordFormat(soundDeviceSettings); sl@0: if (error) sl@0: { sl@0: iInputDevice.Close(); sl@0: } sl@0: } sl@0: } sl@0: User::RequestComplete(iOpenDeviceStatus, error); sl@0: } sl@0: sl@0: EXPORT_C void CRoutingSoundRecordDevice::CancelOpenDevice(TUid aDeviceUid) sl@0: { sl@0: if (aDeviceUid == iDeviceUid) sl@0: { sl@0: if (iDeviceUid != KDeviceUidA2dpHeadset) sl@0: { sl@0: if(Handle() > 0) sl@0: { sl@0: iInputDevice.Close(); sl@0: } sl@0: } sl@0: if (iOpenDeviceStatus && *iOpenDeviceStatus == KRequestPending) sl@0: { sl@0: User::RequestComplete(iOpenDeviceStatus, KErrCancel); sl@0: } sl@0: } sl@0: } sl@0: sl@0: EXPORT_C void CRoutingSoundRecordDevice::CloseDevice(TUid /*aDeviceUid*/, TRequestStatus& aStatus) sl@0: { sl@0: aStatus = KRequestPending;//async not really necessary with RMdaDevSound since close is sync sl@0: if (iInputDevice.Handle()) sl@0: { sl@0: iInputDevice.Close(); sl@0: } sl@0: TRequestStatus* status = &aStatus; sl@0: User::RequestComplete(status, KErrNone); sl@0: } sl@0: sl@0: EXPORT_C TInt CRoutingSoundRecordDevice::GetSupportedSampleRates(RArray& aSupportedDiscreteRates, sl@0: RArray& aSupportedRateRanges) sl@0: { sl@0: aSupportedDiscreteRates.Reset(); sl@0: aSupportedRateRanges.Reset(); sl@0: TInt err = KErrNone; sl@0: if (Handle() > 0) sl@0: { sl@0: RMdaDevSound::TSoundFormatsSupportedBuf formatsSupported; sl@0: iInputDevice.RecordFormatsSupported(formatsSupported); sl@0: TRange range; sl@0: range.iLow = formatsSupported().iMinRate; sl@0: range.iHigh = formatsSupported().iMaxRate; sl@0: err = aSupportedRateRanges.Append(range); sl@0: if(!err) sl@0: { sl@0: aSupportedRateRanges.Reset(); sl@0: } sl@0: } sl@0: else sl@0: { sl@0: err = KErrNotReady; sl@0: } sl@0: sl@0: return err; sl@0: } sl@0: sl@0: EXPORT_C TInt CRoutingSoundRecordDevice::GetSupportedChannels( RArray& aSupportedChannels, sl@0: TMMFStereoSupport& aStereoSupport) sl@0: { sl@0: TInt err = KErrNone; sl@0: if (Handle() > 0) sl@0: { sl@0: RMdaDevSound::TSoundFormatsSupportedBuf formatsSupported; sl@0: iInputDevice.RecordFormatsSupported(formatsSupported); sl@0: aSupportedChannels.Reset(); sl@0: err = aSupportedChannels.Append(formatsSupported().iChannels); sl@0: sl@0: if (err == KErrNone) sl@0: { sl@0: aStereoSupport = EMMFNone; // assume no stereo support for starters sl@0: sl@0: if (formatsSupported().iChannels == 2) sl@0: { sl@0: aStereoSupport = EMMFBothNonAndInterleaved; sl@0: } sl@0: } sl@0: } sl@0: else sl@0: { sl@0: err = KErrNotReady; sl@0: } sl@0: sl@0: return err; sl@0: } sl@0: sl@0: EXPORT_C TInt CRoutingSoundRecordDevice::SetSampleRate(TUint aSampleRate) sl@0: { sl@0: // Assume we don't have a handle to the device sl@0: TInt err = KErrNone; sl@0: if (Handle()) sl@0: { sl@0: RMdaDevSound::TCurrentSoundFormatBuf format; sl@0: iInputDevice.GetRecordFormat(format); sl@0: format().iRate = aSampleRate; sl@0: err = iInputDevice.SetRecordFormat(format); sl@0: } sl@0: iSampleRate = aSampleRate; sl@0: return err; sl@0: } sl@0: sl@0: EXPORT_C TInt CRoutingSoundRecordDevice::SetChannels(TUint aChannels, TMMFStereoSupport aStereoSupport) sl@0: { sl@0: TInt err = KErrNone; sl@0: sl@0: if (Handle() > 0) sl@0: { sl@0: RMdaDevSound::TCurrentSoundFormatBuf format; sl@0: iInputDevice.GetRecordFormat(format); sl@0: format().iChannels = aChannels; sl@0: err = iInputDevice.SetRecordFormat(format); sl@0: } sl@0: iChannels = aChannels; sl@0: iStereoSupport = aStereoSupport; sl@0: return err; sl@0: } sl@0: sl@0: EXPORT_C TInt CRoutingSoundRecordDevice::SetBufferSize(TUint aBufferSize) sl@0: { sl@0: TInt err = KErrNone; sl@0: sl@0: if (iDeviceUid != KDeviceUidA2dpHeadset) sl@0: { sl@0: if (Handle() > 0) sl@0: { sl@0: RMdaDevSound::TCurrentSoundFormatBuf format; sl@0: iInputDevice.GetRecordFormat(format); sl@0: // 1 = mono 2 = stereo sl@0: format().iBufferSize = aBufferSize; sl@0: err = iInputDevice.SetRecordFormat(format); sl@0: } sl@0: } sl@0: iBufferSize = aBufferSize; sl@0: //else we don't need this for bt headset sl@0: return err; sl@0: } sl@0: sl@0: EXPORT_C void CRoutingSoundRecordDevice::FlushBuffer() sl@0: { sl@0: if (Handle() > 0) sl@0: { sl@0: iInputDevice.FlushRecordBuffer(); sl@0: } sl@0: } sl@0: sl@0: EXPORT_C void CRoutingSoundRecordDevice::NotifyError(TRequestStatus& aStatus) sl@0: { sl@0: if (Handle() > 0) sl@0: { sl@0: iInputDevice.NotifyRecordError(aStatus); sl@0: } sl@0: } sl@0: sl@0: EXPORT_C void CRoutingSoundRecordDevice::CancelNotifyError() sl@0: { sl@0: // To avoid a KE0 panic if -ve handle is returned sl@0: if (Handle() > 0) sl@0: { sl@0: iInputDevice.CancelNotifyRecordError(); sl@0: } sl@0: } sl@0: sl@0: EXPORT_C TUint CRoutingSoundRecordDevice::Gain() const sl@0: { sl@0: TUint gain = 0; sl@0: if (Handle() > 0) sl@0: { sl@0: RMdaDevSound* mutableInputDevice = const_cast(&iInputDevice); sl@0: gain = mutableInputDevice->RecordLevel(); sl@0: } sl@0: return gain; sl@0: } sl@0: sl@0: EXPORT_C TInt CRoutingSoundRecordDevice::SetGain(TUint aGain) sl@0: { sl@0: TInt err = KErrNone; sl@0: if (Handle() > 0) sl@0: { sl@0: iInputDevice.SetRecordLevel(aGain); sl@0: } sl@0: else sl@0: { sl@0: err = KErrNotReady; sl@0: } sl@0: return err; sl@0: } sl@0: sl@0: EXPORT_C void CRoutingSoundRecordDevice::RecordData(TDes8& aData, TRequestStatus& aStatus) sl@0: { sl@0: //this handle check should really be removed since it impacts performance sl@0: //, however there do seem to sl@0: //be cases where a record error occus but the client sends an ack before sl@0: //it has time to get the RecordError so keep it for now sl@0: if (Handle() > 0) sl@0: { sl@0: iInputDevice.RecordData(aStatus, aData); sl@0: } sl@0: else sl@0: { sl@0: TRequestStatus* status = &aStatus; sl@0: User::RequestComplete(status, KErrBadHandle); sl@0: } sl@0: } sl@0: sl@0: EXPORT_C void CRoutingSoundRecordDevice::CancelRecordData() sl@0: { sl@0: if (Handle() > 0) sl@0: { sl@0: iInputDevice.CancelRecordData(); sl@0: } sl@0: } sl@0: sl@0: EXPORT_C TUint CRoutingSoundRecordDevice::BytesRecorded() sl@0: { sl@0: // Is there an equivalent call to bytes played for bytes recorded? sl@0: // If not, why do we have this method or what should we return? sl@0: TUint bytesPlayed = 0; sl@0: if (Handle() > 0) sl@0: { sl@0: bytesPlayed = iInputDevice.BytesPlayed(); sl@0: } sl@0: return bytesPlayed; sl@0: } sl@0: sl@0: EXPORT_C TInt CRoutingSoundRecordDevice::Handle() const sl@0: { sl@0: return iInputDevice.Handle(); sl@0: }