os/mm/mmdevicefw/mdf/src/audio/mdasoundadapter/mdasoundadapterbody.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) 2008-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
#include "mdasoundadapterconsts.h"
sl@0
    16
#include "mdasoundadapterbody.h"
sl@0
    17
#include <e32debug.h>
sl@0
    18
sl@0
    19
#include "mmf/utils/rateconvert.h" // if we need to resample
sl@0
    20
sl@0
    21
#include <hal.h>
sl@0
    22
sl@0
    23
_LIT(KPddFileName,"SOUNDSC.PDD");
sl@0
    24
_LIT(KLddFileName,"ESOUNDSC.LDD");
sl@0
    25
sl@0
    26
sl@0
    27
const TInt KBytesPerSample = 2;
sl@0
    28
const TInt KMinBufferSize = 2;
sl@0
    29
sl@0
    30
/**
sl@0
    31
This function raises a panic
sl@0
    32
EDeviceNotOpened is raised when any of the RMdaDevSound APIs are called before opening the device. 
sl@0
    33
*/
sl@0
    34
GLDEF_C void Panic(TSoundAdapterPanicCodes aPanicCode)
sl@0
    35
	{
sl@0
    36
	User::Panic(KSoundAdapterPanicCategory, aPanicCode);
sl@0
    37
	}
sl@0
    38
sl@0
    39
sl@0
    40
const TText8 *RMdaDevSound::CBody::TState::Name() const
sl@0
    41
	{
sl@0
    42
	#ifdef SYMBIAN_SOUNDADAPTER_DEBUG	 
sl@0
    43
	switch(iState)
sl@0
    44
		{
sl@0
    45
		case ENotReady:				return _S8("ENotReady");
sl@0
    46
		case EStopped:				return _S8("EStopped");
sl@0
    47
		case ERecording:			return _S8("ERecording");
sl@0
    48
		case ERecordingPausedInHw:	return _S8("ERecordingPausedInHw");
sl@0
    49
		case ERecordingPausedInSw:	return _S8("ERecordingPausedInSw");
sl@0
    50
		case EPlaying:				return _S8("EPlaying");
sl@0
    51
		case EPlayingPausedInHw: 	return _S8("EPlayingPausedInHw");
sl@0
    52
		case EPlayingPausedInSw:	return _S8("EPlayingPausedInSw");
sl@0
    53
		case EPlayingUnderrun:		return _S8("EPlayingUnderrun");
sl@0
    54
		}
sl@0
    55
	return _S8("CorruptState");
sl@0
    56
	#else
sl@0
    57
	return _S8("");
sl@0
    58
	#endif
sl@0
    59
	}
sl@0
    60
sl@0
    61
	
sl@0
    62
sl@0
    63
RMdaDevSound::CBody::TState &RMdaDevSound::CBody::TState::operator=(TStateEnum aNewState)
sl@0
    64
	{
sl@0
    65
    if(iState != aNewState)
sl@0
    66
        {
sl@0
    67
        #ifdef SYMBIAN_SOUNDADAPTER_DEBUG    
sl@0
    68
        RDebug::Printf("RMdaDevSound state %s -> %s", Name(), TState(aNewState).Name());
sl@0
    69
        #endif
sl@0
    70
        iState = aNewState;
sl@0
    71
        }
sl@0
    72
	return *this;
sl@0
    73
	}
sl@0
    74
sl@0
    75
RMdaDevSound::CBody* RMdaDevSound::CBody::NewL()
sl@0
    76
	{
sl@0
    77
	CBody* self = new(ELeave) CBody();
sl@0
    78
	CleanupStack::PushL(self);
sl@0
    79
	self->ConstructL();
sl@0
    80
	CleanupStack::Pop();
sl@0
    81
	return self;
sl@0
    82
	}
sl@0
    83
sl@0
    84
RMdaDevSound::CBody::~CBody()
sl@0
    85
	{
sl@0
    86
	for(TInt i = 0; i < KPlaySharedChunkBuffers; i++)
sl@0
    87
		{
sl@0
    88
		delete iPlayers[i];
sl@0
    89
		iPlayers[i] = NULL;
sl@0
    90
		}
sl@0
    91
	delete iRecorder;
sl@0
    92
	iRecorder = NULL;
sl@0
    93
	delete iPlayFormatData.iConverter;
sl@0
    94
	delete iRecordFormatData.iConverter;
sl@0
    95
	iPlayChunk.Close();
sl@0
    96
	iPlaySoundDevice.Close();
sl@0
    97
	iRecordChunk.Close();
sl@0
    98
	iRecordSoundDevice.Close();
sl@0
    99
	iConvertedPlayData.Close();
sl@0
   100
	iSavedTrailingData.Close();
sl@0
   101
	iBufferedRecordData.Close();
sl@0
   102
	}
sl@0
   103
	
sl@0
   104
RMdaDevSound::CBody::CBody()
sl@0
   105
	:iState(ENotReady), iBufferOffset(-1)
sl@0
   106
	{
sl@0
   107
	
sl@0
   108
	}
sl@0
   109
sl@0
   110
TVersion RMdaDevSound::CBody::VersionRequired() const
sl@0
   111
	{
sl@0
   112
	if(iPlaySoundDevice.Handle())
sl@0
   113
		{
sl@0
   114
		return iPlaySoundDevice.VersionRequired();
sl@0
   115
		}
sl@0
   116
	else
sl@0
   117
		{
sl@0
   118
		return TVersion();
sl@0
   119
		}
sl@0
   120
	}
sl@0
   121
sl@0
   122
TInt RMdaDevSound::CBody::IsMdaSound()
sl@0
   123
	{
sl@0
   124
	return ETrue;
sl@0
   125
	}
sl@0
   126
	
sl@0
   127
void RMdaDevSound::CBody::ConstructL()
sl@0
   128
	{
sl@0
   129
	// Try to load the audio physical driver
sl@0
   130
    TInt err = User::LoadPhysicalDevice(KPddFileName);
sl@0
   131
	if ((err!=KErrNone) && (err!=KErrAlreadyExists))
sl@0
   132
		{
sl@0
   133
		User::Leave(err);
sl@0
   134
		}
sl@0
   135
    // Try to load the audio logical driver
sl@0
   136
	err = User::LoadLogicalDevice(KLddFileName);
sl@0
   137
    if ((err!=KErrNone) && (err!=KErrAlreadyExists))
sl@0
   138
    	{
sl@0
   139
    	User::Leave(err);
sl@0
   140
    	}
sl@0
   141
	for(TInt i=0; i<KPlaySharedChunkBuffers; i++)
sl@0
   142
		{
sl@0
   143
		iPlayers[i] = new(ELeave) CPlayer(CActive::EPriorityUserInput, *this, i);
sl@0
   144
		iFreePlayers.Push(iPlayers[i]);
sl@0
   145
		}
sl@0
   146
	
sl@0
   147
	iRecorder = new(ELeave) CRecorder(CActive::EPriorityUserInput, *this);
sl@0
   148
	
sl@0
   149
	TInt tmp;
sl@0
   150
	User::LeaveIfError(HAL::Get(HAL::ENanoTickPeriod, tmp));
sl@0
   151
	iNTickPeriodInUsec = tmp;
sl@0
   152
	}
sl@0
   153
sl@0
   154
TInt RMdaDevSound::CBody::Open(TInt /*aUnit*/)
sl@0
   155
	{
sl@0
   156
    #ifdef SYMBIAN_SOUNDADAPTER_DEBUG	
sl@0
   157
        RDebug::Print(_L("RMdaDevSound::CBody::Open "));
sl@0
   158
    #endif	
sl@0
   159
	TInt err = KErrNone;
sl@0
   160
	//Default behavior of this method is to open both the play and record audio devices.
sl@0
   161
	if(!iPlaySoundDevice.Handle() && !iRecordSoundDevice.Handle())
sl@0
   162
        {
sl@0
   163
		err = iPlaySoundDevice.Open(KSoundScTxUnit0);
sl@0
   164
    	if(err == KErrNone)
sl@0
   165
    		{
sl@0
   166
    		err = iRecordSoundDevice.Open(KSoundScRxUnit0);
sl@0
   167
    		}
sl@0
   168
		}
sl@0
   169
	if(err != KErrNone)
sl@0
   170
		{
sl@0
   171
		Close();
sl@0
   172
		}
sl@0
   173
	else
sl@0
   174
	    {
sl@0
   175
		TSoundFormatsSupportedV02Buf capsBuf;
sl@0
   176
		iPlaySoundDevice.Caps(capsBuf);
sl@0
   177
		TInt minBufferSize = KMinBufferSize;
sl@0
   178
		#ifdef SYMBIAN_FORCE_32BIT_LENGTHS
sl@0
   179
		minBufferSize = Max(minBufferSize, 4); // force to 32-bit buffer align
sl@0
   180
		#endif
sl@0
   181
		iRequestMinSize = Max(capsBuf().iRequestMinSize, minBufferSize); 
sl@0
   182
		// work out mask so that x&iRequestMinMask is equiv to x/iRequestMinSize*iRequestMinSize
sl@0
   183
		iRequestMinMask = ~(iRequestMinSize-1); // assume iRequestMinSize is power of 2
sl@0
   184
		iSavedTrailingData.Close();
sl@0
   185
		iSavedTrailingData.Create(iRequestMinSize);
sl@0
   186
	
sl@0
   187
	    iState = EStopped;
sl@0
   188
		iBytesPlayed = 0;
sl@0
   189
	    }
sl@0
   190
sl@0
   191
	return err;
sl@0
   192
	}
sl@0
   193
		
sl@0
   194
TInt RMdaDevSound::CBody::PlayVolume()
sl@0
   195
	{
sl@0
   196
	__ASSERT_DEBUG(iPlaySoundDevice.Handle(), Panic(EDeviceNotOpened));
sl@0
   197
	return iPlaySoundDevice.Volume();	
sl@0
   198
	}
sl@0
   199
	
sl@0
   200
void RMdaDevSound::CBody::SetPlayVolume(TInt aVolume)
sl@0
   201
	{
sl@0
   202
	__ASSERT_DEBUG(iPlaySoundDevice.Handle(), Panic(EDeviceNotOpened));
sl@0
   203
	if(aVolume >=0 && aVolume<=KSoundMaxVolume)
sl@0
   204
		{
sl@0
   205
		iPlaySoundDevice.SetVolume(KLinerToDbConstantLookup[aVolume].iDBValue);
sl@0
   206
		}
sl@0
   207
	}
sl@0
   208
void RMdaDevSound::CBody::SetVolume(TInt aLogarithmicVolume)
sl@0
   209
	{
sl@0
   210
	__ASSERT_DEBUG(iPlaySoundDevice.Handle(), Panic(EDeviceNotOpened));
sl@0
   211
	if(aLogarithmicVolume >= 0 && aLogarithmicVolume <= KSoundMaxVolume)
sl@0
   212
		{
sl@0
   213
		iPlaySoundDevice.SetVolume(aLogarithmicVolume);
sl@0
   214
		}
sl@0
   215
	}
sl@0
   216
	
sl@0
   217
void RMdaDevSound::CBody::CancelPlayData()
sl@0
   218
	{
sl@0
   219
    #ifdef SYMBIAN_SOUNDADAPTER_DEBUG	
sl@0
   220
    RDebug::Printf("RMdaDevSound::CBody::CancelPlayData: state %s", iState.Name());
sl@0
   221
    #endif	
sl@0
   222
	__ASSERT_DEBUG(iPlaySoundDevice.Handle(), Panic(EDeviceNotOpened));
sl@0
   223
sl@0
   224
    // If there is a client request, cancel it
sl@0
   225
    // Must do this before canceling players because otherwise they may just restart!
sl@0
   226
    if(iClientPlayStatus)
sl@0
   227
        {
sl@0
   228
        #ifdef SYMBIAN_SOUNDADAPTER_DEBUG    
sl@0
   229
        RDebug::Printf("msp PlayCancelled complete iClientPlayStatus");
sl@0
   230
		#endif
sl@0
   231
        User::RequestComplete(iClientPlayStatus, KErrCancel); // Call also sets iClientPlayStatus to NULL
sl@0
   232
        }
sl@0
   233
    
sl@0
   234
    // Discard any buffered data
sl@0
   235
    iClientPlayData.Set(0,0);
sl@0
   236
	// Discard any saved trailing data (ie. data saved due driver requiring all requests to be a multiple of iRequestMinSize).
sl@0
   237
	iSavedTrailingData.SetLength(0);
sl@0
   238
sl@0
   239
    // Emulator RSoundSc PDD when running without a soundcard has a major
sl@0
   240
    // issue with cancelling whilst paused. It will not clear the pending
sl@0
   241
    // list (because the timer is not active) and therefore this list will
sl@0
   242
    // later overflow causing hep corruption.
sl@0
   243
    // This means that, for now, we MUST Resume before calling CancelPlayData
sl@0
   244
    // to avoid kernel panics...
sl@0
   245
    
sl@0
   246
    // The device driver will not cancel a request which is in progress...
sl@0
   247
    // So, if we are paused in hw, we must resume before cancelling the
sl@0
   248
    // player otherwise it will hang in CActive::Cancel
sl@0
   249
    if(iState == EPlayingPausedInHw)
sl@0
   250
        {
sl@0
   251
        #ifdef SYMBIAN_SOUNDADAPTER_DEBUG    
sl@0
   252
        RDebug::Printf("msp Resume to avoid hang");
sl@0
   253
        #endif
sl@0
   254
        (void) iPlaySoundDevice.Resume();
sl@0
   255
        }
sl@0
   256
    
sl@0
   257
    // Update state
sl@0
   258
	iState = EStopped;
sl@0
   259
	
sl@0
   260
sl@0
   261
    // The RSoundSc driver will not cancel a request which is in progress (or paused).
sl@0
   262
    // If we just loop across the players, cancelling each individual request and waiting for it to complete,
sl@0
   263
    // several of them will actually play, which is both wrong and time consuming....
sl@0
   264
    // Issue a block cancel upfront to avoid this
sl@0
   265
    iPlaySoundDevice.CancelPlayData();
sl@0
   266
 
sl@0
   267
	// Cancel all players
sl@0
   268
	for (TUint playerIndex=0; playerIndex<KPlaySharedChunkBuffers; ++playerIndex)
sl@0
   269
	    {
sl@0
   270
	    // If the player is active it will call PlayRequestCompleted with aDueToCancelCommand true
sl@0
   271
	    // to update the iFreePlayers and iActivePlayRequestSizes FIFOs.
sl@0
   272
        iPlayers[playerIndex]->Cancel();
sl@0
   273
	    }
sl@0
   274
	
sl@0
   275
	iBufferOffset = -1;
sl@0
   276
	iBufferLength = 0;
sl@0
   277
	
sl@0
   278
	return;
sl@0
   279
	}
