os/mm/devsound/sounddevbt/src/swcodecwrapper/mmfBtSwCodecRecordDataPath.cpp
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
     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\MmfBtSwCodecRecordDatapath.cpp
    15 // 
    16 //
    17 
    18 #include "mmfBtSwCodecRecordDataPath.h"
    19 #include "mmfbtswcodecwrapper.h"
    20 #include <mmfpaniccodes.h>
    21 #include "MMFBtRoutingSoundDevice.h"
    22 
    23 
    24 CMMFSwCodecRecordDataPath* CMMFSwCodecRecordDataPath::NewL(CRoutingSoundRecordDevice* aSoundDevice)
    25 	{
    26 	CMMFSwCodecRecordDataPath* self = new(ELeave) CMMFSwCodecRecordDataPath(aSoundDevice);
    27 	CleanupStack::PushL(self);
    28 	self->ConstructL();
    29 	CleanupStack::Pop();
    30 	return self;
    31 	}
    32 
    33 
    34 void CMMFSwCodecRecordDataPath::ConstructL()
    35 	{
    36 	iAudioRecorder = new (ELeave) CDataPathRecorder(*this,CActive::EPriorityUserInput);
    37 	iSoundDeviceErrorReceiver = new (ELeave) CSoundDevRecordErrorReceiver(*this, CActive::EPriorityUserInput);
    38 	}
    39 
    40 
    41 CMMFSwCodecRecordDataPath::~CMMFSwCodecRecordDataPath()
    42 	{	
    43 	delete iAudioRecorder;
    44 	delete iSoundDeviceErrorReceiver;
    45 
    46 	TRequestStatus status;
    47 	iSoundDevice->CloseDevice(iDeviceUid, status);
    48 	//TODO there should be a timeout for the line below
    49 	User::WaitForRequest(status);
    50 
    51 	if (iCodec)
    52 		{
    53 		delete iSoundDeviceBuffer;
    54 		if (!iCodec->IsNullCodec())
    55 			{
    56 			delete iSinkBuffer;
    57 			}
    58 		}
    59 
    60 
    61 #ifdef __USE_MMF_TRANSFERBUFFERS__
    62 	delete iTransferWindow;
    63 
    64 	if(iTransferBuffer)
    65 		{
    66 		iTransferBuffer->Close();
    67 		delete iTransferBuffer;
    68 		}
    69 #endif
    70 
    71 #ifdef __USE_MMF_PTRBUFFERS__
    72 	delete iPtrBufferMemoryBlock;
    73 #endif
    74 
    75 	}
    76 
    77 
    78 TInt CMMFSwCodecRecordDataPath::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 CMMFSwCodecRecordDataPath::AddCodec(CMMFSwCodec& aCodec)
    95 	{
    96 	if (iCodec)
    97 		{
    98 		return KErrNotSupported; //doesn't support multiple codecs
    99 		}
   100 
   101 	TInt err = KErrNone;
   102 	iCodec = &aCodec;
   103 
   104 	iSinkBufferSize = iCodec->SinkBufferSize();
   105 	iSoundDevBufferSize = iCodec->SourceBufferSize();
   106 
   107 	if ((!iSinkBufferSize)||(!iSoundDevBufferSize))
   108 		{
   109 		err = KErrArgument; //codec plugin has not specified buffer size
   110 		}
   111 
   112 	if (err == KErrNone)
   113 		{
   114 #ifdef __USE_MMF_TRANSFERBUFFERS__
   115 		TRAP(err,iSoundDeviceBuffer = CreateTransferBufferL(iSoundDevBufferSize, static_cast<CMMFTransferBuffer*>(iSoundDeviceBuffer)));
   116 #endif
   117 
   118 #ifdef __USE_MMF_PTRBUFFERS__
   119 		TRAP(err,iSoundDeviceBuffer = CreatePtrBufferL(iSoundDevBufferSize));
   120 #else
   121 		TRAP(err,iSoundDeviceBuffer = CMMFDataBuffer::NewL(iSoundDevBufferSize));
   122 #endif
   123 		}
   124 
   125 	if (err == KErrNone)
   126 		{
   127 		// Allocate data buffer
   128 		if (iCodec->IsNullCodec())
   129 			{//don't need a separate sink buffer if null codec
   130 			iSinkBuffer = NULL; //sink buffer is the sound device buffer	
   131 			}
   132 		else
   133 			{//need a separate sink buffer for the codec
   134 			TRAP(err,iSinkBuffer = CMMFDataBuffer::NewL(iSinkBufferSize));
   135 			}	
   136 		}
   137 	return err;
   138 	}
   139 
   140 
   141 TInt CMMFSwCodecRecordDataPath::Start()
   142 	{
   143 	TInt startError = KErrNone;
   144 	if (!iCodec || !(iSoundDevice->Handle()))
   145 		{//check that a codec has been added and the sound device has been opened
   146 		startError = KErrNotReady;
   147 		}
   148 
   149 	if (!startError)
   150 		{
   151 		// Start the player objects
   152 		iAudioRecorder->Start();
   153 		iSoundDeviceErrorReceiver->Start();
   154 		iSoundDeviceBuffer->SetLastBuffer(EFalse);
   155 		TRAP(startError, FillSoundDeviceBufferL()); //get audio recorder to fill buffer
   156 		if (startError == KErrNone)
   157 			{
   158 			iRecordedBytesCount = 0; //used for debug purposes
   159 			iState = EPlaying;
   160 			}
   161    		}
   162 	return startError;
   163 	}
   164 
   165 
   166 // *** Main Play Loop ***
   167 void CMMFSwCodecRecordDataPath::FillSoundDeviceBufferL()
   168 	{
   169 #ifdef __CYCLE_MMF_DATABUFFERS__
   170 	// Create a new buffer to replicate INC021405 Play-EOF-Play on HwAccelerated solution Panics
   171 	// If the creation fails, we carry on regardless as the original buffer will not have been 
   172 	// destroyed. Must do this as alloc fail tests will not run.
   173 	if(iSoundDeviceBuffer)
   174 		{
   175 		iSoundDeviceBuffer = CycleAudioBuffer(iSoundDeviceBuffer);
   176 		}
   177 #endif // __CYCLE_MMF_DATABUFFERS__	
   178 	iAudioRecorder->RecordData(*iSoundDeviceBuffer);
   179 	}
   180 
   181 
   182 void CMMFSwCodecRecordDataPath::BufferFilledL(CMMFDataBuffer& aBuffer)
   183 	{	
   184 	iSoundDeviceBuffer = &aBuffer;
   185 	iSoundDeviceBuffer->SetStatus(EFull);
   186 	 // Store this to avoid casting several times
   187     TUint length = iSoundDeviceBuffer->BufferSize();
   188 	// Update bytes recorded
   189 	iRecordedBytesCount += length;
   190 
   191 	//If paused then sound driver will keep sending buffers till
   192 	//its flushed - if last buffer then set last buffer flag
   193 	if (length < iSoundDevBufferSize)
   194 		{//assume it's the last buffer
   195 		iSoundDeviceBuffer->SetLastBuffer(ETrue);
   196 		}
   197 
   198 	//buffer ok can send to sink
   199 	FillSinkBufferL(); //convert to sink data type using codec
   200 	User::LeaveIfError(iHwDeviceObserver->EmptyThisHwBuffer(*iSinkBuffer)); //pass onto sink
   201 	}
   202 
   203 
   204 /* 
   205  *  FillSinkBufferL
   206  * 
   207  *	Function to take the data from an already full source buffer and by using
   208  *	a codec if necessary fills the sink buffer
   209  *  @internalComponent
   210  */
   211 void CMMFSwCodecRecordDataPath::FillSinkBufferL()
   212 	{
   213 	CMMFSwCodec::TCodecProcessResult codecProcessResult;
   214 
   215 	if (iCodec->IsNullCodec())
   216 		{//no codec so sound device buffer can be used directly as sink buffer
   217 		iSinkBuffer = iSoundDeviceBuffer;
   218 		iSinkBuffer->SetStatus(EFull);	//sink buffer is full
   219 		}	
   220 	else 
   221 		{
   222 		//pass buffer to codec for processing
   223 		codecProcessResult = iCodec->ProcessL(*iSoundDeviceBuffer, *iSinkBuffer);
   224 		if (iSoundDeviceBuffer->LastBuffer()) //if sound device is last buffer so is sound dev
   225 			{
   226 			iSinkBuffer->SetLastBuffer(ETrue);
   227 			}
   228 		if ((!iSinkBuffer->BufferSize())&&(codecProcessResult.iDstBytesAdded))
   229 			{//the codec has added data but not set the buffer length
   230 			iSinkBuffer->Data().SetLength(codecProcessResult.iDstBytesAdded);
   231 			}
   232 		//only supports EProcessComplete
   233 		switch (codecProcessResult.iCodecProcessStatus)
   234 			{
   235 		case CMMFSwCodec::TCodecProcessResult::EProcessComplete:
   236 		//finished procesing source data - all data in sink buffer
   237 			{
   238 			iSoundDeviceBuffer->SetStatus(EAvailable); //source buffer is now avaialble
   239 			iSinkBuffer->SetStatus(EFull);	//sink buffer is full	
   240 			}
   241 		break;
   242 		case CMMFSwCodec::TCodecProcessResult::EDstNotFilled:
   243 		//finished procesing source data - sink buffer not full could be EOF
   244 			{
   245 			iSoundDeviceBuffer->SetStatus(EAvailable); //source buffer is now avaialble
   246 			iSinkBuffer->SetStatus(EFull);	//sink buffer may not really be full however	
   247 			}
   248 		break;
   249 		case CMMFSwCodec::TCodecProcessResult::EEndOfData:
   250 			//no more data - send what we've got to the sink
   251 			//note we can't always rely on this  - in many cases the codec will not know when
   252 			//it has reached the end of data.
   253 			{
   254 			iSoundDeviceBuffer->SetStatus(EAvailable); //source buffer is now avaialble
   255 			iSinkBuffer->SetStatus(EFull);//sink buffer may not really be 'full' but its as full as it going to get
   256 			//doesn't matter if sink buffer is not full
   257 			}
   258 		break;
   259 		default:
   260 			Panic(EMMFSwCodecWrapperBadCodec); //should never get here - bad codec
   261 			}
   262 		}
   263 	}
   264 
   265 
   266 void CMMFSwCodecRecordDataPath::BufferEmptiedL(const CMMFDataBuffer& aBuffer)
   267 	{
   268 	if (&aBuffer != iSinkBuffer)
   269 		{
   270 		Panic(EMMFSwCodecWrapperBadBuffer);
   271 		}
   272 	if (!aBuffer.LastBuffer())
   273 		{
   274 		FillSoundDeviceBufferL();
   275 		}
   276 	//else the last buffer has been emptied - the observer should stop the
   277 	//hw device.
   278 	}
   279 
   280 //*** End of Main Play Loop ***
   281 
   282 
   283 void CMMFSwCodecRecordDataPath::Stop()
   284 	{
   285 	iAudioRecorder->Stop();//stop audio reocrder
   286 
   287 	iSoundDeviceErrorReceiver->Cancel(); //stop receiving events
   288 
   289 	TRequestStatus status;
   290 	iSoundDevice->CloseDevice(iDeviceUid, status);
   291 	User::WaitForRequest(status);
   292 
   293 #ifdef __CYCLE_MMF_DATABUFFERS__
   294 	// Create a new buffer to replicate INC021405 Play-EOF-Play on HwAccelerated solution Panics
   295 	// If the creation fails, we carry on regardless as the original buffer will not have been 
   296 	// destroyed. Must do this as alloc fail tests will not run.
   297 	if(iSoundDeviceBuffer)
   298 		{
   299 		iSoundDeviceBuffer = CycleAudioBuffer(iSoundDeviceBuffer);
   300 		}
   301 #endif // __CYCLE_MMF_DATABUFFERS__	
   302 
   303 	iState = EStopped;
   304 	}
   305 
   306 
   307 void CMMFSwCodecRecordDataPath::Pause()
   308 	{
   309 	// flush it anyway, whether we're active or not
   310 	// if we are active, then this should result in a call to RunL() pretty soon
   311 	//note that the Pause() in the context of record means buffers are
   312 	//continued to be obtained from the sound driver that have already 
   313 	//been recorded - it just doesn't record any new audio data
   314 #ifdef _SCW_DEBUG
   315 	RDebug::Print(_L("CMMFSwcodecRecordDataPath::Pause"));
   316 #endif
   317 	iSoundDevice->FlushBuffer();
   318 	}
   319 
   320 CRoutingSoundRecordDevice* CMMFSwCodecRecordDataPath::Device()
   321 	{
   322 	return iSoundDevice;
   323 	}
   324 
   325 
   326 void CMMFSwCodecRecordDataPath::SoundDeviceException(TInt aError)
   327 	{
   328 	//this closes RMdaDevSound.
   329 	Stop();
   330 
   331 	//inform devsound so it can update policy
   332 	iHwDeviceObserver->Stopped();
   333 
   334 	// Inform the observer of the exception condition
   335 	// We inform the hw device observer after the policy has been
   336 	// updated incase the observer relied on the error to assume
   337 	// the policy has been updated
   338 	iHwDeviceObserver->Error(aError);
   339 	}
   340 
   341 TUint CMMFSwCodecRecordDataPath::RecordedBytesCount()
   342 	{
   343 	return iRecordedBytesCount;
   344 	}
   345 
   346 
   347 /************************************************************************
   348  *				CDataPathRecorder										*
   349  ************************************************************************/
   350 
   351 CDataPathRecorder::CDataPathRecorder(CMMFSwCodecRecordDataPath& aParent, TInt aPriority)
   352 : CActive(aPriority), iParent(aParent)
   353 	{
   354 	CActiveScheduler::Add(this);
   355 	}
   356 
   357 
   358 CDataPathRecorder::~CDataPathRecorder()
   359 	{
   360 	Cancel();
   361 	}
   362 
   363 
   364 void CDataPathRecorder::Start()
   365 	{
   366 	// No implementation
   367 	}
   368 
   369 
   370 void CDataPathRecorder::RecordData(CMMFDataBuffer& aData)
   371 	{
   372 	iDataFromSource = &aData;
   373 	if (!IsActive())
   374 		{
   375 		iParent.Device()->RecordData(aData.Data(), iStatus);
   376 		SetActive();
   377 		}
   378 	}
   379 
   380 
   381 void CDataPathRecorder::Stop()
   382 	{
   383 #ifdef _SCW_DEBUG
   384 	RDebug::Print(_L("CDataPathRecorder Stop"));
   385 #endif
   386 	Cancel();
   387 	}
   388 
   389 
   390 void CDataPathRecorder::RunL()
   391 	{
   392 #ifdef _SCW_DEBUG
   393 	RDebug::Print(_L("CDataPathRecorder::RunL error[%d]"), iStatus.Int());
   394 #endif
   395 	if (!iStatus.Int())
   396 		{
   397 		iParent.BufferFilledL((CMMFDataBuffer&)*iDataFromSource);
   398 		}
   399 	//if we don't have a sound driver handle then we have stopped
   400 	//but the client still thinks we are recording so swallow error
   401 	else if (iStatus.Int() != KErrBadHandle)
   402 		{ 	
   403 		iParent.SoundDeviceException(iStatus.Int());
   404 		}	
   405 	}
   406 
   407 
   408 TInt CDataPathRecorder::RunError(TInt aError)
   409 	{
   410 	Error(aError);
   411 	return KErrNone;
   412 	}
   413 
   414 
   415 void CDataPathRecorder::DoCancel()
   416 	{
   417 #ifdef _SCW_DEBUG
   418 	RDebug::Print(_L("CDataPathRecorder Cancel"));
   419 #endif
   420 	if (iParent.Device()->Handle())
   421 		{
   422 		iParent.Device()->CancelRecordData();
   423 		iParent.Device()->FlushBuffer();
   424 		}
   425 	}
   426 
   427 
   428 void CDataPathRecorder::Error(TInt aError)
   429 	{ 
   430 	iParent.SoundDeviceException(aError);
   431 	}
   432 
   433 
   434 /************************************************************************
   435  *				CSoundDevRecordErrorReceiver							*
   436  ************************************************************************/
   437 
   438 CSoundDevRecordErrorReceiver::CSoundDevRecordErrorReceiver(CMMFSwCodecRecordDataPath& aParent, TInt aPriority)
   439 : CActive(aPriority), iParent(aParent)
   440 	{
   441 	CActiveScheduler::Add(this);
   442 	}
   443 
   444 
   445 CSoundDevRecordErrorReceiver::~CSoundDevRecordErrorReceiver()
   446 	{
   447 	Cancel();
   448 	}
   449 
   450 
   451 void CSoundDevRecordErrorReceiver::Start()
   452 	{	
   453 	if (!IsActive()) 
   454 		{
   455 		iParent.Device()->NotifyError(iStatus);
   456 		SetActive();
   457 		}
   458 	}
   459 
   460 
   461 void CSoundDevRecordErrorReceiver::Stop()
   462 	{
   463 	Cancel();
   464 	}
   465 
   466 
   467 void CSoundDevRecordErrorReceiver::RunL()
   468 	{
   469 	// An error has been returned--Flush to release mic.
   470 	iParent.Device()->FlushBuffer();
   471 	iParent.SoundDeviceException(iStatus.Int());
   472 	}
   473 
   474 
   475 void CSoundDevRecordErrorReceiver::DoCancel()
   476 	{
   477 	iParent.Device()->CancelNotifyError();
   478 	}
   479 
   480