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