sl@0
   280
	
sl@0
   281
TInt RMdaDevSound::CBody::RecordLevel()
sl@0
   282
	{
sl@0
   283
	__ASSERT_DEBUG(iRecordSoundDevice.Handle(), Panic(EDeviceNotOpened));
sl@0
   284
	return iRecordSoundDevice.Volume();
sl@0
   285
	}
sl@0
   286
	
sl@0
   287
void RMdaDevSound::CBody::SetRecordLevel(TInt aLevel)
sl@0
   288
	{
sl@0
   289
	__ASSERT_DEBUG(iRecordSoundDevice.Handle(), Panic(EDeviceNotOpened));
sl@0
   290
	iRecordSoundDevice.SetVolume(aLevel);	
sl@0
   291
	}
sl@0
   292
	
sl@0
   293
void RMdaDevSound::CBody::CancelRecordData()
sl@0
   294
	{
sl@0
   295
	__ASSERT_DEBUG(iRecordSoundDevice.Handle(), Panic(EDeviceNotOpened));
sl@0
   296
    #ifdef SYMBIAN_SOUNDADAPTER_DEBUG	
sl@0
   297
    RDebug::Printf("RMdaDevSound::CBody::CancelRecordData: state %s", iState.Name());
sl@0
   298
    #endif
sl@0
   299
sl@0
   300
    // Stop recorder object (and its request)
sl@0
   301
    iRecorder->Cancel();
sl@0
   302
    
sl@0
   303
    // Stop driver from recording
sl@0
   304
    iRecordSoundDevice.CancelRecordData();
sl@0
   305
             
sl@0
   306
    // If there is a client request, cancel it
sl@0
   307
    if(iClientRecordStatus)
sl@0
   308
   		{
sl@0
   309
        User::RequestComplete(iClientRecordStatus, KErrNone); // Call also sets iClientPlayStatus to NULL
sl@0
   310
        }
sl@0
   311
sl@0
   312
    iState = EStopped;
sl@0
   313
    return;
sl@0
   314
	}
sl@0
   315
	
sl@0
   316
void RMdaDevSound::CBody::FlushRecordBuffer()
sl@0
   317
	{
sl@0
   318
	__ASSERT_DEBUG(iRecordSoundDevice.Handle(), Panic(EDeviceNotOpened));
sl@0
   319
    #ifdef SYMBIAN_SOUNDADAPTER_DEBUG	
sl@0
   320
        RDebug::Print(_L("RMdaDevSound::CBody::FlushRecordBuffer - implemented by calling PauseRecordBuffer"));
sl@0
   321
    #endif
sl@0
   322
sl@0
   323
	PauseRecordBuffer();
sl@0
   324
	}
sl@0
   325
	
sl@0
   326
TInt RMdaDevSound::CBody::BytesPlayed()
sl@0
   327
	{
sl@0
   328
    #ifdef SYMBIAN_SOUNDADAPTER_DEBUG    
sl@0
   329
    RDebug::Printf("RMdaDevSound::BytesPlayed %s", iState.Name());
sl@0
   330
	#endif
sl@0
   331
sl@0
   332
	return I64LOW(BytesPlayed64());
sl@0
   333
	}
sl@0
   334
sl@0
   335
sl@0
   336
TUint64 RMdaDevSound::CBody::BytesPlayed64()
sl@0
   337
	{
sl@0
   338
	__ASSERT_DEBUG(iPlaySoundDevice.Handle(), Panic(EDeviceNotOpened));
sl@0
   339
sl@0
   340
	TUint64 currentBytesPlayed = KMaxTUint64;
sl@0
   341
sl@0
   342
	switch(iState)
sl@0
   343
	{
sl@0
   344
	case ENotReady:
sl@0
   345
		Panic(EDeviceNotOpened);
sl@0
   346
		break;
sl@0
   347
sl@0
   348
	case EStopped:
sl@0
   349
		currentBytesPlayed = iBytesPlayed;
sl@0
   350
		break;
sl@0
   351
sl@0
   352
	case ERecording:
sl@0
   353
	case ERecordingPausedInHw:
sl@0
   354
	case ERecordingPausedInSw:
sl@0
   355
		Panic(EBadState);
sl@0
   356
		break;
sl@0
   357
sl@0
   358
	case EPlayingPausedInHw: // ie. Play request pending on h/w and paused
sl@0
   359
		// Paused, so use pause time
sl@0
   360
        #ifdef SYMBIAN_SOUNDADAPTER_DEBUG    
sl@0
   361
		RDebug::Printf("EPlayingPausedInHw: iPausedBytes %x %x", I64HIGH(iPausedBytesPlayed), I64LOW(iPausedBytesPlayed));
sl@0
   362
		#endif
sl@0
   363
		currentBytesPlayed = iPausedBytesPlayed;
sl@0
   364
		break;
sl@0
   365
sl@0
   366
	case EPlayingPausedInSw: // ie. Driver not playing or paused
sl@0
   367
		#ifdef SYMBIAN_SOUNDADAPTER_DEBUG	 
sl@0
   368
		RDebug::Printf("EPlayingPausedInSw: iPausedBytesPlayed %x %x", I64HIGH(iPausedBytesPlayed), I64LOW(iPausedBytesPlayed));
sl@0
   369
		#endif
sl@0
   370
		currentBytesPlayed = iPausedBytesPlayed;
sl@0
   371
		break;
sl@0
   372
	case EPlayingUnderrun:
sl@0
   373
		#ifdef SYMBIAN_SOUNDADAPTER_DEBUG	 
sl@0
   374
		RDebug::Printf("EPlayingUnderrun: iBytesPlayed %x %x", I64HIGH(iBytesPlayed), I64LOW(iBytesPlayed));
sl@0
   375
		#endif
sl@0
   376
		currentBytesPlayed = iBytesPlayed;
sl@0
   377
	    break;
sl@0
   378
sl@0
   379
	case EPlaying:
sl@0
   380
		{
sl@0
   381
		// Playing so calculate time since last update to iBytesPlayed
sl@0
   382
		TUint32 curTime = CurrentTimeInMsec();
sl@0
   383
		TUint32 curRequestSize = iActivePlayRequestSizes.Peek();
sl@0
   384
sl@0
   385
		TUint32 extraPlayTime = (curTime >= iStartTime) ? (curTime-iStartTime) : (KMaxTUint32 - (iStartTime-curTime));
sl@0
   386
        #ifdef SYMBIAN_SOUNDADAPTER_DEBUG	 
sl@0
   387
		RDebug::Printf("iStartTime %d curTime %d extraPlayTime %d", iStartTime, curTime, extraPlayTime);
sl@0
   388
		
sl@0
   389
		RDebug::Printf("iPlayFormatData.iSampleRate %d KBytesPerSample %d iNTickPeriodInUsec %d",
sl@0
   390
					   iPlayFormatData.iSampleRate, KBytesPerSample, iNTickPeriodInUsec);
sl@0
   391
        #endif
sl@0
   392
		TUint32 extraBytesPlayed = TUint32((TUint64(extraPlayTime) * iPlayFormatData.iSampleRate * iPlayFormatData.iRequestedChannels * KBytesPerSample)/1000);
sl@0
   393
		if(extraBytesPlayed > curRequestSize)
sl@0
   394
			{
sl@0
   395
            #ifdef SYMBIAN_SOUNDADAPTER_DEBUG	 
sl@0
   396
			RDebug::Printf("caping extraBytes played from %d to %d", extraBytesPlayed, curRequestSize);
sl@0
   397
            #endif
sl@0
   398
			extraBytesPlayed = curRequestSize;
sl@0
   399
			}
sl@0
   400
sl@0
   401
		#ifdef SYMBIAN_SOUNDADAPTER_DEBUG
sl@0
   402
		RDebug::Printf("iBytesPlayed %d extraBytesPlayed %d (curRequestSize %d) -> currentBytesPlayed %x %x",
sl@0
   403
                iBytesPlayed, extraBytesPlayed, curRequestSize, I64HIGH(currentBytesPlayed), I64LOW(currentBytesPlayed));
sl@0
   404
        #endif
sl@0
   405
sl@0
   406
		currentBytesPlayed = iBytesPlayed + extraBytesPlayed;
sl@0
   407
		break;
sl@0
   408
		}
sl@0
   409
	
sl@0
   410
	default:
sl@0
   411
		Panic(EBadState);
sl@0
   412
		break;
sl@0
   413
	}
sl@0
   414
 
sl@0
   415
sl@0
   416
    #ifdef SYMBIAN_SOUNDADAPTER_DEBUG
sl@0
   417
	RDebug::Printf("iPlayFormatData.iConverter %x", iPlayFormatData.iConverter);
sl@0
   418
    #endif
sl@0
   419
sl@0
   420
	if (iPlayFormatData.iConverter)
sl@0
   421
		{
sl@0
   422
		// need to scale bytes played to fit with requested rate and channels, not actual
sl@0
   423
		if (iPlayFormatData.iActualChannels != iPlayFormatData.iRequestedChannels)
sl@0
   424
			{
sl@0
   425
			if (iPlayFormatData.iActualChannels == 2)
sl@0
   426
				{
sl@0
   427
				// requested was mono, we have stereo
sl@0
   428
				currentBytesPlayed /= 2;
sl@0
   429
				}
sl@0
   430
			else 
sl@0
   431
				{
sl@0
   432
				// requested was stereo, we have mono
sl@0
   433
				currentBytesPlayed *= 2;
sl@0
   434
				}
sl@0
   435
			}
sl@0
   436
		if (iPlayFormatData.iSampleRate != iPlayFormatData.iActualRate)
sl@0
   437
			{
sl@0
   438
			currentBytesPlayed = TUint64(currentBytesPlayed*
sl@0
   439
					TReal(iPlayFormatData.iSampleRate)/TReal(iPlayFormatData.iActualRate)); // don't round
sl@0
   440
			}
sl@0
   441
		}
sl@0
   442
sl@0
   443
    #ifdef SYMBIAN_SOUNDADAPTER_DEBUG
sl@0
   444
	RDebug::Printf("currentBytesPlayed %x %x", I64HIGH(currentBytesPlayed), I64LOW(currentBytesPlayed));
sl@0
   445
    #endif
sl@0
   446
	return currentBytesPlayed;
sl@0
   447
	}
sl@0
   448
sl@0
   449
void RMdaDevSound::CBody::ResetBytesPlayed()
sl@0
   450
	{
sl@0
   451
    #ifdef SYMBIAN_SOUNDADAPTER_DEBUG    
sl@0
   452
    RDebug::Printf("RMdaDevSound::CBody::ResetBytesPlayed %s", iState.Name());
sl@0
   453
	#endif
sl@0
   454
	__ASSERT_DEBUG(iPlaySoundDevice.Handle(), Panic(EDeviceNotOpened));
sl@0
   455
	iBytesPlayed = 0;
sl@0
   456
	iPlaySoundDevice.ResetBytesTransferred();
sl@0
   457
	return;
sl@0
   458
	}
sl@0
   459
	
sl@0
   460
void RMdaDevSound::CBody::PausePlayBuffer()
sl@0
   461
	{
sl@0
   462
#ifdef SYMBIAN_SOUNDADAPTER_DEBUG   
sl@0
   463
    RDebug::Printf("RMdaDevSound::CBody::PausePlayBuffer %s", iState.Name());
sl@0
   464
#endif  
sl@0
   465
	switch(iState)
sl@0
   466
		{
sl@0
   467
		case ENotReady:
sl@0
   468
			Panic(EDeviceNotOpened);
sl@0
   469
			break;
sl@0
   470
sl@0
   471
		case EStopped:
sl@0
   472
			// Driver is not playing so pause in s/w
sl@0
   473
			break;
sl@0
   474
sl@0
   475
		case ERecording:
sl@0
   476
		case ERecordingPausedInHw:
sl@0
   477
		case ERecordingPausedInSw:
sl@0
   478
			Panic(EBadState);
sl@0
   479
			break;
sl@0
   480
sl@0
   481
		case EPlayingPausedInHw: // ie. Play request pending on h/w and paused
sl@0
   482
		case EPlayingPausedInSw: // ie. Driver not playing or paused
sl@0
   483
			// Already paused so nothing to do.
sl@0
   484
			break;
sl@0
   485
		case EPlayingUnderrun:
sl@0
   486
			iState = EPlayingPausedInSw;
sl@0
   487
			break;
sl@0
   488
			
sl@0
   489
		case EPlaying:
sl@0
   490
			{
sl@0
   491
			iPauseTime = CurrentTimeInMsec();
sl@0
   492
			iPausedBytesPlayed = BytesPlayed64();
sl@0
   493
			TInt res = iPlaySoundDevice.Pause();
sl@0
   494
			#ifdef SYMBIAN_SOUNDADAPTER_DEBUG   
sl@0
   495
			RDebug::Printf("iPlaySoundDevice.Pause res = %d", res);
sl@0
   496
			#endif
sl@0
   497
 			if(res == KErrNone)
sl@0
   498
				{
sl@0
   499
				iState = EPlayingPausedInHw;
sl@0
   500
				}
sl@0
   501
			else
sl@0
   502
				{
sl@0
   503
			    #ifdef SYMBIAN_SOUNDADAPTER_DEBUG    
sl@0
   504
				RDebug::Printf("msp PausePlayBuffer hw pause unexpectedly failed, doing sw pause");
sl@0
   505
				#endif
sl@0
   506
				iState = EPlayingPausedInSw;
sl@0
   507
				}
sl@0
   508
			break;
sl@0
   509
			}
sl@0
   510
		
sl@0
   511
		default:
sl@0
   512
			Panic(EBadState);
sl@0
   513
			break;
sl@0
   514
		}
sl@0
   515
	
sl@0
   516
	return;
sl@0
   517
	}
