devsound/devsoundrefplugin/src/swcodecwrapper/mmfSwCodecPlayDataPath.cpp
changeset 0 40261b775718
equal deleted inserted replaced
-1:000000000000 0:40261b775718
       
     1 // Copyright (c) 2003-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 // source\server\mmfswcodecplaydatapath.cpp
       
    15 // 
       
    16 //
       
    17 
       
    18 #include "mmfSwCodecPlayDataPath.h"
       
    19 #include <mmf/server/mmfswcodecwrapper.h>
       
    20 #include <mmf/server/mmfswcodecwrappercustominterfacesuids.hrh>
       
    21 #include <mmf/common/mmfpaniccodes.h>
       
    22 #include "mmfSwCodecUtility.h"
       
    23 
       
    24 const TInt KBytesPerSample = 2;
       
    25 const TInt KMaxBytesInSec = 192000; //considering maximum samplerate 96KHz
       
    26 CMMFSwCodecPlayDataPath* CMMFSwCodecPlayDataPath::NewL()
       
    27 	{
       
    28 	CMMFSwCodecPlayDataPath* self = new(ELeave) CMMFSwCodecPlayDataPath;
       
    29 	CleanupStack::PushL(self);
       
    30 	self->ConstructL();
       
    31 	CleanupStack::Pop();
       
    32 	return self;
       
    33 	}
       
    34 
       
    35 
       
    36 void CMMFSwCodecPlayDataPath::ConstructL()
       
    37 	{
       
    38 	iAudioPlayer = new (ELeave) CDataPathPlayer(*this,CActive::EPriorityUserInput);
       
    39 	iSoundDeviceErrorReceiver = new (ELeave) CSoundDevPlayErrorReceiver(*this, CActive::EPriorityUserInput);
       
    40 	iUtility = CMMFSwCodecUtility::NewL();
       
    41 	iVbrFlag = EFalse;
       
    42 	}
       
    43 
       
    44 
       
    45 CMMFSwCodecPlayDataPath::~CMMFSwCodecPlayDataPath()
       
    46 	{
       
    47 	delete iAudioPlayer;
       
    48 	delete iSoundDeviceErrorReceiver;
       
    49 	delete iUtility;
       
    50 
       
    51 	iSoundDevice.Close();
       
    52 
       
    53 	if (iCodec)
       
    54 		{
       
    55 		delete iSourceBuffer;
       
    56 		if (!iCodec->IsNullCodec()) 
       
    57 			{
       
    58 			delete iSoundDeviceBuffer;
       
    59 			}
       
    60 		}
       
    61 
       
    62 #ifdef __USE_MMF_TRANSFERBUFFERS__
       
    63 	delete iTransferWindow;
       
    64 
       
    65 	if(iTransferBuffer)
       
    66 		{
       
    67 		iTransferBuffer->Close();
       
    68 		delete iTransferBuffer;
       
    69 		}
       
    70 #endif
       
    71 
       
    72 #ifdef __USE_MMF_PTRBUFFERS__
       
    73 	delete iPtrBufferMemoryBlock;
       
    74 #endif
       
    75 	}
       
    76 
       
    77 
       
    78 TInt CMMFSwCodecPlayDataPath::SetObserver(MMMFHwDeviceObserver& aObserver)
       
    79 	{
       
    80 	TInt error;
       
    81 	if (iHwDeviceObserver)
       
    82 		{
       
    83 		error =  KErrAlreadyExists;
       
    84 		}
       
    85 	else
       
    86 		{
       
    87 		iHwDeviceObserver = &aObserver;
       
    88 		error  = KErrNone;
       
    89 		}
       
    90 	return error;
       
    91 	}
       
    92 
       
    93 
       
    94 TInt CMMFSwCodecPlayDataPath::AddCodec(CMMFSwCodec& aCodec)
       
    95 	{
       
    96 	if (iCodec)
       
    97 		return KErrNotSupported; //doesn't support multiple codecs
       
    98 
       
    99 	TInt err = KErrNone;
       
   100 	
       
   101 	iCodec = &aCodec;
       
   102 
       
   103 	// Allocate data buffer
       
   104 	iSourceBufferSize = iCodec->SourceBufferSize();
       
   105 	iSoundDevBufferSize = iCodec->SinkBufferSize();
       
   106 
       
   107 	if ((!iSourceBufferSize)||(!iSoundDevBufferSize))
       
   108 		err = KErrArgument; //codec plugin has not specified buffer size
       
   109 
       
   110 	if (err == KErrNone)
       
   111 		{
       
   112 #ifdef __USE_MMF_TRANSFERBUFFERS__
       
   113 		TRAP(err,iSourceBuffer = CreateTransferBufferL(iSourceBufferSize, static_cast<CMMFTransferBuffer*>(iSourceBuffer)));
       
   114 #endif
       
   115 #ifdef __USE_MMF_PTRBUFFERS__
       
   116 		TRAP(err,iSourceBuffer = CreatePtrBufferL(iSourceBufferSize));
       
   117 #else
       
   118 		TRAP(err,iSourceBuffer = CMMFDataBuffer::NewL(iSourceBufferSize));
       
   119 #endif
       
   120 		}
       
   121 	
       
   122 	if (err == KErrNone)
       
   123 		{
       
   124 		if (iCodec->IsNullCodec())
       
   125 			{//use source buffer for sound device buffer	
       
   126 			iSoundDeviceBuffer = NULL;
       
   127 			}
       
   128 		else
       
   129 			{//codec needs separate source and sound device buffers
       
   130 			TRAP(err,iSoundDeviceBuffer = CMMFDataBuffer::NewL(iSoundDevBufferSize));
       
   131 			}
       
   132 		}
       
   133 	return err;
       
   134 	}
       
   135 
       
   136 
       
   137 TInt CMMFSwCodecPlayDataPath::Start()
       
   138 	{
       
   139 	TInt startError = KErrNone;
       
   140 
       
   141 	if (!iCodec) 
       
   142 		{//check that a codec has been added
       
   143 		startError = KErrNotReady;
       
   144 		}
       
   145 	if ((!iSoundDevice.Handle())&&(!startError))
       
   146     	{//check that the sound drivers can be opened
       
   147    		startError = iSoundDevice.Open();
       
   148 		}
       
   149 
       
   150 	if (iState == EPaused)
       
   151 		{//we are paused so need to resume play
       
   152 		if (!startError)
       
   153 			{
       
   154 #ifdef _SCW_DEBUG
       
   155 			RDebug::Print(_L("CMMFSwCodecPlayDataPath::Start-Resume"));
       
   156 #endif
       
   157 			iAudioPlayer->ResumePlaying();
       
   158 			iState = EPlaying;
       
   159 			}
       
   160 		}
       
   161 	else if (!startError)
       
   162 		{
       
   163 #ifdef _SCW_DEBUG
       
   164 		RDebug::Print(_L("CMMFSwCodecPlayDataPath::Start-Normal"));
       
   165 #endif
       
   166 		// get sample rate and channels from RMdaDevSound
       
   167 		RMdaDevSound::TCurrentSoundFormatBuf format;
       
   168 		iSoundDevice.GetPlayFormat(format);
       
   169 		iSampleRate = format().iRate;
       
   170 		iChannels = format().iChannels;
       
   171 		
       
   172 		iNoMoreSourceData = EFalse;
       
   173 		iNoMoreSoundDeviceData = EFalse;
       
   174 		iSourceBuffer->SetLastBuffer(EFalse);
       
   175 		iBytesPlayed = 0;
       
   176 		iState = EPlaying;
       
   177 		iSoundDeviceErrorReceiver->Start();
       
   178 		TRAP(startError,FillSourceBufferL()); //get initial buffer of audio data
       
   179 		if (startError == KErrNone)
       
   180 			{
       
   181 			// Start the player objects
       
   182 			iAudioPlayer->Start();
       
   183 			}
       
   184 		else
       
   185 			{//failed to start up correctly go back to stopped state
       
   186 			iState = EStopped;
       
   187 			iSoundDeviceErrorReceiver->Stop();
       
   188 			}
       
   189    		}
       
   190 	return startError;
       
   191 	}
       
   192 
       
   193 
       
   194 // *** Main Play Loop ***
       
   195 
       
   196 void CMMFSwCodecPlayDataPath::FillSourceBufferL()
       
   197 	{//asks observer to fill the source buffer          
       
   198     // Ask immediately for data from the observer
       
   199 #ifdef __CYCLE_MMF_DATABUFFERS__
       
   200 	// Create a new buffer to replicate INC021405 Play-EOF-Play on HwAccelerated solution Panics
       
   201 	// If the creation fails, we carry on regardless as the original buffer will not have been 
       
   202 	// destroyed. Must do this as alloc fail tests will not run.
       
   203 	if(iSourceBuffer)
       
   204 		{
       
   205 		iSourceBuffer = CycleAudioBuffer(iSourceBuffer);
       
   206 		}
       
   207 #endif // __CYCLE_MMF_DATABUFFERS__	
       
   208 	User::LeaveIfError(iHwDeviceObserver->FillThisHwBuffer(*iSourceBuffer));
       
   209 	
       
   210 	}
       
   211 
       
   212 
       
   213 void CMMFSwCodecPlayDataPath::BufferFilledL(CMMFDataBuffer& aBuffer)
       
   214 	{//call back from observer to indicate buffer has been filled
       
   215 	if (iState == EStopped)
       
   216 		User::Leave(KErrNotReady);//ok if paused?
       
   217 
       
   218 	iSourceBuffer = &aBuffer;
       
   219 	iSourceBuffer->SetStatus(EFull);
       
   220 #ifdef _SCW_DEBUG
       
   221 	RDebug::Print(_L("CMMFSwCodecPlayDataPath::BufferFilledL"));
       
   222 #endif
       
   223 
       
   224 	//need to check that the buffer size is not 0 - if so assume we've reached the end of the data
       
   225 	if (!iSourceBuffer->BufferSize())
       
   226 		{//no buffer  - could be end of source or could be that the source has no data??
       
   227 		iNoMoreSourceData = ETrue;
       
   228 #ifdef _SCW_DEBUG
       
   229 		RDebug::Print(_L("CMMFSwCodecPlayDataPath::BufferFilledL-NoMoreSourceData"));
       
   230 #endif
       
   231 		}
       
   232 	//even if the buffer size is 0 we still 
       
   233 	//need to perform the following to get the sound device callback
       
   234 	FillSoundDeviceBufferL(); //get buffer in pcm16 format for sound device	
       
   235 
       
   236     /* iVbrFlag is added to datapath to avail the alternative dataflow wherein datapath makes sure that 
       
   237     destinationbuffer is filled to its maximum length before sending it to the sound driver. 
       
   238     Sending the buffer directly to the device causes underflow incase of Vorbis codecs.*/
       
   239     if (iVbrFlag)
       
   240     	{
       
   241     	/*There are two cases we need to deal here
       
   242       	1. When the output of the codec is 0 for header data.
       
   243            in that case, repeat till actual decoding of ogg packets and pages.
       
   244         2. When destination buffer is not filled even to its half length, get next source buffer
       
   245            and decode it. This is to avoid underflows when ever we receive little pcm for a 
       
   246            a given source buffer.
       
   247            */
       
   248 	    if (iSoundDeviceBuffer->Data().Length() < iSoundDeviceBuffer->Data().MaxLength()/2 && !(iSoundDeviceBuffer->LastBuffer()))
       
   249 			{
       
   250 	    	iSourceBuffer->SetStatus(EAvailable); //source buffer is now available
       
   251 	    	iSoundDeviceBuffer->SetPosition(iSoundDeviceBuffer->Data().Length());//this indicates the available space in the buffer to the codec
       
   252 	    	FillSourceBufferL();	
       
   253 	    	return;
       
   254 	    	}
       
   255 		else //data is sufficient to avoid underflows
       
   256 			{
       
   257 			iSoundDeviceBuffer->SetPosition(0);
       
   258 			if(iSoundDeviceBuffer->Data().Length()==0 && iSoundDeviceBuffer->LastBuffer())
       
   259 				{
       
   260 				iNoMoreSoundDeviceData = ETrue;
       
   261 				}
       
   262 			}	
       
   263     	}
       
   264 
       
   265     // attenuate the amplitude of the samples if volume ramping has been changed
       
   266 	// and is non-zero
       
   267 	if (iCustomInterface)
       
   268 		{
       
   269 		TTimeIntervalMicroSeconds volumeRamp = iCustomInterface->VolumeRamp();
       
   270 		if (volumeRamp != iVolumeRamp)
       
   271 			{
       
   272 			iVolumeRamp = volumeRamp;
       
   273 			if (iVolumeRamp.Int64() != 0)
       
   274 				{
       
   275 				iUtility->ConfigAudioRamper(
       
   276 					iVolumeRamp.Int64(), 
       
   277 					iSampleRate, 
       
   278 					iChannels);
       
   279 				iRampAudioSample = ETrue;
       
   280 				}
       
   281 			else
       
   282 				{
       
   283 				iRampAudioSample = EFalse;
       
   284 				}
       
   285 
       
   286 			}
       
   287 			if (iRampAudioSample)
       
   288 				iRampAudioSample = iUtility->RampAudio(iSoundDeviceBuffer);
       
   289 		}
       
   290 
       
   291 	iAudioPlayer->PlayData(*iSoundDeviceBuffer); //play data to sound drivers
       
   292 
       
   293 	if (iSourceBuffer->LastBuffer())//check last buffer flag
       
   294 		{
       
   295 		iNoMoreSourceData = ETrue;
       
   296 #ifdef _SCW_DEBUG
       
   297 		RDebug::Print(_L("CMMFSwCodecPlayDataPath::BufferFilledL-LBNoMoreSourceData"));
       
   298 #endif
       
   299 		}
       
   300 	}
       
   301 
       
   302 
       
   303 void CMMFSwCodecPlayDataPath::FillSoundDeviceBufferL()
       
   304 	{//use CMMFSwCodec to fill the sound device buffer
       
   305 	
       
   306 	CMMFSwCodec::TCodecProcessResult codecProcessResult;
       
   307 
       
   308 	if (iCodec->IsNullCodec())
       
   309 		{//no codec so data can be sent direct to sink
       
   310 		iSoundDeviceBuffer = iSourceBuffer;
       
   311 		iSoundDeviceBuffer->SetStatus(EFull);	//sink buffer is full
       
   312 		}	
       
   313 	else 
       
   314 		{	
       
   315 		//pass buffer to codec for processing
       
   316 		codecProcessResult = iCodec->ProcessL(*iSourceBuffer, *iSoundDeviceBuffer);
       
   317 		
       
   318 		if (iSourceBuffer->LastBuffer()) //if source is last buffer so is sound dev
       
   319 			iSoundDeviceBuffer->SetLastBuffer(ETrue);
       
   320 		if ((!iSoundDeviceBuffer->BufferSize())&&(codecProcessResult.iDstBytesAdded))
       
   321 			{//the codec has added data but not set the buffer length
       
   322 			iSoundDeviceBuffer->Data().SetLength(codecProcessResult.iDstBytesAdded);
       
   323 			}
       
   324 		//only supports EProcessComplete
       
   325 		switch (codecProcessResult.iCodecProcessStatus)
       
   326 			{
       
   327 		case CMMFSwCodec::TCodecProcessResult::EProcessComplete:
       
   328 		//finished procesing source data - all data in sink buffer
       
   329 			{
       
   330 			iSoundDeviceBuffer->SetStatus(EFull);	//sink buffer is full	
       
   331 			}
       
   332 		break;
       
   333 #ifdef SYMBIAN_VARIABLE_BITRATE_CODEC
       
   334 		case CMMFSwCodec::TCodecProcessResult::EProcessIncomplete:
       
   335 		//finished procesing source data - all data in sink buffer
       
   336 			{
       
   337 			iSoundDeviceBuffer->SetStatus(EFull);	//sink buffer is full	
       
   338 			}
       
   339 		break;
       
   340 #endif
       
   341 		case CMMFSwCodec::TCodecProcessResult::EDstNotFilled:
       
   342 		//could be the last buffer in which case dst might not get filled
       
   343 			{
       
   344 			iSoundDeviceBuffer->SetStatus(EFull);	//sink buffer is full	
       
   345 			}
       
   346 		break;
       
   347 		case CMMFSwCodec::TCodecProcessResult::EEndOfData:
       
   348 			//no more data - send what we've got to the sink
       
   349 			//note we can't always rely on this  - in many cases the codec will not know when
       
   350 			//it has reached the end of data.
       
   351 			{
       
   352 			iSoundDeviceBuffer->SetStatus(EFull);//sink buffer may not really be 'full' but its as full as it going to get
       
   353 			iNoMoreSourceData = ETrue;
       
   354 			//doesn't matter if sink buffer is not full
       
   355 			}
       
   356 		break;
       
   357 		default:
       
   358 			Panic(EMMFSwCodecWrapperBadCodec); //should never get here - bad codec
       
   359 			}
       
   360 		}
       
   361 	}
       
   362 
       
   363 
       
   364 void CMMFSwCodecPlayDataPath::BufferEmptiedL(const CMMFDataBuffer& aBuffer)
       
   365 	{//call back from CDataPathPlayer when the sound device buffer has been emptied
       
   366 	if (&aBuffer != iSoundDeviceBuffer) 
       
   367 		Panic(EMMFSwCodecWrapperBadBuffer);
       
   368 	if(iVbrFlag && (iSourceBuffer->Status() == EUnAvailable || iNoMoreSourceData))
       
   369 		{//No more source data. Play rest of the decoded data.Inform codec not to consider the source buffer
       
   370 		if(iSourceBuffer->Status()!=EUnAvailable)
       
   371 			{
       
   372 			iSourceBuffer->SetStatus(EUnAvailable);
       
   373 			}
       
   374 		FillSoundDeviceBufferL();
       
   375 		if(iSoundDeviceBuffer->BufferSize() > 0)
       
   376 			{
       
   377 			// attenuate the amplitude of the samples if volume ramping has been changed
       
   378 			// and is non-zero
       
   379 			if (iCustomInterface)
       
   380 				{
       
   381 				TTimeIntervalMicroSeconds volumeRamp = iCustomInterface->VolumeRamp();
       
   382 				if (volumeRamp != iVolumeRamp)
       
   383 					{
       
   384 					iVolumeRamp = volumeRamp;
       
   385 					if (iVolumeRamp.Int64() != 0)
       
   386 						{
       
   387 						iUtility->ConfigAudioRamper(iVolumeRamp.Int64(), iSampleRate, iChannels);
       
   388 						iRampAudioSample = ETrue;
       
   389 						}
       
   390 					else
       
   391 						{
       
   392 						iRampAudioSample = EFalse;
       
   393 						}
       
   394 
       
   395 					}
       
   396 				if (iRampAudioSample)
       
   397 					{
       
   398 					iRampAudioSample = iUtility->RampAudio(iSoundDeviceBuffer);
       
   399 					}
       
   400 					
       
   401 				}
       
   402 			iAudioPlayer->PlayData(*iSoundDeviceBuffer); //play data to sound drivers
       
   403 			return;
       
   404 			}
       
   405 		else
       
   406 			{
       
   407 			if(iNoMoreSourceData)
       
   408 				{
       
   409 				iNoMoreSoundDeviceData = ETrue;
       
   410 				}
       
   411 			iSourceBuffer->SetStatus(EAvailable);
       
   412 			}
       
   413 		}
       
   414 	if (!iNoMoreSourceData) 
       
   415 		FillSourceBufferL();
       
   416 	}
       
   417 
       
   418 //*** End of Main Play Loop ***
       
   419 
       
   420 
       
   421 void CMMFSwCodecPlayDataPath::Stop()
       
   422 	{
       
   423 	iAudioPlayer->Cancel();
       
   424 	iSoundDeviceErrorReceiver->Cancel();
       
   425     iSoundDevice.Close();
       
   426 
       
   427 #ifdef __CYCLE_MMF_DATABUFFERS__
       
   428 	// Create a new buffer to replicate INC021405 Play-EOF-Play on HwAccelerated solution Panics
       
   429 	// If the creation fails, we carry on regardless as the original buffer will not have been 
       
   430 	// destroyed. Must do this as alloc fail tests will not run.
       
   431 	if(iSourceBuffer)
       
   432 		{
       
   433 		iSourceBuffer = CycleAudioBuffer(iSourceBuffer);
       
   434 		}
       
   435 #endif // __CYCLE_MMF_DATABUFFERS__	
       
   436 
       
   437 	iState = EStopped;
       
   438 	}
       
   439 
       
   440 
       
   441 void CMMFSwCodecPlayDataPath::Pause()
       
   442 	{
       
   443 	//since a pause can happen anyway in the datatransfer -need to set to a known 
       
   444 	//state so that when play is resumed the behaviour is predictable
       
   445 	if (iSoundDevice.Handle())
       
   446 		{
       
   447 		iSoundDevice.PausePlayBuffer(); //needs new LDD
       
   448 		iState = EPaused;
       
   449 #ifdef _SCW_DEBUG
       
   450 		RDebug::Print(_L("Pause"));
       
   451 #endif
       
   452 		}
       
   453 	else
       
   454 		{//an error must have occured 
       
   455 		iState = EStopped;
       
   456 		}
       
   457 	}
       
   458 	
       
   459 	
       
   460 TInt CMMFSwCodecPlayDataPath::EmptyBuffers()
       
   461 	{
       
   462 	TInt error = KErrNone;
       
   463 	if (iSoundDevice.Handle() == 0)
       
   464 		{
       
   465 		error = KErrNotReady;
       
   466 		}
       
   467 	else
       
   468 		{ 
       
   469 		iAudioPlayer->Cancel();
       
   470 		iSoundDevice.CancelPlayData();
       
   471 		iSoundDeviceErrorReceiver->Stop();
       
   472 		iState = EStopped;
       
   473 		}
       
   474 	return error;
       
   475 	}	
       
   476 
       
   477 
       
   478 RMdaDevSound& CMMFSwCodecPlayDataPath::Device()
       
   479 	{
       
   480 	return iSoundDevice;
       
   481 	}
       
   482 
       
   483 
       
   484 void CMMFSwCodecPlayDataPath::SoundDeviceException(TInt aError)
       
   485 	{
       
   486 	if(iIgnoreUnderflow)
       
   487 		{
       
   488 		if(!iVbrFlag && aError==KErrUnderflow && !iNoMoreSourceData)
       
   489 			{
       
   490 			//ignore underflow
       
   491 			return;
       
   492 			}
       
   493 		//for VBR codec data,no more source does not mean that no more sounddevice data
       
   494 		//so ignore underflows till the last buffer is played from the codec
       
   495 		else if(iVbrFlag && aError==KErrUnderflow && !iNoMoreSoundDeviceData)
       
   496 			{
       
   497 			//ignore underflow
       
   498 			return;
       
   499 			}	
       
   500 		}
       
   501 	
       
   502 	//this sends a request to the hw device observer usually Devsound
       
   503 	//to update the bytes played
       
   504 	//it is done here so that the sound driver can be closed prior to
       
   505 	//updating the plicy and sending the error back
       
   506 	TUid uidUpdateBytesPlayed;
       
   507 	uidUpdateBytesPlayed.iUid = KMmfHwDeviceObserverUpdateBytesPlayed;
       
   508 	TPtrC8 dummy(0,0);
       
   509 	iHwDeviceObserver->MsgFromHwDevice(uidUpdateBytesPlayed,dummy);
       
   510 
       
   511 	//this closes RMdaDevSound.
       
   512 	Stop(); 
       
   513 
       
   514 	//inform devsound so it can update policy
       
   515 	iHwDeviceObserver->Stopped(); 
       
   516 
       
   517 	// Inform the observer of the exception condition
       
   518 	// We inform the hw device observer after the policy has been
       
   519 	// updated incase the observer relied on the error to assume
       
   520 	// the policy has been updated
       
   521 	iHwDeviceObserver->Error(aError);
       
   522 	}
       
   523 
       
   524 
       
   525 void CMMFSwCodecPlayDataPath::SetPlayCustomInterface(MPlayCustomInterface& aCustomInterface)
       
   526 	{
       
   527 	iCustomInterface = &aCustomInterface;
       
   528 	}
       
   529 	
       
   530 /**
       
   531 Retrieves a custom interface to the device.
       
   532 The reference CMMFSwCodecWrapper supports two  custom interfaces,
       
   533 MEmptyBuffersCustomInterface and MSetVbrFlagCustomInterface
       
   534 
       
   535 @param	aInterface
       
   536 		Interface UID, defined with the custom interface.
       
   537 		aInterface = KMmfUidEmptyBuffersCustomInterface for MEmptyBuffersCustomInterface,
       
   538 					 KSetVbrFlagCustomInterfaceTypeUid for MSetVbrFlagCustomInterface
       
   539 		
       
   540 @return A pointer to the interface implementation, or NULL if the device can not
       
   541 		implement the interface requested. The return value must be cast to the
       
   542 		correct type by the user.
       
   543 */
       
   544 TAny* CMMFSwCodecPlayDataPath::CustomInterface(TUid aInterface)
       
   545 	{
       
   546 	TAny* ret = NULL;
       
   547 	if (aInterface.iUid == KMmfUidEmptyBuffersCustomInterface)
       
   548 		{
       
   549 		MEmptyBuffersCustomInterface* result = static_cast<MEmptyBuffersCustomInterface*> (this);
       
   550 		ret = static_cast<TAny*>(result);
       
   551 		}
       
   552 	else if(aInterface.iUid == KSetVbrFlagCustomInterfaceTypeUid)
       
   553 		{
       
   554 		SetVbrFlag();
       
   555 		}
       
   556 	if (aInterface == KTimePlayedCustomInterfaceTypeUid)
       
   557 		{
       
   558 		MTimePlayedCustomInterface* result = static_cast<MTimePlayedCustomInterface*> (this);
       
   559 		ret = static_cast<TAny*>(result);
       
   560 		}
       
   561 	if (aInterface == KIgnoreUnderflowCustomInterfaceTypeUid)
       
   562 		{
       
   563 		MIgnoreUnderflowEventsCustomInterface* result = static_cast<MIgnoreUnderflowEventsCustomInterface*> (this);
       
   564 		ret = static_cast<TAny*>(result);
       
   565 		}
       
   566 	return ret;
       
   567 	}
       
   568 
       
   569 /**
       
   570 Used to set iVbrFlag on the datapath.
       
   571 
       
   572 This method is used to set the iVbrFlag in datapath. This flag is added to datapath to avail the 
       
   573 alternative dataflow wherein datapath makes sure that destinationbuffer is filled to its maximum length
       
   574 before sending it to the sound driver. Sending the buffer directly to the device causes underflow incase of VBR codecs.
       
   575 */		
       
   576 void CMMFSwCodecPlayDataPath::SetVbrFlag()
       
   577 	{
       
   578 	iVbrFlag = ETrue;
       
   579 	}
       
   580 
       
   581 TInt CMMFSwCodecPlayDataPath::GetTimePlayed(TTimeIntervalMicroSeconds& aTime)
       
   582 	{
       
   583 	if(iSoundDevice.Handle())
       
   584 		{
       
   585 		TInt bytes = iSoundDevice.BytesPlayed();
       
   586 		//Work around for overflow of bytes played from driver.
       
   587 		//This code will be removed when Base provides the TimePlayed() API which returns the play time
       
   588 		//Assuming GetTimePlayed() gets called in an interval not more than 3 secs, reset driver's bytes played when it is near KMaxInt
       
   589 		if(bytes > (KMaxTInt - 3*KMaxBytesInSec))
       
   590 			{
       
   591 			iBytesPlayed = iBytesPlayed+bytes;
       
   592 			iSoundDevice.ResetBytesPlayed();
       
   593 			bytes = 0;
       
   594 			}
       
   595 		TInt64 samplesPlayed = (iBytesPlayed+bytes)/(KBytesPerSample*iChannels);
       
   596 		aTime = (samplesPlayed*1000000)/iSampleRate;
       
   597 		}
       
   598 	else
       
   599 		{
       
   600 		aTime = 0;
       
   601 		}
       
   602 		
       
   603 	return KErrNone;
       
   604 	}
       
   605 
       
   606 void CMMFSwCodecPlayDataPath::IgnoreUnderflowEvents()
       
   607 	{
       
   608 	iIgnoreUnderflow = ETrue;
       
   609 	}
       
   610 /************************************************************************
       
   611  *				CDataPathPlayer											*
       
   612  ************************************************************************/
       
   613 
       
   614 CDataPathPlayer::CDataPathPlayer(CMMFSwCodecPlayDataPath& aParent, TInt aPriority)
       
   615 : CActive(aPriority), iParent(aParent)
       
   616 	{
       
   617 	CActiveScheduler::Add(this);
       
   618 	}
       
   619 
       
   620 
       
   621 CDataPathPlayer::~CDataPathPlayer()
       
   622 	{
       
   623 	Cancel();
       
   624 	}
       
   625 
       
   626 
       
   627 void CDataPathPlayer::Start()
       
   628 	{
       
   629 	// No implementation
       
   630 	}
       
   631 
       
   632 
       
   633 void CDataPathPlayer::ResumePlaying()
       
   634 	{
       
   635 	if (iParent.Device().Handle())
       
   636 		{
       
   637 		//should be ok to call this even if we are active
       
   638 		iParent.Device().ResumePlaying(); 
       
   639 		iResumePlaying = ETrue;
       
   640 		}
       
   641 #ifdef _SCW_DEBUG
       
   642 	RDebug::Print(_L("Playing Resumed"));
       
   643 #endif
       
   644 	}
       
   645 
       
   646 
       
   647 void CDataPathPlayer::PlayData(const CMMFDataBuffer& aData)
       
   648 	{
       
   649 	iDataFromSource = &aData;
       
   650 	if (!IsActive())
       
   651 		{
       
   652 #ifdef _SCW_DEBUG
       
   653 		RDebug::Print(_L("CDataPathPlayer::PlayData"));
       
   654 #endif
       
   655 		iParent.Device().PlayData(iStatus,(STATIC_CAST(const CMMFDataBuffer*, iDataFromSource))->Data());
       
   656 		SetActive();
       
   657 		}
       
   658 	}
       
   659 
       
   660 
       
   661 void CDataPathPlayer::Stop()
       
   662 	{
       
   663 	if (!IsActive())	
       
   664 		iParent.Device().FlushPlayBuffer(); // Otherwise won't be flushed
       
   665 	Cancel();
       
   666 	iParent.SoundDeviceException(KErrCancel);
       
   667 	}
       
   668 
       
   669 
       
   670 void CDataPathPlayer::RunL()
       
   671 	{
       
   672 #ifdef _SCW_DEBUG
       
   673 	RDebug::Print(_L("CDataPathPlayer::RunL error[%d]"), iStatus.Int());
       
   674 #endif
       
   675 	if (iStatus.Int()!=KErrNone)
       
   676 		{ 	
       
   677 		iParent.SoundDeviceException(iStatus.Int());
       
   678 		}
       
   679 	else
       
   680 		{
       
   681 		iParent.BufferEmptiedL(static_cast<const CMMFDataBuffer&>(*iDataFromSource));
       
   682 		iResumePlaying = EFalse;
       
   683 		}
       
   684 	}
       
   685 
       
   686 
       
   687 TInt CDataPathPlayer::RunError(TInt aError)
       
   688 	{
       
   689 	Error(aError);
       
   690 	return KErrNone;
       
   691 	}
       
   692 
       
   693 
       
   694 void CDataPathPlayer::DoCancel()
       
   695 	{
       
   696 	if (iParent.Device().Handle())
       
   697 		{
       
   698 		iParent.Device().CancelPlayData();
       
   699 		iParent.Device().FlushPlayBuffer();
       
   700 		}
       
   701 	}
       
   702 
       
   703 
       
   704 void CDataPathPlayer::Error(TInt aError)
       
   705 	{ 
       
   706 	iParent.SoundDeviceException(aError);
       
   707 	}
       
   708 
       
   709 
       
   710 /************************************************************************
       
   711  *				CSoundDevPlayErrorReceiver											*
       
   712  ************************************************************************/
       
   713 
       
   714 CSoundDevPlayErrorReceiver::CSoundDevPlayErrorReceiver(CMMFSwCodecPlayDataPath& aParent, TInt aPriority)
       
   715 : CActive(aPriority), iParent(aParent)
       
   716 	{
       
   717 	CActiveScheduler::Add(this);
       
   718 	}
       
   719 
       
   720 CSoundDevPlayErrorReceiver::~CSoundDevPlayErrorReceiver()
       
   721 	{
       
   722 	Cancel();
       
   723 	}
       
   724 
       
   725 void CSoundDevPlayErrorReceiver::Start()
       
   726 	{
       
   727 	iParent.Device().NotifyPlayError(iStatus);
       
   728 	SetActive();
       
   729 	}
       
   730 
       
   731 void CSoundDevPlayErrorReceiver::Stop()
       
   732 	{
       
   733 	Cancel();
       
   734 	}
       
   735 
       
   736 void CSoundDevPlayErrorReceiver::RunL()
       
   737 	{
       
   738 	TInt reason = iStatus.Int();
       
   739 	Start();
       
   740 	// An error has been returned
       
   741 #ifdef _SCW_DEBUG
       
   742 	RDebug::Print(_L("CSoundDevPlayErrorReceiver::RunL[%d]"), reason);
       
   743 #endif
       
   744 	iParent.SoundDeviceException(reason);
       
   745 	}
       
   746 
       
   747 void CSoundDevPlayErrorReceiver::DoCancel()
       
   748 	{
       
   749 	iParent.Device().CancelNotifyPlayError();
       
   750 	}
       
   751 
       
   752