mmdevicefw/mdf/src/audio/mdasoundadapter/mdasoundadapterbody.cpp
branchRCL_3
changeset 49 735348f59235
parent 8 bc06d8566074
child 50 948c7f65f6d4
equal deleted inserted replaced
40:f429a0a2075b 49:735348f59235
    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 #ifdef SYMBIAN_SOUNDADAPTER_BYTESPLAYED
    21 #include <hal.h>
    22 	#include <hal.h>
       
    23 #endif
       
    24 
    22 
    25 _LIT(KPddFileName,"SOUNDSC.PDD");
    23 _LIT(KPddFileName,"SOUNDSC.PDD");
    26 _LIT(KLddFileName,"ESOUNDSC.LDD");
    24 _LIT(KLddFileName,"ESOUNDSC.LDD");
    27 
    25 
    28 
    26 
    35 */
    33 */
    36 GLDEF_C void Panic(TSoundAdapterPanicCodes aPanicCode)
    34 GLDEF_C void Panic(TSoundAdapterPanicCodes aPanicCode)
    37 	{
    35 	{
    38 	User::Panic(KSoundAdapterPanicCategory, aPanicCode);
    36 	User::Panic(KSoundAdapterPanicCategory, aPanicCode);
    39 	}
    37 	}
    40 	
    38 
       
    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 
    41 RMdaDevSound::CBody* RMdaDevSound::CBody::NewL()
    75 RMdaDevSound::CBody* RMdaDevSound::CBody::NewL()
    42 	{
    76 	{
    43 	CBody* self = new(ELeave) CBody();
    77 	CBody* self = new(ELeave) CBody();
    44 	CleanupStack::PushL(self);
    78 	CleanupStack::PushL(self);
    45 	self->ConstructL();
    79 	self->ConstructL();
    47 	return self;
    81 	return self;
    48 	}
    82 	}
    49 
    83 
    50 RMdaDevSound::CBody::~CBody()
    84 RMdaDevSound::CBody::~CBody()
    51 	{
    85 	{
    52 	for(TInt i = 0; i < KNumPlayers; i++)
    86 	for(TInt i = 0; i < KPlaySharedChunkBuffers; i++)
    53 		{
    87 		{
    54 		delete iPlayers[i];
    88 		delete iPlayers[i];
    55 		iPlayers[i] = NULL;
    89 		iPlayers[i] = NULL;
    56 		}
    90 		}
    57 	iBufferRemaining.Close();
    91 	delete iRecorder;
    58 	delete iPlayData.iConverter;
    92 	iRecorder = NULL;
    59 	delete iRecordData.iConverter;
    93 	delete iPlayFormatData.iConverter;
    60 	iChunk.Close();
    94 	delete iRecordFormatData.iConverter;
       
    95 	iPlayChunk.Close();
    61 	iPlaySoundDevice.Close();
    96 	iPlaySoundDevice.Close();
       
    97 	iRecordChunk.Close();
    62 	iRecordSoundDevice.Close();
    98 	iRecordSoundDevice.Close();
       
    99 	iConvertedPlayData.Close();
       
   100 	iSavedTrailingData.Close();
       
   101 	iBufferedRecordData.Close();
    63 	}
   102 	}
    64 	
   103 	
    65 RMdaDevSound::CBody::CBody()
   104 RMdaDevSound::CBody::CBody()
    66 	:iState(ENotReady), iBufferIndex(-1), iBufferOffset(-1), iSecondPhaseData(0,0)
   105 	:iState(ENotReady), iBufferOffset(-1)
    67 	{
   106 	{
    68 	
   107 	
    69 	}
   108 	}
    70 
   109 
    71 TVersion RMdaDevSound::CBody::VersionRequired() const
   110 TVersion RMdaDevSound::CBody::VersionRequired() const
    97 	err = User::LoadLogicalDevice(KLddFileName);
   136 	err = User::LoadLogicalDevice(KLddFileName);
    98     if ((err!=KErrNone) && (err!=KErrAlreadyExists))
   137     if ((err!=KErrNone) && (err!=KErrAlreadyExists))
    99     	{
   138     	{
   100     	User::Leave(err);
   139     	User::Leave(err);
   101     	}
   140     	}
   102 	for(TInt i=0; i<KNumPlayers; i++)
   141 	for(TInt i=0; i<KPlaySharedChunkBuffers; i++)
   103 		{
   142 		{
   104 		iPlayers[i] = new(ELeave) CPlayer(CActive::EPriorityUserInput, *this, i);
   143 		iPlayers[i] = new(ELeave) CPlayer(CActive::EPriorityUserInput, *this, i);
   105 		}
   144 		iFreePlayers.Push(iPlayers[i]);
   106 #ifdef SYMBIAN_SOUNDADAPTER_BYTESPLAYED
   145 		}
   107 	User::LeaveIfError(HAL::Get(HALData::EFastCounterFrequency,iFCFrequency));
   146 	
   108 #endif
   147 	iRecorder = new(ELeave) CRecorder(CActive::EPriorityUserInput, *this);
       
   148 	
       
   149 	TInt tmp;
       
   150 	User::LeaveIfError(HAL::Get(HAL::ENanoTickPeriod, tmp));
       
   151 	iNTickPeriodInUsec = tmp;
   109 	}
   152 	}
   110 
   153 
   111 TInt RMdaDevSound::CBody::Open(TInt /*aUnit*/)
   154 TInt RMdaDevSound::CBody::Open(TInt /*aUnit*/)
   112 	{
   155 	{
   113     #ifdef SYMBIAN_SOUNDADAPTER_DEBUG	
   156     #ifdef SYMBIAN_SOUNDADAPTER_DEBUG	
   127 		{
   170 		{
   128 		Close();
   171 		Close();
   129 		}
   172 		}
   130 	else
   173 	else
   131 	    {
   174 	    {
   132 	    iState = EOpened;
   175 		TSoundFormatsSupportedV02Buf capsBuf;
       
   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;
   133 	    }
   189 	    }
       
   190 
   134 	return err;
   191 	return err;
   135 	}
   192 	}
   136 		
   193 		
   137 TInt RMdaDevSound::CBody::PlayVolume()
   194 TInt RMdaDevSound::CBody::PlayVolume()
   138 	{
   195 	{
   158 	}
   215 	}
   159 	
   216 	
   160 void RMdaDevSound::CBody::CancelPlayData()
   217 void RMdaDevSound::CBody::CancelPlayData()
   161 	{
   218 	{
   162     #ifdef SYMBIAN_SOUNDADAPTER_DEBUG	
   219     #ifdef SYMBIAN_SOUNDADAPTER_DEBUG	
   163         RDebug::Print(_L("RMdaDevSound::CBody::CancelPlayData:"));
   220     RDebug::Printf("RMdaDevSound::CBody::CancelPlayData: state %s", iState.Name());
   164     #endif	
   221     #endif	
   165 	__ASSERT_DEBUG(iPlaySoundDevice.Handle(), Panic(EDeviceNotOpened));
   222 	__ASSERT_DEBUG(iPlaySoundDevice.Handle(), Panic(EDeviceNotOpened));
   166 	iPlaySoundDevice.CancelPlayData();
   223 
   167 	iPauseDeviceDriverOnNewData = EFalse;
   224     // If there is a client request, cancel it
   168 	SoundDeviceError(KErrNone);//cancel the players
   225     // Must do this before canceling players because otherwise they may just restart!
       
   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;
   169 	}
   279 	}
   170 	
   280 	
   171 TInt RMdaDevSound::CBody::RecordLevel()
   281 TInt RMdaDevSound::CBody::RecordLevel()
   172 	{
   282 	{
   173 	__ASSERT_DEBUG(iRecordSoundDevice.Handle(), Panic(EDeviceNotOpened));
   283 	__ASSERT_DEBUG(iRecordSoundDevice.Handle(), Panic(EDeviceNotOpened));
   182 	
   292 	
   183 void RMdaDevSound::CBody::CancelRecordData()
   293 void RMdaDevSound::CBody::CancelRecordData()
   184 	{
   294 	{
   185 	__ASSERT_DEBUG(iRecordSoundDevice.Handle(), Panic(EDeviceNotOpened));
   295 	__ASSERT_DEBUG(iRecordSoundDevice.Handle(), Panic(EDeviceNotOpened));
   186     #ifdef SYMBIAN_SOUNDADAPTER_DEBUG	
   296     #ifdef SYMBIAN_SOUNDADAPTER_DEBUG	
   187         RDebug::Print(_L("RMdaDevSound::CBody::CancelRecordData:"));
   297     RDebug::Printf("RMdaDevSound::CBody::CancelRecordData: state %s", iState.Name());
   188     #endif
   298     #endif
   189 	iRecordSoundDevice.CancelRecordData();
   299 
   190 	SoundDeviceError(KErrNone);
   300     // Stop recorder object (and its request)
       
   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;
   191 	}
   314 	}
   192 	
   315 	
   193 void RMdaDevSound::CBody::FlushRecordBuffer()
   316 void RMdaDevSound::CBody::FlushRecordBuffer()
   194 	{
   317 	{
   195 	__ASSERT_DEBUG(iRecordSoundDevice.Handle(), Panic(EDeviceNotOpened));
   318 	__ASSERT_DEBUG(iRecordSoundDevice.Handle(), Panic(EDeviceNotOpened));
   196     #ifdef SYMBIAN_SOUNDADAPTER_DEBUG	
   319     #ifdef SYMBIAN_SOUNDADAPTER_DEBUG	
   197         RDebug::Print(_L("RMdaDevSound::CBody::FlushRecordBuffer"));
   320         RDebug::Print(_L("RMdaDevSound::CBody::FlushRecordBuffer - implemented by calling PauseRecordBuffer"));
   198     #endif
   321     #endif
   199 	
   322 
   200 	if(iState == ERecording)
   323 	PauseRecordBuffer();
   201 	    {
       
   202 		iRecordSoundDevice.Pause();//this is equivalent call in the new sound driver
       
   203     	}
       
   204 	}
   324 	}
   205 	
   325 	
   206 TInt RMdaDevSound::CBody::BytesPlayed()
   326 TInt RMdaDevSound::CBody::BytesPlayed()
   207 	{
   327 	{
       
   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 	{
   208 	__ASSERT_DEBUG(iPlaySoundDevice.Handle(), Panic(EDeviceNotOpened));
   338 	__ASSERT_DEBUG(iPlaySoundDevice.Handle(), Panic(EDeviceNotOpened));
   209 	TInt currentBytesPlayed = 0;
   339 
   210 #ifdef SYMBIAN_SOUNDADAPTER_BYTESPLAYED
   340 	TUint64 currentBytesPlayed = KMaxTUint64;
   211 	if(iTimerActive)
   341 
   212 		{
   342 	switch(iState)
   213 		TUint32 endTime = User::FastCounter();
   343 	{
   214 		TUint timePlayed = 0;
   344 	case ENotReady:
   215 		if(endTime<iStartTime)
   345 		Panic(EDeviceNotOpened);
   216 			{
   346 		break;
   217 			timePlayed = (KMaxTUint32-iStartTime)+endTime;
   347 
   218 			}
   348 	case EStopped:
   219 		else
   349 		currentBytesPlayed = iBytesPlayed;
   220 			{
   350 		break;
   221 			timePlayed = endTime-iStartTime;
   351 
   222 			}	
   352 	case ERecording:
   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
   353 	case ERecordingPausedInHw:
   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
   354 	case ERecordingPausedInSw:
   225 
   355 		Panic(EBadState);
   226 		currentBytesPlayed = iBytesPlayed+I64LOW(bytesPlayed);
   356 		break;
   227         #ifdef SYMBIAN_SOUNDADAPTER_DEBUG
   357 
   228             RDebug::Printf("EstimatedBytesPlayed[%d]  Driver's bytesPlayed[%d]", currentBytesPlayed, iBytesPlayed);
   358 	case EPlayingPausedInHw: // ie. Play request pending on h/w and paused
       
   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);
   229         #endif
   391         #endif
   230 		}
   392 		TUint32 extraBytesPlayed = TUint32((TUint64(extraPlayTime) * iPlayFormatData.iSampleRate * iPlayFormatData.iRequestedChannels * KBytesPerSample)/1000);
   231 	else
   393 		if(extraBytesPlayed > curRequestSize)
   232 		{
   394 			{
   233 		currentBytesPlayed = iPlaySoundDevice.BytesTransferred();
   395             #ifdef SYMBIAN_SOUNDADAPTER_DEBUG	 
   234 		}		
   396 			RDebug::Printf("caping extraBytes played from %d to %d", extraBytesPlayed, curRequestSize);
   235 	
   397             #endif
   236 #else
   398 			extraBytesPlayed = curRequestSize;
   237 	currentBytesPlayed = iPlaySoundDevice.BytesTransferred();
   399 			}
   238 #endif
   400 
   239 	if (iPlayData.iConverter)
   401 		#ifdef SYMBIAN_SOUNDADAPTER_DEBUG
       
   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)
   240 		{
   421 		{
   241 		// need to scale bytes played to fit with requested rate and channels, not actual
   422 		// need to scale bytes played to fit with requested rate and channels, not actual
   242 		if (iPlayData.iActualChannels != iPlayData.iRequestedChannels)
   423 		if (iPlayFormatData.iActualChannels != iPlayFormatData.iRequestedChannels)
   243 			{
   424 			{
   244 			if (iPlayData.iActualChannels == 2)
   425 			if (iPlayFormatData.iActualChannels == 2)
   245 				{
   426 				{
   246 				// requested was mono, we have stereo
   427 				// requested was mono, we have stereo
   247 				currentBytesPlayed /= 2;
   428 				currentBytesPlayed /= 2;
   248 				}
   429 				}
   249 			else 
   430 			else 
   250 				{
   431 				{
   251 				// requested was stereo, we have mono
   432 				// requested was stereo, we have mono
   252 				currentBytesPlayed *= 2;
   433 				currentBytesPlayed *= 2;
   253 				}
   434 				}
   254 			}
   435 			}
   255 		if (iPlayData.iSampleRate != iPlayData.iActualRate)
   436 		if (iPlayFormatData.iSampleRate != iPlayFormatData.iActualRate)
   256 			{
   437 			{
   257 			currentBytesPlayed = TInt(currentBytesPlayed*
   438 			currentBytesPlayed = TUint64(currentBytesPlayed*
   258 					TReal(iPlayData.iSampleRate)/TReal(iPlayData.iActualRate)); // don't round
   439 					TReal(iPlayFormatData.iSampleRate)/TReal(iPlayFormatData.iActualRate)); // don't round
   259 			}
   440 			}
   260 		}
   441 		}
       
   442 
       
   443     #ifdef SYMBIAN_SOUNDADAPTER_DEBUG
       
   444 	RDebug::Printf("currentBytesPlayed %x %x", I64HIGH(currentBytesPlayed), I64LOW(currentBytesPlayed));
       
   445     #endif
   261 	return currentBytesPlayed;
   446 	return currentBytesPlayed;
   262 	}
   447 	}
   263 
   448 
   264 void RMdaDevSound::CBody::ResetBytesPlayed()
   449 void RMdaDevSound::CBody::ResetBytesPlayed()
   265 	{
   450 	{
       
   451     #ifdef SYMBIAN_SOUNDADAPTER_DEBUG    
       
   452     RDebug::Printf("RMdaDevSound::CBody::ResetBytesPlayed %s", iState.Name());
       
   453 	#endif
   266 	__ASSERT_DEBUG(iPlaySoundDevice.Handle(), Panic(EDeviceNotOpened));
   454 	__ASSERT_DEBUG(iPlaySoundDevice.Handle(), Panic(EDeviceNotOpened));
   267 	return iPlaySoundDevice.ResetBytesTransferred();
   455 	iBytesPlayed = 0;
       
   456 	iPlaySoundDevice.ResetBytesTransferred();
       
   457 	return;
   268 	}
   458 	}
   269 	
   459 	
   270 void RMdaDevSound::CBody::PausePlayBuffer()
   460 void RMdaDevSound::CBody::PausePlayBuffer()
   271 	{
   461 	{
   272 	if (iState == EPlaying)
   462 #ifdef SYMBIAN_SOUNDADAPTER_DEBUG   
   273 		{
   463     RDebug::Printf("RMdaDevSound::CBody::PausePlayBuffer %s", iState.Name());
   274         #ifdef SYMBIAN_SOUNDADAPTER_DEBUG   
   464 #endif  
   275             RDebug::Print(_L("RMdaDevSound::CBody::PausePlayBuffer() offset = %d length = %d"), iBufferOffset, iBufferLength);
   465 	switch(iState)
   276         #endif
   466 		{
   277 		__ASSERT_DEBUG(iPlaySoundDevice.Handle(), Panic(EDeviceNotOpened));
   467 		case ENotReady:
   278 		// If iPlayerStatus is NULL, we're not playing currently any data, and the device driver won't pause properly. In this case,
   468 			Panic(EDeviceNotOpened);
   279 		// we set a reminder to ourselves to pause the driver once we have data later
   469 			break;
   280 		if (iPlayerStatus == NULL)
   470 
   281 			{
   471 		case EStopped:
   282 			iPauseDeviceDriverOnNewData = ETrue;
   472 			// Driver is not playing so pause in s/w
   283 			}
   473 			break;
   284 		else
   474 
   285 			{
   475 		case ERecording:
       
   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();
   286 			TInt res = iPlaySoundDevice.Pause();
   493 			TInt res = iPlaySoundDevice.Pause();
   287 			#ifdef SYMBIAN_SOUNDADAPTER_DEBUG   
   494 			#ifdef SYMBIAN_SOUNDADAPTER_DEBUG   
   288 				RDebug::Printf("iPlaySoundDevice.Pause res = %d", res);
   495 			RDebug::Printf("iPlaySoundDevice.Pause res = %d", res);
   289 			#endif
   496 			#endif
   290 			(void)res;
   497  			if(res == KErrNone)
   291 			}
   498 				{
   292 		iState = EPaused;
   499 				iState = EPlayingPausedInHw;
   293 		iTimerActive = EFalse;
   500 				}
   294 		}		
   501 			else
       
   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;
   295 	}
   517 	}
   296 	
   518 	
   297 void RMdaDevSound::CBody::ResumePlaying()
   519 void RMdaDevSound::CBody::ResumePlaying()
   298 	{
   520 	{
       
   521 	#ifdef SYMBIAN_SOUNDADAPTER_DEBUG   
       
   522 	RDebug::Printf("RMdaDevSound::CBody::ResumePlaying %s", iState.Name());
       
   523 	#endif	
       
   524     __ASSERT_DEBUG(iPlaySoundDevice.Handle(), Panic(EDeviceNotOpened));
       
   525 
       
   526 	switch(iState)
       
   527 		{
       
   528 		case ENotReady:
       
   529 			Panic(EDeviceNotOpened);
       
   530 			break;
       
   531 				
       
   532 		case EStopped:
       
   533 			// No change
       
   534 			break;
       
   535 	
       
   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 	}
       
   597 
       
   598 void RMdaDevSound::CBody::PauseRecordBuffer()
       
   599 	{
       
   600     #ifdef SYMBIAN_SOUNDADAPTER_DEBUG   
       
   601     RDebug::Printf("RMdaDevSound::CBody::PauseRecordBuffer %s", iState.Name());
       
   602     #endif
       
   603 	
       
   604 	switch(iState)
       
   605 		{
       
   606 		case ENotReady:
       
   607 			Panic(EDeviceNotOpened);
       
   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 	}
       
   660 
       
   661 void RMdaDevSound::CBody::ResumeRecording()
       
   662 	{
       
   663     #ifdef SYMBIAN_SOUNDADAPTER_DEBUG   
       
   664     RDebug::Printf("RMdaDevSound::CBody::ResumeRecording %s", iState.Name());
       
   665     #endif
   299 	__ASSERT_DEBUG(iPlaySoundDevice.Handle(), Panic(EDeviceNotOpened));
   666 	__ASSERT_DEBUG(iPlaySoundDevice.Handle(), Panic(EDeviceNotOpened));
   300 	iPauseDeviceDriverOnNewData = EFalse;
   667 
   301 	#ifdef SYMBIAN_SOUNDADAPTER_DEBUG   
   668 	switch(iState)
   302 		RDebug::Printf("RMdaDevSound::CBody::ResumePlaying");
   669 		{
   303 	#endif	
   670 		case ENotReady:
   304 	if (iFlushCalledDuringPause)
   671 			Panic(EDeviceNotOpened);
   305 		{
   672 			break;
   306 		// if we resume having called flush, we can't just keep going as the driver does not work
   673 				
   307 		// that way. Instead we cancel so that buffer play completes and a new buffer will be passed
   674 		case EStopped:
   308 		iFlushCalledDuringPause = EFalse;
   675 			// No change
   309 		PlayCancelled();
   676 			break;
   310 		}
   677 	
   311 	else
   678 		case ERecording:
   312 		{
   679 			// No change
   313 		iState = EPlaying;
   680 			break;
   314 		iPlaySoundDevice.Resume();
   681 
   315 		}
   682 		case ERecordingPausedInHw:
   316 	}
   683 			{
   317 
   684 			TInt res = iRecordSoundDevice.Resume();
   318 void RMdaDevSound::CBody::PauseRecordBuffer()
   685 			#ifdef SYMBIAN_SOUNDADAPTER_DEBUG	
   319 	{
   686 			RDebug::Printf("ResumeRecordBuffer ERecordingPausedInHw res = %d", res);
   320 	if(iState == ERecording)
   687 			#endif
   321 	    {	
   688 			if(res == KErrNone)
   322 		__ASSERT_DEBUG(iRecordSoundDevice.Handle(), Panic(EDeviceNotOpened));
   689 				{
   323         #ifdef SYMBIAN_SOUNDADAPTER_DEBUG	
   690 				// Resume ok so a pending request will complete
   324             RDebug::Printf("RMdaDevSound::CBody::PauseRecordBuffer");
   691 				iState = ERecording;
   325         #endif
   692 				}
   326 		iRecordSoundDevice.Pause();
   693 			else
   327 	    }
   694 				{
   328 	}
   695 				iState = EStopped;
   329 
   696 				// Resume failed, so attempt to start a new (pending) request.
   330 void RMdaDevSound::CBody::ResumeRecording()
   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 	}
       
   724 
       
   725 TInt RMdaDevSound::CBody::GetTimePlayed(TTimeIntervalMicroSeconds& aTimePlayed)
   331 	{
   726 	{
   332 	__ASSERT_DEBUG(iPlaySoundDevice.Handle(), Panic(EDeviceNotOpened));
   727 	__ASSERT_DEBUG(iPlaySoundDevice.Handle(), Panic(EDeviceNotOpened));
   333 	iRecordSoundDevice.Resume();
   728 
   334 	}
   729 
   335 
   730 	TUint64 bytesPlayed = BytesPlayed64();
   336 TInt RMdaDevSound::CBody::GetTimePlayed(TTimeIntervalMicroSeconds& aTimePlayed)
   731 
   337 	{
   732 	TUint64 timePlayed = 1000 * 1000 * bytesPlayed / (iPlayFormatData.iSampleRate * iPlayFormatData.iRequestedChannels * KBytesPerSample);
   338 	__ASSERT_DEBUG(iPlaySoundDevice.Handle(), Panic(EDeviceNotOpened));
   733 
   339 	TTimeIntervalMicroSecondsBuf aTimePlayedBuf;
   734 	aTimePlayed = TTimeIntervalMicroSeconds(timePlayed);
   340 	TInt err;
   735 
   341 	err = iPlaySoundDevice.TimePlayed(aTimePlayedBuf);
   736 	return KErrNone;
   342 	if (err == KErrNone)
       
   343 	  {
       
   344 	    aTimePlayed = aTimePlayedBuf();
       
   345 	  }
       
   346 
       
   347 	return err;
       
   348 	}
   737 	}
   349 
   738 
   350 	
   739 	
   351 void RMdaDevSound::CBody::FormatsSupported(TSoundFormatsSupportedBuf& aFormatsSupported, RSoundSc& aSoundDevice)
   740 void RMdaDevSound::CBody::FormatsSupported(TSoundFormatsSupportedBuf& aFormatsSupported, RSoundSc& aSoundDevice)
   352 	{
   741 	{
   403 	// always return the requested, or the initial, not current device setting
   792 	// always return the requested, or the initial, not current device setting
   404 	aFormat().iChannels = aFormatData.iRequestedChannels; // never clear if this is bitmap or value, but effectively the same
   793 	aFormat().iChannels = aFormatData.iRequestedChannels; // never clear if this is bitmap or value, but effectively the same
   405 	aFormat().iRate = aFormatData.iSampleRate;
   794 	aFormat().iRate = aFormatData.iSampleRate;
   406 	}
   795 	}
   407 	
   796 	
       
   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 
   408 TInt RMdaDevSound::CBody::SetFormat(const TCurrentSoundFormatBuf& aFormat, 
   929 TInt RMdaDevSound::CBody::SetFormat(const TCurrentSoundFormatBuf& aFormat, 
   409 									RSoundSc& aSoundDevice,
   930 									RSoundSc& aSoundDevice,
   410 									TFormatData &aFormatData)
   931 									TFormatData &aFormatData)
   411 	{
   932 	{
   412 	TInt err = KErrNotFound;
   933 	TInt err = KErrNotFound;
   413 	TCurrentSoundFormatV02Buf formatBuf;
   934 	TCurrentSoundFormatV02Buf formatBuf;
   414 	
   935 	
   415 	delete aFormatData.iConverter; 
   936 	delete aFormatData.iConverter; 
   416 	aFormatData.iConverter = NULL; // setting this to NULL indicates we are not using converter. No other flag
   937 	aFormatData.iConverter = NULL; // setting this to NULL indicates we are not using converter. No other flag
       
   938 	iConvertedPlayData.Close();
   417 	
   939 	
   418 	TInt wantedRate = aFormat().iRate;
   940 	TInt wantedRate = aFormat().iRate;
   419 	for(TInt index = 0; index < KNumSampleRates; index++ )
   941 	for(TInt index = 0; index < KNumSampleRates; index++ )
   420 		{
   942 		{
   421 		if(wantedRate == KRateEnumLookup[index].iRate)
   943 		if(wantedRate == KRateEnumLookup[index].iRate)
   427 			}
   949 			}
   428 		}
   950 		}
   429 	
   951 	
   430 	if(err == KErrNone)
   952 	if(err == KErrNone)
   431 		{
   953 		{
       
   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
   432 		formatBuf().iChannels = aFormat().iChannels;
   959 		formatBuf().iChannels = aFormat().iChannels;
   433 		formatBuf().iEncoding = ESoundEncoding16BitPCM;
   960 		formatBuf().iEncoding = ESoundEncoding16BitPCM;
   434 		formatBuf().iDataFormat = ESoundDataFormatInterleaved;
   961 		formatBuf().iDataFormat = ESoundDataFormatInterleaved;
   435 		err = aSoundDevice.SetAudioFormat(formatBuf);
   962 		err = aSoundDevice.SetAudioFormat(formatBuf);
   436         #if defined(SYMBIAN_SOUNDADAPTER_FORCECDRATES) || defined (SYMBIAN_SOUNDADAPTER_FORCESTEREO)
   963         #if defined(SYMBIAN_SOUNDADAPTER_FORCECDRATES) || defined (SYMBIAN_SOUNDADAPTER_FORCESTEREO)
   626 																	       aFormatData.iActualChannels,
  1153 																	       aFormatData.iActualChannels,
   627 																	       outputRateToUse, 
  1154 																	       outputRateToUse, 
   628 																		   aFormatData.iRequestedChannels));
  1155 																		   aFormatData.iRequestedChannels));
   629 			}
  1156 			}
   630 		}
  1157 		}
       
  1158 	if(err != KErrNone)
       
  1159 		{
       
  1160 		delete aFormatData.iConverter;
       
  1161 		aFormatData.iConverter= NULL;
       
  1162 		iConvertedPlayData.Close();
       
  1163 		}
   631 	
  1164 	
   632 	return err;
  1165 	return err;
   633 	}
  1166 	}
   634 
  1167 
   635 	
  1168 void RMdaDevSound::CBody::StartRecordRequest()
       
  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 
   636 void RMdaDevSound::CBody::PlayFormatsSupported(TSoundFormatsSupportedBuf& aFormatsSupported)
  1238 void RMdaDevSound::CBody::PlayFormatsSupported(TSoundFormatsSupportedBuf& aFormatsSupported)
   637 	{
  1239 	{
   638 	__ASSERT_DEBUG(iPlaySoundDevice.Handle(), Panic(EDeviceNotOpened));
  1240 	__ASSERT_DEBUG(iPlaySoundDevice.Handle(), Panic(EDeviceNotOpened));
   639 	FormatsSupported(aFormatsSupported, iPlaySoundDevice);
  1241 	FormatsSupported(aFormatsSupported, iPlaySoundDevice);
   640 	}
  1242 	}
   641 	
  1243 	
   642 void RMdaDevSound::CBody::GetPlayFormat(TCurrentSoundFormatBuf& aFormat)
  1244 void RMdaDevSound::CBody::GetPlayFormat(TCurrentSoundFormatBuf& aFormat)
   643 	{
  1245 	{
   644 	__ASSERT_DEBUG(iPlaySoundDevice.Handle(), Panic(EDeviceNotOpened));
  1246 	__ASSERT_DEBUG(iPlaySoundDevice.Handle(), Panic(EDeviceNotOpened));
   645 	GetFormat(aFormat, iPlaySoundDevice, iPlayData);
  1247 	GetFormat(aFormat, iPlaySoundDevice, iPlayFormatData);
   646 	}
  1248 	}
   647 	
  1249 	
   648 TInt RMdaDevSound::CBody::SetPlayFormat(const TCurrentSoundFormatBuf& aFormat)
  1250 TInt RMdaDevSound::CBody::SetPlayFormat(const TCurrentSoundFormatBuf& aFormat)
   649 	{
  1251 	{
   650 	__ASSERT_DEBUG(iPlaySoundDevice.Handle(), Panic(EDeviceNotOpened));
  1252 	__ASSERT_DEBUG(iPlaySoundDevice.Handle(), Panic(EDeviceNotOpened));
   651 	return SetFormat(aFormat, iPlaySoundDevice, iPlayData);
  1253 	return SetFormat(aFormat, iPlaySoundDevice, iPlayFormatData);
   652 	}
  1254 	}
   653 
  1255 
   654 void RMdaDevSound::CBody::RecordFormatsSupported(TSoundFormatsSupportedBuf& aFormatsSupported)
  1256 void RMdaDevSound::CBody::RecordFormatsSupported(TSoundFormatsSupportedBuf& aFormatsSupported)
   655 	{
  1257 	{
   656 	__ASSERT_DEBUG(iRecordSoundDevice.Handle(), Panic(EDeviceNotOpened));
  1258 	__ASSERT_DEBUG(iRecordSoundDevice.Handle(), Panic(EDeviceNotOpened));
   658 	}
  1260 	}
   659 
  1261 
   660 void RMdaDevSound::CBody::GetRecordFormat(TCurrentSoundFormatBuf& aFormat)
  1262 void RMdaDevSound::CBody::GetRecordFormat(TCurrentSoundFormatBuf& aFormat)
   661 	{
  1263 	{
   662 	__ASSERT_DEBUG(iRecordSoundDevice.Handle(), Panic(EDeviceNotOpened));
  1264 	__ASSERT_DEBUG(iRecordSoundDevice.Handle(), Panic(EDeviceNotOpened));
   663 	GetFormat(aFormat, iRecordSoundDevice, iRecordData);	
  1265 	GetFormat(aFormat, iRecordSoundDevice, iRecordFormatData);	
   664 	}
  1266 	}
   665 
  1267 
   666 TInt RMdaDevSound::CBody::SetRecordFormat(const TCurrentSoundFormatBuf& aFormat)
  1268 TInt RMdaDevSound::CBody::SetRecordFormat(const TCurrentSoundFormatBuf& aFormat)
   667 	{
  1269 	{
   668 	__ASSERT_DEBUG(iRecordSoundDevice.Handle(), Panic(EDeviceNotOpened));
  1270 	__ASSERT_DEBUG(iRecordSoundDevice.Handle(), Panic(EDeviceNotOpened));
   669 	return SetFormat(aFormat, iRecordSoundDevice, iRecordData);
  1271 	return SetFormat(aFormat, iRecordSoundDevice, iRecordFormatData);
   670 	}
  1272 	}
   671 	
  1273 	
   672 void RMdaDevSound::CBody::Close()
  1274 void RMdaDevSound::CBody::Close()
   673 	{
  1275 	{
   674     #ifdef SYMBIAN_SOUNDADAPTER_DEBUG
  1276     #ifdef SYMBIAN_SOUNDADAPTER_DEBUG
   675         RDebug::Printf("void RMdaDevSound::CBody::Close() started");
  1277         RDebug::Printf("void RMdaDevSound::CBody::Close() started");
   676     #endif
  1278     #endif
   677 	iBufferIndex = -1;
       
   678 	iBufferOffset = -1;
  1279 	iBufferOffset = -1;
   679 	iBufferLength = 0;
  1280 	iBufferLength = 0;
   680 	iCurrentPlayer = 0;
  1281 
   681 	iTimerActive = EFalse;
  1282 	if(iPlaySoundDevice.Handle() != KNullHandle)
   682 	iChunk.Close();
  1283 	    {
   683 	iPlaySoundDevice.Close();
  1284         // Make sure all player objects are idle
   684 	iRecordSoundDevice.Close();
  1285         CancelPlayData();
       
  1286         iPlayChunk.Close();
       
  1287         iPlaySoundDevice.Close();
       
  1288 	    }
       
  1289 
       
  1290     if(iRecordSoundDevice.Handle() != KNullHandle)
       
  1291         {
       
  1292         CancelRecordData();
       
  1293         iRecordChunk.Close();
       
  1294         iRecordSoundDevice.Close();
       
  1295         }
       
  1296 	
   685 	iState = ENotReady;
  1297 	iState = ENotReady;
   686     #ifdef SYMBIAN_SOUNDADAPTER_DEBUG
  1298     #ifdef SYMBIAN_SOUNDADAPTER_DEBUG
   687         RDebug::Printf("void RMdaDevSound::CBody::Close() ended");
  1299         RDebug::Printf("void RMdaDevSound::CBody::Close() ended");
   688     #endif
  1300     #endif
   689 	}
  1301 	}
   690 		
  1302 
   691 TInt RMdaDevSound::CBody::Handle()
  1303 TInt RMdaDevSound::CBody::Handle()
   692 	{//This method is actually used to check whether the device is opened. Below logic should work
  1304 	{//This method is actually used to check whether the device is opened. Below logic should work
   693 	if(iPlaySoundDevice.Handle())
  1305 	if(iPlaySoundDevice.Handle())
   694 		{
  1306 		{
   695 		return iPlaySoundDevice.Handle();
  1307 		return iPlaySoundDevice.Handle();
   696 		}
  1308 		}
       
  1309 	if(iRecordSoundDevice.Handle())
       
  1310 		{
       
  1311 		return iRecordSoundDevice.Handle();
       
  1312 		}
   697 	return 0;
  1313 	return 0;
   698 	}
  1314 	}
   699 
  1315 
       
  1316 
   700 void RMdaDevSound::CBody::PlayData(TRequestStatus& aStatus, const TDesC8& aData)
  1317 void RMdaDevSound::CBody::PlayData(TRequestStatus& aStatus, const TDesC8& aData)
   701 	{
  1318 	{
   702 	#ifdef SYMBIAN_SOUNDADAPTER_DEBUG
  1319 	#ifdef SYMBIAN_SOUNDADAPTER_DEBUG
   703         RDebug::Printf("RMdaDevSound::CBody::PlayData(0x%x,%d) State=%d Current=%d. Handle=%d.",&aStatus, 
  1320     RDebug::Printf("RMdaDevSound::CBody::PlayData(0x%x,%d) State=%s Handle=%d.",&aStatus, 
   704                 aData.Length(), iState, iCurrentPlayer, iChunk.Handle());
  1321                    aData.Length(), iState.Name(), iPlayChunk.Handle());
   705         RDebug::Printf("KPlayMaxSharedChunkBuffersMask=0x%x KNumPlayersMask=0x%x", 
       
   706                 KPlayMaxSharedChunkBuffersMask, KNumPlayersMask);
       
   707 	#endif
  1322 	#endif
       
  1323 	
   708 	__ASSERT_DEBUG(iPlaySoundDevice.Handle(), Panic(EDeviceNotOpened));
  1324 	__ASSERT_DEBUG(iPlaySoundDevice.Handle(), Panic(EDeviceNotOpened));
   709 	aStatus = KRequestPending;
  1325 	aStatus = KRequestPending;
   710 	iPlayerStatus = &aStatus;//store the status of datapath player
  1326 
   711 	//No support for simultaneous play and record in RMdaDevSound
  1327 	if((iClientPlayStatus != NULL) || InRecordMode())
   712 	if(iState == ERecording)
  1328 		{
   713 		{
  1329 		// We only support one outstanding request
   714 		SoundDeviceError(KErrInUse);
  1330 		// No support for simultaneous play and record in RMdaDevSound
       
  1331 		TRequestStatus *pRequest = &aStatus;
       
  1332 		User::RequestComplete(pRequest, KErrInUse);
   715 		return;
  1333 		return;
   716 		}
  1334 		}
   717 	const TDes8* data = static_cast<const TDes8*>(&aData);
  1335 	iClientPlayStatus = &aStatus;//store the status of datapath player
   718 	
  1336 
   719 	if(!iChunk.Handle())
  1337 	if(iPlayFormatData.iConverter || iSavedTrailingData.Length() != 0)
       
  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())
   720 		{
  1422 		{
   721 		//This is where we setup to play. 
  1423 		//This is where we setup to play. 
   722 		//Configure the shared chunk for two buffers with iBufferSize each
  1424 		//Configure the shared chunk for two buffers with iBufferSize each
   723 		iBufferConfig.iNumBuffers = KPlayMaxSharedChunkBuffers;
  1425 		iPlayBufferConfig.iNumBuffers = KPlaySharedChunkBuffers;
   724 		iDeviceBufferLength = data->MaxLength();
  1426 		iDeviceBufferLength = KPlaySharedChunkBufferSize;
   725 		iBufferConfig.iFlags = 0;//data will be continuous
  1427 		#ifdef SYMBIAN_SOUNDADAPTER_DEBUG	
       
  1428 		RDebug::Printf("iDeviceBufferLength %d", iDeviceBufferLength);
       
  1429 		#endif
       
  1430 		iPlayBufferConfig.iFlags = 0;//data will be continuous
   726 		// If required, use rate converter etc
  1431 		// If required, use rate converter etc
   727 		if (iPlayData.iConverter)
  1432 		iPlayBufferConfig.iBufferSizeInBytes = iDeviceBufferLength;
   728 			{
       
   729 			iDeviceBufferLength = iPlayData.iConverter->MaxConvertBufferSize(iDeviceBufferLength, ETrue);
       
   730 			}
       
   731 		iBufferConfig.iBufferSizeInBytes = iDeviceBufferLength;
       
   732         #ifdef SYMBIAN_SOUNDADAPTER_DEBUG
  1433         #ifdef SYMBIAN_SOUNDADAPTER_DEBUG
   733             RDebug::Printf("number of buffers: [%d]",iBufferConfig.iNumBuffers);
  1434             RDebug::Printf("number of buffers: [%d]",iPlayBufferConfig.iNumBuffers);
   734             RDebug::Printf("BufferSize in Bytes [%d]",iBufferConfig.iBufferSizeInBytes);
  1435             RDebug::Printf("BufferSize in Bytes [%d]",iPlayBufferConfig.iBufferSizeInBytes);
   735         #endif
  1436         #endif
   736 		TPckg<TPlaySharedChunkBufConfig> bufferConfigBuf(iBufferConfig);
  1437 		TPckg<TPlaySharedChunkBufConfig> bufferConfigBuf(iPlayBufferConfig);
   737 		TInt error = iPlaySoundDevice.SetBufferChunkCreate(bufferConfigBuf,iChunk);
  1438 		TInt error = iPlaySoundDevice.SetBufferChunkCreate(bufferConfigBuf,iPlayChunk);
   738 		if(error == KErrNone)
  1439 		if(error == KErrNone)
   739 			{
  1440 			{
   740 			iPlaySoundDevice.GetBufferConfig(bufferConfigBuf);
  1441 			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
       
   751 			}
  1442 			}
   752 		if (error)
  1443 		if (error)
   753 			{
  1444 			{
   754 			SoundDeviceError(error);
  1445 			SoundDeviceError(error);
   755 			return;
  1446 			return;
   756 			}
  1447 			}
   757 		}
  1448 		}
   758 	
  1449 
   759 	iBufferIndex = (iBufferIndex+1) & KPlayMaxSharedChunkBuffersMask;
  1450     StartPlayersAndUpdateState();
   760 	
  1451 
   761 	TPtr8 dataPtr(iChunk.Base()+ iBufferConfig.iBufferOffsetList[iBufferIndex], 0, iDeviceBufferLength);
  1452 	return;	
   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
       
   836 	}
  1453 	}
   837 
  1454 
   838 void RMdaDevSound::CBody::RecordData(TRequestStatus& aStatus, TDes8& aData)
  1455 void RMdaDevSound::CBody::RecordData(TRequestStatus& aStatus, TDes8& aData)
   839 	{
  1456 	{
   840 	__ASSERT_DEBUG(iRecordSoundDevice.Handle(), Panic(EDeviceNotOpened));
  1457 	__ASSERT_DEBUG(iRecordSoundDevice.Handle(), Panic(EDeviceNotOpened));
   841 	aStatus = KRequestPending;
  1458 	aStatus = KRequestPending;
   842 	iRecorderStatus = &aStatus;
  1459 	if((iClientPlayStatus != NULL) || InPlayMode())
   843 	//No support for simultaneous play and record in RMdaDevSound
  1460 		{
   844 	if(iState == EPlaying)
  1461 		// We only support one outstanding request
   845 		{
  1462 		// No support for simultaneous play and record in RMdaDevSound
   846 		SoundDeviceError(KErrInUse);
  1463 		TRequestStatus *pRequest = &aStatus;
       
  1464 		User::RequestComplete(pRequest, KErrInUse);
   847 		return;
  1465 		return;
   848 		}
  1466 		}
   849 
  1467 	iClientRecordStatus = &aStatus;
   850 	iData = &aData;
  1468 	iClientRecordData = &aData;
   851 	
  1469 	iUnderFlowReportedSinceLastPlayOrRecordRequest = EFalse;
   852 	if(!iChunk.Handle())
  1470 
       
  1471 	iPlayChunk.Close();
       
  1472 	if(!iRecordChunk.Handle())
   853 		{
  1473 		{
   854 		//Configure the shared chunk for two buffers with iBufferSize each
  1474 		//Configure the shared chunk for two buffers with iBufferSize each
   855 		iRecordBufferConfig.iNumBuffers = KRecordMaxSharedChunkBuffers;
  1475 		iRecordBufferConfig.iNumBuffers = KRecordMaxSharedChunkBuffers;
   856 		iDeviceBufferLength = iData->MaxLength(); // initial size - resize if needs be
  1476 		iDeviceBufferLength = KRecordSharedChunkBufferSize; // initial size - resize if needs be
   857 		if (iRecordData.iConverter)
  1477 		if (iRecordFormatData.iConverter)
   858 			{
  1478 			{
   859 			// if number of channels used differs from request, resize buffer
  1479 			// if number of channels used differs from request, resize buffer
   860 			// assume we have nice rounded values for buffer.
  1480 			// assume we have nice rounded values for buffer.
   861 			if (iRecordData.iActualChannels>iRecordData.iRequestedChannels)
  1481 			if (iRecordFormatData.iActualChannels>iRecordFormatData.iRequestedChannels)
   862 				{
  1482 				{
   863 				iDeviceBufferLength *= 2; // will record at stereo and convert to mono 
  1483 				iDeviceBufferLength *= 2; // will record at stereo and convert to mono 
   864 				}
  1484 				}
   865 			else if (iRecordData.iActualChannels<iRecordData.iRequestedChannels)
  1485 			else if (iRecordFormatData.iActualChannels<iRecordFormatData.iRequestedChannels)
   866 				{
  1486 				{
   867 				iDeviceBufferLength /= 2; // will record at mono and convert to stereo 
  1487 				iDeviceBufferLength /= 2; // will record at mono and convert to stereo 
   868 				}
  1488 				}
   869 			}
  1489 			}
   870 		iRecordBufferConfig.iBufferSizeInBytes = iDeviceBufferLength;
  1490 		iRecordBufferConfig.iBufferSizeInBytes = iDeviceBufferLength;
   871 		iRecordBufferConfig.iFlags = 0;
  1491 		iRecordBufferConfig.iFlags = 0;
   872 		TPckg<TRecordSharedChunkBufConfig> bufferConfigBuf(iRecordBufferConfig);
  1492 		TPckg<TRecordSharedChunkBufConfig> bufferConfigBuf(iRecordBufferConfig);
   873 		TInt error = iRecordSoundDevice.SetBufferChunkCreate(bufferConfigBuf,iChunk);
  1493 		TInt error = iRecordSoundDevice.SetBufferChunkCreate(bufferConfigBuf,iRecordChunk);
   874 		if(error == KErrNone)
  1494 		if(error == KErrNone)
   875 			{
  1495 			{
   876 			iRecordSoundDevice.GetBufferConfig(bufferConfigBuf);
  1496 			iRecordSoundDevice.GetBufferConfig(bufferConfigBuf);
   877 			}
  1497 			}
   878 		else
  1498 		else
   883 		iState = ERecording;
  1503 		iState = ERecording;
   884 		}		
  1504 		}		
   885     #ifdef SYMBIAN_SOUNDADAPTER_DEBUG
  1505     #ifdef SYMBIAN_SOUNDADAPTER_DEBUG
   886         RDebug::Printf("RMdaDevSound::CBody::RecordData,iBufferOffset[%d]",iBufferOffset);
  1506         RDebug::Printf("RMdaDevSound::CBody::RecordData,iBufferOffset[%d]",iBufferOffset);
   887     #endif
  1507     #endif
   888 	iPlayers[iCurrentPlayer]->RecordData(iBufferLength);
  1508 
   889 	}
  1509 	switch(iState)
   890 	
  1510 		{
   891 void RMdaDevSound::CBody::SoundDeviceError(TInt aError, TInt /*aPlayerIndex*/)
  1511 		case ENotReady:
   892 // This is called by CPlayer objects when there is an error in RunL
  1512 			Panic(EBadState);
   893 	{
  1513 			break;
   894     #ifdef SYMBIAN_SOUNDADAPTER_DEBUG	
  1514 
   895 	RDebug::Print(_L("RMdaDevSound::CBody::SoundDeviceError: aError[%d]"), aError);
  1515 		case EStopped:
   896     #endif	
  1516 		case ERecording:
   897 
  1517 			// Either idle or recording is in progress, therefore we can issue another request			
   898 	//When we get an underflow from one of the players and the other player is active, we are 
  1518 			StartRecordRequest();
   899 	//bound to get an underflow from the other player too. So we ignore the first and process
  1519 			break;
   900 	//the second
  1520 			
   901 	TInt otherPlayerIndex = (iCurrentPlayer+1) & KNumPlayersMask;
  1521 		case ERecordingPausedInHw:
   902 	if (iPlayers[otherPlayerIndex]->IsActive() && aError==KErrUnderflow)
  1522 			// Driver is paused, therefore we can issue a request which will immediately return buffered data
   903 		{
  1523 			// or be aborted (in the driver) with KErrCancelled if there is no more data). nb. That KErrCancelled should not be
   904 		return;
  1524 			// returned to the client because the old RMdaDevSound driver would have completed with KErrNone and zero data length.
   905 		}
  1525 			StartRecordRequest();
   906 	SoundDeviceError(aError);
  1526 			break;
   907 	}
  1527 
       
  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 	
   908 /**
  1551 /**
   909    Note for maintainers: Please note that this method is called from
  1552 	Notify client of error.
   910    CancelPlayData and CancelRecordData with KErrNone as a parameter in order to
  1553 	
   911    cancel the players and reset the internal state.
  1554 	Note that we continue playing/recording if possible.
       
  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.
   912  */
  1561  */
   913 void RMdaDevSound::CBody::SoundDeviceError(TInt aError)
  1562 void RMdaDevSound::CBody::SoundDeviceError(TInt aError)
   914 	{
  1563 	{
   915     #ifdef SYMBIAN_SOUNDADAPTER_DEBUG
  1564     #ifdef SYMBIAN_SOUNDADAPTER_DEBUG
   916 	RDebug::Print(_L("RMdaDevSound::CBody::SoundDeviceError: Error[%d] CurrentPlayer[%d]"), aError, iCurrentPlayer);
  1565 	RDebug::Printf("RMdaDevSound::CBody::SoundDeviceError: Error[%d] state %s", aError, iState.Name());
   917     #endif
  1566     #endif
   918 
  1567 
   919 	for (TInt i=0; i<KNumPlayers; i++)
  1568 	ASSERT(aError != KErrNone);
   920 		{
  1569 	
   921 		if(KErrNone == aError)
  1570 	if(iClientPlayErrorStatus)
   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
       
   939 		{
  1571 		{
   940         #ifdef SYMBIAN_SOUNDADAPTER_DEBUG
  1572         #ifdef SYMBIAN_SOUNDADAPTER_DEBUG
   941             RDebug::Printf("RMdaDevSound::CBody::SoundDeviceError Completing iPlayerErrorStatus");
  1573             RDebug::Printf("RMdaDevSound::CBody::SoundDeviceError Completing iPlayerErrorStatus");
   942         #endif
  1574         #endif
   943 		User::RequestComplete(iPlayErrorStatus, aError);
  1575 
   944 		iPlayErrorStatus = NULL;
  1576 		User::RequestComplete(iClientPlayErrorStatus, aError); // nb call also sets iClientPlayErrorStatus to NULL
   945 		}
  1577 		}
   946 	if(iPlayerStatus)
  1578 
       
  1579   	if(iClientRecordErrorStatus)
   947 		{
  1580 		{
   948         #ifdef SYMBIAN_SOUNDADAPTER_DEBUG
  1581         #ifdef SYMBIAN_SOUNDADAPTER_DEBUG
   949             RDebug::Printf("RMdaDevSound::CBody::SoundDeviceError Completing iPlayerStatus");
  1582             RDebug::Printf("RMdaDevSound::CBody::SoundDeviceError Completing iClientRecordErrorStatus");
   950         #endif
  1583         #endif
   951 		User::RequestComplete(iPlayerStatus, KErrNone); // effectively buffer emptied
  1584 		User::RequestComplete(iClientRecordErrorStatus, aError); // nb call also sets iClientRecordErrorStatus to NULL
   952 		iPlayerStatus = NULL;
  1585 		}
   953 		}
  1586 
   954   	if(iRecordErrorStatus && aError!=KErrNone)
  1587 	return;
   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;
       
   976 	}
  1588 	}
   977 
  1589 
   978 void RMdaDevSound::CBody::NotifyRecordError(TRequestStatus& aStatus)
  1590 void RMdaDevSound::CBody::NotifyRecordError(TRequestStatus& aStatus)
   979 	{
  1591 	{
   980 	aStatus = KRequestPending;
  1592 	aStatus = KRequestPending;
   981 	iRecordErrorStatus = &aStatus;
  1593 	iClientRecordErrorStatus = &aStatus;
   982 	}
  1594 	}
   983 
  1595 
   984 void RMdaDevSound::CBody::NotifyPlayError(TRequestStatus& aStatus)
  1596 void RMdaDevSound::CBody::NotifyPlayError(TRequestStatus& aStatus)
   985 	{
  1597 	{
   986 	aStatus = KRequestPending;
  1598 	aStatus = KRequestPending;
   987 	iPlayErrorStatus = &aStatus;
  1599 	iClientPlayErrorStatus = &aStatus;
   988 	}
  1600 	}
   989 
  1601 
   990 void RMdaDevSound::CBody::CancelNotifyPlayError()
  1602 void RMdaDevSound::CBody::CancelNotifyPlayError()
   991 	{
  1603 	{
   992 	if(iPlayErrorStatus)
  1604 	if(iClientPlayErrorStatus)
   993 		{
  1605 		{
   994 		User::RequestComplete(iPlayErrorStatus, KErrCancel);
  1606 		User::RequestComplete(iClientPlayErrorStatus, KErrCancel);
   995 		}
  1607 		}
   996 	}
  1608 	}
   997 
  1609 
   998 void RMdaDevSound::CBody::CancelNotifyRecordError()
  1610 void RMdaDevSound::CBody::CancelNotifyRecordError()
   999 	{
  1611 	{
  1000 	if(iRecordErrorStatus)
  1612 	if(iClientRecordErrorStatus)
  1001 		{
  1613 		{
  1002 		User::RequestComplete(iRecordErrorStatus, KErrCancel);
  1614 		User::RequestComplete(iClientRecordErrorStatus, KErrCancel);
  1003 		}
  1615 		}
       
  1616 	else
       
  1617 	    {
       
  1618 		#ifdef SYMBIAN_SOUNDADAPTER_DEBUG	
       
  1619         RDebug::Printf("msp BufferEmptied but iClientPlayStatus==NULL");
       
  1620 		#endif
       
  1621 	    }
  1004 	}
  1622 	}
  1005 
  1623 
  1006 void RMdaDevSound::CBody::FlushPlayBuffer()
  1624 void RMdaDevSound::CBody::FlushPlayBuffer()
  1007 	{
  1625 	{
  1008 	__ASSERT_DEBUG(iPlaySoundDevice.Handle(), Panic(EDeviceNotOpened));
  1626 	#ifdef SYMBIAN_SOUNDADAPTER_DEBUG	
  1009 	//There is no equivalent of FlushPlaybuffer in the new sound driver. So use CancelPlayData
  1627     RDebug::Printf("RMdaDevSound::CBody::FlushPlayBuffer calling CancelPlayData");
  1010 	//to simulate the original behavior
  1628 	#endif	
  1011 	if ((iState == EPlaying) || (iState == EPaused))
  1629 	CancelPlayData();
  1012 		{
  1630 	}
  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 
       
  1032 
  1631 
  1033 RSoundSc& RMdaDevSound::CBody::PlaySoundDevice()
  1632 RSoundSc& RMdaDevSound::CBody::PlaySoundDevice()
  1034 	{
  1633 	{
  1035 	return iPlaySoundDevice;
  1634 	return iPlaySoundDevice;
  1036 	}
  1635 	}
  1038 RSoundSc& RMdaDevSound::CBody::RecordSoundDevice()
  1637 RSoundSc& RMdaDevSound::CBody::RecordSoundDevice()
  1039 	{
  1638 	{
  1040 	return iRecordSoundDevice;
  1639 	return iRecordSoundDevice;
  1041 	}
  1640 	}
  1042 	
  1641 	
  1043 RMdaDevSound::CBody::TState RMdaDevSound::CBody::State()
  1642 const RMdaDevSound::CBody::TState &RMdaDevSound::CBody::State() const
  1044 	{
  1643 	{
  1045 	return iState;
  1644 	return iState;
  1046 	}
  1645 	}
  1047 
  1646 
  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 	}
       
  1059 
  1647 
  1060 void RMdaDevSound::CBody::BufferFilled(TInt aBufferOffset)
  1648 void RMdaDevSound::CBody::BufferFilled(TInt aBufferOffset)
  1061 	{
  1649 	{
  1062     #ifdef SYMBIAN_SOUNDADAPTER_DEBUG	
  1650     #ifdef SYMBIAN_SOUNDADAPTER_DEBUG	
  1063         RDebug::Print(_L("RMdaDevSound::CBody::BufferFilled:"));
  1651         RDebug::Print(_L("RMdaDevSound::CBody::BufferFilled:"));
  1064     #endif	
  1652     #endif	
  1065 
  1653 
  1066 	ASSERT(aBufferOffset>=0 || aBufferOffset==KErrCancel);
  1654 	ASSERT(aBufferOffset>=0 || aBufferOffset==KErrCancel);
  1067 	ASSERT(iData); // request should not get this without
  1655 	ASSERT(iClientRecordData); // request should not get this without
  1068 
  1656 
  1069 	if(aBufferOffset==KErrCancel)
  1657 	if(aBufferOffset==KErrCancel)
  1070 		{
  1658 		{
  1071 		//we can get KErrCancel when we call pause and there is no more data left with the driver
  1659 		//we can get KErrCancel when we call pause and there is no more data left with the driver
  1072 		//we send the empty buffer to the HwDevice, where this should trigger the shutdown mechanism
  1660 		//we send the empty buffer to the HwDevice, where this should trigger the shutdown mechanism
  1073 		iData->SetLength(0);
  1661 		iClientRecordData->SetLength(0);
  1074 		User::RequestComplete(iRecorderStatus, KErrNone);
  1662 		User::RequestComplete(iClientRecordStatus, KErrNone);
  1075 		iRecorderStatus = NULL;
  1663 		iClientRecordStatus = NULL;
  1076 		return;
  1664 		return;
  1077 		}
  1665 		}
  1078 		
  1666 		
  1079 	iBufferOffset = aBufferOffset;
  1667 	iBufferOffset = aBufferOffset;
  1080 	//when last buffer is flushed, new driver sometimes gives buffer size of odd number. One of our codecs
  1668 	//when last buffer is flushed, new driver sometimes gives buffer size of odd number. One of our codecs
  1081 	//expects that the buffer size should always be even. Base suggested that we fix in multimedia
  1669 	//expects that the buffer size should always be even. Base suggested that we fix in multimedia
  1082 	//as it is quite complicated to fix in overthere.
  1670 	//as it is quite complicated to fix in overthere.
  1083 	iBufferLength = iBufferLength & 0xfffffffe;
  1671 	iBufferLength = iBufferLength & 0xfffffffe;
  1084 	TPtr8 dataPtr(iChunk.Base()+ iBufferOffset, iBufferLength, iData->MaxLength());
  1672 	TPtr8 dataPtr(iRecordChunk.Base()+ iBufferOffset, iBufferLength, iClientRecordData->MaxLength());
  1085 	if (iRecordData.iConverter)
  1673 	if (iRecordFormatData.iConverter)
  1086 		{
  1674 		{
  1087 		iRecordData.iConverter->Convert(dataPtr, *iData);
  1675 		iRecordFormatData.iConverter->Convert(dataPtr, *iClientRecordData);
  1088 		}
  1676 		}
  1089 	else
  1677 	else
  1090 		{
  1678 		{
  1091 		iData->Copy(dataPtr);
  1679 		iClientRecordData->Copy(dataPtr);
  1092 		}
  1680 		}
  1093     #ifdef SYMBIAN_SOUNDADAPTER_DEBUG
  1681     #ifdef SYMBIAN_SOUNDADAPTER_DEBUG
  1094         RDebug::Print(_L("RMdaDevSound::CBody::BufferFilled: BufferOffset[%d] BufferLen[%d]"), iBufferOffset, iBufferLength);
  1682         RDebug::Print(_L("RMdaDevSound::CBody::BufferFilled: BufferOffset[%d] BufferLen[%d]"), iBufferOffset, iBufferLength);
  1095     #endif
  1683     #endif
  1096 	if(iBufferOffset >= 0)
  1684 	if(iBufferOffset >= 0)
  1097 		{
  1685 		{
  1098 		iRecordSoundDevice.ReleaseBuffer(iBufferOffset);
  1686 		iRecordSoundDevice.ReleaseBuffer(iBufferOffset);
  1099 		}
  1687 		}
  1100 	if(iRecorderStatus)
  1688 	if(iClientRecordStatus)
  1101 		{
  1689 		{
  1102 		User::RequestComplete(iRecorderStatus, KErrNone);
  1690 		User::RequestComplete(iClientRecordStatus, KErrNone);
  1103 		iRecorderStatus = NULL;
  1691 		iClientRecordStatus = NULL;
  1104 		}
  1692 		}
  1105 	}
  1693 	else
  1106 							
  1694 	    {
  1107 void RMdaDevSound::CBody::PlayCancelled()
  1695         RDebug::Printf("msp PlayCancelled but iClientPlayStatus==NULL");
  1108 	{
  1696 	    }
  1109     #ifdef SYMBIAN_SOUNDADAPTER_DEBUG	
  1697 	}
  1110         RDebug::Print(_L("RMdaDevSound::CBody::PlayCancelled:"));
  1698 		
  1111     #endif	
  1699 /*
  1112 
  1700 	This function is called to notify us that a CPlayer's request has completed and what its status was.
  1113 	for (TInt index=0; index<KNumPlayers; index++)
  1701 
  1114 		{
  1702 	It is important to note that:-
  1115 		iPlayers[index]->Cancel();
  1703 	1) RSoundSc driver PlayData requests are guaranteed to complete in order, oldest first
  1116 		}
  1704 	2) If we are overloaded, it is possible for more than one request to complete before any CPlayer::RunL is ran. In
  1117 	iBufferIndex = -1;
  1705 	this situation the CPlayer::RunL functions, and hence this callback, maybe invoked in non-oldest first order
  1118 	iCurrentPlayer = 0;
  1706 
  1119 	iBufferOffset = -1;
  1707 	but
  1120 	iBufferLength = 0;
  1708 
  1121 	iTimerActive = EFalse;
  1709 	a) It is impossible for callback for the second oldest CPlayer to occur before the driver request for the oldest has
  1122 	if(iPlayerStatus)
  1710 	been complete (because of 1)
  1123 		{
  1711 	b) We will always get exactly one callback for every complete request.
  1124 		User::RequestComplete(iPlayerStatus, KErrNone);
  1712 
  1125 		iPlayerStatus = NULL;
  1713 	Therefore this callback notifies us of two subtly separate things:-
  1126 		}
  1714 
  1127 	}
  1715 	i) The oldest request has been completed (so we can reduce can increase the bytes played counter by its length
  1128 	
  1716 	ii) CPlayer aPlayerIndex is free for re-use
  1129 void RMdaDevSound::CBody::UpdateTimeAndBytesPlayed()
  1717 
  1130 	{
  1718 	but we can not assume that aPlayerIndex is the oldest request, therefore we save the play request lengths outside of
  1131 	iBytesPlayed = iPlaySoundDevice.BytesTransferred();
  1719 	the CPlayer object.
  1132 	iStartTime = User::FastCounter();
  1720 */
  1133 	iTimerActive=ETrue;
  1721 void RMdaDevSound::CBody::PlayRequestHasCompleted(CPlayer *aPlayer, TInt aStatus, TBool aDueToCancelCommand)
  1134 	}
  1722 	{
  1135 	
  1723 	// CPlayer is done so put it on the free queue
  1136 TBool RMdaDevSound::CBody::TimerActive()
  1724 	iFreePlayers.Push(aPlayer);
  1137 	{
  1725 
  1138 	return iTimerActive;
  1726 	TUint32 bytesPlayed = iActivePlayRequestSizes.Pop();
  1139 	}
  1727 	// Request has finished therefore now timing the following request to simulate bytes played
  1140 
  1728     iStartTime = CurrentTimeInMsec();
  1141 TBool RMdaDevSound::CBody::FlushCalledDuringPause()
  1729 	if(aDueToCancelCommand)
  1142 	{
  1730 	    {
  1143 	return iFlushCalledDuringPause;
  1731         // Callback due to CPlayer::Cancel/DoCancel being called, therefore we
  1144 	}
  1732         // do not want to update bytes played, process state, report a error or start new players
  1145 	
  1733         return;
       
  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 
  1146 RMdaDevSound::CBody::CPlayer::CPlayer(TInt aPriority, RMdaDevSound::CBody& aParent, TInt aIndex):
  1806 RMdaDevSound::CBody::CPlayer::CPlayer(TInt aPriority, RMdaDevSound::CBody& aParent, TInt aIndex):
  1147 	CActive(aPriority), iParent(aParent), iIndex(aIndex), iBufferOffset(-1), iBufferLength(0)
  1807 	CActive(aPriority), iParent(aParent), iIndex(aIndex), iBufferOffset(-1), iBufferLength(0)
  1148 	{
  1808 	{
  1149 	CActiveScheduler::Add(this);
  1809 	CActiveScheduler::Add(this);
  1150 	}
  1810 	}
  1152 RMdaDevSound::CBody::CPlayer::~CPlayer()
  1812 RMdaDevSound::CBody::CPlayer::~CPlayer()
  1153 	{
  1813 	{
  1154 	Cancel();
  1814 	Cancel();
  1155 	}
  1815 	}
  1156 
  1816 
       
  1817 
  1157 void RMdaDevSound::CBody::CPlayer::RunL()
  1818 void RMdaDevSound::CBody::CPlayer::RunL()
  1158 	{
  1819 	{
  1159     #ifdef SYMBIAN_SOUNDADAPTER_DEBUG	
  1820     #ifdef SYMBIAN_SOUNDADAPTER_DEBUG	
  1160         RDebug::Print(_L("****RMdaDevSound::CBody::CPlayer(%d)::RunL: Error[%d] ParentState[%d] Outstanding[%d], pending[%d]"), 
  1821     RDebug::Printf("****RMdaDevSound::CBody::CPlayer(%d)::RunL: Error[%d] ParentState[%s]", 
  1161                             iIndex, iStatus.Int(), iParent.State(), iParent.iHaveSecondPhaseData, iRequestPending);
  1822                      iIndex, iStatus.Int(), iParent.State().Name());
       
  1823 	RDebug::Printf("iActivePlayRequestSizes.Length() = %d iFreePlayers.Length() = %d (including this one as active)", 
       
  1824 					iParent.iActivePlayRequestSizes.Length(), 
       
  1825 					iParent.iFreePlayers.Length());
  1162     #endif
  1826     #endif
  1163 
  1827 	iParent.PlayRequestHasCompleted(this, iStatus.Int(), EFalse);
  1164 	//this is required to avoid receiving the request completions in the order diff. from the 
  1828 	return;
  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 		}
       
  1232 	}
  1829 	}
  1233 
  1830 
  1234 TInt RMdaDevSound::CBody::CPlayer::RunError(TInt aError)
  1831 TInt RMdaDevSound::CBody::CPlayer::RunError(TInt aError)
  1235 	{
  1832 	{
  1236 	iParent.SoundDeviceError(aError, iIndex);
  1833 	iParent.PlayRequestHasCompleted(this, aError, EFalse);
  1237 	return KErrNone;
  1834 	return KErrNone;
  1238 	}
  1835 	}
  1239 	
  1836 
  1240 void RMdaDevSound::CBody::CPlayer::DoCancel()
  1837 void RMdaDevSound::CBody::CPlayer::DoCancel()
  1241 	{
  1838 	{
  1242 	//nothing to do
       
  1243 #ifdef SYMBIAN_SOUNDADAPTER_DEBUG
  1839 #ifdef SYMBIAN_SOUNDADAPTER_DEBUG
  1244 	RDebug::Printf("RMdaDevSound::CBody::CPlayer(%d)::DoCancel", iIndex);
  1840 	RDebug::Printf("RMdaDevSound::CBody::CPlayer(%d)::DoCancel", iIndex);
  1245 #endif
  1841 #endif
  1246 	}
  1842 	if(iStatus == KRequestPending)
  1247 
  1843 	    {
  1248 void RMdaDevSound::CBody::CPlayer::ResetPlayer()
  1844         // Avoid cancelling requests which have already completed.
       
  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)
  1249 	{
  1855 	{
  1250     #ifdef SYMBIAN_SOUNDADAPTER_DEBUG	
  1856     #ifdef SYMBIAN_SOUNDADAPTER_DEBUG	
  1251 	RDebug::Print(_L("RMdaDevSound::CBody::CPlayer(%d)::ResetPlayer: IsActive[%d] pending[%d] iBufferOffset[%d] iBufferLength[%d]"), iIndex, IsActive(), iRequestPending, iBufferOffset, iBufferLength);
  1857 	RDebug::Print(_L("RMdaDevSound::CBody::CPlayer(%d)::PlayData : IsActive[%d]"),
  1252     #endif
  1858 				  iIndex,    IsActive());
  1253 
  1859 	RDebug::Printf("iActivePlayRequestSizes.Length() = %d iFreePlayers.Length() = %d (inc this player)", 
  1254 	iRequestPending = EFalse;
  1860 					iParent.iActivePlayRequestSizes.Length(), 
  1255 	iBufferOffset = -1;
  1861 					iParent.iFreePlayers.Length());
  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());
       
  1273     #endif	
  1862     #endif	
  1274 
  1863 	
  1275 	ASSERT(!IsActive()); // TODO: remove or replace redundant test
  1864 	iBufferOffset = aChunkOffset;
  1276 	iBufferOffset = aBufferOffset;
       
  1277 	iBufferLength = aLength;
  1865 	iBufferLength = aLength;
  1278 
  1866 
  1279 	iStatus = KRequestPending;
  1867     //Make sure the length is a multiple of 4 to work around an h6 limitation.
       
  1868 	iBufferLength = iBufferLength & 0xfffffffc;
       
  1869 
       
  1870 	// Issue the RSoundSc request
       
  1871 	iParent.PlaySoundDevice().PlayData(iStatus, iBufferOffset, iBufferLength, EFalse);
  1280 	SetActive();
  1872 	SetActive();
  1281 	TRequestStatus* status = &iStatus;
  1873 	return;
  1282 	User::RequestComplete(status, KErrNone);
  1874 	}
  1283 	}
  1875 	
  1284 	
  1876 TUint RMdaDevSound::CBody::CPlayer::GetPlayerIndex() const
  1285 void RMdaDevSound::CBody::CPlayer::RecordData(TInt& aBufferLength)
  1877 	{
       
  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)
  1286 	{
  1893 	{
  1287 	if (!IsActive())
  1894 	if (!IsActive())
  1288 	    {
  1895 	    {
  1289 	    iStatus = KRequestPending;
  1896 	    iStatus = KRequestPending;
  1290         #ifdef SYMBIAN_SOUNDADAPTER_DEBUG
  1897         #ifdef SYMBIAN_SOUNDADAPTER_DEBUG
  1293 	    iParent.RecordSoundDevice().RecordData(iStatus, aBufferLength);
  1900 	    iParent.RecordSoundDevice().RecordData(iStatus, aBufferLength);
  1294 	    SetActive();
  1901 	    SetActive();
  1295 	    }
  1902 	    }
  1296 	}
  1903 	}
  1297 
  1904 
  1298 void RMdaDevSound::CBody::CPlayer::PlaySoundDevice()
  1905 void RMdaDevSound::CBody::CRecorder::RunL()
  1299 	{
  1906 	{
  1300     #ifdef SYMBIAN_SOUNDADAPTER_DEBUG	
  1907     #ifdef SYMBIAN_SOUNDADAPTER_DEBUG	
  1301 	RDebug::Print(_L("RMdaDevSound::CBody::CPlayer(%d)::PlaySoundDevice : IsActive[%d]"), iIndex, IsActive());
  1908     RDebug::Printf("****RMdaDevSound::CBody::CRecorder()::RunL: Error[%d] ParentState[%s]", 
  1302     #endif	
  1909                      iStatus.Int(), iParent.State().Name());
  1303 
  1910     #endif
  1304 #ifdef SYMBIAN_FORCE_32BIT_LENGTHS
  1911 
  1305 	if (iBufferLength%4 != 0)
  1912 	
  1306 		{
  1913 	TInt error = iStatus.Int();
  1307 		// simulate the limitation of some hardware, where -6 is generated if the
  1914 	
  1308 		// buffer length is not divisible by 4.
  1915 	if((error >= 0) || (error == KErrCancel))
  1309 		TRequestStatus*status = &iStatus;
  1916 		{//we can get KErrCancel when we call pause and there is no more data left with the driver
  1310 		User::RequestComplete(status, KErrArgument);
  1917 		iParent.BufferFilled(error);
  1311 		}
  1918 		}
  1312 	else
  1919 	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");
  1313 #endif
  1939 #endif
  1314 		{
  1940     iParent.RecordSoundDevice().Cancel(iStatus);
  1315 		iParent.PlaySoundDevice().PlayData(iStatus, iBufferOffset, iBufferLength, EFalse);
  1941     }
  1316 		// Pause was called when there was no data available. Now that we have data available, we should pause the driver
  1942 
  1317 		if (iParent.iPauseDeviceDriverOnNewData)
  1943 
  1318 			{
  1944 // End of file
  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 	}