sl@0
   518
	
sl@0
   519
void RMdaDevSound::CBody::ResumePlaying()
sl@0
   520
	{
sl@0
   521
	#ifdef SYMBIAN_SOUNDADAPTER_DEBUG   
sl@0
   522
	RDebug::Printf("RMdaDevSound::CBody::ResumePlaying %s", iState.Name());
sl@0
   523
	#endif	
sl@0
   524
    __ASSERT_DEBUG(iPlaySoundDevice.Handle(), Panic(EDeviceNotOpened));
sl@0
   525
sl@0
   526
	switch(iState)
sl@0
   527
		{
sl@0
   528
		case ENotReady:
sl@0
   529
			Panic(EDeviceNotOpened);
sl@0
   530
			break;
sl@0
   531
				
sl@0
   532
		case EStopped:
sl@0
   533
			// No change
sl@0
   534
			break;
sl@0
   535
	
sl@0
   536
		case ERecording:
sl@0
   537
		case ERecordingPausedInHw:
sl@0
   538
		case ERecordingPausedInSw:
sl@0
   539
			Panic(EBadState);
sl@0
   540
			break;
sl@0
   541
			
sl@0
   542
		case EPlaying:
sl@0
   543
			// No change
sl@0
   544
			break;
sl@0
   545
sl@0
   546
		case EPlayingPausedInHw: // ie. Play request pending on h/w and paused
sl@0
   547
			{
sl@0
   548
			// Re-enable reporting of KErrUnderflow (will re-raise KErrUnderflow if nothing to start playing).
sl@0
   549
			iUnderFlowReportedSinceLastPlayOrRecordRequest = EFalse;
sl@0
   550
sl@0
   551
			TInt res = iPlaySoundDevice.Resume();
sl@0
   552
#ifdef SYMBIAN_SOUNDADAPTER_DEBUG	
sl@0
   553
			RDebug::Printf("ResumePlayBuffer EPlayingPausedInHw res = %d", res);
sl@0
   554
#endif
sl@0
   555
			if(res == KErrNone)
sl@0
   556
				{
sl@0
   557
				// Resume ok so a pending request will complete
sl@0
   558
				iState = EPlaying;
sl@0
   559
	            // Update iStartTime to allow for time spent paused
sl@0
   560
	            TUint32 curTime = CurrentTimeInMsec();
sl@0
   561
	            TUint32 timePaused = (curTime >= iPauseTime) ? (curTime-iPauseTime) : (KMaxTUint32 - (iPauseTime-curTime));
sl@0
   562
	            iStartTime += timePaused; // nb. It is harmless if this wraps.
sl@0
   563
				}
sl@0
   564
			else
sl@0
   565
				{
sl@0
   566
				// Resume failed, therefore driver is not playing
sl@0
   567
                // No need to update iStartTime/iPauseTime because these are only used within a driver request
sl@0
   568
                // Change state to Stopped
sl@0
   569
                iState = EStopped;
sl@0
   570
                //  Attempt to start a new (pending) request.
sl@0
   571
                StartPlayersAndUpdateState();
sl@0
   572
				}
sl@0
   573
			break;
sl@0
   574
			}
sl@0
   575
		case EPlayingPausedInSw: // ie. Driver not playing/paused
sl@0
   576
			{
sl@0
   577
			// Driver not playing
sl@0
   578
			// Re-enable reporting of KErrUnderflow (will re-raise KErrUnderflow if nothing to start playing).
sl@0
   579
			iUnderFlowReportedSinceLastPlayOrRecordRequest = EFalse;
sl@0
   580
			// No need to update iStartTime/iPauseTime because these are only used within a driver request
sl@0
   581
			// Change state to Stopped
sl@0
   582
            iState = EStopped;
sl@0
   583
            //	Attempt to start a new (pending) request.
sl@0
   584
			StartPlayersAndUpdateState();
sl@0
   585
			break;
sl@0
   586
			}
sl@0
   587
		case EPlayingUnderrun:
sl@0
   588
			break;
sl@0
   589
				
sl@0
   590
		default:
sl@0
   591
			Panic(EBadState);
sl@0
   592
			break;
sl@0
   593
		}
sl@0
   594
	
sl@0
   595
	return;	
sl@0
   596
	}
sl@0
   597
sl@0
   598
void RMdaDevSound::CBody::PauseRecordBuffer()
sl@0
   599
	{
sl@0
   600
    #ifdef SYMBIAN_SOUNDADAPTER_DEBUG   
sl@0
   601
    RDebug::Printf("RMdaDevSound::CBody::PauseRecordBuffer %s", iState.Name());
sl@0
   602
    #endif
sl@0
   603
	
sl@0
   604
	switch(iState)
sl@0
   605
		{
sl@0
   606
		case ENotReady:
sl@0
   607
			Panic(EDeviceNotOpened);
sl@0
   608
			break;
sl@0
   609
			
sl@0
   610
		case EStopped:
sl@0
   611
			// Driver is not recording so pause in s/w
sl@0
   612
		    // Do not pause because that will cause problems when CAudioDevice::Pause calls
sl@0
   613
			break;
sl@0
   614
sl@0
   615
		case ERecording:
sl@0
   616
			{
sl@0
   617
			TInt res = iRecordSoundDevice.Pause();
sl@0
   618
			#ifdef SYMBIAN_SOUNDADAPTER_DEBUG	
sl@0
   619
			RDebug::Printf("PauseRecordBuffer EPlaying res = %d", res);
sl@0
   620
			#endif
sl@0
   621
			if(res == KErrNone)
sl@0
   622
				{
sl@0
   623
				iState = ERecordingPausedInHw;
sl@0
   624
				}
sl@0
   625
			else
sl@0
   626
				{
sl@0
   627
				#ifdef SYMBIAN_SOUNDADAPTER_DEBUG	
sl@0
   628
				RDebug::Printf("PauseRecordBuffer hw pause unexpectedly failed, doing sw pause");
sl@0
   629
				#endif
sl@0
   630
				iState = ERecordingPausedInSw;
sl@0
   631
				}
sl@0
   632
			break;
sl@0
   633
			}
sl@0
   634
		
sl@0
   635
		case ERecordingPausedInHw:
sl@0
   636
		case ERecordingPausedInSw:
sl@0
   637
			// Already paused so nothing to do.
sl@0
   638
			break;
sl@0
   639
			
sl@0
   640
		case EPlaying:
sl@0
   641
		case EPlayingPausedInHw: // ie. Play request pending on h/w and paused
sl@0
   642
            Panic(EBadState);
sl@0
   643
            break;
sl@0
   644
		    
sl@0
   645
		case EPlayingPausedInSw: 
sl@0
   646
		    // This is an ugly hack to maintain compatibility with CAudioDevice::Pause which
sl@0
   647
		    // calls both PausePlayBuffer and PauseRecordBuffer whilst in stopped, then later calls ResumePlaying
sl@0
   648
		    break;
sl@0
   649
		case EPlayingUnderrun: // ie. Play request pending on h/w and paused
sl@0
   650
			Panic(EBadState);
sl@0
   651
		    break;
sl@0
   652
		    
sl@0
   653
		default:
sl@0
   654
			Panic(EBadState);
sl@0
   655
			break;
sl@0
   656
		}
sl@0
   657
sl@0
   658
	return;	
sl@0
   659
	}
sl@0
   660
sl@0
   661
void RMdaDevSound::CBody::ResumeRecording()
sl@0
   662
	{
sl@0
   663
    #ifdef SYMBIAN_SOUNDADAPTER_DEBUG   
sl@0
   664
    RDebug::Printf("RMdaDevSound::CBody::ResumeRecording %s", iState.Name());
sl@0
   665
    #endif
sl@0
   666
	__ASSERT_DEBUG(iPlaySoundDevice.Handle(), Panic(EDeviceNotOpened));
sl@0
   667
sl@0
   668
	switch(iState)
sl@0
   669
		{
sl@0
   670
		case ENotReady:
sl@0
   671
			Panic(EDeviceNotOpened);
sl@0
   672
			break;
sl@0
   673
				
sl@0
   674
		case EStopped:
sl@0
   675
			// No change
sl@0
   676
			break;
sl@0
   677
	
sl@0
   678
		case ERecording:
sl@0
   679
			// No change
sl@0
   680
			break;
sl@0
   681
sl@0
   682
		case ERecordingPausedInHw:
sl@0
   683
			{
sl@0
   684
			TInt res = iRecordSoundDevice.Resume();
sl@0
   685
			#ifdef SYMBIAN_SOUNDADAPTER_DEBUG	
sl@0
   686
			RDebug::Printf("ResumeRecordBuffer ERecordingPausedInHw res = %d", res);
sl@0
   687
			#endif
sl@0
   688
			if(res == KErrNone)
sl@0
   689
				{
sl@0
   690
				// Resume ok so a pending request will complete
sl@0
   691
				iState = ERecording;
sl@0
   692
				}
sl@0
   693
			else
sl@0
   694
				{
sl@0
   695
				iState = EStopped;
sl@0
   696
				// Resume failed, so attempt to start a new (pending) request.
sl@0
   697
				// If this works, it will update the state to ERecording.
sl@0
   698
				StartRecordRequest();
sl@0
   699
				}
sl@0
   700
			break;
sl@0
   701
			}
sl@0
   702
		case ERecordingPausedInSw:
sl@0
   703
			{
sl@0
   704
			// Update state to stopped and attempt to start any pending request
sl@0
   705
			iState = EStopped;
sl@0
   706
			// If this works, it will update the state to ERecording.
sl@0
   707
			StartRecordRequest();
sl@0
   708
			break;
sl@0
   709
			}
sl@0
   710
sl@0
   711
		case EPlaying:
sl@0
   712
		case EPlayingPausedInHw: // ie. Play request pending on h/w and paused
sl@0
   713
		case EPlayingPausedInSw: // ie. Driver not playing/paused
sl@0
   714
		case EPlayingUnderrun:
sl@0
   715
		default:
sl@0
   716
			Panic(EBadState);
sl@0
   717
			break;
sl@0
   718
		}
sl@0
   719
		
sl@0
   720
		return; 
sl@0
   721
sl@0
   722
sl@0
   723
	}
sl@0
   724
sl@0
   725
TInt RMdaDevSound::CBody::GetTimePlayed(TTimeIntervalMicroSeconds& aTimePlayed)
sl@0
   726
	{
sl@0
   727
	__ASSERT_DEBUG(iPlaySoundDevice.Handle(), Panic(EDeviceNotOpened));
sl@0
   728
sl@0
   729
sl@0
   730
	TUint64 bytesPlayed = BytesPlayed64();
sl@0
   731
sl@0
   732
	TUint64 timePlayed = 1000 * 1000 * bytesPlayed / (iPlayFormatData.iSampleRate * iPlayFormatData.iRequestedChannels * KBytesPerSample);
sl@0
   733
sl@0
   734
	aTimePlayed = TTimeIntervalMicroSeconds(timePlayed);
sl@0
   735
sl@0
   736
	return KErrNone;
sl@0
   737
	}
sl@0
   738
sl@0
   739
	
sl@0
   740
void RMdaDevSound::CBody::FormatsSupported(TSoundFormatsSupportedBuf& aFormatsSupported, RSoundSc& aSoundDevice)
sl@0
   741
	{
sl@0
   742
	TSoundFormatsSupportedV02Buf supportedFormat;
sl@0
   743
	aSoundDevice.Caps(supportedFormat);
sl@0
   744
	TUint32 rates = supportedFormat().iRates;
sl@0
   745
	
sl@0
   746
	for(TInt i = KNumSampleRates-1; i > 0 ;i--)//min to max
sl@0
   747
		{
sl@0
   748
		if(rates & KRateEnumLookup[i].iRateConstant)
sl@0
   749
			{
sl@0
   750
			aFormatsSupported().iMinRate = KRateEnumLookup[i].iRate;
sl@0
   751
			break;
sl@0
   752
			}
sl@0
   753
		}
sl@0
   754
	for(TInt i = 0; i < KNumSampleRates; i++)//max to min
sl@0
   755
		{
sl@0
   756
		if(rates & KRateEnumLookup[i].iRateConstant)
sl@0
   757
			{
sl@0
   758
			aFormatsSupported().iMaxRate = KRateEnumLookup[i].iRate;
sl@0
   759
			break;
sl@0
   760
			}
sl@0
   761
		}
sl@0
   762
	TUint32 enc = supportedFormat().iEncodings;
sl@0
   763
	
sl@0
   764
	if (enc & KSoundEncoding16BitPCM)
sl@0
   765
		{
sl@0
   766
		aFormatsSupported().iEncodings = EMdaSoundEncoding16BitPCM;// Always defaults to this
sl@0
   767
		}
sl@0
   768
	if (enc & KSoundEncoding8BitPCM)
sl@0
   769
		{
sl@0
   770
		aFormatsSupported().iEncodings |= EMdaSoundEncoding8BitPCM;
sl@0
   771
		}
sl@0
   772
	TUint32 channels = supportedFormat().iChannels;
sl@0
   773
	
sl@0
   774
	if (channels & KSoundStereoChannel)
sl@0
   775
		{
sl@0
   776
		aFormatsSupported().iChannels = 2;
sl@0
   777
		}
sl@0
   778
	else
sl@0
   779
		{
sl@0
   780
		aFormatsSupported().iChannels = 1;
sl@0
   781
		}
sl@0
   782
	aFormatsSupported().iMinBufferSize = supportedFormat().iRequestMinSize;
sl@0
   783
	aFormatsSupported().iMaxBufferSize = KMaxBufferSize;
sl@0
   784
	aFormatsSupported().iMinVolume = 0;
sl@0
   785
	aFormatsSupported().iMaxVolume = KSoundMaxVolume;
sl@0
   786
	}
