diff -r 000000000000 -r 1bce908db942 multimediacommscontroller/mmccjitterbuffer/src/mccjitterbuffer.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/multimediacommscontroller/mmccjitterbuffer/src/mccjitterbuffer.cpp Tue Feb 02 01:04:58 2010 +0200 @@ -0,0 +1,710 @@ +/* +* Copyright (c) 2004-2008 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: JitterBuffer component capable to audioframe buffering. +* +*/ + + + + +// INCLUDE FILES +#include +#include "mccjitterbuffer.h" +#include "mccjitterbufferimpl.h" +#include "mccinternaldef.h" +#include "mccinternalevents.h" +#include "mccjitterbufferlogs.h" +#include "mccjitterbufferobserver.h" + +// LOCAL CONSTANTS +const TUint KAdaptUpdateIval = 250; + +// ============================= LOCAL FUNCTIONS =============================== + +// ============================ MEMBER FUNCTIONS =============================== + +// ----------------------------------------------------------------------------- +// CMccJitterBuffer::CMccJitterBuffer +// C++ default constructor can NOT contain any code, that +// might leave. +// ----------------------------------------------------------------------------- +// +CMccJitterBuffer::CMccJitterBuffer( MJitterBufferObserver* aObserver ) : + MDataSink( KMccJitterBufferUid ), MDataSource( KMccJitterBufferUid ), + iState( EJBufStopped ), + iObserver ( aObserver ) + { + + } + +// ----------------------------------------------------------------------------- +// CMccJitterBuffer::NewL +// Static constructor. +// ----------------------------------------------------------------------------- +// +EXPORT_C CMccJitterBuffer* CMccJitterBuffer::NewL( MJitterBufferObserver* aObserver ) + { + CMccJitterBuffer* self = new ( ELeave ) CMccJitterBuffer( aObserver ); + return self; + } + +// ----------------------------------------------------------------------------- +// CMccJitterBuffer::~CMccJitterBuffer +// Destructor deallocate memory. +// ----------------------------------------------------------------------------- +// +CMccJitterBuffer::~CMccJitterBuffer() + { + __JITTER_BUFFER_INT1( "CMccJitterBuffer::~CMccJitterBuffer:", + reinterpret_cast( this ) ) + __JITTER_BUFFER_INT1( "CMccJitterBuffer::~CMccJitterBuffer iDataSink:", + reinterpret_cast( iDataSink ) ) + __JITTER_BUFFER_INT1( "CMccJitterBuffer::~CMccJitterBuffer iDataSource:", + reinterpret_cast( iDataSource ) ) + __JITTER_BUFFER_INT1( "CMccJitterBuffer::~CMccJitterBuffer iSinkBuffer:", + reinterpret_cast( iSinkBuffer ) ) + __JITTER_BUFFER_INT1( "CMccJitterBuffer::~CMccJitterBuffer iBufferImpl:", + reinterpret_cast( iBufferImpl ) ) + + if ( iDataSink ) + { + iDataSink->SinkThreadLogoff(); + } + + if ( !iSnkBufRef ) + { + delete iSinkBuffer; + } + + delete iBufferImpl; + } + +// ----------------------------------------------------------------------------- +// CMccJitterBuffer::SetupL +// Setup Jitterbuffer +// ----------------------------------------------------------------------------- +// +EXPORT_C void CMccJitterBuffer::SetupL( TInt /*aBufferSize*/, TInt aPlayThreshold, + const TMccCodecInfo& aCInfo ) + { + __JITTER_BUFFER( "CMccJitterBuffer::SetupL" ) + + __ASSERT_ALWAYS( iDataSink, User::Leave( KErrNotReady ) ); + + if( !iBufferImpl ) + { + iBufferImpl = CMccJitterBufferImpl::NewL( iObserver ); + } + + MMMFAudioOutput* output = static_cast( iDataSink ); + iBufferImpl->SetupL( aPlayThreshold, + aCInfo, + output->SoundDevice(), + iEventHandler, + MCC_ENDPOINT_ID( iDataSink ) ); + } + +// ----------------------------------------------------------------------------- +// CMccJitterBuffer::ResetBuffer +// Reset Jitterbuffer +// ----------------------------------------------------------------------------- +// +EXPORT_C void CMccJitterBuffer::ResetBuffer( TBool aPlayTone ) + { + if ( iBufferImpl ) + { + iBufferImpl->ResetBuffer( aPlayTone ); + } + } + +// ----------------------------------------------------------------------------- +// CMccJitterBuffer::DelayDownL +// Delay Down +// ----------------------------------------------------------------------------- +// +EXPORT_C void CMccJitterBuffer::DelayDownL() + { + User::LeaveIfNull( iBufferImpl ); + iBufferImpl->DelayDownL(); + } + +// ----------------------------------------------------------------------------- +// CMccJitterBuffer::DelayUpL +// Delay Up +// ----------------------------------------------------------------------------- +// +EXPORT_C void CMccJitterBuffer::DelayUpL() + { + User::LeaveIfNull( iBufferImpl ); + iBufferImpl->DelayUpL(); + } + +// ----------------------------------------------------------------------------- +// CMccJitterBuffer::SetSinkDataTypeCode +// From MDataSink +// ----------------------------------------------------------------------------- +// +TInt CMccJitterBuffer::SetSinkDataTypeCode( TFourCC aSinkFourCC, TMediaId aMediaId ) + { + if( KUidMediaTypeAudio == aMediaId.iMediaType ) + { + __JITTER_BUFFER( "CMccJitterBuffer::SetSinkDataTypeCode To iDataSink" ) + + return iDataSink->SetSinkDataTypeCode( aSinkFourCC, aMediaId ); + } + else + { + __JITTER_BUFFER( "CMccJitterBuffer::SetSinkDataTypeCode NOT SUPPORTED" ) + + return KErrNotSupported; + } + } + +// ----------------------------------------------------------------------------- +// CMccJitterBuffer::SetSourceDataTypeCode +// +// ----------------------------------------------------------------------------- +// +TInt CMccJitterBuffer::SetSourceDataTypeCode( TFourCC aSourceFourCC, TMediaId aMediaId ) + { + if( KUidMediaTypeAudio == aMediaId.iMediaType ) + { + __JITTER_BUFFER( "CMccJitterBuffer::SetSourceDataTypeCode To iDataSource" ) + + return iDataSource->SetSourceDataTypeCode( aSourceFourCC, aMediaId ); + } + else + { + __JITTER_BUFFER( "CMccJitterBuffer::SetSourceDataTypeCode NOT SUPPORTED" ) + + return KErrNotSupported; + } + } + +// ----------------------------------------------------------------------------- +// CMccJitterBuffer::SinkDataTypeCode +// From MDataSink +// ----------------------------------------------------------------------------- +// +TFourCC CMccJitterBuffer::SinkDataTypeCode( TMediaId aMediaId ) + { + if( KUidMediaTypeAudio == aMediaId.iMediaType ) + { + __JITTER_BUFFER( "CMccJitterBuffer::SinkDataTypeCode From iDataSink" ) + + return iDataSink->SinkDataTypeCode( aMediaId ); + } + else + { + // Default to NULL FourCC + __JITTER_BUFFER( "CMccJitterBuffer::SinkDataTypeCode DEFAULT" ) + + return TFourCC(); + } + } + +// ----------------------------------------------------------------------------- +// CMccJitterBuffer::SourceDataTypeCode +// From MDataSource +// ----------------------------------------------------------------------------- +// +TFourCC CMccJitterBuffer::SourceDataTypeCode( TMediaId aMediaId ) + { + if( KUidMediaTypeAudio == aMediaId.iMediaType ) + { + __JITTER_BUFFER( "CMccJitterBuffer::SourceDataTypeCode From iDataSource" ) + + return iDataSource->SourceDataTypeCode( aMediaId ); + } + else + { + // Default to NULL FourCC + __JITTER_BUFFER( "CMccJitterBuffer::SourceDataTypeCode DEFAULT" ) + + return TFourCC(); + } + } + +// ----------------------------------------------------------------------------- +// CMccJitterBuffer::ConstructSinkL +// From MDataSink +// ----------------------------------------------------------------------------- +// +void CMccJitterBuffer::ConstructSinkL( const TDesC8& /*aInitData*/ ) + { + User::Leave( KErrNotSupported ); + } + +// ----------------------------------------------------------------------------- +// CMccJitterBuffer::ConstructSourceL +// From MDataSource +// ----------------------------------------------------------------------------- +// +void CMccJitterBuffer::ConstructSourceL( const TDesC8& /*aInitData*/ ) + { + User::Leave( KErrNotSupported ); + } + +// ----------------------------------------------------------------------------- +// CMccJitterBuffer::SinkThreadLogon +// From MDataSink +// ----------------------------------------------------------------------------- +// +TInt CMccJitterBuffer::SinkThreadLogon( MAsyncEventHandler& aEventHandler ) + { + if( !iEventHandler ) + { + if( iDataSink ) + { + __JITTER_BUFFER( "CMccJitterBuffer::SinkThreadLogon NORMAL" ) + + iEventHandler = &aEventHandler; + return iDataSink->SinkThreadLogon( aEventHandler ); + } + else + { + __JITTER_BUFFER( "CMccJitterBuffer::SinkThreadLogon KErrNotReady" ) + + return KErrNotReady; + } + } + else + { + __JITTER_BUFFER( "CMccJitterBuffer::SinkThreadLogon KErrAlreadyExists" ) + + return KErrAlreadyExists; + } + } + +// ----------------------------------------------------------------------------- +// CMccJitterBuffer::SourceThreadLogon +// From MDataSource +// ----------------------------------------------------------------------------- +// +TInt CMccJitterBuffer::SourceThreadLogon( MAsyncEventHandler& /*aEventHandler*/ ) + { + __JITTER_BUFFER( "CMccJitterBuffer::SourceThreadLogon" ) + + // Jitter buffer is used always as a datasink, so we do not support any + // source threads logging on. + return KErrNotSupported; + } + +// ----------------------------------------------------------------------------- +// CMccJitterBuffer::SinkThreadLogoff +// From MDataSink +// ----------------------------------------------------------------------------- +// +void CMccJitterBuffer::SinkThreadLogoff() + { + __JITTER_BUFFER( "CMccJitterBuffer::SinkThreadLogoff in" ) + + iEventHandler = NULL; + + if( iBufferImpl ) + { + delete iBufferImpl; + iBufferImpl = NULL; + } + + if( iDataSink ) + { + iDataSink->SinkThreadLogoff(); + iDataSink = NULL; + } + + if ( !iSnkBufRef ) + { + delete iSinkBuffer; + } + + iSinkBuffer = NULL; + + __JITTER_BUFFER( "CMccJitterBuffer::SinkThreadLogoff out" ) + } + +// ----------------------------------------------------------------------------- +// CMccJitterBuffer::SinkPrimeL +// +// ----------------------------------------------------------------------------- +// +void CMccJitterBuffer::SinkPrimeL() + { + __JITTER_BUFFER( "CMccJitterBuffer::SinkPrimeL" ) + + iState = EJBufPrimed; + this->ResetBuffer(); + iDataSink->SinkPrimeL(); + } + +// ----------------------------------------------------------------------------- +// CMccJitterBuffer::SinkPlayL +// +// ----------------------------------------------------------------------------- +// +void CMccJitterBuffer::SinkPlayL() + { + __JITTER_BUFFER("CMccJitterBuffer::SinkPlayL iDataSink->SinkPlayL" ) + + iState = EJBufPlaying; + iDataSink->SinkPlayL(); + iSnkBufRef = ETrue; // Sinkbuffer owned by MMF + iRequestSize = 0; + + __JITTER_BUFFER( "CMccJitterBuffer::SinkPlayL CreateSinkBufferL" ) + + iSinkBuffer = iDataSink->CreateSinkBufferL( KUidMediaTypeAudio, iSnkBufRef ); + + // If buffer has not been supplied via CreateSinkBufferL, must use + // asynchronous buffer creation + if ( !iSinkBuffer ) + { + __JITTER_BUFFER( "CMccJitterBuffer::SinkPlayL EmptyBufferL ASYNC CREATION" ) + + iDataSink->EmptyBufferL( iSinkBuffer, this, KUidMediaTypeAudio ); + } + else + { + //we have a sink buffer from CreateSinkBufferL + __JITTER_BUFFER( "CMccJitterBuffer::SinkPlayL EmptyBufferL SYNC CREATION" ) + + iSinkBuffer->SetStatus( EAvailable ); + } + + iPlayedFrames = 0; + } + +// ----------------------------------------------------------------------------- +// CMccJitterBuffer::SinkPauseL +// +// ----------------------------------------------------------------------------- +// +void CMccJitterBuffer::SinkPauseL() + { + __JITTER_BUFFER( "CMccJitterBuffer::SinkPauseL" ) + + iState = EJBufPaused; + ResetBuffer(); + iDataSink->SinkPauseL(); + iPlayedFrames = 0; + + // If sinkbuffer is not a reference then we need to delete it here so that + // play - pause - play works. Also devsound creates new buffers when + // resuming from Pause through Play. + if ( !iSnkBufRef ) + { + delete iSinkBuffer; + } + + iSinkBuffer = NULL; + } + +// ----------------------------------------------------------------------------- +// CMccJitterBuffer::SinkStopL +// +// ----------------------------------------------------------------------------- +// +void CMccJitterBuffer::SinkStopL() + { + __JITTER_BUFFER( "CMccJitterBuffer::SinkStopL" ) + + iState = EJBufStopped; + ResetBuffer(); + iDataSink->SinkStopL(); + iPlayedFrames = 0; + if ( !iSnkBufRef ) + { + delete iSinkBuffer; + } + + iSinkBuffer = NULL; + } + + +// ----------------------------------------------------------------------------- +// CMccJitterBuffer::CanCreateSinkBuffer +// From MDataSink +// ----------------------------------------------------------------------------- +// +TBool CMccJitterBuffer::CanCreateSinkBuffer() + { + // CMccJitterBuffer can't create buffers + return EFalse; + } + +// ----------------------------------------------------------------------------- +// CMccJitterBuffer::CanCreateSourceBuffer +// From MDataSource +// ----------------------------------------------------------------------------- +// +TBool CMccJitterBuffer::CanCreateSourceBuffer() + { + // CMccJitterBuffer can't create buffers + return EFalse; + } + +// ----------------------------------------------------------------------------- +// CMccJitterBuffer::CreateSinkBufferL +// From MDataSink +// ----------------------------------------------------------------------------- +// +CMMFBuffer* CMccJitterBuffer::CreateSinkBufferL( TMediaId /*aMediaId*/, + TBool& /*aReference*/ ) + { + // CMccJitterBuffer can't create buffers + User::Leave( KErrNotSupported ); + return NULL; + } + +// ----------------------------------------------------------------------------- +// CMccJitterBuffer::CreateSourceBufferL +// From MDataSource +// ----------------------------------------------------------------------------- +// +CMMFBuffer* CMccJitterBuffer::CreateSourceBufferL( TMediaId /*aMediaId*/, + TBool& /*aReference*/ ) + { + // CMccJitterBuffer can't create buffers + User::Leave( KErrNotSupported ); + return NULL; + } + +// ----------------------------------------------------------------------------- +// CMccJitterBuffer::FillBufferL +// From MDataSource +// ----------------------------------------------------------------------------- +// +void CMccJitterBuffer::FillBufferL( CMMFBuffer* /*aBuffer*/, + MDataSink* /*aConsumer*/, + TMediaId /*aMediaId*/ ) + { + __JITTER_BUFFER( "CMccJitterBuffer::FillBufferL KErrNotSupported" ) + + User::Leave( KErrNotSupported ); + } + +// ----------------------------------------------------------------------------- +// CMccJitterBuffer::EmptyBufferL +// From MDataSink +// ----------------------------------------------------------------------------- +// +void CMccJitterBuffer::EmptyBufferL( CMMFBuffer* aBuffer, + MDataSource* aSupplier, + TMediaId /*aMediaId*/ ) + { + if( iBufferImpl && ( iState == EJBufPlaying ) ) + { + __ASSERT_ALWAYS( iBufferImpl->BufferLength(), User::Leave( KErrNotReady ) ); + + __JITTER_BUFFER_INT1( "CMccJitterBuffer::EmptyBufferL BUF_SZ:", aBuffer->BufferSize() ) + __JITTER_BUFFER_INT1( "CMccJitterBuffer::EmptyBufferL REQ_SZ:", aBuffer->RequestSize() ) + + // Adaptation control will be done based on played frames + iBufferImpl->AddDataFrameL( aBuffer ); + aBuffer->SetStatus( EAvailable ); + } + + // Inform the source immediately so that packets keep on flowing in + if ( aSupplier ) + { + aSupplier->BufferEmptiedL( aBuffer ); + } + } + +// ----------------------------------------------------------------------------- +// CMccJitterBuffer::BufferFilledL +// +// ----------------------------------------------------------------------------- +// +void CMccJitterBuffer::BufferFilledL( CMMFBuffer* /*aBuffer*/ ) + { + __JITTER_BUFFER( "CMccJitterBuffer::BufferFilledL KErrNotSupported" ) + + User::Leave( KErrNotSupported ); + } + +// ----------------------------------------------------------------------------- +// CMccJitterBuffer::BufferEmptiedL +// +// ----------------------------------------------------------------------------- +// +void CMccJitterBuffer::BufferEmptiedL( CMMFBuffer* aBuffer ) + { + __JITTER_BUFFER( "CMccJitterBuffer::BufferEmptiedL" ) + + User::LeaveIfNull( aBuffer ); + iSinkBuffer = aBuffer; + iSinkBuffer->SetStatus( EAvailable ); + + if( iBufferImpl && iBufferImpl->BufferLength() ) + { + __JITTER_BUFFER( "CMccJitterBuffer::BufferEmptiedL NORMAL" ) + + // Check for request size changes if current codec happens to support + // dynamic codec frame length changes. Currently only needed for + // supporting 10/20ms variants of G.711 codec. Also one frame has two + // bytes extra for the frameheader, so we remove it here. + const TInt reqSize( iSinkBuffer->RequestSize() - KVoIPHeaderLength ); + if ( reqSize != iRequestSize && + iBufferImpl->CurrentCodec() == KMccFourCCIdG711 ) + { + __JITTER_BUFFER_INT1( "CMccJitterBuffer::BufferEmptiedL reqSize: ", reqSize ) + __JITTER_BUFFER_INT1( "CMccJitterBuffer::BufferEmptiedL iRequestSize: ", iRequestSize ) + iRequestSize = reqSize; + + if ( iObserver ) + { + // We don't do this on emulator as it will kick us in the teeth + // later when re-calculating jitterbuffer size. + #ifndef __WINSCW__ + iObserver->DynamicBufferChangeRequest( iRequestSize ); + #endif + } + } + + iBufferImpl->GetDataFrameL( iSinkBuffer ); + iPlayedFrames++; + + if( KAdaptUpdateIval == iPlayedFrames ) + { + // Don't care about the error if frames haven't been received yet + // because it's sensible to do the adaptation only when there is + // actual data in the buffer + iPlayedFrames = 0; + SendJitterBufferEventToClient(); + } + + iSinkBuffer->SetStatus( EFull ); + iDataSink->EmptyBufferL( iSinkBuffer, this, KUidMediaTypeAudio ); + } + else + { + __JITTER_BUFFER( "CMccJitterBuffer::BufferEmptiedL KErrNotReady" ) + + User::Leave( KErrNotReady ); + } + } + +// ----------------------------------------------------------------------------- +// CMccJitterBuffer::AddDataSinkL +// From MDataSource +// ----------------------------------------------------------------------------- +// +EXPORT_C void CMccJitterBuffer::AddDataSinkL( MDataSink* aSink ) + { + if( iDataSink ) + { + __JITTER_BUFFER( "CMccJitterBuffer::AddDataSinkL KErrAlreadyExists" ) + + User::Leave( KErrAlreadyExists ); + } + else + { + User::LeaveIfNull( aSink ); + if( KUidMmfAudioOutput == aSink->DataSinkType() ) + { + __JITTER_BUFFER( "CMccJitterBuffer::AddDataSinkL AUDIO SINK" ) + + iDataSink = aSink; + } + else + { + __JITTER_BUFFER( "CMccJitterBuffer::AddDataSinkL KErrArgument" ) + + User::Leave( KErrArgument ); + } + } + } + +// ----------------------------------------------------------------------------- +// CMccJitterBuffer::AddDataSourceL +// From MDataSource +// ----------------------------------------------------------------------------- +// +EXPORT_C void CMccJitterBuffer::AddDataSourceL( MDataSource* aSource ) + { + __JITTER_BUFFER( "CMccJitterBuffer::AddDataSourceL" ) + + User::LeaveIfNull( aSource ); + iDataSource = aSource; + } + +// ----------------------------------------------------------------------------- +// CMccJitterBuffer::SendJitterBufferEventToClient +// +// ----------------------------------------------------------------------------- +// +void CMccJitterBuffer::SendJitterBufferEventToClient() + { + TMccJitterBufferEventData eventData; + iBufferImpl->GenerateStatistics( eventData ); + + if( iEventHandler ) + { + TMccEvent event( 0, + 0, + 0, + MCC_ENDPOINT_ID( iDataSink ), + KMccEventCategoryStream, + KMccEventNone, + KErrNone, + KNullDesC8 ); + + event.iEventData.Copy( TMccJitterBufferEventDataPackage( eventData ) ); + + TMccInternalEvent internalEvent( KMccJitterBufferUid, + EMccInternalJitterEventStatusReport, + event ); + + iEventHandler->SendEventToClient( internalEvent ); + } + else + { + __JITTER_BUFFER( "CMccJitterBuffer::RunError, iEventHandler=NULL" ) + } + } + +// ----------------------------------------------------------------------------- +// CMccJitterBuffer::GetDataSink +// Get DataSink +// ----------------------------------------------------------------------------- +// +EXPORT_C MDataSink* CMccJitterBuffer::GetDataSink() + { + return iDataSink; + } + +// ----------------------------------------------------------------------------- +// CMccJitterBuffer::NegotiateL +// From MDataSink +// ----------------------------------------------------------------------------- +// +void CMccJitterBuffer::NegotiateL( MDataSource& aDataSource ) + { + if( iDataSink ) + { + __JITTER_BUFFER( "CMccJitterBuffer::NegotiateL" ) + + iDataSink->NegotiateL( aDataSource ); + } + else + { + __JITTER_BUFFER( "CMccJitterBuffer::NegotiateL KErrNotReady" ) + + User::Leave( KErrNotReady ); + } + } + +// End of File +