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