sl@0
   787
	
sl@0
   788
void RMdaDevSound::CBody::GetFormat(TCurrentSoundFormatBuf& aFormat, 
sl@0
   789
									RSoundSc& /*aSoundDevice*/,
sl@0
   790
									const TFormatData &aFormatData)
sl@0
   791
	{
sl@0
   792
	// always return the requested, or the initial, not current device setting
sl@0
   793
	aFormat().iChannels = aFormatData.iRequestedChannels; // never clear if this is bitmap or value, but effectively the same
sl@0
   794
	aFormat().iRate = aFormatData.iSampleRate;
sl@0
   795
	}
sl@0
   796
	
sl@0
   797
void RMdaDevSound::CBody::StartPlayersAndUpdateState()
sl@0
   798
	{
sl@0
   799
	__ASSERT_DEBUG(iPlaySoundDevice.Handle(), Panic(EDeviceNotOpened));
sl@0
   800
sl@0
   801
	switch(iState)
sl@0
   802
		{
sl@0
   803
		case ENotReady:
sl@0
   804
			Panic(EDeviceNotOpened);
sl@0
   805
			break;
sl@0
   806
				
sl@0
   807
		case EStopped:
sl@0
   808
 			// Allow following code to queue more driver play requests and check for stopped
sl@0
   809
			break;
sl@0
   810
	
sl@0
   811
		case ERecording:
sl@0
   812
		case ERecordingPausedInHw:
sl@0
   813
		case ERecordingPausedInSw:
sl@0
   814
			Panic(EBadState);
sl@0
   815
			break;
sl@0
   816
			
sl@0
   817
		case EPlaying:
sl@0
   818
           // Allow following code to queue more driver play requests  and check for stopped
sl@0
   819
		    break;
sl@0
   820
		case EPlayingPausedInHw: // ie. Play request pending on h/w and paused
sl@0
   821
			// Allow following code to queue more driver play requests
sl@0
   822
			break;
sl@0
   823
		
sl@0
   824
		case EPlayingPausedInSw:
sl@0
   825
			// Paused but driver not playing+paused, therefore do not queue new requests until ResumePlaying
sl@0
   826
			return;
sl@0
   827
		case EPlayingUnderrun:
sl@0
   828
			break;
sl@0
   829
				
sl@0
   830
		default:
sl@0
   831
			Panic(EBadState);
sl@0
   832
			break;
sl@0
   833
		}
sl@0
   834
sl@0
   835
	// iState is now either EStopped, EPlaying or EPlayingPausedInHw
sl@0
   836
    __ASSERT_DEBUG(((iState == EStopped) || (iState == EPlaying) || (iState == EPlayingPausedInHw) || (iState == EPlayingUnderrun)), Panic(EBadState));
sl@0
   837
sl@0
   838
	while( (iClientPlayData.Length() != 0) && (! iFreePlayers.IsEmpty()))
sl@0
   839
		{
sl@0
   840
		// More data to play and more players,  so issue another request 
sl@0
   841
sl@0
   842
		bool wasIdle = iFreePlayers.IsFull();
sl@0
   843
		// Get a free player		
sl@0
   844
		CPlayer *player = iFreePlayers.Pop();
sl@0
   845
		// Calculate length of request
sl@0
   846
		TUint32 lengthToPlay = iClientPlayData.Length();
sl@0
   847
		if(lengthToPlay > iDeviceBufferLength)
sl@0
   848
		    {
sl@0
   849
            lengthToPlay = iDeviceBufferLength;
sl@0
   850
		    }
sl@0
   851
sl@0
   852
		// Remember request length, so we can update bytes played when it finishes
sl@0
   853
		iActivePlayRequestSizes.Push(lengthToPlay);
sl@0
   854
sl@0
   855
		// Find offset to copy data to
sl@0
   856
		TUint playerIndex = player->GetPlayerIndex();
sl@0
   857
		ASSERT(playerIndex < KPlaySharedChunkBuffers);
sl@0
   858
		TUint chunkOffset = iPlayBufferConfig.iBufferOffsetList[playerIndex];
sl@0
   859
sl@0
   860
		// Copy data
sl@0
   861
		TPtr8 destPtr(iPlayChunk.Base()+ chunkOffset, 0, iDeviceBufferLength);
sl@0
   862
		destPtr.Copy(iClientPlayData.Mid(0, lengthToPlay));
sl@0
   863
sl@0
   864
		// Update iClientPlayData to remove the data just queued
sl@0
   865
		iClientPlayData.Set(iClientPlayData.Right(iClientPlayData.Length()-lengthToPlay));
sl@0
   866
sl@0
   867
		// Start the CPlayer
sl@0
   868
		player->PlayData(chunkOffset, lengthToPlay);
sl@0
   869
		if(wasIdle)
sl@0
   870
			{
sl@0
   871
			iState = EPlaying;
sl@0
   872
			iStartTime = CurrentTimeInMsec();
sl@0
   873
			
sl@0
   874
			}
sl@0
   875
		
sl@0
   876
		}
sl@0
   877
sl@0
   878
	// Check if the client request is now complete
sl@0
   879
	if(iClientPlayData.Length() == 0 && iClientPlayStatus)
sl@0
   880
		{
sl@0
   881
		// We have queued all the client play data to the driver so we can now complete the client request.
sl@0
   882
		// If actual playback fails, we will notify the client via the Play Error notification mechanism.
sl@0
   883
		#ifdef SYMBIAN_SOUNDADAPTER_DEBUG	
sl@0
   884
		RDebug::Printf("RMdaDevSound::CBody::StartPlayersAndUpdateState completing client request");
sl@0
   885
		#endif
sl@0
   886
		User::RequestComplete(iClientPlayStatus, KErrNone); // This call also sets iClientPlayStatus to NULL
sl@0
   887
		}
sl@0
   888
	
sl@0
   889
    //nb. iState is now either EStopped, EPlaying or EPlayingPausedInHw (see previous switch and assert)
sl@0
   890
	if(iState != EPlayingPausedInHw)
sl@0
   891
	    {
sl@0
   892
        if(iFreePlayers.IsFull())
sl@0
   893
            {
sl@0
   894
            // Free fifo is full, therefore there are no active players
sl@0
   895
            iState = EPlayingUnderrun;
sl@0
   896
			if(! iUnderFlowReportedSinceLastPlayOrRecordRequest)
sl@0
   897
				{
sl@0
   898
				// We report KErrUnderflow if we have not already reported it since the last PlayData call.
sl@0
   899
				// Note that 
sl@0
   900
				// i) We do NOT report driver underflows.
sl@0
   901
				// ii) We report underflow when we run out of data to pass to the driver.
sl@0
   902
				// iii) We throttle this reporting
sl@0
   903
				// iv) We WILL report KErrUnderflow if already stopped and asked to play a zero length buffer
sl@0
   904
				// The last point is required because the client maps a manual stop command into a devsound play with a 
sl@0
   905
				// zero length buffer and the last buffer flag set, this in turn is mapped to a Playdata calll with an empty buffer
sl@0
   906
				// which is expected to complete ok and cause a KErrUnderflow error to be reported...
sl@0
   907
				iUnderFlowReportedSinceLastPlayOrRecordRequest = ETrue;
sl@0
   908
				#ifdef SYMBIAN_SOUNDADAPTER_DEBUG	
sl@0
   909
		        RDebug::Printf("RMdaDevSound::CBody::StartPlayersAndUpdateState stopped and iUnderFlowReportedSinceLastPlayOrRecordRequest false so raising KErrUnderflow");
sl@0
   910
				#endif
sl@0
   911
				
sl@0
   912
				// Discard any saved trailing data (ie. data saved due driver requiring all requests to be a multiple of iRequestMinSize).
sl@0
   913
				// This maybe because client is delibrately letting us underflow to play silence. In that case we do not want to
sl@0
   914
				// play the trailing data at the beginning of the new data issued after the silence...
sl@0
   915
				iSavedTrailingData.SetLength(0);
sl@0
   916
sl@0
   917
				SoundDeviceError(KErrUnderflow);
sl@0
   918
				}
sl@0
   919
            }
sl@0
   920
        else
sl@0
   921
            {
sl@0
   922
            // Free fifo not full, therefore there are active players
sl@0
   923
            iState = EPlaying;
sl@0
   924
            }
sl@0
   925
	    }
sl@0
   926
	return;
sl@0
   927
	}
sl@0
   928
sl@0
   929
TInt RMdaDevSound::CBody::SetFormat(const TCurrentSoundFormatBuf& aFormat, 
sl@0
   930
									RSoundSc& aSoundDevice,
sl@0
   931
									TFormatData &aFormatData)
sl@0
   932
	{
sl@0
   933
	TInt err = KErrNotFound;
sl@0
   934
	TCurrentSoundFormatV02Buf formatBuf;
sl@0
   935
	
sl@0
   936
	delete aFormatData.iConverter; 
sl@0
   937
	aFormatData.iConverter = NULL; // setting this to NULL indicates we are not using converter. No other flag
sl@0
   938
	iConvertedPlayData.Close();
sl@0
   939
	
sl@0
   940
	TInt wantedRate = aFormat().iRate;
sl@0
   941
	for(TInt index = 0; index < KNumSampleRates; index++ )
sl@0
   942
		{
sl@0
   943
		if(wantedRate == KRateEnumLookup[index].iRate)
sl@0
   944
			{
sl@0
   945
			formatBuf().iRate = KRateEnumLookup[index].iRateEnum;
sl@0
   946
			aFormatData.iSampleRate = wantedRate;
sl@0
   947
			err = KErrNone;
sl@0
   948
			break;
sl@0
   949
			}
sl@0
   950
		}
sl@0
   951
	
sl@0
   952
	if(err == KErrNone)
sl@0
   953
		{
sl@0
   954
		// Assume, for now, we support the requested channels and rate
sl@0
   955
		aFormatData.iActualChannels = aFormatData.iRequestedChannels;
sl@0
   956
		aFormatData.iActualRate = aFormatData.iSampleRate;
sl@0
   957
sl@0
   958
		// Attempt to configure driver
sl@0
   959
		formatBuf().iChannels = aFormat().iChannels;
sl@0
   960
		formatBuf().iEncoding = ESoundEncoding16BitPCM;
sl@0
   961
		formatBuf().iDataFormat = ESoundDataFormatInterleaved;
sl@0
   962
		err = aSoundDevice.SetAudioFormat(formatBuf);
sl@0
   963
        #if defined(SYMBIAN_SOUNDADAPTER_FORCECDRATES) || defined (SYMBIAN_SOUNDADAPTER_FORCESTEREO)
sl@0
   964
            err = KErrNotSupported; // force Negotiate - for debugging
sl@0
   965
        #endif
sl@0
   966
		if (err==KErrNotSupported)
sl@0
   967
			{
sl@0
   968
			// don't support directly. Perhaps can rate convert?
sl@0
   969
			err = NegotiateFormat(aFormat, aSoundDevice, aFormatData);
sl@0
   970
			}
sl@0
   971
		}
sl@0
   972
	return err;	
sl@0
   973
	}
sl@0
   974
	
sl@0
   975
TInt RMdaDevSound::CBody::NegotiateFormat(const TCurrentSoundFormatBuf& aFormat, 
sl@0
   976
										  RSoundSc& aSoundDevice, 
sl@0
   977
										  TFormatData &aFormatData)
