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