os/mm/devsound/devsoundrefplugin/src/swcodecwrapper/mmfSwCodecConvertDataPath.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) 2003-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\mmfswcodecconvertdatapath.cpp
sl@0
    15
// 
sl@0
    16
//
sl@0
    17
sl@0
    18
#include "mmfSwCodecConvertDataPath.h"
sl@0
    19
#include <mmf/server/mmfswcodecwrapper.h>
sl@0
    20
#include <mmf/common/mmfpaniccodes.h>
sl@0
    21
sl@0
    22
sl@0
    23
CMMFSwCodecConvertDataPath* CMMFSwCodecConvertDataPath::NewL()
sl@0
    24
	{
sl@0
    25
	CMMFSwCodecConvertDataPath* self = new(ELeave) CMMFSwCodecConvertDataPath;
sl@0
    26
	CleanupStack::PushL(self);
sl@0
    27
	self->ConstructL();
sl@0
    28
	CleanupStack::Pop();
sl@0
    29
	return self;
sl@0
    30
	}
sl@0
    31
sl@0
    32
sl@0
    33
void CMMFSwCodecConvertDataPath::ConstructL()
sl@0
    34
	{
sl@0
    35
	iDataPathConverter = new (ELeave) CDataPathConverter(*this,CActive::EPriorityUserInput);
sl@0
    36
	}
sl@0
    37
sl@0
    38
sl@0
    39
CMMFSwCodecConvertDataPath::~CMMFSwCodecConvertDataPath()
sl@0
    40
	{	
sl@0
    41
	delete iDataPathConverter;
sl@0
    42
	if (iCodec)
sl@0
    43
		{
sl@0
    44
		delete iSourceBuffer;
sl@0
    45
		if (!iCodec->IsNullCodec()) 
sl@0
    46
			delete iSinkBuffer;
sl@0
    47
		}
sl@0
    48
	}
sl@0
    49
sl@0
    50
sl@0
    51
TInt CMMFSwCodecConvertDataPath::SetObserver(MMMFHwDeviceObserver& aObserver)
sl@0
    52
	{
sl@0
    53
	TInt error;
sl@0
    54
	if (iHwDeviceObserver)
sl@0
    55
		{
sl@0
    56
		error =  KErrAlreadyExists;
sl@0
    57
		}
sl@0
    58
	else
sl@0
    59
		{
sl@0
    60
		iHwDeviceObserver = &aObserver;
sl@0
    61
		error  = KErrNone;
sl@0
    62
		}
sl@0
    63
	return error;
sl@0
    64
	}
sl@0
    65
sl@0
    66
sl@0
    67
TInt CMMFSwCodecConvertDataPath::AddCodec(CMMFSwCodec& aCodec)
sl@0
    68
	{
sl@0
    69
	if (iCodec)
sl@0
    70
		return KErrNotSupported; //doesn't support multiple codecs
sl@0
    71
sl@0
    72
	TInt err = KErrNone;
sl@0
    73
	iCodec = &aCodec;
sl@0
    74
sl@0
    75
	iSourceBufferSize = iCodec->SourceBufferSize();
sl@0
    76
	iSinkBufferSize = iCodec->SinkBufferSize();
sl@0
    77
sl@0
    78
	if ((!iSourceBufferSize)||(!iSinkBufferSize))
sl@0
    79
		err = KErrArgument; //codec plugin has not specified buffer size
sl@0
    80
sl@0
    81
	if (err == KErrNone)
sl@0
    82
		{
sl@0
    83
		TRAP(err,iSourceBuffer = CMMFDataBuffer::NewL(iSourceBufferSize));
sl@0
    84
		}
sl@0
    85
sl@0
    86
	if (err == KErrNone)
sl@0
    87
		{
sl@0
    88
		// Allocate data buffer
sl@0
    89
		if (iCodec->IsNullCodec())
sl@0
    90
			{//don't need a separate sink buffer if null codec
sl@0
    91
			iSinkBuffer = NULL; //sink buffer is the sound device buffer	
sl@0
    92
			}
sl@0
    93
		else
sl@0
    94
			{//need a separate sink buffer for the codec
sl@0
    95
			TRAP(err,iSinkBuffer = CMMFDataBuffer::NewL(iSinkBufferSize));
sl@0
    96
			}	
sl@0
    97
		}
sl@0
    98
	return err;
sl@0
    99
	}
sl@0
   100
sl@0
   101
sl@0
   102