sl@0
   978
	{
sl@0
   979
	ASSERT(!aFormatData.iConverter); // we don't clear on fail - so assuming NULL to start with
sl@0
   980
	
sl@0
   981
	TInt err = KErrNotFound;
sl@0
   982
	TCurrentSoundFormatV02Buf formatBuf;
sl@0
   983
sl@0
   984
	// find out first what the driver supports
sl@0
   985
	TSoundFormatsSupportedV02Buf supportedFormat;
sl@0
   986
	aSoundDevice.Caps(supportedFormat);
sl@0
   987
	TUint32 supportedRates = supportedFormat().iRates;
sl@0
   988
    #ifdef SYMBIAN_SOUNDADAPTER_FORCECDRATES
sl@0
   989
        supportedRates &= KSoundRate11025Hz| KSoundRate22050Hz | KSoundRate44100Hz; // only use CD rates - for debugging
sl@0
   990
    #endif
sl@0
   991
	
sl@0
   992
	// For PlayCase:
sl@0
   993
	// 		first try to find the first rate below or equal to the requested that is supported
sl@0
   994
	// 		initially go down and be fussy, but if we pass the requested rate find the first that
sl@0
   995
	// 		is supported
sl@0
   996
	// For RecordCase:
sl@0
   997
	//		We want the next rate above consistently - we go down from this to the requested rate.
sl@0
   998
	//		If there is one, we don't support - we _never_ upsample.
sl@0
   999
	// note that the table is given in descending order, so we start with the highest
sl@0
  1000
	TInt wantedRate = aFormat().iRate;
sl@0
  1001
	TInt takeTheFirst = EFalse;
sl@0
  1002
	TInt nextUpValidIndex = -1;
sl@0
  1003
	for(TInt index = 0; index < KNumSampleRates; index++ )
sl@0
  1004
		{
sl@0
  1005
		TBool lookingAtRequestedRate = wantedRate == KRateEnumLookup[index].iRate;
sl@0
  1006
		TSoundRate wantedEnum = KRateEnumLookup[index].iRateEnum;
sl@0
  1007
		TUint32 equivBitmap = KRateEnumLookup[index].iRateConstant;
sl@0
  1008
		TBool isSupported = (equivBitmap & supportedRates) != EFalse;
sl@0
  1009
		if (lookingAtRequestedRate || takeTheFirst)
sl@0
  1010
			{
sl@0
  1011
			if (isSupported)
sl@0
  1012
				{
sl@0
  1013
				// this rate is supported
sl@0
  1014
				formatBuf().iRate = wantedEnum;
sl@0
  1015
				aFormatData.iActualRate = KRateEnumLookup[index].iRate;
sl@0
  1016
				err = KErrNone;
sl@0
  1017
				break;				
sl@0
  1018
				}
sl@0
  1019
			}
sl@0
  1020
		else if (!takeTheFirst)
sl@0
  1021
			{
sl@0
  1022
			// while we are still looking for the rate, want to cache any supported index
sl@0
  1023
			// at end of loop, this will be the first rate above ours that is supported
sl@0
  1024
			// use for fallback if required
sl@0
  1025
			if (isSupported)
sl@0
  1026
				{
sl@0
  1027
				nextUpValidIndex = index;
sl@0
  1028
				}
sl@0
  1029
			}
sl@0
  1030
		if (lookingAtRequestedRate)
sl@0
  1031
			{
sl@0
  1032
			// if we get this far we've gone passed the wanted rate. For play we enable
sl@0
  1033
			// "takeTheFirst". For record we just abort.
sl@0
  1034
			if (&aSoundDevice==&iPlaySoundDevice)
sl@0
  1035
				{
sl@0
  1036
				takeTheFirst = ETrue;
sl@0
  1037
				}
sl@0
  1038
			else
sl@0
  1039
				{
sl@0
  1040
				break;
sl@0
  1041
				}
sl@0
  1042
			}
sl@0
  1043
		}
sl@0
  1044
		
sl@0
  1045
	if (err)
sl@0
  1046
		{
sl@0
  1047
		// if there is one above the requested rate, use that
sl@0
  1048
		if (nextUpValidIndex>=0)
sl@0
  1049
			{
sl@0
  1050
			TSoundRate wantedEnum = KRateEnumLookup[nextUpValidIndex].iRateEnum;
sl@0
  1051
			formatBuf().iRate = wantedEnum;
sl@0
  1052
			aFormatData.iActualRate = KRateEnumLookup[nextUpValidIndex].iRate;
sl@0
  1053
			err = KErrNone;		
sl@0
  1054
			}
sl@0
  1055
		}
sl@0
  1056
		
sl@0
  1057
	if (err)
sl@0
  1058
		{
sl@0
  1059
		// should have something!
sl@0
  1060
		return err;
sl@0
  1061
		}
sl@0
  1062
		
sl@0
  1063
	aFormatData.iSampleRate = wantedRate; // iSampleRate is our requested/apparent rate, not the device rate.
sl@0
  1064
	
sl@0
  1065
	TUint32 channelsSupported = supportedFormat().iChannels;
sl@0
  1066
    #ifdef SYMBIAN_SOUNDADAPTER_FORCESTEREO
sl@0
  1067
        channelsSupported &= KSoundStereoChannel; // don't use mono - for debugging
sl@0
  1068
    #endif
sl@0
  1069
	if(KSoundAdapterForceStereo==1)
sl@0
  1070
	    {
sl@0
  1071
	    channelsSupported &= KSoundStereoChannel;
sl@0
  1072
#ifdef SYMBIAN_SOUNDADAPTER_DEBUG
sl@0
  1073
	    RDebug::Print(_L("Added stereo support."));
sl@0
  1074
#endif
sl@0
  1075
	    }
sl@0
  1076
	if (aFormat().iChannels == 1)
sl@0
  1077
		{
sl@0
  1078
		aFormatData.iRequestedChannels = 1;
sl@0
  1079
		// want mono
sl@0
  1080
		if (channelsSupported & KSoundMonoChannel)
sl@0
  1081
			{
sl@0
  1082
			// mono is supported, as usual
sl@0
  1083
			aFormatData.iActualChannels = 1;
sl@0
  1084
			}
sl@0
  1085
		else if (channelsSupported & KSoundStereoChannel)
sl@0
  1086
			{
sl@0
  1087
			aFormatData.iActualChannels = 2;
sl@0
  1088
			}
sl@0
  1089
		else
sl@0
  1090
			{
sl@0
  1091
			return KErrNotSupported; // should not get this far for real
sl@0
  1092
			}
sl@0
  1093
		}
sl@0
  1094
	else if (aFormat().iChannels == 2)
sl@0
  1095
		{
sl@0
  1096
		aFormatData.iRequestedChannels = 2;
sl@0
  1097
		// want stereo
sl@0
  1098
		if (channelsSupported & KSoundStereoChannel)
sl@0
  1099
			{
sl@0
  1100
			// stereo is supported, as usual
sl@0
  1101
			aFormatData.iActualChannels = 2;
sl@0
  1102
			}
sl@0
  1103
		else if (channelsSupported & KSoundMonoChannel)
sl@0
  1104
			{
sl@0
  1105
			aFormatData.iActualChannels = 1;
sl@0
  1106
			}
sl@0
  1107
		else
sl@0
  1108
			{
sl@0
  1109
			return KErrNotSupported; // should not get this far for real
sl@0
  1110
			}
sl@0
  1111
		}
sl@0
  1112
	else
sl@0
  1113
		{
sl@0
  1114
		return KErrNotSupported; // unknown number of channels requested!
sl@0
  1115
		}
sl@0
  1116
	
sl@0
  1117
	formatBuf().iChannels = aFormatData.iActualChannels;
sl@0
  1118
	
sl@0
  1119
	formatBuf().iEncoding = ESoundEncoding16BitPCM;
sl@0
  1120
	formatBuf().iDataFormat = ESoundDataFormatInterleaved;
sl@0
  1121
	err = aSoundDevice.SetAudioFormat(formatBuf);
sl@0
  1122
	
sl@0
  1123
	if (!err)
sl@0
  1124
		{
sl@0
  1125
		ASSERT(!aFormatData.iConverter); // pre-condition at top of function anyway
sl@0
  1126
		if (&aSoundDevice==&iPlaySoundDevice)
sl@0
  1127
			{
sl@0
  1128
            #ifdef SYMBIAN_SOUNDADAPTER_DEBUG
sl@0
  1129
                RDebug::Print(_L("RMdaDevSound::CBody::NegotiateFormat: Convert:CreateL from %d/%d to %d/%d"), 
sl@0
  1130
                            aFormatData.iSampleRate, aFormatData.iRequestedChannels, 
sl@0
  1131
                            aFormatData.iActualRate, aFormatData.iActualChannels);
sl@0
  1132
            #endif																	       
sl@0
  1133
			// when playing we convert from requested to actual
sl@0
  1134
			TRAP(err, aFormatData.iConverter = CChannelAndSampleRateConverter::CreateL(aFormatData.iSampleRate, 
sl@0
  1135
																		   aFormatData.iRequestedChannels, 
sl@0
  1136
																	       aFormatData.iActualRate, 
sl@0
  1137
																	       aFormatData.iActualChannels));
sl@0
  1138
			}
sl@0
  1139
		else
sl@0
  1140
			{
sl@0
  1141
			// when recording we convert from actual to requested
sl@0
  1142
			TInt outputRateToUse = aFormatData.iSampleRate;
sl@0
  1143
            #ifdef SYMBIAN_SKIP_RESAMPLE_ON_RECORD
sl@0
  1144
                // with this macro just channel convert at most
sl@0
  1145
                outputRateToUse = aFormatData.iActualRate;
sl@0
  1146
            #endif
sl@0
  1147
            #ifdef SYMBIAN_SOUNDADAPTER_DEBUG
sl@0
  1148
                RDebug::Print(_L("RMdaDevSound::CBody::NegotiateFormat: Convert:CreateL from %d/%d to %d/%d"), 
sl@0
  1149
                            aFormatData.iActualRate, aFormatData.iActualChannels,
sl@0
  1150
                            aFormatData.iSampleRate, aFormatData.iRequestedChannels); 
sl@0
  1151
            #endif																	       
sl@0
  1152
			TRAP(err, aFormatData.iConverter = CChannelAndSampleRateConverter::CreateL(aFormatData.iActualRate, 
sl@0
  1153
																	       aFormatData.iActualChannels,
sl@0
  1154
																	       outputRateToUse, 
sl@0
  1155
																		   aFormatData.iRequestedChannels));
sl@0
  1156
			}
sl@0
  1157
		}
sl@0
  1158
	if(err != KErrNone)
sl@0
  1159
		{
sl@0
  1160
		delete aFormatData.iConverter;
sl@0
  1161
		aFormatData.iConverter= NULL;
sl@0
  1162
		iConvertedPlayData.Close();
sl@0
  1163
		}
sl@0
  1164
	
sl@0
  1165
	return err;
sl@0
  1166
	}
sl@0
  1167
sl@0
  1168
void RMdaDevSound::CBody::StartRecordRequest()
sl@0
  1169
	{
sl@0
  1170
	__ASSERT_DEBUG(iRecordSoundDevice.Handle(), Panic(EDeviceNotOpened));
sl@0
  1171
	
sl@0
  1172
	iRecorder->RecordData(iBufferLength);
sl@0
  1173
	}
sl@0
  1174
sl@0
  1175
// Note both InRecordMode and InPlayMode return EFalse for ENotReady and EStopped
sl@0
  1176
TBool RMdaDevSound::CBody::InRecordMode()const
sl@0
  1177
	{
sl@0
  1178
	switch(iState)
sl@0
  1179
		{
sl@0
  1180
		case ENotReady:
sl@0
  1181
		case EStopped:
sl@0
  1182
			return EFalse;
sl@0
  1183
			
sl@0
  1184
		case ERecording:
sl@0
  1185
		case ERecordingPausedInHw:
sl@0
  1186
		case ERecordingPausedInSw:
sl@0
  1187
			return ETrue;
sl@0
  1188
			
sl@0
  1189
		case EPlaying:
sl@0
  1190
		case EPlayingPausedInHw: 
sl@0
  1191
		case EPlayingPausedInSw:
sl@0
  1192
		case EPlayingUnderrun:
sl@0
  1193
			return EFalse;
sl@0
  1194
			
sl@0
  1195
		default:
sl@0
  1196
			Panic(EBadState);
sl@0
  1197
			break;
sl@0
  1198
		}
sl@0
  1199
	return EFalse;
sl@0
  1200
	}
sl@0
  1201
sl@0
  1202
TBool RMdaDevSound::CBody::InPlayMode() const
sl@0
  1203
	{
sl@0
  1204
	switch(iState)
sl@0
  1205
		{
sl@0
  1206
		case ENotReady:
sl@0
  1207
		case EStopped:
sl@0
  1208
			return EFalse;
sl@0
  1209
			
sl@0
  1210
		case ERecording:
sl@0
  1211
		case ERecordingPausedInHw:
sl@0
  1212
		case ERecordingPausedInSw:
sl@0
  1213
			return EFalse;
sl@0
  1214
			
sl@0
  1215
		case EPlaying:
sl@0
  1216
		case EPlayingPausedInHw: 
sl@0
  1217
		case EPlayingPausedInSw:
sl@0
  1218
		case EPlayingUnderrun:
sl@0
  1219
			return ETrue;
sl@0
  1220
			
sl@0
  1221
		default:
sl@0
  1222
			Panic(EBadState);
sl@0
  1223
			break;
sl@0
  1224
		}
sl@0
  1225
	
sl@0
  1226
	return EFalse;
sl@0
  1227
	}
sl@0
  1228
sl@0
  1229
sl@0
  1230
TUint32 RMdaDevSound::CBody::CurrentTimeInMsec() const
sl@0
  1231
	{
sl@0
  1232
	TUint64 tmp = User::NTickCount();
sl@0
  1233
	tmp *= iNTickPeriodInUsec;
sl@0
  1234
	tmp /= 1000;
sl@0
  1235
	return TUint32(tmp);
sl@0
  1236
	}
sl@0
  1237
sl@0
  1238
void RMdaDevSound::CBody::PlayFormatsSupported(TSoundFormatsSupportedBuf& aFormatsSupported)
sl@0
  1239
	{
sl@0
  1240
	__ASSERT_DEBUG(iPlaySoundDevice.Handle(), Panic(EDeviceNotOpened));
sl@0
  1241
	FormatsSupported(aFormatsSupported, iPlaySoundDevice);
sl@0
  1242
	}
sl@0
  1243
	
sl@0
  1244
void RMdaDevSound::CBody::GetPlayFormat(TCurrentSoundFormatBuf& aFormat)
sl@0
  1245
	{
sl@0
  1246
	__ASSERT_DEBUG(iPlaySoundDevice.Handle(), Panic(EDeviceNotOpened));
sl@0
  1247
	GetFormat(aFormat, iPlaySoundDevice, iPlayFormatData);
sl@0
  1248
	}
sl@0
  1249
	
sl@0
  1250
