diff -r 000000000000 -r 1bce908db942 multimediacommscontroller/mmccmultiplexer/src/mccsinkitem.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/multimediacommscontroller/mmccmultiplexer/src/mccsinkitem.cpp Tue Feb 02 01:04:58 2010 +0200 @@ -0,0 +1,622 @@ +/* +* Copyright (c) 2006 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: +* +*/ + + + + +// INCLUDE FILES +#include +#include +#include "rtpheader.h" +#include "mccsinkitem.h" +#include "formatstatemachine.h" +#include "mccmultiplexerlogs.h" +#include "mccinternaldef.h" +#include "mccinternalevents.h" +#include "mccuids.hrh" + +// MACROS + +#define MCC_PAYLOAD_READ( a ) static_cast( a ) + +// LOCAL FUNCTION PROTOTYPES + +// LOCAL CONSTANTS + +const TInt KMccBadDataCount = 20; + +const TInt KMccMaxStoredBuffers = 10; + +// ============================= LOCAL FUNCTIONS =============================== + +// ============================ MEMBER FUNCTIONS =============================== + +// ----------------------------------------------------------------------------- +// CMccSinkItem::NewLC +// ----------------------------------------------------------------------------- +// +CMccSinkItem* CMccSinkItem::NewLC( + MDataSink* aSink, + TBool aSinkIsDecoder, + TUid aMediaType, + TBool aPassAllBuffersSink ) + { + CMccSinkItem* self = + new ( ELeave ) CMccSinkItem( aMediaType, aPassAllBuffersSink ); + CleanupStack::PushL( self ); + self->ConstructL( aSink, aSinkIsDecoder ); + return self; + } + +// ----------------------------------------------------------------------------- +// CMccSinkItem::~CMccSinkItem +// ----------------------------------------------------------------------------- +// +CMccSinkItem::~CMccSinkItem() + { + iStoredBuffers.ResetAndDestroy(); + iPayloadsToAccept.Close(); + } + +// ----------------------------------------------------------------------------- +// CMccSinkItem::BufferFilledL +// ----------------------------------------------------------------------------- +// +void CMccSinkItem::BufferFilledL( + CMMFBuffer* aBuffer, + const TRtpRecvHeader* aHeaderInfo, + TBool aPrimary, + TUid aMediaType ) + { + __MULTIPLEXER_INT1( "CMccSinkItem::BufferFilledL, sinkitem:", + reinterpret_cast( this ) ) + + CMMFBuffer* completedBuffer = NULL; + + CMMFDataBuffer* dataBuffer = static_cast( aBuffer ); + + if ( aMediaType != KNullUid && MediaType() != aMediaType ) + { + __MULTIPLEXER( "CMccSinkItem::BufferFilledL, wrong media type" ) + return; + } + + if ( HandleBadDataL( dataBuffer ) ) + { + __MULTIPLEXER( "CMccSinkItem::BufferFilledL, stopping buffer forwarding" ) + return; + } + + if ( aHeaderInfo + && ( KErrNotFound != iPayloadsToAccept.Find( aHeaderInfo->iPayloadType ) ) ) + { + __MULTIPLEXER( "CMccSinkItem::BufferFilledL, payload type demultiplexing" ) + + if ( iRequestedBuffer ) + { + __MULTIPLEXER( "CMccSinkItem::BufferFilledL, fillbuffer request exists" ) + + CopyBufferL( iRequestedBuffer, aBuffer ); + completedBuffer = iRequestedBuffer; + iRequestedBuffer = NULL; + } + } + else if ( iPassAllBuffersSink ) + { + __MULTIPLEXER( "CMccSinkItem::BufferFilledL, in passall buffers mode" ) + + // Do not zero the request, sink will eat all buffers + // once it has requested for one + if ( iRequestedBuffer ) + { + completedBuffer = aBuffer; + } + } + else if ( iPassAllRequestsSource ) + { + __MULTIPLEXER( "CMccSinkItem::BufferFilledL, in passall requests mode" ) + + // If in passall mode, buffer received from source must match with the + // one the sink gave when requesting the buffer fill + if ( iRequestedBuffer && + iRequestedBuffer == aBuffer ) + { + __MULTIPLEXER( "CMccSinkItem::BufferFilledL, existing fillbuffer request" ) + + completedBuffer = aBuffer; + iRequestedBuffer = NULL; + } + } + else if ( iRequestedBuffer && aPrimary ) + { + __MULTIPLEXER( "CMccSinkItem::BufferFilledL, existing fillbuffer request for primary" ) + + completedBuffer = aBuffer; + iRequestedBuffer = NULL; + } + else + { + if ( iRequestedBuffer ) + { + __MULTIPLEXER( "CMccSinkItem::BufferFilledL, existing fillbuffer request" ) + + // If secondary sink has already requested buffer fill, the request + // can be completed immediately + CopyBufferL( iRequestedBuffer, aBuffer ); + completedBuffer = iRequestedBuffer; + iRequestedBuffer = NULL; + } + else + { + // Otherwise the buffer has to be "stored" + StoreBufferL( aBuffer ); + } + } + + if ( completedBuffer ) + { + if ( iDecoder && aHeaderInfo ) + { + iDecoder->DataBufferFilledL( completedBuffer, *aHeaderInfo ); + } + else + { + Sink()->BufferFilledL( completedBuffer ); + } + } + + __MULTIPLEXER( "CMccSinkItem::BufferFilledL, exit" ) + } + +// ----------------------------------------------------------------------------- +// CMccSinkItem::FillBufferRequestL +// ----------------------------------------------------------------------------- +// +void CMccSinkItem::FillBufferRequestL( CMMFBuffer* aBuffer ) + { + __MULTIPLEXER_INT1( "CMccSinkItem::FillBufferRequestL, sinkitem:", + reinterpret_cast( this ) ) + + CMMFBuffer* storedBuffer = GetStoredBuffer(); + if ( storedBuffer ) + { + __MULTIPLEXER( "CMccSinkItem::FillBufferRequestL, stored buffer exists" ) + + CleanupStack::PushL( storedBuffer ); + CopyBufferL( aBuffer, storedBuffer ); + CleanupStack::PopAndDestroy( storedBuffer ); + + Sink()->BufferFilledL( aBuffer ); + } + else + { + __MULTIPLEXER( "CMccSinkItem::FillBufferRequestL, store fillbuffer request" ) + + iRequestedBuffer = aBuffer; + } + + __MULTIPLEXER( "CMccSinkItem::FillBufferRequestL, exit" ) + } + +// ----------------------------------------------------------------------------- +// CMccSinkItem::Match +// ----------------------------------------------------------------------------- +// +TBool CMccSinkItem::Match( MDataSink* aSink ) + { + return ( Sink() == aSink ); + } + +// ----------------------------------------------------------------------------- +// CMccSinkItem::SourceThreadLogon +// ----------------------------------------------------------------------------- +// +TInt CMccSinkItem::SourceThreadLogon( MAsyncEventHandler& aEventHandler ) + { + iEventHandler = &aEventHandler; + return KErrNone; + } + +// ----------------------------------------------------------------------------- +// CMccSinkItem::SendEventToClient +// ----------------------------------------------------------------------------- +// +TInt CMccSinkItem::SendEventToClient( const TMMFEvent& aEvent ) + { + __MULTIPLEXER( "CMccSinkItem::SendEventToClient" ) + + // Filter duplicate stream state change events. Errors are always reported. + // Check also whether the event is targeted for specific payload type. + // + + TInt ret( KErrNotReady ); + TBool sendEvent( ETrue ); + + if ( IS_MCC_EVENT( aEvent ) ) + { + TMccEvent* mccEventPtr = + reinterpret_cast( aEvent ).iMccEvent; + + if ( mccEventPtr && MCC_STREAM_STATE_CHANGE_EVENT( mccEventPtr ) && + !mccEventPtr->iErrorCode ) + { + sendEvent = HandleStreamStateChangeEvent( *mccEventPtr ); + ret = KErrNone; + } + else if ( mccEventPtr && + mccEventPtr->iEventNumData == KMccPayloadSpecificEvent && + mccEventPtr->iReserved != KMccPTNotDefined ) + { + __MULTIPLEXER_INT1( "CMccSinkItem::SendEventToClient, event for payload type:", + mccEventPtr->iReserved ) + + sendEvent = + ( iPayloadsToAccept.Find( mccEventPtr->iReserved ) != KErrNotFound ); + } + else + { + // NOP + } + } + + if ( iEventHandler && sendEvent ) + { + ret = iEventHandler->SendEventToClient( aEvent ); + } + else + { + __MULTIPLEXER( "CMccSinkItem::SendEventToClient, dropping event" ) + } + return ret; + } + +// ----------------------------------------------------------------------------- +// CMccSinkItem::MediaType +// ----------------------------------------------------------------------------- +// +TUid CMccSinkItem::MediaType() const + { + return iMediaType; + } + +// ----------------------------------------------------------------------------- +// CMccSinkItem::RegisterPayloadTypesL +// ----------------------------------------------------------------------------- +// +void CMccSinkItem::RegisterPayloadTypesL( const RArray& aPayloadTypes ) + { + __MULTIPLEXER( "CMccSinkItem::RegisterPayloadTypesL" ) + + TInt ind = aPayloadTypes.Count(); + while ( ind-- ) + { + if ( KErrNotFound == iPayloadsToAccept.Find( aPayloadTypes[ind]) ) + { + iPayloadsToAccept.AppendL( aPayloadTypes[ind] ); + } + else + { + User::Leave( KErrAlreadyExists ); + } + } + } + +// ----------------------------------------------------------------------------- +// CMccSinkItem::RegisteredPayloadTypes +// ----------------------------------------------------------------------------- +// +const RArray& CMccSinkItem::RegisteredPayloadTypes() const + { + return iPayloadsToAccept; + } + +// ----------------------------------------------------------------------------- +// CMccSinkItem::RequestedBuffer +// ----------------------------------------------------------------------------- +// +CMMFBuffer* CMccSinkItem::RequestedBuffer() + { + return iRequestedBuffer; + } + +// ----------------------------------------------------------------------------- +// CMccSinkItem::EventHandler +// ----------------------------------------------------------------------------- +// +MAsyncEventHandler* CMccSinkItem::EventHandler() + { + return iEventHandler; + } + +// ----------------------------------------------------------------------------- +// CMccSinkItem::SetMultiplexerState +// ----------------------------------------------------------------------------- +// +void CMccSinkItem::SetMultiplexerState( CMccMultiplexer::TMccMultiplexerState aState ) + { + __MULTIPLEXER_INT2( "CMccSinkItem::SetMultiplexerState, sinkitem:", + reinterpret_cast( this ), + " state:", aState ) + iState = aState; + } + +// ----------------------------------------------------------------------------- +// CMccSinkItem::MultiplexerState +// ----------------------------------------------------------------------------- +// +CMccMultiplexer::TMccMultiplexerState CMccSinkItem::MultiplexerState() const + { + return iState; + } + +// ----------------------------------------------------------------------------- +// CMccSinkItem::SetSourceMode +// ----------------------------------------------------------------------------- +// +void CMccSinkItem::SetSourceMode( TBool aPassAllRequestsSource ) + { + __MULTIPLEXER_INT1( "CMccSinkItem::SetSourceMode, sinkitem:", + reinterpret_cast( this ) ) + __MULTIPLEXER_INT1( "CMccSinkItem::SetSourceMode, mediatype:", + iMediaType.iUid ) + __MULTIPLEXER_INT1( "CMccSinkItem::SetSourceMode, mode:", + aPassAllRequestsSource ) + + iPassAllRequestsSource = aPassAllRequestsSource; + } + +// ----------------------------------------------------------------------------- +// CMccSinkItem::PassAllRequestsToSource +// ----------------------------------------------------------------------------- +// +TBool CMccSinkItem::PassAllRequestsToSource() const + { + return iPassAllRequestsSource; + } + +// ----------------------------------------------------------------------------- +// CMccSinkItem::CMccSinkItem +// ----------------------------------------------------------------------------- +// +TUid CMccSinkItem::ResolveMediaType( CMMFBuffer* aBuffer ) const + { + if ( aBuffer && iPassAllRequestsSource && iRequestedBuffer == aBuffer ) + { + return MediaType(); + } + return KNullUid; + } + +// ----------------------------------------------------------------------------- +// CMccSinkItem::CMccSinkItem +// ----------------------------------------------------------------------------- +// +CMccSinkItem::CMccSinkItem( TUid aMediaType, TBool aPassAllBuffersSink ) : + iMediaType( aMediaType ), + iPassAllBuffersSink( aPassAllBuffersSink ), + iReportedEvent( KMccEventNone ), iBadDataCount( 0 ) + { + } + +// ----------------------------------------------------------------------------- +// CMccSinkItem::Sink +// ----------------------------------------------------------------------------- +// +void CMccSinkItem::ConstructL( MDataSink* aSink, TBool aSinkIsDecoder ) + { + __MULTIPLEXER( "CMccSinkItem::ConstructL" ) + + __ASSERT_ALWAYS( aSink, User::Leave( KErrArgument ) ); + + if ( aSinkIsDecoder ) + { + __MULTIPLEXER( "CMccSinkItem::ConstructL, sink is decoder" ) + + CMMFFormatDecode* decoder = static_cast( aSink ); + + iDecoder = MCC_PAYLOAD_READ( decoder ); + } + else + { + iSink = aSink; + } + + __MULTIPLEXER( "CMccSinkItem::ConstructL, exit" ) + } + +// ----------------------------------------------------------------------------- +// CMccSinkItem::Sink +// ----------------------------------------------------------------------------- +// +MDataSink* CMccSinkItem::Sink() + { + if ( iDecoder ) + { + return iDecoder; + } + + return iSink; + } + +// --------------------------------------------------------------------------- +// CMccSinkItem::CopyBufferL +// --------------------------------------------------------------------------- +// +void CMccSinkItem::CopyBufferL( + CMMFBuffer* aDesBuffer, + CMMFBuffer* aOrigBuffer ) + { + __ASSERT_ALWAYS( aDesBuffer && aOrigBuffer, User::Leave( KErrArgument ) ); + + // Copy buffer setting + aDesBuffer->SetFrameNumber( aOrigBuffer->FrameNumber() ); + aDesBuffer->SetLastBuffer( aOrigBuffer->LastBuffer() ); + aDesBuffer->SetPosition( aOrigBuffer->Position() ); + // Note: setting the status to available clears the buffer data + aDesBuffer->SetStatus( aOrigBuffer->Status() ); + aDesBuffer->SetTimeToPlay( aOrigBuffer->TimeToPlay() ); + + // Copy buffer data + CMMFDataBuffer* desBuffer = static_cast( aDesBuffer ); + CMMFDataBuffer* origBuffer = static_cast( aOrigBuffer ); + + __ASSERT_ALWAYS( desBuffer->Data().MaxLength() >= (TInt) origBuffer->BufferSize(), + User::Leave( KErrOverflow ) ); + + desBuffer->Data().Copy( origBuffer->Data() ); + } + +// --------------------------------------------------------------------------- +// CMccSinkItem::IsInternalDecoder +// --------------------------------------------------------------------------- +// +TBool CMccSinkItem::IsInternalDecoder( TUid aDecoderUid ) const + { + TUint32 decoderUid = aDecoderUid.iUid; + return ( decoderUid == KImplUidAmrPayloadFormatDecode || + decoderUid == KImplUidAnyPayloadFormatDecode || + decoderUid == KImplUidDTMFPayloadFormatDecode || + decoderUid == KImplUidRedPayloadFormatDecode ); + + } + +// --------------------------------------------------------------------------- +// CMccSinkItem::StoreBufferL +// --------------------------------------------------------------------------- +// +void CMccSinkItem::StoreBufferL( CMMFBuffer* aBuffer ) + { + __MULTIPLEXER( "CMccSinkItem::StoreBufferL" ) + + // If secondary sink has not yet requested buffer fill, the buffer + // will be stored + if ( iStoredBuffers.Count() >= KMccMaxStoredBuffers ) + { + __MULTIPLEXER( "CMccSinkItem::BufferFilledL, dropping oldest stored buffer!" ) + delete iStoredBuffers[ 0 ]; + iStoredBuffers.Remove( 0 ); + } + + CMMFDataBuffer* storedBuffer = CMMFDataBuffer::NewL( aBuffer->BufferSize() ); + + CleanupStack::PushL( storedBuffer ); + CopyBufferL( storedBuffer, aBuffer ); + iStoredBuffers.AppendL( storedBuffer ); + CleanupStack::Pop( storedBuffer ); + + __MULTIPLEXER( "CMccSinkItem::StoreBufferL, exit" ) + } + +// --------------------------------------------------------------------------- +// CMccSinkItem::GetStoredBuffer +// --------------------------------------------------------------------------- +// +CMMFBuffer* CMccSinkItem::GetStoredBuffer() + { + CMMFBuffer* buffer = NULL; + + if ( iStoredBuffers.Count() > 0 ) + { + buffer = iStoredBuffers[ 0 ]; + iStoredBuffers.Remove( 0 ); + } + + return buffer; + } + +// --------------------------------------------------------------------------- +// CMccSinkItem::HandleBadData +// --------------------------------------------------------------------------- +// +TBool CMccSinkItem::HandleBadDataL( CMMFDataBuffer* aBuffer ) + { + TBool stopBufferForwarding( EFalse ); + if ( aBuffer == NULL || !aBuffer->BufferSize() ) + { + __MULTIPLEXER( "CMccSinkItem::HandleBadDataL, bad data received" ) + iBadDataCount++; + if ( iBadDataCount >= KMccBadDataCount && iEventHandler ) + { + __MULTIPLEXER( "CMccSinkItem::HandleBadDataL, pausing stream" ) + iBadDataCount = 0; + + TMccEvent* event = new ( ELeave ) TMccEvent; + CleanupStack::PushL( event ); + event->iEndpointId = 0; + event->iEventCategory = KMccEventCategoryStreamControl; + event->iEventType = KMccStreamPaused; + event->iErrorCode = KErrNone; + + TMccInternalEvent internalEvent( KMccMultiplexerUid, EMccInternalEventNone, + *event ); + + User::LeaveIfError( iEventHandler->SendEventToClient( internalEvent ) ); + + CleanupStack::PopAndDestroy( event ); + __MULTIPLEXER( "CMccSinkItem::HandleBadDataL, pausing event sent" ) + + stopBufferForwarding = ETrue; + } + } + else + { + iBadDataCount = 0; + } + + return stopBufferForwarding; + } + +// --------------------------------------------------------------------------- +// CMccSinkItem::HandleStreamStateChangeEvent +// --------------------------------------------------------------------------- +// +TBool CMccSinkItem::HandleStreamStateChangeEvent( TMccEvent& aEvent ) + { + TBool sendEvent( ETrue ); + + // Modify started event to resumed event if previously paused + if ( aEvent.iEventType == KMccStreamStarted && + iReportedEvent == KMccStreamPaused ) + { + __MULTIPLEXER( "CMccSinkItem::SendEventToClient, modify event type" ) + aEvent.iEventType = KMccStreamResumed; + } + + // Automatic started/resumed event is not forwarded if this user hasn't yet + // started the source + if ( aEvent.iEventNumData == KMccAutomaticEvent && + ( aEvent.iEventType == KMccStreamStarted || + aEvent.iEventType == KMccStreamResumed ) ) + { + sendEvent = ( iState >= CMccMultiplexer::EPlaying ); + + __MULTIPLEXER_INT1( + "CMccSinkItem::SendEventToClient, automatic event send:", sendEvent ) + } + + if ( sendEvent ) + { + sendEvent = ( aEvent.iEventType != iReportedEvent ); + + iReportedEvent = aEvent.iEventType; + } + + return sendEvent; + } + +// End of File +