TInt CMMFSwCodecConvertDataPath::Start()
sl@0
   103
	{
sl@0
   104
	TInt startError = KErrNone;
sl@0
   105
	if (!iCodec) 
sl@0
   106
		{//check that a codec has been added
sl@0
   107
		startError = KErrNotReady;
sl@0
   108
		}
sl@0
   109
	if (!startError)
sl@0
   110
		{
sl@0
   111
		// Start the player objects
sl@0
   112
		iSourceBuffer->SetLastBuffer(EFalse);
sl@0
   113
		iDataPathConverter->Start();
sl@0
   114
		iState = EPlaying;
sl@0
   115
		iNoMoreSourceData = EFalse;
sl@0
   116
   		}
sl@0
   117
	return startError;
sl@0
   118
	}
sl@0
   119
sl@0
   120
sl@0
   121
sl@0
   122
void CMMFSwCodecConvertDataPath::Stop()
sl@0
   123
	{
sl@0
   124
	iDataPathConverter->Cancel();
sl@0
   125
	iState = EStopped;
sl@0
   126
	}
sl@0
   127
sl@0
   128
sl@0
   129
void CMMFSwCodecConvertDataPath::Pause()
sl@0
   130
	{//pause is equivalent to stop for a data transfer
sl@0
   131
	iDataPathConverter->Cancel();
sl@0
   132
	iState = EStopped;
sl@0
   133
	}
sl@0
   134
sl@0
   135
/*** Main play loop ***/
sl@0
   136
sl@0
   137
void CMMFSwCodecConvertDataPath::FillSourceBufferL()
sl@0
   138
	{
sl@0
   139
	STATIC_CAST(CMMFDataBuffer*, iSourceBuffer)->SetRequestSizeL(iSourceBufferSize);
sl@0
   140
            
sl@0
   141
    // Ask immediately for data from the observer
sl@0
   142
	User::LeaveIfError(iHwDeviceObserver->FillThisHwBuffer(*iSourceBuffer));
sl@0
   143
	}
sl@0
   144
sl@0
   145
 /** 
sl@0
   146
 *  BufferFilledL.  
sl@0
   147
 *	(from MDataSink)
sl@0
   148
 * 
sl@0
   149
 *	called by the CMMFDataPath's MDataSource when it has filled the buffer
sl@0
   150
 *  @internalComponent
sl@0
   151
 *	@param aBuffer
sl@0
   152
 *	
sl@0
   153
 */
sl@0
   154
void CMMFSwCodecConvertDataPath::BufferFilledL(CMMFDataBuffer& aBuffer)
sl@0
   155
	{	
sl@0
   156
	iSourceBuffer = &aBuffer;
sl@0
   157
	iSourceBuffer->SetStatus(EFull);
sl@0
   158
sl@0
   159
	//need to check that the buffer size is not 0 - 
sl@0
   160
	//if so assume we've reached the end of the data
sl@0
   161
	if (!iSourceBuffer->BufferSize())
sl@0
   162
		{//no buffer  - could be end of source or could be that the source has no data
sl@0
   163
		//also need to check the sink buffer is available else there is still some
sl@0
   164
		//stuff to do before the sink buffer is freed
sl@0
   165
		if (iSinkBuffer->Status()==EAvailable)
sl@0
   166
			{
sl@0
   167
			iNoMoreSourceData = ETrue;
sl@0
   168
			}
sl@0
   169
		}
sl@0
   170
	else
sl@0
   171
		{
sl@0
   172
		if (iSourceBuffer->LastBuffer()) //also check last buffer flag
sl@0
   173
			iNoMoreSourceData = ETrue;
sl@0
   174
		iDataPathConverter->ChangeConvertState(CDataPathConverter::EFillingSinkBuffer);
sl@0
   175
		}
sl@0
   176
	}
sl@0
   177
sl@0
   178
/* 
sl@0
   179
 *  FillSinkBufferL
sl@0
   180
 * 
sl@0
   181
 *	Function to take the data from an already full source buffer and by using
sl@0
   182
 *	a codec if necessary fills the sink buffer
sl@0
   183
 *  @internalComponent
sl@0
   184
 */
sl@0
   185