TInt RMdaDevSound::CBody::SetPlayFormat(const TCurrentSoundFormatBuf& aFormat)
sl@0
  1251
	{
sl@0
  1252
	__ASSERT_DEBUG(iPlaySoundDevice.Handle(), Panic(EDeviceNotOpened));
sl@0
  1253
	return SetFormat(aFormat, iPlaySoundDevice, iPlayFormatData);
sl@0
  1254
	}
sl@0
  1255
sl@0
  1256
void RMdaDevSound::CBody::RecordFormatsSupported(TSoundFormatsSupportedBuf& aFormatsSupported)
sl@0
  1257
	{
sl@0
  1258
	__ASSERT_DEBUG(iRecordSoundDevice.Handle(), Panic(EDeviceNotOpened));
sl@0
  1259
	FormatsSupported(aFormatsSupported, iRecordSoundDevice);
sl@0
  1260
	}
sl@0
  1261
sl@0
  1262
void RMdaDevSound::CBody::GetRecordFormat(TCurrentSoundFormatBuf& aFormat)
sl@0
  1263
	{
sl@0
  1264
	__ASSERT_DEBUG(iRecordSoundDevice.Handle(), Panic(EDeviceNotOpened));
sl@0
  1265
	GetFormat(aFormat, iRecordSoundDevice, iRecordFormatData);	
sl@0
  1266
	}
sl@0
  1267
sl@0
  1268
TInt RMdaDevSound::CBody::SetRecordFormat(const TCurrentSoundFormatBuf& aFormat)
sl@0
  1269
	{
sl@0
  1270
	__ASSERT_DEBUG(iRecordSoundDevice.Handle(), Panic(EDeviceNotOpened));
sl@0
  1271
	return SetFormat(aFormat, iRecordSoundDevice, iRecordFormatData);
sl@0
  1272
	}
sl@0
  1273
	
sl@0
  1274
void RMdaDevSound::CBody::Close()
sl@0
  1275
	{
sl@0
  1276
    #ifdef SYMBIAN_SOUNDADAPTER_DEBUG
sl@0
  1277
        RDebug::Printf("void RMdaDevSound::CBody::Close() started");
sl@0
  1278
    #endif
sl@0
  1279
	iBufferOffset = -1;
sl@0
  1280
	iBufferLength = 0;
sl@0
  1281
sl@0
  1282
	if(iPlaySoundDevice.Handle() != KNullHandle)
sl@0
  1283
	    {
sl@0
  1284
        // Make sure all player objects are idle
sl@0
  1285
        CancelPlayData();
sl@0
  1286
        iPlayChunk.Close();
sl@0
  1287
        iPlaySoundDevice.Close();
sl@0
  1288
	    }
sl@0
  1289
sl@0
  1290
    if(iRecordSoundDevice.Handle() != KNullHandle)
sl@0
  1291
        {
sl@0
  1292
        CancelRecordData();
sl@0
  1293
        iRecordChunk.Close();
sl@0
  1294
        iRecordSoundDevice.Close();
sl@0
  1295
        }
sl@0
  1296
	
sl@0
  1297
	iState = ENotReady;
sl@0
  1298
    #ifdef SYMBIAN_SOUNDADAPTER_DEBUG
sl@0
  1299
        RDebug::Printf("void RMdaDevSound::CBody::Close() ended");
sl@0
  1300
    #endif
sl@0
  1301
	}
sl@0
  1302
sl@0
  1303
TInt RMdaDevSound::CBody::Handle()
sl@0
  1304
	{//This method is actually used to check whether the device is opened. Below logic should work
sl@0
  1305
	if(iPlaySoundDevice.Handle())
sl@0
  1306
		{
sl@0
  1307
		return iPlaySoundDevice.Handle();
sl@0
  1308
		}
sl@0
  1309
	if(iRecordSoundDevice.Handle())
sl@0
  1310
		{
sl@0
  1311
		return iRecordSoundDevice.Handle();
sl@0
  1312
		}
sl@0
  1313
	return 0;
sl@0
  1314
	}
sl@0
  1315
sl@0
  1316
sl@0
  1317
void RMdaDevSound::CBody::PlayData(TRequestStatus& aStatus, const TDesC8& aData)
sl@0
  1318
	{
sl@0
  1319
	#ifdef SYMBIAN_SOUNDADAPTER_DEBUG
sl@0
  1320
    RDebug::Printf("RMdaDevSound::CBody::PlayData(0x%x,%d) State=%s Handle=%d.",&aStatus, 
sl@0
  1321
                   aData.Length(), iState.Name(), iPlayChunk.Handle());
sl@0
  1322
	#endif
sl@0
  1323
	
sl@0
  1324
	__ASSERT_DEBUG(iPlaySoundDevice.Handle(), Panic(EDeviceNotOpened));
sl@0
  1325
	aStatus = KRequestPending;
sl@0
  1326
sl@0
  1327
	if((iClientPlayStatus != NULL) || InRecordMode())
sl@0
  1328
		{
sl@0
  1329
		// We only support one outstanding request
sl@0
  1330
		// No support for simultaneous play and record in RMdaDevSound
sl@0
  1331
		TRequestStatus *pRequest = &aStatus;
sl@0
  1332
		User::RequestComplete(pRequest, KErrInUse);
sl@0
  1333
		return;
sl@0
  1334
		}
sl@0
  1335
	iClientPlayStatus = &aStatus;//store the status of datapath player
sl@0
  1336
sl@0
  1337
	if(iPlayFormatData.iConverter || iSavedTrailingData.Length() != 0)
sl@0
  1338
		{
sl@0
  1339
		// Need a conversion buffer
sl@0
  1340
        // Needs to hold any trailing data truncated from the previous request (due
sl@0
  1341
        // to alignment requirements) and either the new data, or the new rate adapted data
sl@0
  1342
		TUint32 spaceRequired = iSavedTrailingData.Length();
sl@0
  1343
		if(iPlayFormatData.iConverter)
sl@0
  1344
			{
sl@0
  1345
			// Doing rate conversion so also need space for the converted data
sl@0
  1346
			spaceRequired += iPlayFormatData.iConverter->MaxConvertBufferSize(aData.Length());
sl@0
  1347
			}
sl@0
  1348
		else
sl@0
  1349
			{
sl@0
  1350
			// Not doing rate adaptation therefore only need to allow for the new incoming data
sl@0
  1351
			spaceRequired += aData.Length();
sl@0
  1352
			}
sl@0
  1353
		// Check if existing buffer exists and is big enough
sl@0
  1354
		if(iConvertedPlayData.MaxLength() < spaceRequired)
sl@0
  1355
			{
sl@0
  1356
			iConvertedPlayData.Close();
sl@0
  1357
			TInt err = iConvertedPlayData.Create(spaceRequired);
sl@0
  1358
			if(err)
sl@0
  1359
				{
sl@0
  1360
				User::RequestComplete(iClientPlayStatus, err);
sl@0
  1361
				return;
sl@0
  1362
				}
sl@0
  1363
			}
sl@0
  1364
sl@0
  1365
		// Truncate iConvertedPlayData and copy in saved trailing data (if any)
sl@0
  1366
		iConvertedPlayData = iSavedTrailingData;
sl@0
  1367
		iSavedTrailingData.SetLength(0);
sl@0
  1368
		
sl@0
  1369
		// Now append rate adapted data or incoming data
sl@0
  1370
		if (iPlayFormatData.iConverter)
sl@0
  1371
			{
sl@0
  1372
            // The convertor will panic if it fails to convert any data, therefore
sl@0
  1373
            // we avoid passing it an empty source buffer
sl@0
  1374
			if(aData.Length() != 0)
sl@0
  1375
				{
sl@0
  1376
                TPtr8 destPtr((TUint8 *)iConvertedPlayData.Ptr()+iConvertedPlayData.Length(), 0, iConvertedPlayData.MaxLength()-iConvertedPlayData.Length());
sl@0
  1377
				TInt len = iPlayFormatData.iConverter->Convert(aData, destPtr);
sl@0
  1378
				iConvertedPlayData.SetLength(iConvertedPlayData.Length() + destPtr.Length());
sl@0
  1379
				if(len != aData.Length())
sl@0
  1380
					{
sl@0
  1381
					#ifdef SYMBIAN_SOUNDADAPTER_DEBUG
sl@0
  1382
					RDebug::Printf("RMdaDevSound::CBody::PlayData converted %d	but expected to convert %d", len, aData.Length());
sl@0
  1383
					#endif
sl@0
  1384
					}
sl@0
  1385
				}
sl@0
  1386
			}
sl@0
  1387
		else
sl@0
  1388
			{
sl@0
  1389
			iConvertedPlayData.Append(aData);
sl@0
  1390
			}
sl@0
  1391
		iClientPlayData.Set(iConvertedPlayData);
sl@0
  1392
		}
sl@0
  1393
	else
sl@0
  1394
		{
sl@0
  1395
		// Do not need a conversion buffer so just aim the descriptor at the data
sl@0
  1396
		iClientPlayData.Set(aData);
sl@0
  1397
		}
sl@0
  1398
	iUnderFlowReportedSinceLastPlayOrRecordRequest = EFalse;
sl@0
  1399
sl@0
  1400
	// All driver requests must be an exact multiple of iRequestMinSize
sl@0
  1401
	TUint32 trailingDataLen = iClientPlayData.Length() % iRequestMinSize;
sl@0
  1402
	if(trailingDataLen)
sl@0
  1403
		{
sl@0
  1404
		// Not a multiple of iRequestMinSize, so need to truncate current request, and save trailing bytes for 
sl@0
  1405
		// inclusion at the beginning of the next request
sl@0
  1406
		iSavedTrailingData = iClientPlayData.Right(trailingDataLen);
sl@0
  1407
		iClientPlayData.Set(iClientPlayData.Left(iClientPlayData.Length()-trailingDataLen));
sl@0
  1408
		}
sl@0
  1409
sl@0
  1410
    #ifdef SYMBIAN_FORCE_32BIT_LENGTHS
sl@0
  1411
	if (iClientPlayData.Length()%4 != 0)
sl@0
  1412
	    {
sl@0
  1413
        // simulate the limitation of some hardware, where -6 is generated if the
sl@0
  1414
        // buffer length is not divisible by 4.
sl@0
  1415
        TRequestStatus *pRequest = &aStatus;
sl@0
  1416
        User::RequestComplete(pRequest, KErrArgument);
sl@0
  1417
	}
sl@0
  1418
    #endif
sl@0
  1419
sl@0
  1420
	iRecordChunk.Close();
sl@0
  1421
	if(!iPlayChunk.Handle())
sl@0
  1422
		{
sl@0
  1423
		//This is where we setup to play. 
sl@0
  1424
		//Configure the shared chunk for two buffers with iBufferSize each
sl@0
  1425
		iPlayBufferConfig.iNumBuffers = KPlaySharedChunkBuffers;
sl@0
  1426
		iDeviceBufferLength = KPlaySharedChunkBufferSize;
sl@0
  1427
		#ifdef SYMBIAN_SOUNDADAPTER_DEBUG	
sl@0
  1428
		RDebug::Printf("iDeviceBufferLength %d", iDeviceBufferLength);
sl@0
  1429
		#endif
sl@0
  1430
		iPlayBufferConfig.iFlags = 0;//data will be continuous
sl@0
  1431
		// If required, use rate converter etc
sl@0
  1432
		iPlayBufferConfig.iBufferSizeInBytes = iDeviceBufferLength;
sl@0
  1433
        #ifdef SYMBIAN_SOUNDADAPTER_DEBUG
sl@0
  1434
            RDebug::Printf("number of buffers: [%d]",iPlayBufferConfig.iNumBuffers);
sl@0
  1435
            RDebug::Printf("BufferSize in Bytes [%d]",iPlayBufferConfig.iBufferSizeInBytes);
sl@0
  1436
        #endif
sl@0
  1437
		TPckg<TPlaySharedChunkBufConfig> bufferConfigBuf(iPlayBufferConfig);
sl@0
  1438
		TInt error = iPlaySoundDevice.SetBufferChunkCreate(bufferConfigBuf,iPlayChunk);
sl@0
  1439
		if(error == KErrNone)
sl@0
  1440
			{
sl@0
  1441
			iPlaySoundDevice.GetBufferConfig(bufferConfigBuf);
sl@0
  1442
			}
sl@0
  1443
		if (error)
sl@0
  1444
			{
sl@0
  1445
			SoundDeviceError(error);
sl@0
  1446
			return;
sl@0
  1447
			}
sl@0
  1448
		}
sl@0
  1449
sl@0
  1450
    StartPlayersAndUpdateState();
sl@0
  1451
sl@0
  1452
	return;	
sl@0
  1453
	}
sl@0
  1454
sl@0
  1455
