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