void CMMFSwCodecConvertDataPath::FillSinkBufferL()
sl@0
   186
	{
sl@0
   187
	CMMFSwCodec::TCodecProcessResult codecProcessResult;
sl@0
   188
sl@0
   189
	if (iCodec->IsNullCodec())
sl@0
   190
		{//no codec so data can be sent direct to sink
sl@0
   191
		iSinkBuffer = iSourceBuffer;
sl@0
   192
		iSinkBuffer->SetStatus(EFull);	//sink buffer is full
sl@0
   193
		}	
sl@0
   194
	else 
sl@0
   195
		{	
sl@0
   196
		//pass buffer to codec for processing
sl@0
   197
		codecProcessResult = iCodec->ProcessL(*iSourceBuffer, *iSinkBuffer);
sl@0
   198
		if (iSourceBuffer->LastBuffer()) //if source is last buffer so is sink
sl@0
   199
			iSinkBuffer->SetLastBuffer(ETrue);
sl@0
   200
		if ((!iSinkBuffer->BufferSize())&&(codecProcessResult.iDstBytesAdded))
sl@0
   201
			{//the codec has added data but not set the buffer length
sl@0
   202
			iSinkBuffer->Data().SetLength(codecProcessResult.iDstBytesAdded);
sl@0
   203
			}
sl@0
   204
	
sl@0
   205
		//only supports EProcessComplete
sl@0
   206
		switch (codecProcessResult.iCodecProcessStatus)
sl@0
   207
			{
sl@0
   208
		case CMMFSwCodec::TCodecProcessResult::EProcessComplete:
sl@0
   209
		//finished procesing source data - all data in sink buffer
sl@0
   210
			{
sl@0
   211
			iSourceBuffer->SetStatus(EAvailable); //source buffer is now avaialble
sl@0
   212
			iSinkBuffer->SetStatus(EFull);	//sink buffer is full	
sl@0
   213
			}
sl@0
   214
		break;
sl@0
   215
		case CMMFSwCodec::TCodecProcessResult::EDstNotFilled:
sl@0
   216
		//could be the last buffer in which case dst might not get filled
sl@0
   217
			{
sl@0
   218
			iSourceBuffer->SetStatus(EAvailable); //source buffer is now avaialble
sl@0
   219
			iSinkBuffer->SetStatus(EFull);	//sink buffer is full	
sl@0
   220
			}
sl@0
   221
		break;
sl@0
   222
		case CMMFSwCodec::TCodecProcessResult::EEndOfData:
sl@0
   223
			//no more data - send what we've got to the sink
sl@0
   224
			//note we can't always rely on this  - in many cases the codec will not know when
sl@0
   225
			//it has reached the end of data.
sl@0
   226
			{
sl@0
   227
			iSourceBuffer->SetStatus(EAvailable); //source buffer is now avaialble
sl@0
   228
			iSinkBuffer->SetStatus(EFull);//sink buffer may not really be 'full' but its as full as it going to get
sl@0
   229
			//doesn't matter if sink buffer is not full
sl@0
   230
			}
sl@0
   231
		break;
sl@0
   232
		default:
sl@0
   233
			Panic(EMMFSwCodecWrapperBadCodec); //should never get here - bad codec
sl@0
   234
			}
sl@0
   235
		}
sl@0
   236
	iDataPathConverter->ChangeConvertState(CDataPathConverter::EEmptyingSinkBuffer);
sl@0
   237
	}
sl@0
   238
sl@0
   239
sl@0
   240
void CMMFSwCodecConvertDataPath::EmptySinkBufferL()
sl@0
   241
	{
sl@0
   242
	User::LeaveIfError(iHwDeviceObserver->EmptyThisHwBuffer(*iSinkBuffer));
sl@0
   243
	}
sl@0
   244
sl@0
   245
sl@0
   246
void CMMFSwCodecConvertDataPath::BufferEmptiedL(const CMMFDataBuffer& aBuffer)
sl@0
   247
	{
sl@0
   248
	if (&aBuffer != iSinkBuffer)
sl@0
   249
		User::Leave(KErrArgument);
sl@0
   250
	if (!iNoMoreSourceData) 
sl@0
   251
		iDataPathConverter->ChangeConvertState(CDataPathConverter::EFillingSourceBuffer);
sl@0
   252
	else //no more source data so signal EOF
sl@0
   253
		SoundDeviceException(KErrEof);
sl@0
   254
	}
sl@0
   255
sl@0
   256
void CMMFSwCodecConvertDataPath::SoundDeviceException(TInt aError)
sl@0
   257
	{
sl@0
   258
	// Inform the observer of the exception condition
sl@0
   259
	iHwDeviceObserver->Error(aError);
sl@0
   260
sl@0
   261
	Stop();
sl@0
   262
sl@0
   263
	// Let the observer know we're fully stopped
sl@0
   264
    iHwDeviceObserver->Stopped();	
sl@0
   265
	}
sl@0
   266
sl@0
   267
RMdaDevSound& CMMFSwCodecConvertDataPath::Device()
sl@0
   268
	{
sl@0
   269
	return iDummyDevSound;//convert doesn't have a RMdaDevSound
sl@0
   270
	}
sl@0
   271
sl@0
   272
/*** End of main play loop ***/
sl@0
   273
sl@0
   274
sl@0
   275
sl@0
   276
sl@0
   277
/************************************************************************
sl@0
   278
 *				CDataPathConverter	
sl@0
   279
 * This class performs the main data transfer between the source and the sink
sl@0
   280
 * This is done in a separate class as opposed to CMMFSwCodecConvertDataPath
sl@0
   281
 * because the class needs to be an active object to avoid recursive call stacks
sl@0
   282
 * in cases where the source and sink are not active objects - which is
sl@0
   283
 * the case with descriptors.  Making CMMFSwCodecConvertDataPath derive
sl@0
   284
 * from CActive is less desirable as it would involve multiple inheretence
sl@0
   285
 ************************************************************************/