void RMdaDevSound::CBody::RecordData(TRequestStatus& aStatus, TDes8& aData)
sl@0
  1456
	{
sl@0
  1457
	__ASSERT_DEBUG(iRecordSoundDevice.Handle(), Panic(EDeviceNotOpened));
sl@0
  1458
	aStatus = KRequestPending;
sl@0
  1459
	if((iClientPlayStatus != NULL) || InPlayMode())
sl@0
  1460
		{
sl@0
  1461
		// We only support one outstanding request
sl@0
  1462
		// No support for simultaneous play and record in RMdaDevSound
sl@0
  1463
		TRequestStatus *pRequest = &aStatus;
sl@0
  1464
		User::RequestComplete(pRequest, KErrInUse);
sl@0
  1465
		return;
sl@0
  1466
		}
sl@0
  1467
	iClientRecordStatus = &aStatus;
sl@0
  1468
	iClientRecordData = &aData;
sl@0
  1469
	iUnderFlowReportedSinceLastPlayOrRecordRequest = EFalse;
sl@0
  1470
sl@0
  1471
	iPlayChunk.Close();
sl@0
  1472
	if(!iRecordChunk.Handle())
sl@0
  1473
		{
sl@0
  1474
		//Configure the shared chunk for two buffers with iBufferSize each
sl@0
  1475
		iRecordBufferConfig.iNumBuffers = KRecordMaxSharedChunkBuffers;
sl@0
  1476
		iDeviceBufferLength = KRecordSharedChunkBufferSize; // initial size - resize if needs be
sl@0
  1477
		if (iRecordFormatData.iConverter)
sl@0
  1478
			{
sl@0
  1479
			// if number of channels used differs from request, resize buffer
sl@0
  1480
			// assume we have nice rounded values for buffer.
sl@0
  1481
			if (iRecordFormatData.iActualChannels>iRecordFormatData.iRequestedChannels)
sl@0
  1482
				{
sl@0
  1483
				iDeviceBufferLength *= 2; // will record at stereo and convert to mono 
sl@0
  1484
				}
sl@0
  1485
			else if (iRecordFormatData.iActualChannels<iRecordFormatData.iRequestedChannels)
sl@0
  1486
				{
sl@0
  1487
				iDeviceBufferLength /= 2; // will record at mono and convert to stereo 
sl@0
  1488
				}
sl@0
  1489
			}
sl@0
  1490
		iRecordBufferConfig.iBufferSizeInBytes = iDeviceBufferLength;
sl@0
  1491
		iRecordBufferConfig.iFlags = 0;
sl@0
  1492
		TPckg<TRecordSharedChunkBufConfig> bufferConfigBuf(iRecordBufferConfig);
sl@0
  1493
		TInt error = iRecordSoundDevice.SetBufferChunkCreate(bufferConfigBuf,iRecordChunk);
sl@0
  1494
		if(error == KErrNone)
sl@0
  1495
			{
sl@0
  1496
			iRecordSoundDevice.GetBufferConfig(bufferConfigBuf);
sl@0
  1497
			}
sl@0
  1498
		else
sl@0
  1499
			{
sl@0
  1500
			SoundDeviceError(error);
sl@0
  1501
			return;
sl@0
  1502
			}
sl@0
  1503
		iState = ERecording;
sl@0
  1504
		}		
sl@0
  1505
    #ifdef SYMBIAN_SOUNDADAPTER_DEBUG
sl@0
  1506
        RDebug::Printf("RMdaDevSound::CBody::RecordData,iBufferOffset[%d]",iBufferOffset);
sl@0
  1507
    #endif
sl@0
  1508
sl@0
  1509
	switch(iState)
sl@0
  1510
		{
sl@0
  1511
		case ENotReady:
sl@0
  1512
			Panic(EBadState);
sl@0
  1513
			break;
sl@0
  1514
sl@0
  1515
		case EStopped:
sl@0
  1516
		case ERecording:
sl@0
  1517
			// Either idle or recording is in progress, therefore we can issue another request			
sl@0
  1518
			StartRecordRequest();
sl@0
  1519
			break;
sl@0
  1520
			
sl@0
  1521
		case ERecordingPausedInHw:
sl@0
  1522
			// Driver is paused, therefore we can issue a request which will immediately return buffered data
sl@0
  1523
			// or be aborted (in the driver) with KErrCancelled if there is no more data). nb. That KErrCancelled should not be
sl@0
  1524
			// returned to the client because the old RMdaDevSound driver would have completed with KErrNone and zero data length.
sl@0
  1525
			StartRecordRequest();
sl@0
  1526
			break;
sl@0
  1527
sl@0
  1528
		case ERecordingPausedInSw:
sl@0
  1529
			// Paused in s/w but driver is not paused, therefore can not issue a new request to driver because
sl@0
  1530
			// it would re-start recording.
sl@0
  1531
			// This implies we were paused whilst the h/w was not recording, so there is no buffered data.
sl@0
  1532
			
sl@0
  1533
			// Complete the request with KErrNone and no data.
sl@0
  1534
			iClientRecordData->SetLength(0);
sl@0
  1535
			User::RequestComplete(iClientRecordStatus, KErrNone);
sl@0
  1536
			break;
sl@0
  1537
			
sl@0
  1538
		case EPlaying:
sl@0
  1539
		case EPlayingPausedInHw:
sl@0
  1540
		case EPlayingPausedInSw: 
sl@0
  1541
		case EPlayingUnderrun:
sl@0
  1542
			Panic(EBadState);
sl@0
  1543
			break;
sl@0
  1544
			
sl@0
  1545
		default:
sl@0
  1546
			Panic(EBadState);
sl@0
  1547
			break;
sl@0
  1548
		}
sl@0
  1549
	}
sl@0
  1550
	
sl@0
  1551
/**
sl@0
  1552
	Notify client of error.
sl@0
  1553
	
sl@0
  1554
	Note that we continue playing/recording if possible.
sl@0
  1555
	
sl@0
  1556
	We do not maintain information which could map the error back to a particular client play/record request
sl@0
  1557
	and therefore we have to notify the client of error every time it happens.
sl@0
  1558
	
sl@0
  1559
	nb. A client play/record request is completed with KErrNone if it queues ok - All errors are reported via the Notify*Error
sl@0
  1560
	mechanism.
sl@0
  1561
 */
sl@0
  1562
void RMdaDevSound::CBody::SoundDeviceError(TInt aError)
sl@0
  1563
	{
sl@0
  1564
    #ifdef SYMBIAN_SOUNDADAPTER_DEBUG
sl@0
  1565
	RDebug::Printf("RMdaDevSound::CBody::SoundDeviceError: Error[%d] state %s", aError, iState.Name());
sl@0
  1566
    #endif
sl@0
  1567
sl@0
  1568
	ASSERT(aError != KErrNone);
sl@0
  1569
	
sl@0
  1570
	if(iClientPlayErrorStatus)
sl@0
  1571
		{
sl@0
  1572
        #ifdef SYMBIAN_SOUNDADAPTER_DEBUG
sl@0
  1573
            RDebug::Printf("RMdaDevSound::CBody::SoundDeviceError Completing iPlayerErrorStatus");
sl@0
  1574
        #endif
sl@0
  1575
sl@0
  1576
		User::RequestComplete(iClientPlayErrorStatus, aError); // nb call also sets iClientPlayErrorStatus to NULL
sl@0
  1577
		}
sl@0
  1578
sl@0
  1579
  	if(iClientRecordErrorStatus)
sl@0
  1580
		{
sl@0
  1581
        #ifdef SYMBIAN_SOUNDADAPTER_DEBUG
sl@0
  1582
            RDebug::Printf("RMdaDevSound::CBody::SoundDeviceError Completing iClientRecordErrorStatus");
sl@0
  1583
        #endif
sl@0
  1584
		User::RequestComplete(iClientRecordErrorStatus, aError); // nb call also sets iClientRecordErrorStatus to NULL
sl@0
  1585
		}
sl@0
  1586
sl@0
  1587
	return;
sl@0
  1588
	}
sl@0
  1589
sl@0
  1590
void RMdaDevSound::CBody::NotifyRecordError(TRequestStatus& aStatus)
sl@0
  1591
	{
sl@0
  1592
	aStatus = KRequestPending;
sl@0
  1593
	iClientRecordErrorStatus = &aStatus;
sl@0
  1594
	}
sl@0
  1595
sl@0
  1596
void RMdaDevSound::CBody::NotifyPlayError(TRequestStatus& aStatus)
sl@0
  1597
	{
sl@0
  1598
	aStatus = KRequestPending;
sl@0
  1599
	iClientPlayErrorStatus = &aStatus;
sl@0
  1600
	}
sl@0
  1601
sl@0
  1602
void RMdaDevSound::CBody::CancelNotifyPlayError()
sl@0
  1603
	{
sl@0
  1604
	if(iClientPlayErrorStatus)
sl@0
  1605
		{
sl@0
  1606
		User::RequestComplete(iClientPlayErrorStatus, KErrCancel);
sl@0
  1607
		}
sl@0
  1608
	}
sl@0
  1609
sl@0
  1610
void RMdaDevSound::CBody::CancelNotifyRecordError()
sl@0
  1611
	{
sl@0
  1612
	if(iClientRecordErrorStatus)
sl@0
  1613
		{
sl@0
  1614
		User::RequestComplete(iClientRecordErrorStatus, KErrCancel);
sl@0
  1615
		}
sl@0
  1616
	else
sl@0
  1617
	    {
sl@0
  1618
		#ifdef SYMBIAN_SOUNDADAPTER_DEBUG	
sl@0
  1619
        RDebug::Printf("msp BufferEmptied but iClientPlayStatus==NULL");
sl@0
  1620
		#endif
sl@0
  1621
	    }
sl@0
  1622
	}
sl@0
  1623
sl@0
  1624
void RMdaDevSound::CBody::FlushPlayBuffer()
sl@0
  1625
	{
sl@0
  1626
	#ifdef SYMBIAN_SOUNDADAPTER_DEBUG	
sl@0
  1627
    RDebug::Printf("RMdaDevSound::CBody::FlushPlayBuffer calling CancelPlayData");
sl@0
  1628
	#endif	
sl@0
  1629
	CancelPlayData();
sl@0
  1630
	}
sl@0
  1631
sl@0
  1632
RSoundSc& RMdaDevSound::CBody::PlaySoundDevice()
sl@0
  1633
	{
sl@0
  1634
	return iPlaySoundDevice;
sl@0
  1635
	}
sl@0
  1636
sl@0
  1637
RSoundSc& RMdaDevSound::CBody::RecordSoundDevice()
sl@0
  1638
	{
sl@0
  1639
	return iRecordSoundDevice;
sl@0
  1640
	}
sl@0
  1641
	
sl@0
  1642
const RMdaDevSound::CBody::TState &RMdaDevSound::CBody::State() const
sl@0
  1643
	{
sl@0
  1644
	return iState;
sl@0
  1645
	}
sl@0
  1646
sl@0
  1647
sl@0
  1648
void RMdaDevSound::CBody::BufferFilled(TInt aBufferOffset)
sl@0
  1649
	{
sl@0
  1650
    #ifdef SYMBIAN_SOUNDADAPTER_DEBUG	
sl@0
  1651
        RDebug::Print(_L("RMdaDevSound::CBody::BufferFilled:"));
sl@0
  1652
    #endif	
sl@0
  1653
sl@0
  1654
	ASSERT(aBufferOffset>=0 || aBufferOffset==KErrCancel);
sl@0
  1655
	ASSERT(iClientRecordData); // request should not get this without
sl@0
  1656
sl@0
  1657
	if(aBufferOffset==KErrCancel)
sl@0
  1658
		{
sl@0
  1659
		//we can get KErrCancel when we call pause and there is no more data left with the driver
sl@0
  1660
		//we send the empty buffer to the HwDevice, where this should trigger the shutdown mechanism
sl@0
  1661
		iClientRecordData->SetLength(0);
sl@0
  1662
		User::RequestComplete(iClientRecordStatus, KErrNone);
sl@0
  1663
		iClientRecordStatus = NULL;
sl@0
  1664
		return;
sl@0
  1665
		}
sl@0
  1666
		
sl@0
  1667
	iBufferOffset = aBufferOffset;
sl@0
  1668
	//when last buffer is flushed, new driver sometimes gives buffer size of odd number. One of our codecs
sl@0
  1669
	//expects that the buffer size should always be even. Base suggested that we fix in multimedia
sl@0
  1670
	//as it is quite complicated to fix in overthere.
sl@0
  1671
	iBufferLength = iBufferLength & 0xfffffffe;
sl@0
  1672
	TPtr8 dataPtr(iRecordChunk.Base()+ iBufferOffset, iBufferLength, iClientRecordData->MaxLength());
sl@0
  1673
	if (iRecordFormatData.iConverter)
sl@0
  1674
		{
sl@0
  1675
		iRecordFormatData.iConverter->Convert(dataPtr, *iClientRecordData);
sl@0
  1676
		}
sl@0
  1677
	else
sl@0
  1678
		{
sl@0
  1679
		iClientRecordData->Copy(dataPtr);
sl@0
  1680
		}
sl@0
  1681
    #ifdef SYMBIAN_SOUNDADAPTER_DEBUG
sl@0
  1682
        RDebug::Print(_L("RMdaDevSound::CBody::BufferFilled: BufferOffset[%d] BufferLen[%d]"), iBufferOffset, iBufferLength);
sl@0
  1683
    #endif
sl@0
  1684
	if(iBufferOffset >= 0)
sl@0
  1685
		{
sl@0
  1686
		iRecordSoundDevice.ReleaseBuffer(iBufferOffset);
sl@0
  1687
		}
sl@0
  1688
	if(iClientRecordStatus)
sl@0
  1689
		{
sl@0
  1690
		User::RequestComplete(iClientRecordStatus, KErrNone);
sl@0
  1691
		iClientRecordStatus = NULL;
sl@0
  1692
		}
sl@0
  1693
	else
sl@0
  1694
	    {
sl@0
  1695
        RDebug::Printf("msp PlayCancelled but iClientPlayStatus==NULL");
sl@0
  1696
	    }
sl@0
  1697
	}
sl@0
  1698
		
sl@0
  1699
/*
sl@0
  1700
	This function is called to notify us that a CPlayer's request has completed and what its status was.
sl@0
  1701
sl@0
  1702
	It is important to note that:-
sl@0
  1703
	1) RSoundSc driver PlayData requests are guaranteed to complete in order, oldest first
sl@0
  1704
	2) If we are overloaded, it is possible for more than one request to complete before any CPlayer::RunL is ran. In
sl@0
  1705
	this situation the CPlayer::RunL functions, and hence this callback, maybe invoked in non-oldest first order
sl@0
  1706
sl@0
  1707
	but
sl@0
  1708
sl@0
  1709
	a) It is impossible for callback for the second oldest CPlayer to occur before the driver request for the oldest has
sl@0
  1710
	been complete (because of 1)
sl@0
  1711
	b) We will always get exactly one callback for every complete request.
sl@0
  1712
sl@0
  1713
	Therefore this callback notifies us of two subtly separate things:-
sl@0
  1714
sl@0
  1715
	i) The oldest request has been completed (so we can reduce can increase the bytes played counter by its length
sl@0
  1716
	ii) CPlayer aPlayerIndex is free for re-use
sl@0
  1717
sl@0
  1718
	but we can not assume that aPlayerIndex is the oldest request, therefore we save the play request lengths outside of
sl@0
  1719
	the CPlayer object.
sl@0
  1720
*/
sl@0
  1721
