1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/mm/devsound/sounddevbt/src/RoutingSoundDevice/MMFBtRoutingSoundDevice.cpp Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,963 @@
1.4 +// Copyright (c) 2005-2009 Nokia Corporation and/or its subsidiary(-ies).
1.5 +// All rights reserved.
1.6 +// This component and the accompanying materials are made available
1.7 +// under the terms of "Eclipse Public License v1.0"
1.8 +// which accompanies this distribution, and is available
1.9 +// at the URL "http://www.eclipse.org/legal/epl-v10.html".
1.10 +//
1.11 +// Initial Contributors:
1.12 +// Nokia Corporation - initial contribution.
1.13 +//
1.14 +// Contributors:
1.15 +//
1.16 +// Description:
1.17 +//
1.18 +
1.19 +#include <mmfbase.h>
1.20 +#include <bttypes.h>
1.21 +#include "MMFBtRoutingSoundDevice.h"
1.22 +
1.23 +// Sound drivers
1.24 +_LIT(KPddFileName,"ESDRV.PDD");
1.25 +_LIT(KLddFileName,"ESOUND.LDD");
1.26 +
1.27 +
1.28 +
1.29 +
1.30 +EXPORT_C CRoutingSoundPlayDevice* CRoutingSoundPlayDevice::NewL()
1.31 + {
1.32 + CRoutingSoundPlayDevice* self = new(ELeave) CRoutingSoundPlayDevice();
1.33 + CleanupStack::PushL(self);
1.34 + self->ConstructL();
1.35 + CleanupStack::Pop(self);
1.36 + return self;
1.37 + }
1.38 +
1.39 +void CRoutingSoundPlayDevice::ConstructL()
1.40 + {
1.41 + }
1.42 +
1.43 +CRoutingSoundPlayDevice::CRoutingSoundPlayDevice()
1.44 + {
1.45 + }
1.46 +
1.47 +EXPORT_C CRoutingSoundPlayDevice::~CRoutingSoundPlayDevice()
1.48 + {
1.49 + if (iDeviceUid != KDeviceUidA2dpHeadset)
1.50 + {
1.51 + if (iSpeakerDevice.Handle() > 0)
1.52 + {
1.53 + iSpeakerDevice.Close();
1.54 + }
1.55 + }
1.56 + else
1.57 + {
1.58 + iBTDevice.Close();
1.59 + }
1.60 + }
1.61 +
1.62 +EXPORT_C void CRoutingSoundPlayDevice::Initialize( TUid aDeviceUid,
1.63 + const TDesC8& aDeviceConfig,
1.64 + TRequestStatus& aStatus)
1.65 + {
1.66 + TInt err = KErrNone;
1.67 + iDeviceUid = aDeviceUid;
1.68 + iInitializeStatus = &aStatus;
1.69 +
1.70 + if (iDeviceUid == KDeviceUidA2dpHeadset)
1.71 + {
1.72 + // Connect to the Bluetooth client
1.73 + err = iBTDevice.Connect();
1.74 + if (!err)
1.75 + {
1.76 + // Get the Bluetooth device's address using the descriptor
1.77 + iBTAddress = TBTDevAddr(aDeviceConfig);
1.78 + // Initialize
1.79 + iBTDevice.Initialize(iBTAddress, *iInitializeStatus);
1.80 + }
1.81 + else
1.82 + {
1.83 + // Failed to connect
1.84 + User::RequestComplete(iInitializeStatus, err);
1.85 + }
1.86 + }
1.87 +
1.88 + else if ((iDeviceUid == KDeviceUidSpeaker)||(iDeviceUid == KDeviceUidMic))
1.89 + {
1.90 + // aDeviceConfig must be NULL to reach here (see 5.1 of design doc)
1.91 + // Load the drivers
1.92 + // Try to load the audio physical driver
1.93 + err = User::LoadPhysicalDevice(KPddFileName);
1.94 + if ((err == KErrNone) || (err == KErrAlreadyExists))
1.95 + {
1.96 + // Try to load the audio logical driver
1.97 + err = User::LoadLogicalDevice(KLddFileName);
1.98 + }
1.99 +
1.100 + if (err == KErrAlreadyExists)
1.101 + {
1.102 + // It's not a problem if the drivers have already
1.103 + // been loaded so reset the error code accordingly
1.104 + err = KErrNone;
1.105 + }
1.106 + // Completed to load the drivers so signal
1.107 + User::RequestComplete(iInitializeStatus, err);
1.108 + }
1.109 + else
1.110 + {
1.111 + // Unexpected Uid
1.112 + User::RequestComplete(iInitializeStatus, KErrNotSupported);
1.113 + }
1.114 + }
1.115 +
1.116 +EXPORT_C void CRoutingSoundPlayDevice::CancelInitialize(TUid aDeviceUid)
1.117 + {
1.118 + if (aDeviceUid == iDeviceUid)
1.119 + {//can only cancel bt headset initialize
1.120 + if (aDeviceUid == KDeviceUidA2dpHeadset)
1.121 + {
1.122 + iBTDevice.CancelInitialize();
1.123 + }
1.124 + if (iInitializeStatus && *iInitializeStatus == KRequestPending)
1.125 + {
1.126 + User::RequestComplete(iInitializeStatus, KErrCancel);
1.127 + }
1.128 + }
1.129 + }
1.130 +
1.131 +/**
1.132 + * OpenDevice() is used when a specific client needs a handle to the sound
1.133 + * device and is called after permission has been given by the policy server.
1.134 + * TODO - what's the required behaviour when calling OpenDevice repeatedly
1.135 + * (without calling CloseDevice in between) - prevent it (as now by checking the
1.136 + * handle) or just return the KErrInUse code?
1.137 + * TODO:
1.138 + * Check differences in behaviour: RMdaDevSound must be Opened before any "Set"
1.139 + * calls can be made on it, whereas BT headset's settings can be changed
1.140 + * after it has been initialized but before it's been opened.
1.141 + */
1.142 +EXPORT_C void CRoutingSoundPlayDevice::OpenDevice( TUid aDeviceUid,
1.143 + TRequestStatus& aStatus)
1.144 + {
1.145 + iOpenDeviceStatus = &aStatus;
1.146 + if (aDeviceUid == KDeviceUidSpeaker)
1.147 + {
1.148 + TInt error = KErrNone;
1.149 + if (!Handle())
1.150 + {
1.151 + error = iSpeakerDevice.Open();
1.152 + if ((!error)||(error == KErrAlreadyExists))
1.153 + {
1.154 + error = KErrNone;//swallow KErrAlreadyExists
1.155 + //update the configuration here ignore error
1.156 + //it'll get picked up below if not opened due to error
1.157 + RMdaDevSound::TCurrentSoundFormatBuf soundDeviceSettings;
1.158 + iSpeakerDevice.GetPlayFormat(soundDeviceSettings);
1.159 + soundDeviceSettings().iEncoding = RMdaDevSound::EMdaSoundEncoding16BitPCM;
1.160 + if (iSampleRate)
1.161 + {
1.162 + soundDeviceSettings().iRate = iSampleRate;
1.163 + }
1.164 + if (iChannels)
1.165 + {
1.166 + soundDeviceSettings().iChannels = iChannels;
1.167 + }
1.168 + //tell sound driver what buffer size to expect
1.169 + //it is up the the implementor to make use the device can support
1.170 + //the required buffer size
1.171 + if (iBufferSize)
1.172 + {
1.173 + soundDeviceSettings().iBufferSize = iBufferSize;
1.174 + }
1.175 + error = iSpeakerDevice.SetPlayFormat(soundDeviceSettings);
1.176 + if (error)
1.177 + {
1.178 + iSpeakerDevice.Close();
1.179 + }
1.180 + }
1.181 + }
1.182 + User::RequestComplete(iOpenDeviceStatus, error);
1.183 + }
1.184 + else if (aDeviceUid == KDeviceUidA2dpHeadset)
1.185 + {
1.186 + iBTDevice.OpenDevice(*iOpenDeviceStatus);
1.187 + }
1.188 + else
1.189 + {
1.190 + User::RequestComplete(iOpenDeviceStatus, KErrNotSupported);
1.191 + }
1.192 + }
1.193 +
1.194 +EXPORT_C void CRoutingSoundPlayDevice::CancelOpenDevice(TUid aDeviceUid)
1.195 + {
1.196 + if (aDeviceUid == iDeviceUid)
1.197 + {
1.198 + if (aDeviceUid != KDeviceUidA2dpHeadset)
1.199 + {
1.200 + if(Handle() > 0)
1.201 + {
1.202 + iSpeakerDevice.Close();
1.203 + }
1.204 + }
1.205 + else
1.206 + {
1.207 + iBTDevice.CancelOpenDevice();
1.208 + }
1.209 + if (iOpenDeviceStatus && *iOpenDeviceStatus == KRequestPending)
1.210 + {
1.211 + User::RequestComplete(iOpenDeviceStatus, KErrCancel);
1.212 + }
1.213 + }
1.214 + }
1.215 +
1.216 +EXPORT_C void CRoutingSoundPlayDevice::CloseDevice(TUid aDeviceUid, TRequestStatus& aStatus)
1.217 + {
1.218 + if (aDeviceUid != KDeviceUidA2dpHeadset)
1.219 + {
1.220 + aStatus = KRequestPending;
1.221 + if (Handle() > 0)
1.222 + {
1.223 + iSpeakerDevice.Close();
1.224 + }
1.225 + TRequestStatus* status = &aStatus;
1.226 + User::RequestComplete(status, KErrNone);
1.227 + }
1.228 + else
1.229 + {
1.230 + iCloseDeviceStatus = &aStatus;
1.231 + iBTDevice.CloseDevice(*iCloseDeviceStatus);
1.232 + }
1.233 + }
1.234 +
1.235 +EXPORT_C TInt CRoutingSoundPlayDevice::GetSupportedDataTypes(RArray<TFourCC>& aSupportedDataTypes)
1.236 + {
1.237 + TInt err = KErrNone;
1.238 + if (iDeviceUid != KDeviceUidA2dpHeadset)
1.239 + {
1.240 + if (Handle() > 0)
1.241 + {
1.242 + RMdaDevSound::TSoundFormatsSupportedBuf formats;
1.243 + iSpeakerDevice.PlayFormatsSupported(formats);
1.244 + // Only PCM16 is supported (what about unsigned PCM16 and big-endian versions?)
1.245 + err = aSupportedDataTypes.Append(KMMFFourCCCodePCM16);
1.246 + if (!err)
1.247 + {
1.248 + aSupportedDataTypes.Reset();
1.249 + }
1.250 + }
1.251 + else
1.252 + {
1.253 + err = KErrNotReady;
1.254 + }
1.255 + }
1.256 + else
1.257 + {
1.258 + TRAP(err, iBTDevice.GetSupportedDataTypesL(aSupportedDataTypes));
1.259 + }
1.260 +
1.261 + return err;
1.262 + }
1.263 +
1.264 +EXPORT_C TInt CRoutingSoundPlayDevice::GetSupportedSampleRates(RArray<TUint>& aSupportedDiscreteRates,
1.265 + RArray<TRange>& aSupportedRateRanges)
1.266 + {
1.267 + TInt err = KErrNone;
1.268 + aSupportedDiscreteRates.Reset();
1.269 + aSupportedRateRanges.Reset();
1.270 + if (iDeviceUid != KDeviceUidA2dpHeadset)
1.271 + {
1.272 + if (Handle() > 0)
1.273 + {
1.274 + RMdaDevSound::TSoundFormatsSupportedBuf formatsSupported;
1.275 + iSpeakerDevice.PlayFormatsSupported(formatsSupported);
1.276 + TRange range;
1.277 + range.iLow = formatsSupported().iMinRate;
1.278 + range.iHigh = formatsSupported().iMaxRate;
1.279 + err = aSupportedRateRanges.Append(range);
1.280 + if (err != KErrNone)
1.281 + {
1.282 + aSupportedRateRanges.Reset();
1.283 + }
1.284 + }
1.285 + else
1.286 + {
1.287 + err = KErrNotReady;
1.288 + }
1.289 + }
1.290 + else
1.291 + {
1.292 + TRAP(err, iBTDevice.GetSupportedSampleRatesL(aSupportedDiscreteRates,
1.293 + aSupportedRateRanges);)
1.294 + }
1.295 +
1.296 + return err;
1.297 + }
1.298 +
1.299 +EXPORT_C TInt CRoutingSoundPlayDevice::GetSupportedChannels(RArray<TUint>& aSupportedChannels,
1.300 + TMMFStereoSupport& aStereoSupport)
1.301 + {
1.302 + TInt err = KErrNone;
1.303 + aSupportedChannels.Reset();
1.304 + if (iDeviceUid != KDeviceUidA2dpHeadset)
1.305 + {
1.306 + if (Handle() > 0)
1.307 + {
1.308 + RMdaDevSound::TCurrentSoundFormatBuf soundDeviceSettings;
1.309 + iSpeakerDevice.GetPlayFormat(soundDeviceSettings);
1.310 + //1 = mono 2 = stereo
1.311 + err = aSupportedChannels.Append(soundDeviceSettings().iChannels);
1.312 + if (soundDeviceSettings().iChannels != 2)
1.313 + {
1.314 + // No stereo support
1.315 + aStereoSupport = EMMFNone;
1.316 + }
1.317 + else
1.318 + {
1.319 + aStereoSupport = EMMFBothNonAndInterleaved;
1.320 + }
1.321 + }
1.322 + else
1.323 + {
1.324 + err = KErrNotReady;
1.325 + }
1.326 + }
1.327 + else
1.328 + {
1.329 + TRAP(err, iBTDevice.GetSupportedChannelsL(aSupportedChannels, aStereoSupport));
1.330 + }
1.331 +
1.332 + return err;
1.333 + }
1.334 +
1.335 +EXPORT_C TInt CRoutingSoundPlayDevice::SetDataType(const TFourCC& aDataType)
1.336 + {
1.337 + TInt err = KErrNone;
1.338 + if (iDeviceUid != KDeviceUidA2dpHeadset)
1.339 + {
1.340 + if (Handle() > 0)
1.341 + {
1.342 + if (aDataType == KMMFFourCCCodePCM16)
1.343 + {
1.344 + // Section 5 of design doc => only PCM16 is supported
1.345 + RMdaDevSound::TCurrentSoundFormatBuf soundDeviceSettings;
1.346 + iSpeakerDevice.GetPlayFormat(soundDeviceSettings);
1.347 + soundDeviceSettings().iEncoding = RMdaDevSound::EMdaSoundEncoding16BitPCM;
1.348 + err = iSpeakerDevice.SetPlayFormat(soundDeviceSettings);
1.349 + }
1.350 + else
1.351 + {
1.352 + // Trying to set an unsupported data type
1.353 + err = KErrNotSupported;
1.354 + }
1.355 + }
1.356 + // else actually doesn't really matter - we always set the sound driver to pcm16 anyway
1.357 + }
1.358 + else
1.359 + {
1.360 + err = iBTDevice.SetDataType(aDataType);
1.361 + }
1.362 +
1.363 + return err;
1.364 + }
1.365 +
1.366 +EXPORT_C TInt CRoutingSoundPlayDevice::SetSampleRate(TUint aSampleRate)
1.367 + {
1.368 + TInt err = KErrNone;
1.369 +
1.370 + if (iDeviceUid != KDeviceUidA2dpHeadset)
1.371 + {
1.372 + if (Handle())
1.373 + {
1.374 + RMdaDevSound::TCurrentSoundFormatBuf soundDeviceSettings;
1.375 + iSpeakerDevice.GetPlayFormat(soundDeviceSettings);
1.376 + soundDeviceSettings().iRate = aSampleRate;
1.377 + err = iSpeakerDevice.SetPlayFormat(soundDeviceSettings);
1.378 + }
1.379 + //should also check whether we support aSampleRate
1.380 + }
1.381 + else
1.382 + {
1.383 + err = iBTDevice.SetSampleRate(aSampleRate);
1.384 + }
1.385 +
1.386 + iSampleRate = aSampleRate;
1.387 + return err;
1.388 + }
1.389 +
1.390 +EXPORT_C TInt CRoutingSoundPlayDevice::SetChannels( TUint aChannels,
1.391 + TMMFStereoSupport aStereoSupport)
1.392 + {
1.393 + TInt err = KErrNone;
1.394 +
1.395 + if (iDeviceUid != KDeviceUidA2dpHeadset)
1.396 + {
1.397 + if (Handle() > 0)
1.398 + {
1.399 + RMdaDevSound::TCurrentSoundFormatBuf soundDeviceSettings;
1.400 + iSpeakerDevice.GetPlayFormat(soundDeviceSettings);
1.401 + // 1 = mono 2 = stereo
1.402 + soundDeviceSettings().iChannels = aChannels;
1.403 + err = iSpeakerDevice.SetPlayFormat(soundDeviceSettings);
1.404 + }
1.405 + }
1.406 + else
1.407 + {
1.408 + err = iBTDevice.SetChannels(aChannels, aStereoSupport);
1.409 + }
1.410 + iChannels = aChannels;
1.411 + iStereoSupport = aStereoSupport;
1.412 + return err;
1.413 + }
1.414 +
1.415 +EXPORT_C TInt CRoutingSoundPlayDevice::SetBufferSize(TUint aBufferSize)
1.416 + {
1.417 + TInt err = KErrNone;
1.418 +
1.419 + if (iDeviceUid != KDeviceUidA2dpHeadset)
1.420 + {
1.421 + if (Handle() > 0)
1.422 + {
1.423 + RMdaDevSound::TCurrentSoundFormatBuf soundDeviceSettings;
1.424 + iSpeakerDevice.GetPlayFormat(soundDeviceSettings);
1.425 + // 1 = mono 2 = stereo
1.426 + soundDeviceSettings().iBufferSize = aBufferSize;
1.427 + err = iSpeakerDevice.SetPlayFormat(soundDeviceSettings);
1.428 + }
1.429 + }
1.430 + iBufferSize = aBufferSize;
1.431 + //else we don't need this for bt headset
1.432 + return err;
1.433 + }
1.434 +
1.435 +EXPORT_C void CRoutingSoundPlayDevice::FlushBuffer()
1.436 + {
1.437 + if (iDeviceUid != KDeviceUidA2dpHeadset)
1.438 + {
1.439 + if (Handle() > 0)
1.440 + {
1.441 + iSpeakerDevice.FlushPlayBuffer();
1.442 + }
1.443 + }
1.444 + else
1.445 + {
1.446 + iBTDevice.FlushBuffer();
1.447 + }
1.448 + }
1.449 +
1.450 +EXPORT_C void CRoutingSoundPlayDevice::NotifyError(TRequestStatus& aStatus)
1.451 + {
1.452 + if (iDeviceUid != KDeviceUidA2dpHeadset)
1.453 + {
1.454 + if (Handle() > 0)
1.455 + {
1.456 + iSpeakerDevice.NotifyPlayError(aStatus);
1.457 + }
1.458 + }
1.459 + else
1.460 + {
1.461 + iBTDevice.NotifyError(aStatus);
1.462 + }
1.463 + }
1.464 +
1.465 +EXPORT_C void CRoutingSoundPlayDevice::CancelNotifyError()
1.466 + {
1.467 + if (iDeviceUid != KDeviceUidA2dpHeadset)
1.468 + {
1.469 + // To avoid a KE0 panic if -ve handle is returned
1.470 + if (Handle() > 0)
1.471 + {
1.472 + iSpeakerDevice.CancelNotifyPlayError();
1.473 + }
1.474 + }
1.475 + else
1.476 + {
1.477 + iBTDevice.CancelNotifyError();
1.478 + }
1.479 + }
1.480 +
1.481 +EXPORT_C TUint CRoutingSoundPlayDevice::Volume() const
1.482 + {
1.483 + TUint volume = 0;
1.484 + if (iDeviceUid != KDeviceUidA2dpHeadset)
1.485 + {
1.486 + if (Handle() > 0)
1.487 + {
1.488 + RMdaDevSound* mutableSpeakerDevice = const_cast<RMdaDevSound*>(&iSpeakerDevice);
1.489 + volume = mutableSpeakerDevice->PlayVolume();
1.490 + }
1.491 + }
1.492 + else
1.493 + {
1.494 + volume = iBTDevice.Volume();
1.495 + }
1.496 + return volume;
1.497 + }
1.498 +
1.499 +EXPORT_C TInt CRoutingSoundPlayDevice::SetVolume(TUint aVolume)
1.500 + {
1.501 + TInt err = KErrNone;
1.502 + if (iDeviceUid != KDeviceUidA2dpHeadset)
1.503 + {
1.504 + if (Handle() > 0)
1.505 + {
1.506 + iSpeakerDevice.SetPlayVolume(aVolume);
1.507 + }
1.508 + }
1.509 + else
1.510 + {
1.511 + err = iBTDevice.SetVolume(aVolume);
1.512 + }
1.513 + return err;
1.514 + }
1.515 +
1.516 +EXPORT_C void CRoutingSoundPlayDevice::PlayData(const TDesC8& aData, TRequestStatus& aStatus)
1.517 + {
1.518 + if (iDeviceUid != KDeviceUidA2dpHeadset)
1.519 + {
1.520 + if (Handle() > 0)
1.521 + {
1.522 + iSpeakerDevice.PlayData(aStatus, aData);
1.523 + }
1.524 + else
1.525 + {
1.526 + TRequestStatus* status = &aStatus;
1.527 + User::RequestComplete(status, KErrBadHandle);
1.528 + }
1.529 + }
1.530 + else
1.531 + {
1.532 + iBTDevice.PlayData(aData, aStatus);
1.533 + }
1.534 + }
1.535 +
1.536 +EXPORT_C void CRoutingSoundPlayDevice::CancelPlayData()
1.537 + {
1.538 + if (iDeviceUid != KDeviceUidA2dpHeadset)
1.539 + {
1.540 + if (Handle() > 0)
1.541 + {
1.542 + iSpeakerDevice.CancelPlayData();
1.543 + }
1.544 + }
1.545 + else
1.546 + {
1.547 + iBTDevice.CancelPlayData();
1.548 + }
1.549 + }
1.550 +
1.551 +EXPORT_C TUint CRoutingSoundPlayDevice::BytesPlayed()
1.552 + {
1.553 + TUint bytes = 0;
1.554 + if (iDeviceUid != KDeviceUidA2dpHeadset)
1.555 + {
1.556 + if (Handle() > 0)
1.557 + {
1.558 + bytes = iSpeakerDevice.BytesPlayed();
1.559 + }
1.560 + }
1.561 + else
1.562 + {
1.563 + bytes = iBTDevice.BytesPlayed();
1.564 + }
1.565 +
1.566 + return bytes;
1.567 + }
1.568 +
1.569 +EXPORT_C TInt CRoutingSoundPlayDevice::ResetBytesPlayed()
1.570 + {
1.571 + if (iDeviceUid != KDeviceUidA2dpHeadset)
1.572 + {
1.573 + if (Handle() > 0)
1.574 + {
1.575 + iSpeakerDevice.ResetBytesPlayed();
1.576 + }
1.577 + }
1.578 + else
1.579 + {
1.580 + iBTDevice.ResetBytesPlayed();
1.581 + }
1.582 + return KErrNone; // why are we returing a value?
1.583 + }
1.584 +
1.585 +EXPORT_C TInt CRoutingSoundPlayDevice::PauseBuffer()
1.586 + {
1.587 + if (iDeviceUid != KDeviceUidA2dpHeadset)
1.588 + {
1.589 + if (Handle() > 0)
1.590 + {
1.591 + iSpeakerDevice.PausePlayBuffer();
1.592 + }
1.593 + }
1.594 + else
1.595 + {
1.596 + iBTDevice.PauseBuffer();
1.597 + }
1.598 + return KErrNone;
1.599 + }
1.600 +
1.601 +EXPORT_C TInt CRoutingSoundPlayDevice::ResumePlaying()
1.602 + {
1.603 + if (iDeviceUid != KDeviceUidA2dpHeadset)
1.604 + {
1.605 + if (Handle() > 0)
1.606 + {
1.607 + iSpeakerDevice.ResumePlaying();
1.608 + }
1.609 + }
1.610 + else
1.611 + {
1.612 + iBTDevice.ResumePlaying();
1.613 + }
1.614 + return KErrNone;
1.615 + }
1.616 +
1.617 +EXPORT_C TInt CRoutingSoundPlayDevice::Handle() const
1.618 + {
1.619 + TInt handle;
1.620 + if (iDeviceUid != KDeviceUidA2dpHeadset)
1.621 + {
1.622 + handle = iSpeakerDevice.Handle();
1.623 + }
1.624 + else
1.625 + {
1.626 + handle = iBTDevice.Handle();
1.627 + }
1.628 + return handle;
1.629 + }
1.630 +
1.631 +/**
1.632 + * Implementation of CRoutingSoundRecordDevice.
1.633 + */
1.634 +EXPORT_C CRoutingSoundRecordDevice* CRoutingSoundRecordDevice::NewL()
1.635 + {
1.636 + CRoutingSoundRecordDevice* self = new(ELeave) CRoutingSoundRecordDevice();
1.637 + CleanupStack::PushL(self);
1.638 + self->ConstructL();
1.639 + CleanupStack::Pop(self);
1.640 + return self;
1.641 + }
1.642 +
1.643 +void CRoutingSoundRecordDevice::ConstructL()
1.644 + {
1.645 + //...
1.646 + }
1.647 +
1.648 +CRoutingSoundRecordDevice::CRoutingSoundRecordDevice()
1.649 + {
1.650 + }
1.651 +
1.652 +EXPORT_C CRoutingSoundRecordDevice::~CRoutingSoundRecordDevice()
1.653 + {
1.654 + if (iInputDevice.Handle())
1.655 + {
1.656 + iInputDevice.Close();
1.657 + }
1.658 + }
1.659 +
1.660 +
1.661 +EXPORT_C void CRoutingSoundRecordDevice::Initialize(TUid aDeviceUid,
1.662 + const TDesC8& /*aDeviceConfig*/,
1.663 + TRequestStatus& aStatus)
1.664 +
1.665 + {
1.666 + iDeviceUid = aDeviceUid;
1.667 + TRequestStatus* status = &aStatus;
1.668 + TInt ret = KErrNone;
1.669 + if (iDeviceUid == KDeviceUidMic)
1.670 + {
1.671 + // Load the drivers
1.672 + // Try to load the audio physical driver
1.673 + ret = User::LoadPhysicalDevice(KPddFileName);
1.674 + if ((ret == KErrNone) || (ret == KErrAlreadyExists))
1.675 + {
1.676 + // Try to load the audio logical driver
1.677 + ret = User::LoadLogicalDevice(KLddFileName);
1.678 + }
1.679 +
1.680 + if (ret == KErrAlreadyExists)
1.681 + {
1.682 + // It's not a problem if the drivers have already
1.683 + // been loaded so reset the error code accordingly
1.684 + ret = KErrNone;
1.685 + }
1.686 + }
1.687 + else
1.688 + {
1.689 + ret = KErrNotSupported;
1.690 + }
1.691 +
1.692 + User::RequestComplete(status, ret);
1.693 + }
1.694 +
1.695 +EXPORT_C void CRoutingSoundRecordDevice::CancelInitialize(TUid /*aDeviceUid*/)
1.696 + {
1.697 + // Nothing to do
1.698 + }
1.699 +
1.700 +EXPORT_C void CRoutingSoundRecordDevice::OpenDevice(TUid /*aDeviceUid*/, TRequestStatus& aStatus)
1.701 + {
1.702 + iOpenDeviceStatus = &aStatus;
1.703 + TInt error = KErrNone;
1.704 + if (!iInputDevice.Handle())
1.705 + {
1.706 + error = iInputDevice.Open();
1.707 + if ((!error)||(error == KErrAlreadyExists))
1.708 + {
1.709 + error = KErrNone;//swallow KErrAlreadyExists
1.710 + //update the configuration here ignore error
1.711 + //it'll get picked up below if not opened due to error
1.712 + RMdaDevSound::TCurrentSoundFormatBuf soundDeviceSettings;
1.713 + iInputDevice.GetRecordFormat(soundDeviceSettings);
1.714 + soundDeviceSettings().iEncoding = RMdaDevSound::EMdaSoundEncoding16BitPCM;
1.715 + if (iSampleRate)
1.716 + {
1.717 + soundDeviceSettings().iRate = iSampleRate;
1.718 + }
1.719 + if (iChannels)
1.720 + {
1.721 + soundDeviceSettings().iChannels = iChannels;
1.722 + }
1.723 + //tell sound driver what buffer size to expect
1.724 + //it is up the the implementor to make use the device can support
1.725 + //the required buffer size
1.726 + if (iBufferSize)
1.727 + {
1.728 + soundDeviceSettings().iBufferSize = iBufferSize;
1.729 + }
1.730 + error = iInputDevice.SetRecordFormat(soundDeviceSettings);
1.731 + if (error)
1.732 + {
1.733 + iInputDevice.Close();
1.734 + }
1.735 + }
1.736 + }
1.737 + User::RequestComplete(iOpenDeviceStatus, error);
1.738 + }
1.739 +
1.740 +EXPORT_C void CRoutingSoundRecordDevice::CancelOpenDevice(TUid aDeviceUid)
1.741 + {
1.742 + if (aDeviceUid == iDeviceUid)
1.743 + {
1.744 + if (iDeviceUid != KDeviceUidA2dpHeadset)
1.745 + {
1.746 + if(Handle() > 0)
1.747 + {
1.748 + iInputDevice.Close();
1.749 + }
1.750 + }
1.751 + if (iOpenDeviceStatus && *iOpenDeviceStatus == KRequestPending)
1.752 + {
1.753 + User::RequestComplete(iOpenDeviceStatus, KErrCancel);
1.754 + }
1.755 + }
1.756 + }
1.757 +
1.758 +EXPORT_C void CRoutingSoundRecordDevice::CloseDevice(TUid /*aDeviceUid*/, TRequestStatus& aStatus)
1.759 + {
1.760 + aStatus = KRequestPending;//async not really necessary with RMdaDevSound since close is sync
1.761 + if (iInputDevice.Handle())
1.762 + {
1.763 + iInputDevice.Close();
1.764 + }
1.765 + TRequestStatus* status = &aStatus;
1.766 + User::RequestComplete(status, KErrNone);
1.767 + }
1.768 +
1.769 +EXPORT_C TInt CRoutingSoundRecordDevice::GetSupportedSampleRates(RArray<TUint>& aSupportedDiscreteRates,
1.770 + RArray<TRange>& aSupportedRateRanges)
1.771 + {
1.772 + aSupportedDiscreteRates.Reset();
1.773 + aSupportedRateRanges.Reset();
1.774 + TInt err = KErrNone;
1.775 + if (Handle() > 0)
1.776 + {
1.777 + RMdaDevSound::TSoundFormatsSupportedBuf formatsSupported;
1.778 + iInputDevice.RecordFormatsSupported(formatsSupported);
1.779 + TRange range;
1.780 + range.iLow = formatsSupported().iMinRate;
1.781 + range.iHigh = formatsSupported().iMaxRate;
1.782 + err = aSupportedRateRanges.Append(range);
1.783 + if(!err)
1.784 + {
1.785 + aSupportedRateRanges.Reset();
1.786 + }
1.787 + }
1.788 + else
1.789 + {
1.790 + err = KErrNotReady;
1.791 + }
1.792 +
1.793 + return err;
1.794 + }
1.795 +
1.796 +EXPORT_C TInt CRoutingSoundRecordDevice::GetSupportedChannels( RArray<TUint>& aSupportedChannels,
1.797 + TMMFStereoSupport& aStereoSupport)
1.798 + {
1.799 + TInt err = KErrNone;
1.800 + if (Handle() > 0)
1.801 + {
1.802 + RMdaDevSound::TSoundFormatsSupportedBuf formatsSupported;
1.803 + iInputDevice.RecordFormatsSupported(formatsSupported);
1.804 + aSupportedChannels.Reset();
1.805 + err = aSupportedChannels.Append(formatsSupported().iChannels);
1.806 +
1.807 + if (err == KErrNone)
1.808 + {
1.809 + aStereoSupport = EMMFNone; // assume no stereo support for starters
1.810 +
1.811 + if (formatsSupported().iChannels == 2)
1.812 + {
1.813 + aStereoSupport = EMMFBothNonAndInterleaved;
1.814 + }
1.815 + }
1.816 + }
1.817 + else
1.818 + {
1.819 + err = KErrNotReady;
1.820 + }
1.821 +
1.822 + return err;
1.823 + }
1.824 +
1.825 +EXPORT_C TInt CRoutingSoundRecordDevice::SetSampleRate(TUint aSampleRate)
1.826 + {
1.827 + // Assume we don't have a handle to the device
1.828 + TInt err = KErrNone;
1.829 + if (Handle())
1.830 + {
1.831 + RMdaDevSound::TCurrentSoundFormatBuf format;
1.832 + iInputDevice.GetRecordFormat(format);
1.833 + format().iRate = aSampleRate;
1.834 + err = iInputDevice.SetRecordFormat(format);
1.835 + }
1.836 + iSampleRate = aSampleRate;
1.837 + return err;
1.838 + }
1.839 +
1.840 +EXPORT_C TInt CRoutingSoundRecordDevice::SetChannels(TUint aChannels, TMMFStereoSupport aStereoSupport)
1.841 + {
1.842 + TInt err = KErrNone;
1.843 +
1.844 + if (Handle() > 0)
1.845 + {
1.846 + RMdaDevSound::TCurrentSoundFormatBuf format;
1.847 + iInputDevice.GetRecordFormat(format);
1.848 + format().iChannels = aChannels;
1.849 + err = iInputDevice.SetRecordFormat(format);
1.850 + }
1.851 + iChannels = aChannels;
1.852 + iStereoSupport = aStereoSupport;
1.853 + return err;
1.854 + }
1.855 +
1.856 +EXPORT_C TInt CRoutingSoundRecordDevice::SetBufferSize(TUint aBufferSize)
1.857 + {
1.858 + TInt err = KErrNone;
1.859 +
1.860 + if (iDeviceUid != KDeviceUidA2dpHeadset)
1.861 + {
1.862 + if (Handle() > 0)
1.863 + {
1.864 + RMdaDevSound::TCurrentSoundFormatBuf format;
1.865 + iInputDevice.GetRecordFormat(format);
1.866 + // 1 = mono 2 = stereo
1.867 + format().iBufferSize = aBufferSize;
1.868 + err = iInputDevice.SetRecordFormat(format);
1.869 + }
1.870 + }
1.871 + iBufferSize = aBufferSize;
1.872 + //else we don't need this for bt headset
1.873 + return err;
1.874 + }
1.875 +
1.876 +EXPORT_C void CRoutingSoundRecordDevice::FlushBuffer()
1.877 + {
1.878 + if (Handle() > 0)
1.879 + {
1.880 + iInputDevice.FlushRecordBuffer();
1.881 + }
1.882 + }
1.883 +
1.884 +EXPORT_C void CRoutingSoundRecordDevice::NotifyError(TRequestStatus& aStatus)
1.885 + {
1.886 + if (Handle() > 0)
1.887 + {
1.888 + iInputDevice.NotifyRecordError(aStatus);
1.889 + }
1.890 + }
1.891 +
1.892 +EXPORT_C void CRoutingSoundRecordDevice::CancelNotifyError()
1.893 + {
1.894 + // To avoid a KE0 panic if -ve handle is returned
1.895 + if (Handle() > 0)
1.896 + {
1.897 + iInputDevice.CancelNotifyRecordError();
1.898 + }
1.899 + }
1.900 +
1.901 +EXPORT_C TUint CRoutingSoundRecordDevice::Gain() const
1.902 + {
1.903 + TUint gain = 0;
1.904 + if (Handle() > 0)
1.905 + {
1.906 + RMdaDevSound* mutableInputDevice = const_cast<RMdaDevSound*>(&iInputDevice);
1.907 + gain = mutableInputDevice->RecordLevel();
1.908 + }
1.909 + return gain;
1.910 + }
1.911 +
1.912 +EXPORT_C TInt CRoutingSoundRecordDevice::SetGain(TUint aGain)
1.913 + {
1.914 + TInt err = KErrNone;
1.915 + if (Handle() > 0)
1.916 + {
1.917 + iInputDevice.SetRecordLevel(aGain);
1.918 + }
1.919 + else
1.920 + {
1.921 + err = KErrNotReady;
1.922 + }
1.923 + return err;
1.924 + }
1.925 +
1.926 +EXPORT_C void CRoutingSoundRecordDevice::RecordData(TDes8& aData, TRequestStatus& aStatus)
1.927 + {
1.928 + //this handle check should really be removed since it impacts performance
1.929 + //, however there do seem to
1.930 + //be cases where a record error occus but the client sends an ack before
1.931 + //it has time to get the RecordError so keep it for now
1.932 + if (Handle() > 0)
1.933 + {
1.934 + iInputDevice.RecordData(aStatus, aData);
1.935 + }
1.936 + else
1.937 + {
1.938 + TRequestStatus* status = &aStatus;
1.939 + User::RequestComplete(status, KErrBadHandle);
1.940 + }
1.941 + }
1.942 +
1.943 +EXPORT_C void CRoutingSoundRecordDevice::CancelRecordData()
1.944 + {
1.945 + if (Handle() > 0)
1.946 + {
1.947 + iInputDevice.CancelRecordData();
1.948 + }
1.949 + }
1.950 +
1.951 +EXPORT_C TUint CRoutingSoundRecordDevice::BytesRecorded()
1.952 + {
1.953 + // Is there an equivalent call to bytes played for bytes recorded?
1.954 + // If not, why do we have this method or what should we return?
1.955 + TUint bytesPlayed = 0;
1.956 + if (Handle() > 0)
1.957 + {
1.958 + bytesPlayed = iInputDevice.BytesPlayed();
1.959 + }
1.960 + return bytesPlayed;
1.961 + }
1.962 +
1.963 +EXPORT_C TInt CRoutingSoundRecordDevice::Handle() const
1.964 + {
1.965 + return iInputDevice.Handle();
1.966 + }