os/mm/devsound/sounddevbt/src/RoutingSoundDevice/MMFBtRoutingSoundDevice.cpp
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
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".
     7 //
     8 // Initial Contributors:
     9 // Nokia Corporation - initial contribution.
    10 //
    11 // Contributors:
    12 //
    13 // Description:
    14 //
    15 
    16 #include <mmfbase.h>
    17 #include <bttypes.h>
    18 #include "MMFBtRoutingSoundDevice.h"
    19 
    20 // Sound drivers
    21 _LIT(KPddFileName,"ESDRV.PDD");
    22 _LIT(KLddFileName,"ESOUND.LDD");
    23 
    24 
    25 
    26 
    27 EXPORT_C CRoutingSoundPlayDevice* CRoutingSoundPlayDevice::NewL()
    28 	{
    29 	CRoutingSoundPlayDevice* self = new(ELeave) CRoutingSoundPlayDevice();
    30 	CleanupStack::PushL(self);
    31 	self->ConstructL();
    32 	CleanupStack::Pop(self);
    33 	return self;
    34 	}
    35 
    36 void CRoutingSoundPlayDevice::ConstructL()
    37 	{
    38 	}
    39 	
    40 CRoutingSoundPlayDevice::CRoutingSoundPlayDevice()
    41 	{
    42 	}
    43 	
    44 EXPORT_C CRoutingSoundPlayDevice::~CRoutingSoundPlayDevice()
    45 	{
    46 	if (iDeviceUid != KDeviceUidA2dpHeadset)
    47 		{
    48 		if (iSpeakerDevice.Handle() > 0)
    49 			{
    50 			iSpeakerDevice.Close();
    51 			}
    52 		}
    53 	else
    54 		{
    55 		iBTDevice.Close();
    56 		}
    57 	}
    58 
    59 EXPORT_C void CRoutingSoundPlayDevice::Initialize(	TUid aDeviceUid,
    60 													const TDesC8& aDeviceConfig,
    61 													TRequestStatus& aStatus)
    62 	{
    63 	TInt err = KErrNone;
    64 	iDeviceUid = aDeviceUid;
    65 	iInitializeStatus = &aStatus;
    66 
    67 	if (iDeviceUid == KDeviceUidA2dpHeadset)
    68 		{
    69 		// Connect to the Bluetooth client
    70 		err = iBTDevice.Connect();
    71 		if (!err)
    72 			{
    73 			// Get the Bluetooth device's address using the descriptor
    74 			iBTAddress = TBTDevAddr(aDeviceConfig);
    75 			// Initialize
    76 			iBTDevice.Initialize(iBTAddress, *iInitializeStatus);
    77 			}
    78 		else
    79 			{
    80 			// Failed to connect
    81 			User::RequestComplete(iInitializeStatus, err);
    82 			}
    83 		}
    84 
    85 	else if ((iDeviceUid == KDeviceUidSpeaker)||(iDeviceUid == KDeviceUidMic))
    86 		{
    87 		// aDeviceConfig must be NULL to reach here (see 5.1 of design doc)
    88 		// Load the drivers
    89 		// Try to load the audio physical driver
    90 	    err = User::LoadPhysicalDevice(KPddFileName);
    91 		if ((err == KErrNone) || (err == KErrAlreadyExists))
    92 			{
    93 		    // Try to load the audio logical driver
    94 			err = User::LoadLogicalDevice(KLddFileName);
    95 		    }
    96 		
    97 		if (err == KErrAlreadyExists)
    98 			{
    99 			// It's not a problem if the drivers have already
   100 			// been loaded so reset the error code accordingly
   101 			err = KErrNone;
   102 			}
   103 		// Completed to load the drivers so signal
   104 		User::RequestComplete(iInitializeStatus, err);
   105 		}
   106 	else
   107 		{
   108 		// Unexpected Uid
   109 		User::RequestComplete(iInitializeStatus, KErrNotSupported);
   110 		}
   111 	}
   112 
   113 EXPORT_C void CRoutingSoundPlayDevice::CancelInitialize(TUid aDeviceUid)
   114 	{
   115 	if (aDeviceUid == iDeviceUid)
   116 		{//can only cancel bt headset initialize
   117 		if (aDeviceUid == KDeviceUidA2dpHeadset)
   118 			{
   119 			iBTDevice.CancelInitialize();
   120 			}
   121 		if (iInitializeStatus && *iInitializeStatus == KRequestPending)
   122 			{
   123 			User::RequestComplete(iInitializeStatus, KErrCancel);				
   124 			}		
   125 		}
   126 	}
   127 	
   128 /**
   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?
   134  *	TODO:
   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.
   138  */
   139 EXPORT_C void CRoutingSoundPlayDevice::OpenDevice(	TUid aDeviceUid,
   140 													TRequestStatus& aStatus)
   141 	{
   142 	iOpenDeviceStatus = &aStatus;
   143 	if (aDeviceUid == KDeviceUidSpeaker)
   144 		{
   145 		TInt error = KErrNone;
   146 		if (!Handle())
   147 			{
   148 			error = iSpeakerDevice.Open();
   149 			if ((!error)||(error == KErrAlreadyExists))
   150 				{
   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;
   157 				if (iSampleRate)
   158 					{
   159 					soundDeviceSettings().iRate = iSampleRate;
   160 					}
   161 				if (iChannels)
   162 					{
   163 					soundDeviceSettings().iChannels = iChannels;
   164 					}
   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
   168 				if (iBufferSize)
   169 					{	
   170 					soundDeviceSettings().iBufferSize = iBufferSize;
   171 					}
   172 				error = iSpeakerDevice.SetPlayFormat(soundDeviceSettings);
   173 				if (error)
   174 					{
   175 					iSpeakerDevice.Close();
   176 					}
   177 				}
   178 			}
   179 		User::RequestComplete(iOpenDeviceStatus, error);
   180 		}
   181 	else if (aDeviceUid == KDeviceUidA2dpHeadset)
   182 		{
   183 		iBTDevice.OpenDevice(*iOpenDeviceStatus);
   184 		}
   185 	else
   186 		{
   187 		User::RequestComplete(iOpenDeviceStatus, KErrNotSupported);
   188 		}
   189 	}
   190 	
   191 EXPORT_C void CRoutingSoundPlayDevice::CancelOpenDevice(TUid aDeviceUid)
   192 	{
   193 	if (aDeviceUid == iDeviceUid)
   194 		{
   195 		if (aDeviceUid != KDeviceUidA2dpHeadset)
   196 			{
   197 			if(Handle() > 0)
   198 			 	{
   199 			 	iSpeakerDevice.Close();
   200 			 	}
   201 			}
   202 		else
   203 			{
   204 			iBTDevice.CancelOpenDevice();
   205 			}
   206 		if (iOpenDeviceStatus && *iOpenDeviceStatus == KRequestPending)
   207 			{
   208 			User::RequestComplete(iOpenDeviceStatus, KErrCancel);				
   209 			}		
   210 		}
   211 	}
   212 
   213 EXPORT_C void CRoutingSoundPlayDevice::CloseDevice(TUid aDeviceUid, TRequestStatus& aStatus)
   214 	{
   215 	if (aDeviceUid != KDeviceUidA2dpHeadset)
   216 		{
   217 		aStatus = KRequestPending;
   218 		if (Handle() > 0)
   219 			{
   220 			iSpeakerDevice.Close();
   221 			}
   222 		TRequestStatus* status = &aStatus;
   223 		User::RequestComplete(status, KErrNone);
   224 		}
   225 	else
   226 		{
   227 		iCloseDeviceStatus = &aStatus;
   228 		iBTDevice.CloseDevice(*iCloseDeviceStatus);
   229 		}
   230 	}
   231 	
   232 EXPORT_C TInt CRoutingSoundPlayDevice::GetSupportedDataTypes(RArray<TFourCC>& aSupportedDataTypes)
   233 	{
   234 	TInt err = KErrNone;
   235 	if (iDeviceUid != KDeviceUidA2dpHeadset)
   236 		{
   237 		if (Handle() > 0)
   238 			{
   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);
   243 			if (!err)
   244 				{
   245 				aSupportedDataTypes.Reset();
   246 				}
   247 			}
   248 		else
   249 			{
   250 			err = KErrNotReady;
   251 			}
   252 		}
   253 	else
   254 		{
   255 		TRAP(err, iBTDevice.GetSupportedDataTypesL(aSupportedDataTypes));
   256 		}
   257 
   258 	return err;
   259 	}
   260 	
   261 EXPORT_C TInt CRoutingSoundPlayDevice::GetSupportedSampleRates(RArray<TUint>& aSupportedDiscreteRates,
   262 																RArray<TRange>& aSupportedRateRanges)
   263 	{
   264 	TInt err = KErrNone;
   265 	aSupportedDiscreteRates.Reset();
   266 	aSupportedRateRanges.Reset();
   267 	if (iDeviceUid != KDeviceUidA2dpHeadset)
   268 		{
   269 		if (Handle() > 0)
   270 			{
   271 			RMdaDevSound::TSoundFormatsSupportedBuf formatsSupported;
   272 			iSpeakerDevice.PlayFormatsSupported(formatsSupported);
   273 			TRange range;
   274 			range.iLow = formatsSupported().iMinRate;
   275 			range.iHigh = formatsSupported().iMaxRate;
   276 			err = aSupportedRateRanges.Append(range);
   277 			if (err != KErrNone)
   278 				{
   279 				aSupportedRateRanges.Reset();
   280 				}
   281 			}
   282 		else
   283 			{
   284 			err = KErrNotReady;
   285 			}
   286 		}
   287 	else
   288 		{
   289 		TRAP(err, iBTDevice.GetSupportedSampleRatesL(aSupportedDiscreteRates,
   290 													aSupportedRateRanges);)
   291 		}
   292 	
   293 	return err;
   294 	}
   295 	
   296 EXPORT_C TInt CRoutingSoundPlayDevice::GetSupportedChannels(RArray<TUint>& aSupportedChannels,
   297 															TMMFStereoSupport& aStereoSupport)
   298 	{
   299 	TInt err = KErrNone;
   300 	aSupportedChannels.Reset();
   301 	if (iDeviceUid != KDeviceUidA2dpHeadset)
   302 		{
   303 		if (Handle() > 0)
   304 			{
   305 			RMdaDevSound::TCurrentSoundFormatBuf soundDeviceSettings;
   306 			iSpeakerDevice.GetPlayFormat(soundDeviceSettings);
   307 			//1 = mono 2 = stereo
   308 			err = aSupportedChannels.Append(soundDeviceSettings().iChannels);
   309 			if (soundDeviceSettings().iChannels != 2)
   310 				{
   311 				// No stereo support
   312 				aStereoSupport = EMMFNone;
   313 				}
   314 			else
   315 				{
   316 				aStereoSupport = EMMFBothNonAndInterleaved;
   317 				}
   318 			}
   319 		else
   320 			{
   321 			err = KErrNotReady;
   322 			}
   323 		}
   324 	else
   325 		{
   326 		TRAP(err, iBTDevice.GetSupportedChannelsL(aSupportedChannels, aStereoSupport));
   327 		}
   328 	
   329 	return err;
   330 	}
   331 	
   332 EXPORT_C TInt CRoutingSoundPlayDevice::SetDataType(const TFourCC& aDataType)
   333 	{
   334 	TInt err = KErrNone;
   335 	if (iDeviceUid != KDeviceUidA2dpHeadset)
   336 		{
   337 		if (Handle() > 0)
   338 			{
   339 			if (aDataType == KMMFFourCCCodePCM16)
   340 				{
   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);
   346 				}
   347 			else
   348 				{
   349 				// Trying to set an unsupported data type
   350 				err = KErrNotSupported;
   351 				}
   352 			}
   353 		// else actually doesn't really matter - we always set the sound driver to pcm16 anyway
   354 		}
   355 	else
   356 		{
   357 		err = iBTDevice.SetDataType(aDataType);
   358 		}
   359 		
   360 	return err;
   361 	}
   362 
   363 EXPORT_C TInt CRoutingSoundPlayDevice::SetSampleRate(TUint aSampleRate)
   364 	{
   365 	TInt err = KErrNone;
   366 
   367 	if (iDeviceUid != KDeviceUidA2dpHeadset)
   368 		{
   369 		if (Handle())
   370 			{
   371 			RMdaDevSound::TCurrentSoundFormatBuf soundDeviceSettings;
   372 			iSpeakerDevice.GetPlayFormat(soundDeviceSettings);
   373 			soundDeviceSettings().iRate = aSampleRate;
   374 			err = iSpeakerDevice.SetPlayFormat(soundDeviceSettings);
   375 			}
   376 	//should also check whether we support aSampleRate
   377 		}
   378 	else
   379 		{
   380 		err = iBTDevice.SetSampleRate(aSampleRate);
   381 		}
   382 	
   383 	iSampleRate = aSampleRate;
   384 	return err;
   385 	}
   386 
   387 EXPORT_C TInt CRoutingSoundPlayDevice::SetChannels(	TUint aChannels,
   388 													TMMFStereoSupport aStereoSupport)
   389 	{
   390 	TInt err = KErrNone;
   391 	
   392 	if (iDeviceUid != KDeviceUidA2dpHeadset)
   393 		{
   394 		if (Handle() > 0)
   395 			{
   396 			RMdaDevSound::TCurrentSoundFormatBuf soundDeviceSettings;
   397 			iSpeakerDevice.GetPlayFormat(soundDeviceSettings);
   398 			// 1 = mono 2 = stereo
   399 			soundDeviceSettings().iChannels = aChannels;			
   400 			err = iSpeakerDevice.SetPlayFormat(soundDeviceSettings);
   401 			}
   402 		}
   403 	else
   404 		{
   405 		err = iBTDevice.SetChannels(aChannels, aStereoSupport);
   406 		}
   407 	iChannels = aChannels;
   408 	iStereoSupport = aStereoSupport;
   409 	return err;	
   410 	}
   411 	
   412 EXPORT_C TInt CRoutingSoundPlayDevice::SetBufferSize(TUint aBufferSize)
   413 	{
   414 	TInt err = KErrNone;
   415 	
   416 	if (iDeviceUid != KDeviceUidA2dpHeadset)
   417 		{
   418 		if (Handle() > 0)
   419 			{
   420 			RMdaDevSound::TCurrentSoundFormatBuf soundDeviceSettings;
   421 			iSpeakerDevice.GetPlayFormat(soundDeviceSettings);
   422 			// 1 = mono 2 = stereo
   423 			soundDeviceSettings().iBufferSize = aBufferSize;			
   424 			err = iSpeakerDevice.SetPlayFormat(soundDeviceSettings);
   425 			}
   426 		}
   427 	iBufferSize = aBufferSize;
   428 	//else we don't need this for bt headset
   429 	return err;
   430 	}
   431 
   432 EXPORT_C void CRoutingSoundPlayDevice::FlushBuffer()
   433 	{
   434 	if (iDeviceUid != KDeviceUidA2dpHeadset)
   435 		{
   436 		if (Handle() > 0)
   437 			{
   438 			iSpeakerDevice.FlushPlayBuffer();
   439 			}
   440 		}
   441 	else
   442 		{
   443 		iBTDevice.FlushBuffer();
   444 		}
   445 	}
   446 
   447 EXPORT_C void CRoutingSoundPlayDevice::NotifyError(TRequestStatus& aStatus)
   448 	{
   449 	if (iDeviceUid != KDeviceUidA2dpHeadset)
   450 		{
   451 		if (Handle() > 0)
   452 			{
   453 			iSpeakerDevice.NotifyPlayError(aStatus);
   454 			}
   455 		}
   456 	else
   457 		{
   458 		iBTDevice.NotifyError(aStatus);
   459 		}
   460 	}
   461 
   462 EXPORT_C void CRoutingSoundPlayDevice::CancelNotifyError()
   463 	{
   464 	if (iDeviceUid != KDeviceUidA2dpHeadset)
   465 		{
   466 		// To avoid a KE0 panic if -ve handle is returned
   467 		if (Handle() > 0)
   468 			{		
   469 			iSpeakerDevice.CancelNotifyPlayError();
   470 			}
   471 		}
   472 	else
   473 		{
   474 		iBTDevice.CancelNotifyError();
   475 		}	
   476 	}
   477 
   478 EXPORT_C TUint CRoutingSoundPlayDevice::Volume() const
   479 	{
   480 	TUint volume = 0;
   481 	if (iDeviceUid != KDeviceUidA2dpHeadset)
   482 		{
   483 		if (Handle() > 0)
   484 			{
   485 			RMdaDevSound* mutableSpeakerDevice = const_cast<RMdaDevSound*>(&iSpeakerDevice);
   486 			volume = mutableSpeakerDevice->PlayVolume();
   487 			}
   488 		}
   489 	else
   490 		{
   491 		volume = iBTDevice.Volume();
   492 		}
   493 	return volume;
   494 	}
   495 	
   496 EXPORT_C TInt CRoutingSoundPlayDevice::SetVolume(TUint aVolume)
   497 	{
   498 	TInt err = KErrNone;
   499 	if (iDeviceUid != KDeviceUidA2dpHeadset)
   500 		{
   501 		if (Handle() > 0)
   502 			{
   503 			iSpeakerDevice.SetPlayVolume(aVolume);
   504 			}
   505 		}
   506 	else
   507 		{
   508 		err = iBTDevice.SetVolume(aVolume);
   509 		}
   510 	return err;
   511 	}
   512 	
   513 EXPORT_C void CRoutingSoundPlayDevice::PlayData(const TDesC8& aData, TRequestStatus& aStatus)
   514 	{
   515 	if (iDeviceUid != KDeviceUidA2dpHeadset)
   516 		{
   517 		if (Handle() > 0)
   518 			{
   519 			iSpeakerDevice.PlayData(aStatus, aData);
   520 			}
   521 		else
   522 			{
   523 			TRequestStatus* status = &aStatus;
   524 			User::RequestComplete(status, KErrBadHandle);
   525 			}
   526 		}
   527 	else
   528 		{
   529 		iBTDevice.PlayData(aData, aStatus);
   530 		}
   531 	}
   532 	
   533 EXPORT_C void CRoutingSoundPlayDevice::CancelPlayData()
   534 	{
   535 	if (iDeviceUid != KDeviceUidA2dpHeadset)
   536 		{
   537 		if (Handle() > 0)
   538 			{
   539 			iSpeakerDevice.CancelPlayData();
   540 			}
   541 		}
   542 	else
   543 		{
   544 		iBTDevice.CancelPlayData();
   545 		}
   546 	}
   547 	
   548 EXPORT_C TUint CRoutingSoundPlayDevice::BytesPlayed()
   549 	{
   550 	TUint bytes = 0;
   551 	if (iDeviceUid != KDeviceUidA2dpHeadset)
   552 		{
   553 		if (Handle() > 0)
   554 			{
   555 			bytes = iSpeakerDevice.BytesPlayed();
   556 			}
   557 		}
   558 	else
   559 		{
   560 		bytes = iBTDevice.BytesPlayed();
   561 		}
   562 
   563 	return bytes;
   564 	}
   565 	
   566 EXPORT_C TInt CRoutingSoundPlayDevice::ResetBytesPlayed()
   567 	{
   568 	if (iDeviceUid != KDeviceUidA2dpHeadset)
   569 		{
   570 		if (Handle() > 0)
   571 			{		
   572 			iSpeakerDevice.ResetBytesPlayed();
   573 			}
   574 		}
   575 	else
   576 		{
   577 		iBTDevice.ResetBytesPlayed();
   578 		}
   579 	return KErrNone;	// why are we returing a value?
   580 	}
   581 	
   582 EXPORT_C TInt CRoutingSoundPlayDevice::PauseBuffer()
   583 	{
   584 	if (iDeviceUid != KDeviceUidA2dpHeadset)
   585 		{
   586 		if (Handle() > 0)
   587 			{
   588 			iSpeakerDevice.PausePlayBuffer();
   589 			}
   590 		}
   591 	else
   592 		{
   593 		iBTDevice.PauseBuffer();
   594 		}
   595 	return KErrNone;
   596 	}
   597 
   598 EXPORT_C TInt CRoutingSoundPlayDevice::ResumePlaying()
   599 	{
   600 	if (iDeviceUid != KDeviceUidA2dpHeadset)
   601 		{
   602 		if (Handle() > 0)
   603 			{
   604 			iSpeakerDevice.ResumePlaying();
   605 			}
   606 		}
   607 	else
   608 		{
   609 		iBTDevice.ResumePlaying();
   610 		}
   611 	return KErrNone;
   612 	}
   613 	
   614 EXPORT_C TInt CRoutingSoundPlayDevice::Handle() const
   615 	{
   616 	TInt handle;
   617 	if (iDeviceUid != KDeviceUidA2dpHeadset)
   618 		{
   619 		handle = iSpeakerDevice.Handle();
   620 		}
   621 	else
   622 		{
   623 		handle = iBTDevice.Handle();
   624 		}
   625 	return handle;
   626 	}
   627 	
   628 /**
   629  * Implementation of CRoutingSoundRecordDevice.
   630  */
   631 EXPORT_C CRoutingSoundRecordDevice* CRoutingSoundRecordDevice::NewL()
   632 	{
   633 	CRoutingSoundRecordDevice* self = new(ELeave) CRoutingSoundRecordDevice();
   634 	CleanupStack::PushL(self);
   635 	self->ConstructL();
   636 	CleanupStack::Pop(self);
   637 	return self;
   638 	}
   639 
   640 void CRoutingSoundRecordDevice::ConstructL()
   641 	{
   642 	//...
   643 	}
   644 	
   645 CRoutingSoundRecordDevice::CRoutingSoundRecordDevice()
   646 	{
   647 	}
   648 
   649 EXPORT_C CRoutingSoundRecordDevice::~CRoutingSoundRecordDevice()
   650 	{
   651 	if (iInputDevice.Handle())
   652 		{
   653 		iInputDevice.Close();
   654 		}
   655 	}
   656 	
   657 
   658 EXPORT_C void CRoutingSoundRecordDevice::Initialize(TUid aDeviceUid,
   659 													const TDesC8& /*aDeviceConfig*/,
   660 													TRequestStatus& aStatus)
   661 
   662 	{
   663 	iDeviceUid = aDeviceUid;
   664 	TRequestStatus* status = &aStatus;
   665 	TInt ret = KErrNone;
   666 	if (iDeviceUid == KDeviceUidMic)
   667 		{
   668 		// Load the drivers
   669 		// Try to load the audio physical driver
   670 	    ret = User::LoadPhysicalDevice(KPddFileName);
   671 		if ((ret == KErrNone) || (ret == KErrAlreadyExists))
   672 			{
   673 		    // Try to load the audio logical driver
   674 			ret = User::LoadLogicalDevice(KLddFileName);
   675 		    }
   676 		
   677 		if (ret == KErrAlreadyExists)
   678 			{
   679 			// It's not a problem if the drivers have already
   680 			// been loaded so reset the error code accordingly
   681 			ret = KErrNone;
   682 			}
   683 		}
   684 	else
   685 		{
   686 		ret = KErrNotSupported;
   687 		}
   688 
   689 	User::RequestComplete(status, ret);
   690 	}
   691 
   692 EXPORT_C void CRoutingSoundRecordDevice::CancelInitialize(TUid /*aDeviceUid*/)
   693 	{
   694 	// Nothing to do
   695 	}
   696 
   697 EXPORT_C void CRoutingSoundRecordDevice::OpenDevice(TUid /*aDeviceUid*/, TRequestStatus& aStatus)
   698 	{
   699 	iOpenDeviceStatus = &aStatus;
   700 	TInt error = KErrNone;
   701 	if (!iInputDevice.Handle())
   702 		{
   703 		error = iInputDevice.Open();
   704 		if ((!error)||(error == KErrAlreadyExists))
   705 			{
   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;
   712 			if (iSampleRate)
   713 				{
   714 				soundDeviceSettings().iRate = iSampleRate;
   715 				}
   716 			if (iChannels)
   717 				{
   718 				soundDeviceSettings().iChannels = iChannels;
   719 				}
   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
   723 			if (iBufferSize)
   724 				{	
   725 				soundDeviceSettings().iBufferSize = iBufferSize;
   726 				}
   727 			error = iInputDevice.SetRecordFormat(soundDeviceSettings);
   728 			if (error)
   729 				{
   730 				iInputDevice.Close();
   731 				}
   732 			}
   733 		}
   734 	User::RequestComplete(iOpenDeviceStatus, error);
   735 	}
   736 
   737 EXPORT_C void CRoutingSoundRecordDevice::CancelOpenDevice(TUid aDeviceUid)
   738 	{
   739 	if (aDeviceUid == iDeviceUid)
   740 		{
   741 		if (iDeviceUid != KDeviceUidA2dpHeadset)
   742 			{
   743 			if(Handle() > 0)
   744 			 	{
   745 			 	iInputDevice.Close();
   746 			 	}
   747 			}
   748 		if (iOpenDeviceStatus && *iOpenDeviceStatus == KRequestPending)
   749 			{
   750 			User::RequestComplete(iOpenDeviceStatus, KErrCancel);				
   751 			}		
   752 		}
   753 	}
   754 	
   755 EXPORT_C void CRoutingSoundRecordDevice::CloseDevice(TUid /*aDeviceUid*/, TRequestStatus& aStatus)
   756 	{
   757 	aStatus = KRequestPending;//async not really necessary with RMdaDevSound since close is sync
   758 	if (iInputDevice.Handle())
   759 		{
   760 		iInputDevice.Close();
   761 		}
   762 	TRequestStatus* status = &aStatus;
   763 	User::RequestComplete(status, KErrNone);
   764 	}	
   765 
   766 EXPORT_C TInt CRoutingSoundRecordDevice::GetSupportedSampleRates(RArray<TUint>& aSupportedDiscreteRates,
   767 																RArray<TRange>& aSupportedRateRanges)
   768 	{
   769 	aSupportedDiscreteRates.Reset();
   770 	aSupportedRateRanges.Reset();
   771 	TInt err = KErrNone;
   772 	if (Handle() > 0)
   773 		{
   774 		RMdaDevSound::TSoundFormatsSupportedBuf formatsSupported;
   775 		iInputDevice.RecordFormatsSupported(formatsSupported);
   776 		TRange range;
   777 		range.iLow = formatsSupported().iMinRate;
   778 		range.iHigh = formatsSupported().iMaxRate;
   779 		err = aSupportedRateRanges.Append(range);
   780 		if(!err)
   781 			{
   782 			aSupportedRateRanges.Reset();
   783 			}
   784 		}
   785 	else
   786 		{
   787 		err = KErrNotReady;
   788 		}
   789 
   790 	return err;
   791 	}
   792 	
   793 EXPORT_C TInt CRoutingSoundRecordDevice::GetSupportedChannels(	RArray<TUint>& aSupportedChannels,
   794 																TMMFStereoSupport& aStereoSupport)
   795 	{
   796 	TInt err = KErrNone;
   797 	if (Handle() > 0)
   798 		{
   799 		RMdaDevSound::TSoundFormatsSupportedBuf formatsSupported;
   800 		iInputDevice.RecordFormatsSupported(formatsSupported);
   801 		aSupportedChannels.Reset();
   802 		err = aSupportedChannels.Append(formatsSupported().iChannels);
   803 		
   804 		if (err == KErrNone)
   805 			{
   806 			aStereoSupport = EMMFNone;	// assume no stereo support for starters
   807 
   808 			if (formatsSupported().iChannels == 2)
   809 				{
   810 				aStereoSupport = EMMFBothNonAndInterleaved;		
   811 				}
   812 			}
   813 		}
   814 	else
   815 		{
   816 		err = KErrNotReady;
   817 		}
   818 
   819 	return err;
   820 	}
   821 
   822 EXPORT_C TInt CRoutingSoundRecordDevice::SetSampleRate(TUint aSampleRate)
   823 	{
   824 	// Assume we don't have a handle to the device
   825 	TInt err = KErrNone;
   826 	if (Handle())
   827 		{
   828 		RMdaDevSound::TCurrentSoundFormatBuf format;
   829 		iInputDevice.GetRecordFormat(format);
   830 		format().iRate = aSampleRate;
   831 		err = iInputDevice.SetRecordFormat(format);		
   832 		}
   833 	iSampleRate = aSampleRate;
   834 	return err;
   835 	}
   836 
   837 EXPORT_C TInt CRoutingSoundRecordDevice::SetChannels(TUint aChannels, TMMFStereoSupport aStereoSupport)
   838 	{
   839 	TInt err = KErrNone;
   840 	
   841 	if (Handle() > 0)
   842 		{
   843 		RMdaDevSound::TCurrentSoundFormatBuf format;
   844 		iInputDevice.GetRecordFormat(format);
   845 		format().iChannels = aChannels;
   846 		err = iInputDevice.SetRecordFormat(format);			
   847 		}
   848 	iChannels = aChannels;
   849 	iStereoSupport = aStereoSupport;	
   850 	return err;
   851 	}
   852 	
   853 EXPORT_C TInt CRoutingSoundRecordDevice::SetBufferSize(TUint aBufferSize)
   854 	{
   855 	TInt err = KErrNone;
   856 	
   857 	if (iDeviceUid != KDeviceUidA2dpHeadset)
   858 		{
   859 		if (Handle() > 0)
   860 			{
   861 			RMdaDevSound::TCurrentSoundFormatBuf format;
   862 			iInputDevice.GetRecordFormat(format);
   863 			// 1 = mono 2 = stereo
   864 			format().iBufferSize = aBufferSize;			
   865 			err = iInputDevice.SetRecordFormat(format);
   866 			}
   867 		}
   868 	iBufferSize = aBufferSize;
   869 	//else we don't need this for bt headset
   870 	return err;
   871 	}
   872 
   873 EXPORT_C void CRoutingSoundRecordDevice::FlushBuffer()
   874 	{
   875 	if (Handle() > 0)
   876 		{
   877 		iInputDevice.FlushRecordBuffer();
   878 		}
   879 	}
   880 
   881 EXPORT_C void CRoutingSoundRecordDevice::NotifyError(TRequestStatus& aStatus)
   882 	{
   883 	if (Handle() > 0)
   884 		{
   885 		iInputDevice.NotifyRecordError(aStatus);
   886 		}
   887 	}
   888 
   889 EXPORT_C void CRoutingSoundRecordDevice::CancelNotifyError()
   890 	{
   891 	// To avoid a KE0 panic if -ve handle is returned
   892 	if (Handle() > 0)
   893 		{
   894 		iInputDevice.CancelNotifyRecordError();
   895 		}
   896 	}
   897 
   898 EXPORT_C TUint CRoutingSoundRecordDevice::Gain() const
   899 	{
   900 	TUint gain = 0;
   901 	if (Handle() > 0)
   902 		{
   903 		RMdaDevSound* mutableInputDevice = const_cast<RMdaDevSound*>(&iInputDevice);
   904 		gain = mutableInputDevice->RecordLevel();		
   905 		}
   906 	return gain;
   907 	}
   908 	
   909 EXPORT_C TInt CRoutingSoundRecordDevice::SetGain(TUint aGain)
   910 	{
   911 	TInt err = KErrNone;
   912 	if (Handle() > 0)
   913 		{
   914 		iInputDevice.SetRecordLevel(aGain);
   915 		}
   916 	else
   917 		{
   918 		err = KErrNotReady;
   919 		}
   920 	return err;
   921 	}
   922 	
   923 EXPORT_C void CRoutingSoundRecordDevice::RecordData(TDes8& aData, TRequestStatus& aStatus)
   924 	{
   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
   929 	if (Handle() > 0)
   930 		{
   931 		iInputDevice.RecordData(aStatus, aData);
   932 		}
   933 	else
   934 		{
   935 		TRequestStatus* status = &aStatus;
   936 		User::RequestComplete(status, KErrBadHandle);
   937 		}
   938 	}
   939 	
   940 EXPORT_C void CRoutingSoundRecordDevice::CancelRecordData()
   941 	{
   942 	if (Handle() > 0)
   943 		{
   944 		iInputDevice.CancelRecordData();
   945 		}
   946 	}
   947 	
   948 EXPORT_C TUint CRoutingSoundRecordDevice::BytesRecorded()
   949 	{
   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;
   953 	if (Handle() > 0)
   954 		{
   955 		bytesPlayed = iInputDevice.BytesPlayed();
   956 		}
   957 	return bytesPlayed; 
   958 	}
   959 
   960 EXPORT_C TInt CRoutingSoundRecordDevice::Handle() const
   961 	{
   962 	return iInputDevice.Handle();
   963 	}