sl@0
   286
sl@0
   287
CMMFSwCodecConvertDataPath::CDataPathConverter::CDataPathConverter(CMMFSwCodecConvertDataPath& aParent, TInt aPriority)
sl@0
   288
: CActive(aPriority), iParent(aParent)
sl@0
   289
	{
sl@0
   290
	CActiveScheduler::Add(this);
sl@0
   291
	iConvertState = EIdle;
sl@0
   292
	}
sl@0
   293
sl@0
   294
sl@0
   295
CMMFSwCodecConvertDataPath::CDataPathConverter::~CDataPathConverter()
sl@0
   296
	{
sl@0
   297
	Cancel();
sl@0
   298
	}
sl@0
   299
sl@0
   300
/** 
sl@0
   301
 *  Start
sl@0
   302
 * 
sl@0
   303
 *	Starts active scheduler 'play' loop
sl@0
   304
 *  @internalComponent
sl@0
   305
 */
sl@0
   306
void CMMFSwCodecConvertDataPath::CDataPathConverter::Start()
sl@0
   307
	{
sl@0
   308
	// If we're not already active, complete a request on ourselves to kick off the state machine
sl@0
   309
	if (iConvertState == EIdle)
sl@0
   310
		iConvertState = EFillingSourceBuffer;
sl@0
   311
	if (!IsActive())
sl@0
   312
		{
sl@0
   313
		TRequestStatus* stat = &iStatus;
sl@0
   314
		User::RequestComplete(stat, KErrNone);
sl@0
   315
		SetActive();
sl@0
   316
		}
sl@0
   317
	}
sl@0
   318
sl@0
   319
sl@0
   320
void CMMFSwCodecConvertDataPath::CDataPathConverter::ChangeConvertState(TConvertState aNewConvertState)
sl@0
   321
	{
sl@0
   322
	TRequestStatus* stat = &iStatus;
sl@0
   323
	//change state
sl@0
   324
	iConvertState = aNewConvertState;
sl@0
   325
	if (!IsActive())
sl@0
   326
		{
sl@0
   327
		User::RequestComplete(stat, KErrNone);
sl@0
   328
		SetActive();
sl@0
   329
		}
sl@0
   330
	}
sl@0
   331
sl@0
   332
/*** Main Convert Loop ***/
sl@0
   333
sl@0
   334
void CMMFSwCodecConvertDataPath::CDataPathConverter::FillSourceBufferL()
sl@0
   335
	{
sl@0
   336
	iParent.FillSourceBufferL();
sl@0
   337
	}
sl@0
   338
sl@0
   339
void CMMFSwCodecConvertDataPath::CDataPathConverter::FillSinkBufferL()
sl@0
   340
	{
sl@0
   341
	iParent.FillSinkBufferL();
sl@0
   342
	}
sl@0
   343
sl@0
   344
void CMMFSwCodecConvertDataPath::CDataPathConverter::EmptySinkBufferL()
sl@0
   345
	{
sl@0
   346
	iParent.EmptySinkBufferL();
sl@0
   347
	}
sl@0
   348
sl@0
   349
/*** End of main convert loop ***/
sl@0
   350
sl@0
   351
sl@0
   352
void CMMFSwCodecConvertDataPath::CDataPathConverter::RunL()
sl@0
   353
	{
sl@0
   354
	switch (iConvertState)
sl@0
   355
		{
sl@0
   356
		case EFillingSourceBuffer:
sl@0
   357
			FillSourceBufferL();
sl@0
   358
			break;
sl@0
   359
		case EFillingSinkBuffer:
sl@0
   360
			FillSinkBufferL();
sl@0
   361
			break;
sl@0
   362
		case EEmptyingSinkBuffer:
sl@0
   363
			EmptySinkBufferL();
sl@0
   364
			break;
sl@0
   365
		case EIdle:
sl@0
   366
			break;
sl@0
   367
		}
sl@0
   368
	}
sl@0
   369
sl@0
   370
void CMMFSwCodecConvertDataPath::CDataPathConverter::DoCancel()
sl@0
   371
	{
sl@0
   372
	//don't need to do anything as we don't have any async requests to other objects
sl@0
   373
	}
sl@0
   374
sl@0
   375
TInt CMMFSwCodecConvertDataPath::CDataPathConverter::RunError(TInt aError)
sl@0
   376
	{
sl@0
   377
	iParent.SoundDeviceException(aError);
sl@0
   378
	return KErrNone;
sl@0
   379
	}
sl@0
   380
sl@0
   381
sl@0
   382
sl@0
   383