void RMdaDevSound::CBody::PlayRequestHasCompleted(CPlayer *aPlayer, TInt aStatus, TBool aDueToCancelCommand)
sl@0
  1722
	{
sl@0
  1723
	// CPlayer is done so put it on the free queue
sl@0
  1724
	iFreePlayers.Push(aPlayer);
sl@0
  1725
sl@0
  1726
	TUint32 bytesPlayed = iActivePlayRequestSizes.Pop();
sl@0
  1727
	// Request has finished therefore now timing the following request to simulate bytes played
sl@0
  1728
    iStartTime = CurrentTimeInMsec();
sl@0
  1729
	if(aDueToCancelCommand)
sl@0
  1730
	    {
sl@0
  1731
        // Callback due to CPlayer::Cancel/DoCancel being called, therefore we
sl@0
  1732
        // do not want to update bytes played, process state, report a error or start new players
sl@0
  1733
        return;
sl@0
  1734
	    }
sl@0
  1735
	
sl@0
  1736
	// Update iBytesPlayed by the length of the oldest request (which might not be the one that CPlayer was 
sl@0
  1737
	// handling).
sl@0
  1738
	iBytesPlayed += bytesPlayed;
sl@0
  1739
	#ifdef SYMBIAN_SOUNDADAPTER_DEBUG	
sl@0
  1740
    RDebug::Printf("PlayRequestHasCompleted increasing iBytesPlayed by %d to %d", bytesPlayed, iBytesPlayed);
sl@0
  1741
	#endif
sl@0
  1742
	
sl@0
  1743
    // Process state
sl@0
  1744
	switch(iState)
sl@0
  1745
		{
sl@0
  1746
		case ENotReady:
sl@0
  1747
			Panic(EDeviceNotOpened);
sl@0
  1748
			break;
sl@0
  1749
				
sl@0
  1750
		case EStopped:
sl@0
  1751
			// Will happen if we are doing CancelPlayData processing with active players
sl@0
  1752
			break;
sl@0
  1753
		
sl@0
  1754
		case ERecording:
sl@0
  1755
		case ERecordingPausedInHw:
sl@0
  1756
		case ERecordingPausedInSw:
sl@0
  1757
			Panic(EBadState);
sl@0
  1758
			break;
sl@0
  1759
			
sl@0
  1760
		case EPlaying:
sl@0
  1761
			// Normal situation
sl@0
  1762
			break;
sl@0
  1763
sl@0
  1764
		case EPlayingPausedInHw: 
sl@0
  1765
			// H/W was/is paused, but there must have been an already complete request that we had not 
sl@0
  1766
			// processed yet.
sl@0
  1767
			// There must be at least one more pending request on h/w, otherwise the h/w would have refused to pause
sl@0
  1768
			// I would expect this be rare, but it happens quite often...
sl@0
  1769
            #ifdef SYMBIAN_SOUNDADAPTER_DEBUG
sl@0
  1770
			ASSERT(iActivePlayRequestSizes.Length() != 0);
sl@0
  1771
            #endif
sl@0
  1772
			// Need to update the start and pause time to now because we have just updated the actual iBytesPlayed
sl@0
  1773
			// and logically the h/w is paused at the beginning of the next request
sl@0
  1774
			iStartTime = CurrentTimeInMsec();
sl@0
  1775
			iPauseTime = iStartTime;
sl@0
  1776
			break;
sl@0
  1777
		
sl@0
  1778
		case EPlayingPausedInSw:
sl@0
  1779
			// This will happen if there is only a single hw request outstanding, and the hardware has finished it, but the
sl@0
  1780
			// corresponding RunL has not run yet (in which case PausePlayBuffer will have attempted to use h/w pause,
sl@0
  1781
			// but the driver call would have failed, and the state changed to EPlayingPausedInSw).
sl@0
  1782
			iStartTime = CurrentTimeInMsec();
sl@0
  1783
			iPauseTime = iStartTime;
sl@0
  1784
			return;
sl@0
  1785
		case EPlayingUnderrun:
sl@0
  1786
			break;
sl@0
  1787
				
sl@0
  1788
		default:
sl@0
  1789
			Panic(EBadState);
sl@0
  1790
			break;
sl@0
  1791
		}
sl@0
  1792
sl@0
  1793
sl@0
  1794
	// If we have an error, report it to the client
sl@0
  1795
	// We NEVER report driver underflow, instead we report KErrUnderflow if we run out of data to pass to driver.
sl@0
  1796
	if( (aStatus != KErrNone) && (aStatus != KErrUnderflow) )
sl@0
  1797
		{
sl@0
  1798
		SoundDeviceError(aStatus);
sl@0
  1799
		}
sl@0
  1800
sl@0
  1801
    // If appropriate start more players
sl@0
  1802
	StartPlayersAndUpdateState();
sl@0
  1803
	return;
sl@0
  1804
	}
sl@0
  1805
sl@0
  1806
RMdaDevSound::CBody::CPlayer::CPlayer(TInt aPriority, RMdaDevSound::CBody& aParent, TInt aIndex):
sl@0
  1807
	CActive(aPriority), iParent(aParent), iIndex(aIndex), iBufferOffset(-1), iBufferLength(0)
sl@0
  1808
	{
sl@0
  1809
	CActiveScheduler::Add(this);
sl@0
  1810
	}
sl@0
  1811
sl@0
  1812
RMdaDevSound::CBody::CPlayer::~CPlayer()
sl@0
  1813
	{
sl@0
  1814
	Cancel();
sl@0
  1815
	}
sl@0
  1816
sl@0
  1817
sl@0
  1818
void RMdaDevSound::CBody::CPlayer::RunL()
sl@0
  1819
	{
sl@0
  1820
    #ifdef SYMBIAN_SOUNDADAPTER_DEBUG	
sl@0
  1821
    RDebug::Printf("****RMdaDevSound::CBody::CPlayer(%d)::RunL: Error[%d] ParentState[%s]", 
sl@0
  1822
                     iIndex, iStatus.Int(), iParent.State().Name());
sl@0
  1823
	RDebug::Printf("iActivePlayRequestSizes.Length() = %d iFreePlayers.Length() = %d (including this one as active)", 
sl@0
  1824
					iParent.iActivePlayRequestSizes.Length(), 
sl@0
  1825
					iParent.iFreePlayers.Length());
sl@0
  1826
    #endif
sl@0
  1827
	iParent.PlayRequestHasCompleted(this, iStatus.Int(), EFalse);
sl@0
  1828
	return;
sl@0
  1829
	}
sl@0
  1830
sl@0
  1831
TInt RMdaDevSound::CBody::CPlayer::RunError(TInt aError)
sl@0
  1832
	{
sl@0
  1833
	iParent.PlayRequestHasCompleted(this, aError, EFalse);
sl@0
  1834
	return KErrNone;
sl@0
  1835
	}
sl@0
  1836
sl@0
  1837
void RMdaDevSound::CBody::CPlayer::DoCancel()
sl@0
  1838
	{
sl@0
  1839
#ifdef SYMBIAN_SOUNDADAPTER_DEBUG
sl@0
  1840
	RDebug::Printf("RMdaDevSound::CBody::CPlayer(%d)::DoCancel", iIndex);
sl@0
  1841
#endif
sl@0
  1842
	if(iStatus == KRequestPending)
sl@0
  1843
	    {
sl@0
  1844
        // Avoid cancelling requests which have already completed.
sl@0
  1845
        // It wastes time, and might provoke a sound driver problem
sl@0
  1846
	    #ifdef SYMBIAN_SOUNDADAPTER_DEBUG	
sl@0
  1847
        RDebug::Printf("RMdaDevSound::CBody::CPlayer::DoCancel - would have cancelled driver request");
sl@0
  1848
		#endif
sl@0
  1849
        iParent.PlaySoundDevice().Cancel(iStatus);
sl@0
  1850
	    }
sl@0
  1851
	iParent.PlayRequestHasCompleted(this, KErrCancel, ETrue);
sl@0
  1852
	}
sl@0
  1853
sl@0
  1854
void RMdaDevSound::CBody::CPlayer::PlayData(TUint aChunkOffset, TInt aLength)
sl@0
  1855
	{
sl@0
  1856
    #ifdef SYMBIAN_SOUNDADAPTER_DEBUG	
sl@0
  1857
	RDebug::Print(_L("RMdaDevSound::CBody::CPlayer(%d)::PlayData : IsActive[%d]"),
sl@0
  1858
				  iIndex,    IsActive());
sl@0
  1859
	RDebug::Printf("iActivePlayRequestSizes.Length() = %d iFreePlayers.Length() = %d (inc this player)", 
sl@0
  1860
					iParent.iActivePlayRequestSizes.Length(), 
sl@0
  1861
					iParent.iFreePlayers.Length());
sl@0
  1862
    #endif	
sl@0
  1863
	
sl@0
  1864
	iBufferOffset = aChunkOffset;
sl@0
  1865
	iBufferLength = aLength;
sl@0
  1866
sl@0
  1867
    //Make sure the length is a multiple of 4 to work around an h6 limitation.
sl@0
  1868
	iBufferLength = iBufferLength & 0xfffffffc;
sl@0
  1869
sl@0
  1870
	// Issue the RSoundSc request
sl@0
  1871
	iParent.PlaySoundDevice().PlayData(iStatus, iBufferOffset, iBufferLength, EFalse);
sl@0
  1872
	SetActive();
sl@0
  1873
	return;
sl@0
  1874
	}
sl@0
  1875
	
sl@0
  1876
TUint RMdaDevSound::CBody::CPlayer::GetPlayerIndex() const
sl@0
  1877
	{
sl@0
  1878
	return iIndex;
sl@0
  1879
	}
sl@0
  1880
sl@0
  1881
RMdaDevSound::CBody::CRecorder::CRecorder(TInt aPriority, RMdaDevSound::CBody& aParent):
sl@0
  1882
    CActive(aPriority), iParent(aParent), iBufferOffset(-1), iBufferLength(0)
sl@0
  1883
    {
sl@0
  1884
    CActiveScheduler::Add(this);
sl@0
  1885
    }
sl@0
  1886
sl@0
  1887
RMdaDevSound::CBody::CRecorder::~CRecorder()
sl@0
  1888
    {
sl@0
  1889
    Cancel();
sl@0
  1890
    }
sl@0
  1891
sl@0
  1892
void RMdaDevSound::CBody::CRecorder::RecordData(TInt& aBufferLength)
sl@0
  1893
	{
sl@0
  1894
	if (!IsActive())
sl@0
  1895
	    {
sl@0
  1896
	    iStatus = KRequestPending;
sl@0
  1897
        #ifdef SYMBIAN_SOUNDADAPTER_DEBUG
sl@0
  1898
            RDebug::Printf("Recording request: BufferLength[%d]", aBufferLength);
sl@0
  1899
        #endif
sl@0
  1900
	    iParent.RecordSoundDevice().RecordData(iStatus, aBufferLength);
sl@0
  1901
	    SetActive();
sl@0
  1902
	    }
sl@0
  1903
	}
sl@0
  1904
sl@0
  1905
void RMdaDevSound::CBody::CRecorder::RunL()
sl@0
  1906
	{
sl@0
  1907
    #ifdef SYMBIAN_SOUNDADAPTER_DEBUG	
sl@0
  1908
    RDebug::Printf("****RMdaDevSound::CBody::CRecorder()::RunL: Error[%d] ParentState[%s]", 
sl@0
  1909
                     iStatus.Int(), iParent.State().Name());
sl@0
  1910
    #endif
sl@0
  1911
sl@0
  1912
	
sl@0
  1913
	TInt error = iStatus.Int();
sl@0
  1914
	
sl@0
  1915
	if((error >= 0) || (error == KErrCancel))
sl@0
  1916
		{//we can get KErrCancel when we call pause and there is no more data left with the driver
sl@0
  1917
		iParent.BufferFilled(error);
sl@0
  1918
		}
sl@0
  1919
	else 
sl@0
  1920
		{
sl@0
  1921
        #ifdef SYMBIAN_SOUNDADAPTER_DEBUG	
sl@0
  1922
            RDebug::Print(_L("RMdaDevSound::CBody::CPlayer()::RunL: Error[%d]"), error);
sl@0
  1923
        #endif
sl@0
  1924
		iParent.SoundDeviceError(error);
sl@0
  1925
		}
sl@0
  1926
	}
sl@0
  1927
sl@0
  1928
	
sl@0
  1929
TInt RMdaDevSound::CBody::CRecorder::RunError(TInt aError)
sl@0
  1930
    {
sl@0
  1931
    iParent.SoundDeviceError(aError);
sl@0
  1932
    return KErrNone;
sl@0
  1933
    }
sl@0
  1934
sl@0
  1935
void RMdaDevSound::CBody::CRecorder::DoCancel()
sl@0
  1936
    {
sl@0
  1937
#ifdef SYMBIAN_SOUNDADAPTER_DEBUG
sl@0
  1938
    RDebug::Printf("RMdaDevSound::CBody::CRecorder()::DoCancel");
sl@0
  1939
#endif
sl@0
  1940
    iParent.RecordSoundDevice().Cancel(iStatus);
sl@0
  1941
    }
sl@0
  1942
sl@0
  1943
sl@0
  1944
// End of file