devsound/sounddevbt/src/swcodecwrapper/mmfBtSwCodecPlayDataPath.cpp
changeset 0 40261b775718
equal deleted inserted replaced
-1:000000000000 0:40261b775718
       
     1 // Copyright (c) 2005-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\MmfBtSwCodecPlayDatapath.cpp
       
    15 // 
       
    16 //
       
    17 
       
    18 #include "mmfBtSwCodecPlayDataPath.h"
       
    19 #include "mmfbtswcodecwrapper.h"
       
    20 #include "mmfbtswcodecwrappercustominterfacesuids.hrh"
       
    21 #include <mmfpaniccodes.h>
       
    22 #include "mmfBtSwCodecUtility.h"
       
    23 
       
    24 #include "MMFBtRoutingSoundDevice.h"
       
    25 #include "A2dpBTHeadsetAudioIfClientServer.h" // for TRange (will be deprecated)
       
    26 
       
    27 CMMFSwCodecPlayDataPath* CMMFSwCodecPlayDataPath::NewL(	CRoutingSoundPlayDevice* aSoundDevice,
       
    28 														TUid aDeviceUid)
       
    29 	{
       
    30 	CMMFSwCodecPlayDataPath* self = new(ELeave) CMMFSwCodecPlayDataPath(aSoundDevice,
       
    31 																		aDeviceUid);
       
    32 	CleanupStack::PushL(self);
       
    33 	self->ConstructL();
       
    34 	CleanupStack::Pop();
       
    35 	return self;
       
    36 	}
       
    37 
       
    38 
       
    39 void CMMFSwCodecPlayDataPath::ConstructL()
       
    40 	{
       
    41 	iAudioPlayer = new (ELeave) CDataPathPlayer(*this,CActive::EPriorityUserInput);
       
    42 	iSoundDeviceErrorReceiver = new (ELeave) CSoundDevPlayErrorReceiver(*this, CActive::EPriorityUserInput);
       
    43 	iUtility = CMMFSwCodecUtility::NewL();
       
    44 	}
       
    45 
       
    46 
       
    47 CMMFSwCodecPlayDataPath::~CMMFSwCodecPlayDataPath()
       
    48 	{
       
    49 	delete iAudioPlayer;
       
    50 	delete iSoundDeviceErrorReceiver;
       
    51 	delete iUtility;
       
    52 
       
    53 	TRequestStatus status;
       
    54 	iSoundDevice->CloseDevice(iDeviceUid, status);
       
    55 	//TODO there should be a timeout for the line below
       
    56 	User::WaitForRequest(status);
       
    57 
       
    58 	if (iCodec)
       
    59 		{
       
    60 		delete iSourceBuffer;
       
    61 		if (!iCodec->IsNullCodec()) 
       
    62 			{
       
    63 			delete iSoundDeviceBuffer;
       
    64 			}
       
    65 		}
       
    66 
       
    67 #ifdef __USE_MMF_TRANSFERBUFFERS__
       
    68 	delete iTransferWindow;
       
    69 
       
    70 	if(iTransferBuffer)
       
    71 		{
       
    72 		iTransferBuffer->Close();
       
    73 		delete iTransferBuffer;
       
    74 		}
       
    75 #endif
       
    76 
       
    77 #ifdef __USE_MMF_PTRBUFFERS__
       
    78 	delete iPtrBufferMemoryBlock;
       
    79 #endif
       
    80 	}
       
    81 
       
    82 
       
    83 TInt CMMFSwCodecPlayDataPath::SetObserver(MMMFHwDeviceObserver& aObserver)
       
    84 	{
       
    85 	TInt error;
       
    86 	if (iHwDeviceObserver)
       
    87 		{
       
    88 		error =  KErrAlreadyExists;
       
    89 		}
       
    90 	else
       
    91 		{
       
    92 		iHwDeviceObserver = &aObserver;
       
    93 		error  = KErrNone;
       
    94 		}
       
    95 	return error;
       
    96 	}
       
    97 
       
    98 
       
    99 TInt CMMFSwCodecPlayDataPath::AddCodec(CMMFSwCodec& aCodec)
       
   100 	{
       
   101 	if (iCodec)
       
   102 		{
       
   103 		return KErrNotSupported; //doesn't support multiple codecs		
       
   104 		}
       
   105 
       
   106 	TInt err = KErrNone;
       
   107 	
       
   108 	iCodec = &aCodec;
       
   109 
       
   110 	// Allocate data buffer
       
   111 	iSourceBufferSize = iCodec->SourceBufferSize();
       
   112 	iSoundDevBufferSize = iCodec->SinkBufferSize();
       
   113 
       
   114 	if ((!iSourceBufferSize) || (!iSoundDevBufferSize))
       
   115 		{
       
   116 		err = KErrArgument; //codec plugin has not specified buffer size		
       
   117 		}
       
   118 
       
   119 	if (err == KErrNone)
       
   120 		{
       
   121 #ifdef __USE_MMF_TRANSFERBUFFERS__
       
   122 		TRAP(err,iSourceBuffer = CreateTransferBufferL(iSourceBufferSize, static_cast<CMMFTransferBuffer*>(iSourceBuffer)));
       
   123 #endif
       
   124 #ifdef __USE_MMF_PTRBUFFERS__
       
   125 		TRAP(err,iSourceBuffer = CreatePtrBufferL(iSourceBufferSize));
       
   126 #else
       
   127 		TRAP(err,iSourceBuffer = CMMFDataBuffer::NewL(iSourceBufferSize));
       
   128 #endif
       
   129 		}
       
   130 	
       
   131 	if (err == KErrNone)
       
   132 		{
       
   133 		if (iCodec->IsNullCodec())
       
   134 			{//use source buffer for sound device buffer	
       
   135 			iSoundDeviceBuffer = NULL;
       
   136 			}
       
   137 		else
       
   138 			{//codec needs separate source and sound device buffers
       
   139 			TRAP(err,iSoundDeviceBuffer = CMMFDataBuffer::NewL(iSoundDevBufferSize));
       
   140 			}
       
   141 		}
       
   142 	return err;
       
   143 	}
       
   144 
       
   145 
       
   146 TInt CMMFSwCodecPlayDataPath::Start()
       
   147 	{
       
   148 	TInt startError = KErrNone;
       
   149 
       
   150 	if (!iCodec || (!iSoundDevice->Handle()))
       
   151 		{
       
   152 		//check that a codec has been added and the sound device is open
       
   153 		startError = KErrNotReady;
       
   154 		}
       
   155 
       
   156 	if (iState == EPaused)
       
   157 		{//we are paused so need to resume play
       
   158 		if (!startError)
       
   159 			{
       
   160 #ifdef _SCW_DEBUG
       
   161 			RDebug::Print(_L("CMMFSwCodecPlayDataPath::Start-Resume"));
       
   162 #endif
       
   163 			iAudioPlayer->ResumePlaying();
       
   164 			iState = EPlaying;
       
   165 			}
       
   166 		}
       
   167 	else if (!startError)
       
   168 		{
       
   169 #ifdef _SCW_DEBUG
       
   170 		RDebug::Print(_L("CMMFSwCodecPlayDataPath::Start-Normal"));
       
   171 #endif
       
   172 		if (!startError)
       
   173 			{
       
   174 			iNoMoreSourceData = EFalse;
       
   175 			iSourceBuffer->SetLastBuffer(EFalse);
       
   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    		}
       
   191 	return startError;
       
   192 	}
       
   193 
       
   194 
       
   195 // *** Main Play Loop ***
       
   196 
       
   197 void CMMFSwCodecPlayDataPath::FillSourceBufferL()
       
   198 	{//asks observer to fill the source buffer          
       
   199     // Ask immediately for data from the observer
       
   200 #ifdef __CYCLE_MMF_DATABUFFERS__
       
   201 	// Create a new buffer to replicate INC021405 Play-EOF-Play on HwAccelerated solution Panics
       
   202 	// If the creation fails, we carry on regardless as the original buffer will not have been 
       
   203 	// destroyed. Must do this as alloc fail tests will not run.
       
   204 	if(iSourceBuffer)
       
   205 		{
       
   206 		iSourceBuffer = CycleAudioBuffer(iSourceBuffer);
       
   207 		}
       
   208 #endif // __CYCLE_MMF_DATABUFFERS__	
       
   209 	User::LeaveIfError(iHwDeviceObserver->FillThisHwBuffer(*iSourceBuffer));
       
   210 	
       
   211 	}
       
   212 
       
   213 
       
   214 void CMMFSwCodecPlayDataPath::BufferFilledL(CMMFDataBuffer& aBuffer)
       
   215 	{//call back from observer to indicate buffer has been filled
       
   216 	if (iState == EStopped)
       
   217 		User::Leave(KErrNotReady);//ok if paused?
       
   218 
       
   219 	iSourceBuffer = &aBuffer;
       
   220 	iSourceBuffer->SetStatus(EFull);
       
   221 #ifdef _SCW_DEBUG
       
   222 	RDebug::Print(_L("CMMFSwCodecPlayDataPath::BufferFilledL"));
       
   223 #endif
       
   224 
       
   225 	//need to check that the buffer size is not 0 - if so assume we've reached the end of the data
       
   226 	if (!iSourceBuffer->BufferSize())
       
   227 		{//no buffer  - could be end of source or could be that the source has no data??
       
   228 		iNoMoreSourceData = ETrue;
       
   229 #ifdef _SCW_DEBUG
       
   230 		RDebug::Print(_L("CMMFSwCodecPlayDataPath::BufferFilledL-NoMoreSourceData"));
       
   231 #endif
       
   232 		}
       
   233 	//even if the buffer size is 0 we still 
       
   234 	//need to perform the following to get the sound device callback
       
   235 	FillSoundDeviceBufferL(); //get buffer in pcm16 format for sound device	
       
   236 
       
   237     // attenuate the amplitude of the samples if volume ramping has been changed
       
   238 	// and is non-zero
       
   239 	if (iCustomInterface)
       
   240 		{
       
   241 		TTimeIntervalMicroSeconds volumeRamp = iCustomInterface->VolumeRamp();
       
   242 		if (volumeRamp != iVolumeRamp)
       
   243 			{
       
   244 			iVolumeRamp = volumeRamp;
       
   245 			if (iVolumeRamp.Int64() != 0)
       
   246 				{
       
   247 				iUtility->ConfigAudioRamper(
       
   248 					iVolumeRamp.Int64(), 
       
   249 					iSampleRate, 
       
   250 					iChannels);
       
   251 				iRampAudioSample = ETrue;
       
   252 				}
       
   253 			else
       
   254 				{
       
   255 				iRampAudioSample = EFalse;
       
   256 				}
       
   257 			}
       
   258 			if (iRampAudioSample)
       
   259 				{
       
   260 				iRampAudioSample = iUtility->RampAudio(iSoundDeviceBuffer);
       
   261 				}
       
   262 		}
       
   263 
       
   264 	iAudioPlayer->PlayData(*iSoundDeviceBuffer); //play data to sound drivers
       
   265 
       
   266 	if (iSourceBuffer->LastBuffer())//check last buffer flag
       
   267 		{
       
   268 		iNoMoreSourceData = ETrue;
       
   269 #ifdef _SCW_DEBUG
       
   270 		RDebug::Print(_L("CMMFSwCodecPlayDataPath::BufferFilledL-LBNoMoreSourceData"));
       
   271 #endif
       
   272 		}
       
   273 	}
       
   274 
       
   275 
       
   276 void CMMFSwCodecPlayDataPath::FillSoundDeviceBufferL()
       
   277 	{//use CMMFSwCodec to fill the sound device buffer
       
   278 	
       
   279 	CMMFSwCodec::TCodecProcessResult codecProcessResult;
       
   280 
       
   281 	if (iCodec->IsNullCodec())
       
   282 		{//no codec so data can be sent direct to sink
       
   283 		iSoundDeviceBuffer = iSourceBuffer;
       
   284 		iSoundDeviceBuffer->SetStatus(EFull);	//sink buffer is full
       
   285 		}	
       
   286 	else 
       
   287 		{	
       
   288 		//pass buffer to codec for processing
       
   289 		codecProcessResult = iCodec->ProcessL(*iSourceBuffer, *iSoundDeviceBuffer);
       
   290 		if (iSourceBuffer->LastBuffer()) //if source is last buffer so is sound dev
       
   291 			iSoundDeviceBuffer->SetLastBuffer(ETrue);
       
   292 		if ((!iSoundDeviceBuffer->BufferSize())&&(codecProcessResult.iDstBytesAdded))
       
   293 			{//the codec has added data but not set the buffer length
       
   294 			iSoundDeviceBuffer->Data().SetLength(codecProcessResult.iDstBytesAdded);
       
   295 			}
       
   296 		//only supports EProcessComplete
       
   297 		switch (codecProcessResult.iCodecProcessStatus)
       
   298 			{
       
   299 		case CMMFSwCodec::TCodecProcessResult::EProcessComplete:
       
   300 		//finished procesing source data - all data in sink buffer
       
   301 			{
       
   302 			iSoundDeviceBuffer->SetStatus(EFull);	//sink buffer is full	
       
   303 			}
       
   304 		break;
       
   305 		case CMMFSwCodec::TCodecProcessResult::EDstNotFilled:
       
   306 		//could be the last buffer in which case dst might not get filled
       
   307 			{
       
   308 			iSoundDeviceBuffer->SetStatus(EFull);	//sink buffer is full	
       
   309 			}
       
   310 		break;
       
   311 		case CMMFSwCodec::TCodecProcessResult::EEndOfData:
       
   312 			//no more data - send what we've got to the sink
       
   313 			//note we can't always rely on this  - in many cases the codec will not know when
       
   314 			//it has reached the end of data.
       
   315 			{
       
   316 			iSoundDeviceBuffer->SetStatus(EFull);//sink buffer may not really be 'full' but its as full as it going to get
       
   317 			iNoMoreSourceData = ETrue;
       
   318 			//doesn't matter if sink buffer is not full
       
   319 			}
       
   320 		break;
       
   321 		default:
       
   322 			Panic(EMMFSwCodecWrapperBadCodec); //should never get here - bad codec
       
   323 			}
       
   324 		}
       
   325 	}
       
   326 
       
   327 
       
   328 void CMMFSwCodecPlayDataPath::BufferEmptiedL(const CMMFDataBuffer& aBuffer)
       
   329 	{//call back from CDataPathPlayer when the sound device buffer has been emptied
       
   330 	if (&aBuffer != iSoundDeviceBuffer) 
       
   331 		Panic(EMMFSwCodecWrapperBadBuffer);
       
   332 	if (!iNoMoreSourceData) 
       
   333 		FillSourceBufferL();
       
   334 	}
       
   335 
       
   336 //*** End of Main Play Loop ***
       
   337 
       
   338 
       
   339 void CMMFSwCodecPlayDataPath::Stop()
       
   340 	{
       
   341 	iAudioPlayer->Cancel();
       
   342 	iSoundDeviceErrorReceiver->Cancel();
       
   343 	TRequestStatus status;
       
   344 	iSoundDevice->CloseDevice(iDeviceUid, status);
       
   345 	User::WaitForRequest(status);
       
   346 
       
   347 #ifdef __CYCLE_MMF_DATABUFFERS__
       
   348 	// Create a new buffer to replicate INC021405 Play-EOF-Play on HwAccelerated solution Panics
       
   349 	// If the creation fails, we carry on regardless as the original buffer will not have been 
       
   350 	// destroyed. Must do this as alloc fail tests will not run.
       
   351 	if(iSourceBuffer)
       
   352 		{
       
   353 		iSourceBuffer = CycleAudioBuffer(iSourceBuffer);
       
   354 		}
       
   355 #endif // __CYCLE_MMF_DATABUFFERS__	
       
   356 
       
   357 	iState = EStopped;
       
   358 	}
       
   359 
       
   360 
       
   361 void CMMFSwCodecPlayDataPath::Pause()
       
   362 	{
       
   363 	//since a pause can happen anyway in the datatransfer -need to set to a known 
       
   364 	//state so that when play is resumed the behaviour is predictable
       
   365 	if (iSoundDevice->Handle())
       
   366 		{
       
   367 		iSoundDevice->PauseBuffer(); // ignores return value?
       
   368 		iState = EPaused;
       
   369 #ifdef _SCW_DEBUG
       
   370 		RDebug::Print(_L("Pause"));
       
   371 #endif
       
   372 		}
       
   373 	else
       
   374 		{//an error must have occured 
       
   375 		iState = EStopped;
       
   376 		}
       
   377 	}
       
   378 
       
   379 
       
   380 CRoutingSoundPlayDevice* CMMFSwCodecPlayDataPath::Device()
       
   381 	{
       
   382 	return iSoundDevice;
       
   383 	}
       
   384 
       
   385 void CMMFSwCodecPlayDataPath::SoundDeviceException(TInt aError)
       
   386 	{
       
   387 	//this sends a request to the hw device observer usually Devsound
       
   388 	//to update the bytes played
       
   389 	//it is done here so that the sound driver can be closed prior to
       
   390 	//updating the plicy and sending the error back
       
   391 	TUid uidUpdateBytesPlayed;
       
   392 	uidUpdateBytesPlayed.iUid = KMmfHwDeviceObserverUpdateBytesPlayed;
       
   393 	TPtrC8 dummy(0,0);
       
   394 	iHwDeviceObserver->MsgFromHwDevice(uidUpdateBytesPlayed,dummy);
       
   395 
       
   396 	//this closes RMdaDevSound.
       
   397 	Stop(); 
       
   398 
       
   399 	//inform devsound so it can update policy
       
   400 	iHwDeviceObserver->Stopped(); 
       
   401 
       
   402 	// Inform the observer of the exception condition
       
   403 	// We inform the hw device observer after the policy has been
       
   404 	// updated incase the observer relied on the error to assume
       
   405 	// the policy has been updated
       
   406 	iHwDeviceObserver->Error(aError);
       
   407 	}
       
   408 
       
   409 
       
   410 void CMMFSwCodecPlayDataPath::SetPlayCustomInterface(MPlayCustomInterface& aCustomInterface)
       
   411 	{
       
   412 	iCustomInterface = &aCustomInterface;
       
   413 	}
       
   414 	
       
   415 void CMMFSwCodecPlayDataPath::SetConfigForAudioRamp(TUint aSampleRate, TUint aChannels)
       
   416 	{
       
   417 	iSampleRate = aSampleRate;
       
   418 	iChannels = aChannels;
       
   419 	}
       
   420 
       
   421 /************************************************************************
       
   422  *				CDataPathPlayer											*
       
   423  ************************************************************************/
       
   424 
       
   425 CDataPathPlayer::CDataPathPlayer(CMMFSwCodecPlayDataPath& aParent, TInt aPriority)
       
   426 : CActive(aPriority), iParent(aParent)
       
   427 	{
       
   428 	CActiveScheduler::Add(this);
       
   429 	}
       
   430 
       
   431 
       
   432 CDataPathPlayer::~CDataPathPlayer()
       
   433 	{
       
   434 	Cancel();
       
   435 	}
       
   436 
       
   437 
       
   438 void CDataPathPlayer::Start()
       
   439 	{
       
   440 	// No implementation
       
   441 	}
       
   442 
       
   443 
       
   444 void CDataPathPlayer::ResumePlaying()
       
   445 	{
       
   446 	if (iParent.Device()->Handle())
       
   447 		{
       
   448 		//should be ok to call this even if we are active
       
   449 		iParent.Device()->ResumePlaying();
       
   450 		iResumePlaying = ETrue;
       
   451 		}
       
   452 #ifdef _SCW_DEBUG
       
   453 	RDebug::Print(_L("Playing Resumed"));
       
   454 #endif
       
   455 	}
       
   456 
       
   457 
       
   458 void CDataPathPlayer::PlayData(const CMMFDataBuffer& aData)
       
   459 	{
       
   460 	iDataFromSource = &aData;
       
   461 	if (!IsActive())
       
   462 		{
       
   463 #ifdef _SCW_DEBUG
       
   464 		RDebug::Print(_L("CDataPathPlayer::PlayData"));
       
   465 #endif
       
   466 		iParent.Device()->PlayData(aData.Data(), iStatus);
       
   467 		SetActive();
       
   468 		}
       
   469 	}
       
   470 
       
   471 
       
   472 void CDataPathPlayer::Stop()
       
   473 	{
       
   474 	if (!IsActive())
       
   475 		{
       
   476 		iParent.Device()->FlushBuffer();
       
   477 		}
       
   478 	Cancel();
       
   479 	iParent.SoundDeviceException(KErrCancel);
       
   480 	}
       
   481 
       
   482 
       
   483 void CDataPathPlayer::RunL()
       
   484 	{
       
   485 #ifdef _SCW_DEBUG
       
   486 	RDebug::Print(_L("CDataPathPlayer::RunL error[%d]"), iStatus.Int());
       
   487 #endif
       
   488 	if (!iStatus.Int())
       
   489 		{
       
   490 		iParent.BufferEmptiedL(static_cast<const CMMFDataBuffer&>(*iDataFromSource));
       
   491 		iResumePlaying = EFalse;
       
   492 		}
       
   493 	//if we don't have a sound driver handle then we have stopped
       
   494 	//but the client still thinks we are recording so swallow error
       
   495 	else if (iStatus.Int()!= KErrBadHandle)
       
   496 		{ 	
       
   497 		iParent.SoundDeviceException(iStatus.Int());
       
   498 		}
       
   499 	}
       
   500 
       
   501 
       
   502 TInt CDataPathPlayer::RunError(TInt aError)
       
   503 	{
       
   504 	Error(aError);
       
   505 	return KErrNone;
       
   506 	}
       
   507 
       
   508 
       
   509 void CDataPathPlayer::DoCancel()
       
   510 	{
       
   511 	if (iParent.Device()->Handle())
       
   512 		{
       
   513 		iParent.Device()->CancelPlayData();
       
   514 		iParent.Device()->FlushBuffer();
       
   515 		}
       
   516 	}
       
   517 
       
   518 
       
   519 void CDataPathPlayer::Error(TInt aError)
       
   520 	{ 
       
   521 	iParent.SoundDeviceException(aError);
       
   522 	}
       
   523 
       
   524 
       
   525 /************************************************************************
       
   526  *				CSoundDevPlayErrorReceiver								*
       
   527  ************************************************************************/
       
   528 
       
   529 CSoundDevPlayErrorReceiver::CSoundDevPlayErrorReceiver(CMMFSwCodecPlayDataPath& aParent, TInt aPriority)
       
   530 : CActive(aPriority), iParent(aParent)
       
   531 	{
       
   532 	CActiveScheduler::Add(this);
       
   533 	}
       
   534 
       
   535 CSoundDevPlayErrorReceiver::~CSoundDevPlayErrorReceiver()
       
   536 	{
       
   537 	Cancel();
       
   538 	}
       
   539 
       
   540 void CSoundDevPlayErrorReceiver::Start()
       
   541 	{
       
   542 	iParent.Device()->NotifyError(iStatus);
       
   543 	SetActive();
       
   544 	}
       
   545 
       
   546 void CSoundDevPlayErrorReceiver::Stop()
       
   547 	{
       
   548 	Cancel();
       
   549 	}
       
   550 
       
   551 void CSoundDevPlayErrorReceiver::RunL()
       
   552 	{
       
   553 	// An error has been returned
       
   554 #ifdef _SCW_DEBUG
       
   555 	RDebug::Print(_L("CSoundDevPlayErrorReceiver::RunL[%d]"), iStatus.Int());
       
   556 #endif
       
   557 	iParent.SoundDeviceException(iStatus.Int());
       
   558 	}
       
   559 
       
   560 void CSoundDevPlayErrorReceiver::DoCancel()
       
   561 	{
       
   562 	iParent.Device()->CancelNotifyError();
       
   563 	}
       
   564 
       
   565