diff -r 000000000000 -r 79dd3e2336a0 devsound/devsoundrefplugin/src/swcodecwrapper/mmfSwCodecConvertDataPath.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/devsound/devsoundrefplugin/src/swcodecwrapper/mmfSwCodecConvertDataPath.cpp Fri Oct 08 19:40:43 2010 +0100 @@ -0,0 +1,383 @@ +// Copyright (c) 2003-2009 Nokia Corporation and/or its subsidiary(-ies). +// All rights reserved. +// This component and the accompanying materials are made available +// under the terms of "Eclipse Public License v1.0" +// which accompanies this distribution, and is available +// at the URL "http://www.eclipse.org/legal/epl-v10.html". +// +// Initial Contributors: +// Nokia Corporation - initial contribution. +// +// Contributors: +// +// Description: +// source\server\mmfswcodecconvertdatapath.cpp +// +// + +#include "mmfSwCodecConvertDataPath.h" +#include +#include + + +CMMFSwCodecConvertDataPath* CMMFSwCodecConvertDataPath::NewL() + { + CMMFSwCodecConvertDataPath* self = new(ELeave) CMMFSwCodecConvertDataPath; + CleanupStack::PushL(self); + self->ConstructL(); + CleanupStack::Pop(); + return self; + } + + +void CMMFSwCodecConvertDataPath::ConstructL() + { + iDataPathConverter = new (ELeave) CDataPathConverter(*this,CActive::EPriorityUserInput); + } + + +CMMFSwCodecConvertDataPath::~CMMFSwCodecConvertDataPath() + { + delete iDataPathConverter; + if (iCodec) + { + delete iSourceBuffer; + if (!iCodec->IsNullCodec()) + delete iSinkBuffer; + } + } + + +TInt CMMFSwCodecConvertDataPath::SetObserver(MMMFHwDeviceObserver& aObserver) + { + TInt error; + if (iHwDeviceObserver) + { + error = KErrAlreadyExists; + } + else + { + iHwDeviceObserver = &aObserver; + error = KErrNone; + } + return error; + } + + +TInt CMMFSwCodecConvertDataPath::AddCodec(CMMFSwCodec& aCodec) + { + if (iCodec) + return KErrNotSupported; //doesn't support multiple codecs + + TInt err = KErrNone; + iCodec = &aCodec; + + iSourceBufferSize = iCodec->SourceBufferSize(); + iSinkBufferSize = iCodec->SinkBufferSize(); + + if ((!iSourceBufferSize)||(!iSinkBufferSize)) + err = KErrArgument; //codec plugin has not specified buffer size + + if (err == KErrNone) + { + TRAP(err,iSourceBuffer = CMMFDataBuffer::NewL(iSourceBufferSize)); + } + + if (err == KErrNone) + { + // Allocate data buffer + if (iCodec->IsNullCodec()) + {//don't need a separate sink buffer if null codec + iSinkBuffer = NULL; //sink buffer is the sound device buffer + } + else + {//need a separate sink buffer for the codec + TRAP(err,iSinkBuffer = CMMFDataBuffer::NewL(iSinkBufferSize)); + } + } + return err; + } + + +TInt CMMFSwCodecConvertDataPath::Start() + { + TInt startError = KErrNone; + if (!iCodec) + {//check that a codec has been added + startError = KErrNotReady; + } + if (!startError) + { + // Start the player objects + iSourceBuffer->SetLastBuffer(EFalse); + iDataPathConverter->Start(); + iState = EPlaying; + iNoMoreSourceData = EFalse; + } + return startError; + } + + + +void CMMFSwCodecConvertDataPath::Stop() + { + iDataPathConverter->Cancel(); + iState = EStopped; + } + + +void CMMFSwCodecConvertDataPath::Pause() + {//pause is equivalent to stop for a data transfer + iDataPathConverter->Cancel(); + iState = EStopped; + } + +/*** Main play loop ***/ + +void CMMFSwCodecConvertDataPath::FillSourceBufferL() + { + STATIC_CAST(CMMFDataBuffer*, iSourceBuffer)->SetRequestSizeL(iSourceBufferSize); + + // Ask immediately for data from the observer + User::LeaveIfError(iHwDeviceObserver->FillThisHwBuffer(*iSourceBuffer)); + } + + /** + * BufferFilledL. + * (from MDataSink) + * + * called by the CMMFDataPath's MDataSource when it has filled the buffer + * @internalComponent + * @param aBuffer + * + */ +void CMMFSwCodecConvertDataPath::BufferFilledL(CMMFDataBuffer& aBuffer) + { + iSourceBuffer = &aBuffer; + iSourceBuffer->SetStatus(EFull); + + //need to check that the buffer size is not 0 - + //if so assume we've reached the end of the data + if (!iSourceBuffer->BufferSize()) + {//no buffer - could be end of source or could be that the source has no data + //also need to check the sink buffer is available else there is still some + //stuff to do before the sink buffer is freed + if (iSinkBuffer->Status()==EAvailable) + { + iNoMoreSourceData = ETrue; + } + } + else + { + if (iSourceBuffer->LastBuffer()) //also check last buffer flag + iNoMoreSourceData = ETrue; + iDataPathConverter->ChangeConvertState(CDataPathConverter::EFillingSinkBuffer); + } + } + +/* + * FillSinkBufferL + * + * Function to take the data from an already full source buffer and by using + * a codec if necessary fills the sink buffer + * @internalComponent + */ +void CMMFSwCodecConvertDataPath::FillSinkBufferL() + { + CMMFSwCodec::TCodecProcessResult codecProcessResult; + + if (iCodec->IsNullCodec()) + {//no codec so data can be sent direct to sink + iSinkBuffer = iSourceBuffer; + iSinkBuffer->SetStatus(EFull); //sink buffer is full + } + else + { + //pass buffer to codec for processing + codecProcessResult = iCodec->ProcessL(*iSourceBuffer, *iSinkBuffer); + if (iSourceBuffer->LastBuffer()) //if source is last buffer so is sink + iSinkBuffer->SetLastBuffer(ETrue); + if ((!iSinkBuffer->BufferSize())&&(codecProcessResult.iDstBytesAdded)) + {//the codec has added data but not set the buffer length + iSinkBuffer->Data().SetLength(codecProcessResult.iDstBytesAdded); + } + + //only supports EProcessComplete + switch (codecProcessResult.iCodecProcessStatus) + { + case CMMFSwCodec::TCodecProcessResult::EProcessComplete: + //finished procesing source data - all data in sink buffer + { + iSourceBuffer->SetStatus(EAvailable); //source buffer is now avaialble + iSinkBuffer->SetStatus(EFull); //sink buffer is full + } + break; + case CMMFSwCodec::TCodecProcessResult::EDstNotFilled: + //could be the last buffer in which case dst might not get filled + { + iSourceBuffer->SetStatus(EAvailable); //source buffer is now avaialble + iSinkBuffer->SetStatus(EFull); //sink buffer is full + } + break; + case CMMFSwCodec::TCodecProcessResult::EEndOfData: + //no more data - send what we've got to the sink + //note we can't always rely on this - in many cases the codec will not know when + //it has reached the end of data. + { + iSourceBuffer->SetStatus(EAvailable); //source buffer is now avaialble + iSinkBuffer->SetStatus(EFull);//sink buffer may not really be 'full' but its as full as it going to get + //doesn't matter if sink buffer is not full + } + break; + default: + Panic(EMMFSwCodecWrapperBadCodec); //should never get here - bad codec + } + } + iDataPathConverter->ChangeConvertState(CDataPathConverter::EEmptyingSinkBuffer); + } + + +void CMMFSwCodecConvertDataPath::EmptySinkBufferL() + { + User::LeaveIfError(iHwDeviceObserver->EmptyThisHwBuffer(*iSinkBuffer)); + } + + +void CMMFSwCodecConvertDataPath::BufferEmptiedL(const CMMFDataBuffer& aBuffer) + { + if (&aBuffer != iSinkBuffer) + User::Leave(KErrArgument); + if (!iNoMoreSourceData) + iDataPathConverter->ChangeConvertState(CDataPathConverter::EFillingSourceBuffer); + else //no more source data so signal EOF + SoundDeviceException(KErrEof); + } + +void CMMFSwCodecConvertDataPath::SoundDeviceException(TInt aError) + { + // Inform the observer of the exception condition + iHwDeviceObserver->Error(aError); + + Stop(); + + // Let the observer know we're fully stopped + iHwDeviceObserver->Stopped(); + } + +RMdaDevSound& CMMFSwCodecConvertDataPath::Device() + { + return iDummyDevSound;//convert doesn't have a RMdaDevSound + } + +/*** End of main play loop ***/ + + + + +/************************************************************************ + * CDataPathConverter + * This class performs the main data transfer between the source and the sink + * This is done in a separate class as opposed to CMMFSwCodecConvertDataPath + * because the class needs to be an active object to avoid recursive call stacks + * in cases where the source and sink are not active objects - which is + * the case with descriptors. Making CMMFSwCodecConvertDataPath derive + * from CActive is less desirable as it would involve multiple inheretence + ************************************************************************/ + +CMMFSwCodecConvertDataPath::CDataPathConverter::CDataPathConverter(CMMFSwCodecConvertDataPath& aParent, TInt aPriority) +: CActive(aPriority), iParent(aParent) + { + CActiveScheduler::Add(this); + iConvertState = EIdle; + } + + +CMMFSwCodecConvertDataPath::CDataPathConverter::~CDataPathConverter() + { + Cancel(); + } + +/** + * Start + * + * Starts active scheduler 'play' loop + * @internalComponent + */ +void CMMFSwCodecConvertDataPath::CDataPathConverter::Start() + { + // If we're not already active, complete a request on ourselves to kick off the state machine + if (iConvertState == EIdle) + iConvertState = EFillingSourceBuffer; + if (!IsActive()) + { + TRequestStatus* stat = &iStatus; + User::RequestComplete(stat, KErrNone); + SetActive(); + } + } + + +void CMMFSwCodecConvertDataPath::CDataPathConverter::ChangeConvertState(TConvertState aNewConvertState) + { + TRequestStatus* stat = &iStatus; + //change state + iConvertState = aNewConvertState; + if (!IsActive()) + { + User::RequestComplete(stat, KErrNone); + SetActive(); + } + } + +/*** Main Convert Loop ***/ + +void CMMFSwCodecConvertDataPath::CDataPathConverter::FillSourceBufferL() + { + iParent.FillSourceBufferL(); + } + +void CMMFSwCodecConvertDataPath::CDataPathConverter::FillSinkBufferL() + { + iParent.FillSinkBufferL(); + } + +void CMMFSwCodecConvertDataPath::CDataPathConverter::EmptySinkBufferL() + { + iParent.EmptySinkBufferL(); + } + +/*** End of main convert loop ***/ + + +void CMMFSwCodecConvertDataPath::CDataPathConverter::RunL() + { + switch (iConvertState) + { + case EFillingSourceBuffer: + FillSourceBufferL(); + break; + case EFillingSinkBuffer: + FillSinkBufferL(); + break; + case EEmptyingSinkBuffer: + EmptySinkBufferL(); + break; + case EIdle: + break; + } + } + +void CMMFSwCodecConvertDataPath::CDataPathConverter::DoCancel() + { + //don't need to do anything as we don't have any async requests to other objects + } + +TInt CMMFSwCodecConvertDataPath::CDataPathConverter::RunError(TInt aError) + { + iParent.SoundDeviceException(aError); + return KErrNone; + } + + + +