diff -r 826cea16efd9 -r 13a33d82ad98 dvrengine/CommonRecordingEngine/src/CCRStreamingSession.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dvrengine/CommonRecordingEngine/src/CCRStreamingSession.cpp Wed Sep 01 12:20:37 2010 +0100 @@ -0,0 +1,865 @@ +/* +* Copyright (c) 2007 Nokia Corporation and/or its subsidiary(-ies). +* All rights reserved. +* This component and the accompanying materials are made available +* under the terms of the License "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: Class for streaming session. Owns a source, number of buffers* +*/ + + + + +// INCLUDES +#include "VideoServiceUtilsConf.hrh" +#include "CCRStreamingSession.h" +#include "CCRRtspSink.h" +#include "CCRNullSink.h" +#include "CCRPacketBuffer.h" +#include +#include "CCRRtspPacketSource.h" +#ifdef RD_IPTV_FEA_RTP_CLIP_SUPPORT +#include "CCRXpsSink.h" +#include "CCRRtpRecordSink.h" +#include "CCRRtpFileSource.h" +#include "CCRNullSource.h" +#endif // RD_IPTV_FEA_RTP_CLIP_SUPPORT +#include "MCRStreamObserver.h" +#include "CCRPacketSinkBase.h" +#include "CCRConnection.h" +#include "CCRengine.h" +#include "videoserviceutilsLogger.h" + +// CONSTANTS +const TInt KMaxRtspPackets( 400 ); +#ifdef RD_IPTV_FEA_RTP_CLIP_SUPPORT +const TInt KMaxRtpPackets( 500 ); +#endif // RD_IPTV_FEA_RTP_CLIP_SUPPORT + +// ============================ MEMBER FUNCTIONS =============================== + +// ----------------------------------------------------------------------------- +// CCRStreamingSession::NewL +// +// ----------------------------------------------------------------------------- +// +CCRStreamingSession* CCRStreamingSession::NewL( + RSocketServ& aSockServer, + CCRConnection* aConnection, + CCREngine& aEngine ) + { + CCRStreamingSession* self = new( ELeave ) CCRStreamingSession( + aSockServer, aConnection, aEngine ); + CleanupStack::PushL( self ); + self->ConstructL(); + CleanupStack::Pop( self ); + return self; + } + +// ----------------------------------------------------------------------------- +// CCRStreamingSession::CCRStreamingSession +// +// ----------------------------------------------------------------------------- +// +CCRStreamingSession::CCRStreamingSession( + RSocketServ& aSockServer, + CCRConnection* aConnection, + CCREngine& aEngine ) + : iSockServer( aSockServer ), + iConnection( aConnection ), + iEngine( aEngine ) + { + // None + } + +// ----------------------------------------------------------------------------- +// CCRStreamingSession::ConstructL +// +// ----------------------------------------------------------------------------- +// +void CCRStreamingSession::ConstructL() + { + LOG( "CCRStreamingSession::ConstructL()" ); + + // Note, quite high priority + iCleanUp = new ( ELeave ) CAsyncCallBack( CActive::EPriorityStandard ); + } + +// ----------------------------------------------------------------------------- +// CCRStreamingSession::~CCREStreamingSession +// +// ----------------------------------------------------------------------------- +// +CCRStreamingSession::~CCRStreamingSession() + { + LOG( "CCRStreamingSession::~CCRStreamingSession()" ); + + delete iCleanUp; + iSinks.ResetAndDestroy(); + iSinksToDelete.Reset(); + delete iSource; + delete iBuffer; + iConnection = NULL; + } + +// ----------------------------------------------------------------------------- +// CCRStreamingSession::OpenSourceL +// Opens RTSP streaming source. +// ----------------------------------------------------------------------------- +// +void CCRStreamingSession::OpenSourceL( + const SCRRtspParams& aParams, + const TDesC& aSessionDefinition ) + { + LOG( "CCRStreamingSession::OpenSourceL(), RTSP Url" ) + + if ( !iSource && iConnection ) + { + iSourceChecksum = SourceDefinition( aSessionDefinition ); + iSource = CCRRtspPacketSource::NewL( + aParams, *iConnection, iSockServer, *this, *this ); + iSource->RegisterConnectionObs( &iEngine ); + } + } + +// ----------------------------------------------------------------------------- +// CCRStreamingSession::OpenSourceL +// Opens RTP clip streaming source. +// ----------------------------------------------------------------------------- +// +void CCRStreamingSession::OpenSourceL( + const SCRRtpPlayParams& aParams, + CRtpClipHandler*& aClipHandler, + const TDesC& aSessionDefinition ) + { + LOG( "CCRStreamingSession::OpenSourceL(), RTP clip" ) + +#ifdef RD_IPTV_FEA_RTP_CLIP_SUPPORT + + if ( !iSource ) + { + iSourceChecksum = SourceDefinition( aSessionDefinition ); + iBuffer = CCRPacketBuffer::NewL( KMaxRtpPackets ); + iSource = CCRRtpFileSource::NewL( aParams, aClipHandler, *this, *this ); + iSource->SetBuffer( iBuffer ); + } + +#else // RD_IPTV_FEA_RTP_CLIP_SUPPORT + ( void )aParams; + ( void )aClipHandler; + ( void )aSessionDefinition; + User::Leave( KErrNotSupported ); +#endif // RD_IPTV_FEA_RTP_CLIP_SUPPORT + } + +// ----------------------------------------------------------------------------- +// CCRStreamingSession::OpenSourceL +// Opens RTP clip streaming source. +// ----------------------------------------------------------------------------- +// +void CCRStreamingSession::OpenSourceL( + const RFile& aRtpHandle, + CRtpClipHandler*& aClipHandler, + const TDesC& aSessionDefinition ) + { + LOG( "CCRStreamingSession::OpenSourceL(), RTP handle" ) + +#ifdef RD_IPTV_FEA_RTP_CLIP_SUPPORT + + if ( !iSource ) + { + iSourceChecksum = SourceDefinition( aSessionDefinition ); + iBuffer = CCRPacketBuffer::NewL( KMaxRtpPackets ); + iSource = CCRRtpFileSource::NewL( aRtpHandle, aClipHandler, *this, *this ); + iSource->SetBuffer( iBuffer ); + } + +#else // RD_IPTV_FEA_RTP_CLIP_SUPPORT + ( void )aRtpHandle; + ( void )aClipHandler; + ( void )aSessionDefinition; + User::Leave( KErrNotSupported ); +#endif // RD_IPTV_FEA_RTP_CLIP_SUPPORT + } + +// ----------------------------------------------------------------------------- +// CCRStreamingSession::OpenSourceL +// Opens DVB-H live streaming source. +// ----------------------------------------------------------------------------- +// +void CCRStreamingSession::OpenSourceL( + const SCRLiveParams& /*aLiveParams*/, + const TDesC& /*aSessionDefinition*/ ) + { + LOG( "CCRStreamingSession::OpenSourceL(), DVB-H live" ) + + User::Leave( KErrNotSupported ); + } + +// ----------------------------------------------------------------------------- +// CCRStreamingSession::OpenSourceL +// Opens RTP clip as a live streaming source. +// ----------------------------------------------------------------------------- +// +void CCRStreamingSession::OpenSourceL( const TDesC& aSessionDefinition ) + { + LOG( "CCRStreamingSession::OpenSourceL(), Null" ) + +#ifdef RD_IPTV_FEA_RTP_CLIP_SUPPORT + + if ( !iSource ) + { + iSourceChecksum = SourceDefinition( aSessionDefinition ); + iBuffer = CCRPacketBuffer::NewL( KMaxRtpPackets ); + iSource = CCRNullSource::NewL( aSessionDefinition, *this, *this ); + iSource->SetBuffer( iBuffer ); + } + +#else // RD_IPTV_FEA_RTP_CLIP_SUPPORT + ( void )aSessionDefinition; + User::Leave( KErrNotSupported ); +#endif // RD_IPTV_FEA_RTP_CLIP_SUPPORT + } + +// ----------------------------------------------------------------------------- +// CCRStreamingSession::SourceDefinition +// +// ----------------------------------------------------------------------------- +// +TUint CCRStreamingSession::SourceDefinition( const TDesC& aName ) + { + TUint checkSum( 0 ); + for ( TInt i( aName.Length() - 1 ); i >= 0; i-- ) + { + checkSum += aName[i]; + } + + // And for rtsp packet source do use different id + // if udp is blocked and we're using tcp then. + if ( iSource && iSource->Id() == ECRRtspSourceId && + iConnection && + iConnection->GetHeuristic ( CCRConnection::EUdpStreamingBlocked ) ) + { + checkSum++; + } + + return checkSum; + } + +// ----------------------------------------------------------------------------- +// CCRStreamingSession::SourceChecksum +// +// ----------------------------------------------------------------------------- +// +TUint CCRStreamingSession::SourceChecksum() + { + return iSourceChecksum; + } + +//----------------------------------------------------------------------------- +// CCRStreamingSession::CreateAndSetBufferL +// +//----------------------------------------------------------------------------- +// +void CCRStreamingSession::CreateAndSetBufferL() + { + if ( iSource && iBuffer == NULL ) + { + iBuffer = CCRPacketBuffer::NewL( KMaxRtspPackets ); + iSource->SetBuffer( iBuffer ); + } + } + +//----------------------------------------------------------------------------- +// CCRStreamingSession::CreateRtspSinkL +// +//----------------------------------------------------------------------------- +// +void CCRStreamingSession::CreateRtspSinkL( const TInt& aLoopbackPort ) + { + LOG( "CCRStreamingSession::CreateRtspSinkL()" ) + + if ( iConnection ) + { + // Only one RTSP sink at the time + DeleteSink( ECRRtspSinkId ); + + // New sink + CCRRtspSink* sink = CCRRtspSink::NewL( + *iConnection, iSockServer, ECRRtspSinkId, aLoopbackPort, *this ); + CleanupStack::PushL( sink ); + User::LeaveIfError( iSinks.Append( sink ) ); + CleanupStack::Pop( sink ); + } + } + +//----------------------------------------------------------------------------- +// CCRStreamingSession::CreateXpsSinkL +// +//----------------------------------------------------------------------------- +// +void CCRStreamingSession::CreateXpsSinkL() + { + LOG( "CCRStreamingSession::CreateXpsSinkL()" ) + +#ifdef RD_IPTV_FEA_RTP_CLIP_SUPPORT + + CCRXpsSink* sink = CCRXpsSink::NewL( ECRXpsSinkId, *this ); + CleanupStack::PushL( sink ); + User::LeaveIfError( iSinks.Append( sink ) ); + CleanupStack::Pop( sink ); +#else // RD_IPTV_FEA_RTP_CLIP_SUPPORT + User::Leave( KErrNotSupported ); +#endif // RD_IPTV_FEA_RTP_CLIP_SUPPORT + } + +//----------------------------------------------------------------------------- +// CCRStreamingSession::Create3gpRecordSinkL +// +//----------------------------------------------------------------------------- +// +void CCRStreamingSession::Create3gpRecordSinkL( + const SCRRecordParams& /*aRecordParams*/ ) + { + LOG( "CCRStreamingSession::Create3gpRecordSinkL()" ) + + User::Leave( KErrNotSupported ); + /* + CCR3gpRecordSink* sink = CCR3gpRecordSink::NewL( ECR3gpRecSinkId, *this ); + CleanupStack::PushL( sink ); + User::LeaveIfError( iSinks.Append( sink ) ); + CleanupStack::Pop( sink ); + */ + } + +//----------------------------------------------------------------------------- +// CCRStreamingSession::CreateRtpRecordSinkL +// +//----------------------------------------------------------------------------- +// +void CCRStreamingSession::CreateRtpRecordSinkL( + const SCRRecordParams& aRecordParams, + CRtpClipHandler*& aClipHandler ) + { + LOG( "CCRStreamingSession::CreateRtpRecordSinkL()" ) + +#ifdef RD_IPTV_FEA_RTP_CLIP_SUPPORT + // Create record sink + CCRRtpRecordSink* sink = CCRRtpRecordSink::NewL( + aRecordParams, ECRRtpRecSinkId, *this, &iEngine, aClipHandler ); + CleanupStack::PushL( sink ); + User::LeaveIfError( iSinks.Append( sink ) ); + CleanupStack::Pop( sink ); + +#else // RD_IPTV_FEA_RTP_CLIP_SUPPORT + ( void )aRecordParams; + ( void )aClipHandler; + User::Leave( KErrNotSupported ); +#endif // RD_IPTV_FEA_RTP_CLIP_SUPPORT + } + +//----------------------------------------------------------------------------- +// CCRStreamingSession::PostActionL +// +//----------------------------------------------------------------------------- +// +void CCRStreamingSession::PostActionL() + { + User::LeaveIfNull( iSource ); + iSource->PostActionL(); + } + +//----------------------------------------------------------------------------- +// CCRStreamingSession::PlayCommand +// +//----------------------------------------------------------------------------- +// +TInt CCRStreamingSession::PlayCommand( + const TReal& aStartPos, + const TReal& aEndPos ) + { + if ( iSource ) + { + return iSource->Play( aStartPos, aEndPos ); + } + + return KErrCompletion; + } + +//----------------------------------------------------------------------------- +// CCRStreamingSession::PauseCommand +// +//----------------------------------------------------------------------------- +// +TInt CCRStreamingSession::PauseCommand() + { + if ( iSource ) + { + return iSource->Pause(); + } + + return KErrCompletion; + } + +//----------------------------------------------------------------------------- +// CCRStreamingSession::StopCommand +// +//----------------------------------------------------------------------------- +// +TInt CCRStreamingSession::StopCommand() + { + if ( iSource && iSinks.Count() >= 1 ) + { + return iSource->Stop(); + } + + return KErrCompletion; + } + +//----------------------------------------------------------------------------- +// CCRStreamingSession::SetPosition +// +//----------------------------------------------------------------------------- +// +TInt CCRStreamingSession::SetPosition( const TInt64 aPosition ) + { + if ( iSource ) + { + return iSource->SetPosition( aPosition ); + } + + return KErrCompletion; + } + +//----------------------------------------------------------------------------- +// CCRStreamingSession::GetPosition +// +//----------------------------------------------------------------------------- +// +TInt CCRStreamingSession::GetPosition( TInt64& aPosition, TInt64& aDuration ) + { + if ( iSource ) + { + return iSource->GetPosition( aPosition, aDuration ); + } + + return KErrCompletion; + } + +//----------------------------------------------------------------------------- +// CCRStreamingSession::PauseCommand +// +//----------------------------------------------------------------------------- +// +TInt CCRStreamingSession::PauseCommand( const TCRSinkId& aSinkId ) + { + // Pauses current sink action + for ( TInt i( iSinks.Count() - 1 ); i >= 0; i-- ) + { + if ( aSinkId == iSinks[i]->Id() ) + { + return iSinks[i]->Pause(); + } + } + + return KErrCompletion; + } + +//----------------------------------------------------------------------------- +// CCRStreamingSession::RestoreCommand +// +//----------------------------------------------------------------------------- +// +TInt CCRStreamingSession::RestoreCommand( const TCRSinkId& aSinkId ) + { + // Pauses current sink action + for ( TInt i( iSinks.Count() - 1 ); i >= 0; i-- ) + { + if ( aSinkId == iSinks[i]->Id() ) + { + return iSinks[i]->Restore(); + } + } + + return KErrCompletion; + } + +//----------------------------------------------------------------------------- +// CCRStreamingSession::StopCommand +// +//----------------------------------------------------------------------------- +// +TInt CCRStreamingSession::StopCommand( const TCRSinkId& aSinkId ) + { + // Stop current sink action + for ( TInt i( iSinks.Count() - 1 ); i >= 0; i-- ) + { + if ( aSinkId == iSinks[i]->Id() ) + { + iSinks[i]->Stop(); + return KErrNone; + } + } + + return KErrCompletion; + } + +//----------------------------------------------------------------------------- +// CCRStreamingSession::TransferSink +// +//----------------------------------------------------------------------------- +// +TInt CCRStreamingSession::TransferSink( + const TCRSinkId& aSinkId, + CCRStreamingSession& aTargetSession ) + { + LOG1( "CCRStreamingSession::TransferSink(), aSinkId: %d", aSinkId ); + + for ( TInt i( iSinks.Count() - 1 ); i >= 0; i-- ) + { + if ( iSinks[i]->Id() == aSinkId ) + { + TInt err( aTargetSession.AddNewSink( iSinks[i] ) ); + if ( !err ) + { + iBuffer->RemoveSink( iSinks[i] ); + iSinks.Remove( i ); + } + + return err; + } + } + + return KErrCompletion; + } + +//----------------------------------------------------------------------------- +// CCRStreamingSession::AddNewSink +// +//----------------------------------------------------------------------------- +// +TInt CCRStreamingSession::AddNewSink( CCRPacketSinkBase* aSink ) + { + LOG1( "CCRStreamingSession::AddNewSink(), aSink->Id: %d", aSink->Id() ); + + for ( TInt i( iSinks.Count() - 1 ); i >= 0; i-- ) + { + if ( aSink->Id() == iSinks[i]->Id() ) + { + LOG( "CCRStreamingSession::AddNewSink(), Sink already exist !" ); + return KErrInUse; + } + } + + // Add new sink + TInt err( iSinks.Append( aSink ) ); + if ( !err ) + { + err = iBuffer->AddSink( iSinks[iSinks.Count() - 1] ); + } + + return err; + } + +//----------------------------------------------------------------------------- +// CCRStreamingSession::ClipHandlerUsed +// +//----------------------------------------------------------------------------- +// +TBool CCRStreamingSession::ClipHandlerUsed() + { + // Used in source + if ( iSource && iSource->Id() == ECRRtpSourceId ) + { + return ETrue; + } + + // Used in any Sink + for ( TInt i( iSinks.Count() - 1 ); i >= 0; i-- ) + { + if ( iSinks[i]->Id() == ECRRtpRecSinkId ) + { + return ETrue; + } + } + + return EFalse; + } + +//----------------------------------------------------------------------------- +// CCRStreamingSession::CreateNullSinkL +// +//----------------------------------------------------------------------------- +// +void CCRStreamingSession::CreateNullSinkL() + { + CCRNullSink* sink = CCRNullSink::NewL( ECRNullSinkId, *this ); + sink->RegisterConnectionObs( &iEngine ); + CleanupStack::PushL( sink ); + User::LeaveIfError( iSinks.Append( sink ) ); + CleanupStack::Pop( sink ); + } + +//----------------------------------------------------------------------------- +// CCRStreamingSession::InitializeSinks +// +//----------------------------------------------------------------------------- +// +void CCRStreamingSession::InitializeSinks() + { + if ( iSource && iBuffer ) + { + TPtrC8 sdp( NULL, 0 ); + TInt err( iSource->GetSdp( sdp ) ); + if ( err ) + { + LOG1( "CCRStreamingSession::InitializeSinks(), GetSdp() Failed: %d", err ); + SourceStop(); + } + else + { + for ( TInt i( 0 ); i < iSinks.Count(); i++ ) + { + TRAP( err, iSinks[i]->SetSdpL( sdp ) ); + if ( err ) + { + LOG1( "CCRStreamingSession::InitializeSinks(), SetSdpL() Failed: %d", err ); + SinkStops( iSinks[i]->Id() ); + return; + } + + iSinks[i]->SetBuffer( iBuffer ); + err = iBuffer->AddSink( iSinks[i] ); + if ( err ) + { + LOG1( "CCRStreamingSession::InitializeSinks(), AddSink() Failed: %d", err ); + SourceStop(); + return; + } + } + + iEngine.ConnectionStatusChange( + SourceChecksum(), MCRConnectionObserver::ECRSdpAvailable, KErrNone ); + } + } + } + +//----------------------------------------------------------------------------- +// CCRStreamingSession::SetSeqAndTs() +//----------------------------------------------------------------------------- +// +void CCRStreamingSession::SetSeqAndTs() + { + if ( iSource ) + { + TUint audioSeq( 0 ); + TUint audioTS( 0 ); + TUint videoSeq( 0 ); + TUint videoTS( 0 ); + TReal lowerRange( KRealZero ); + TReal upperRange( KRealMinusOne ); + + iSource->GetRange( lowerRange,upperRange ); + iSource->SeqAndTS( audioSeq, audioTS, videoSeq, videoTS ); + + for ( TInt j( 0 ); j < iSinks.Count(); j++ ) + { + if ( !( lowerRange == KRealZero && upperRange == KRealMinusOne ) ) + { + iSinks[j]->SetRange( lowerRange,upperRange ); + } + + iSinks[j]->SetSeqAndTS( audioSeq, audioTS, videoSeq, videoTS ); + } + } + } + +//----------------------------------------------------------------------------- +// CCRStreamingSession::SinkStops() +// So, a sink wants to quit. we can't just delete it here as return. Statement +// would then take us to deleted instance: put up a cleanup CAsyncCallBack and +// return. +//----------------------------------------------------------------------------- +// +void CCRStreamingSession::SinkStops( const TCRSinkId& aSinkId ) + { + LOG1( "CCRStreamingSession::SinkStops(), aSinkId: %d", aSinkId ); + + // InsertInSignedKeyOrderL checks for duplicate, if there is already + // entry for that sink, the array will remain unchanged + TRAPD( err, iSinksToDelete.InsertInSignedKeyOrderL( aSinkId ) ); + if ( err ) + { + LOG1( "CCRStreamingSession::SinkStops(), InsertInSignedKeyOrderL leaved %d", err ); + } + + // If not already active and sinks to delete? + if ( !iCleanUp->IsActive() && iSinksToDelete.Count() ) + { + TCallBack cb( SinkStopCallBack, this ); + iCleanUp->Set( cb ); + iCleanUp->CallBack(); + } + } + +//----------------------------------------------------------------------------- +// CCRStreamingSession::SourceRestore() +//----------------------------------------------------------------------------- +// +void CCRStreamingSession::SourceRestore() + { + if ( iSource ) + { + iSource->Restore(); + } + } + +//----------------------------------------------------------------------------- +// CCRStreamingSession::SourceStop() +//----------------------------------------------------------------------------- +// +void CCRStreamingSession::SourceStop() + { + // Session is useless without a source so ask engine to clean it all up + iEngine.SessionStop( this ); + } + +// ----------------------------------------------------------------------------- +// CCRStreamingSession::StatusChanged +// +// ----------------------------------------------------------------------------- +// +void CCRStreamingSession::StatusChanged( + MCRPacketSource::TCRPacketSourceState aStatus ) + { + LOG1( "CCRStreamingSession::StatusChanged(), aStatus: %d", aStatus ); + + switch ( aStatus ) + { + case MCRPacketSource::ERtpStateIdle: + break; + + case MCRPacketSource::ERtpStateSdpAvailable: + TRAPD( err, CreateAndSetBufferL() ); + if ( err ) + { + LOG1( "CCRStreamingSession::StatusChanged(), CreateAndSetBuffers leaved: %d", err ); + } + + InitializeSinks(); + break; + + case MCRPacketSource::ERtpStateSeqAndTSAvailable: + SetSeqAndTs(); + break; + + case MCRPacketSource::ERtpStateSetupRepply: + case MCRPacketSource::ERtpStatePlaying: + { + for ( TInt j( iSinks.Count() - 1 ); j >= 0; j-- ) + { + iSinks[j]->StatusChanged( aStatus ) ; + } + } + break; + + case MCRPacketSource::ERtpStateClosing: + SourceStop(); + break; + + default: + // None. + break; + } + } + +//----------------------------------------------------------------------------- +// CCRStreamingSession::SinkStopCallBack() +// +//----------------------------------------------------------------------------- +// +TInt CCRStreamingSession::SinkStopCallBack( TAny* aThis ) + { + CCRStreamingSession* self = static_cast( aThis ); + LOG1( "CCRStreamingSession::SinkStopCallBack(), iSinksToDelete count: %d", + self->iSinksToDelete.Count() ); + self->DoSinkStop(); + return self->iSinksToDelete.Count(); + } + +//----------------------------------------------------------------------------- +// CCRStreamingSession::DoSinkStop() +// +//----------------------------------------------------------------------------- +// +void CCRStreamingSession::DoSinkStop( void ) + { + LOG( "CCRStreamingSession::DoSinkStop() in" ); + + for ( TInt i( iSinksToDelete.Count() - 1 ); i >= 0; i-- ) + { + for ( TInt j( iSinks.Count() - 1 ); j >= 0; j-- ) + { + if ( iSinks[j]->Id() == iSinksToDelete[i] ) + { + TInt remainingSinks( 0 ); + if ( iBuffer ) + { + // If we never got sdp, we never had a buffer + remainingSinks = iBuffer->RemoveSink( iSinks[j] ); + } + + if ( remainingSinks < 1 ) + { + // No sinks remaing for our buffers, I'm feeling useless + if ( iSource ) + { + iSource->Stop(); + } + } + + delete iSinks[j]; + iSinks[j] = NULL; + iSinks.Remove( j ); + } + } + } + + iSinksToDelete.Reset(); + LOG( "CCRStreamingSession::DoSinkStop() out" ); + } + +//----------------------------------------------------------------------------- +// CCRStreamingSession::DeleteSink +// +//----------------------------------------------------------------------------- +// +void CCRStreamingSession::DeleteSink( const TCRSinkId& aSinkId ) + { + for ( TInt i( iSinks.Count() - 1 ); i >= 0 ; i-- ) + { + if ( iSinks[i]->Id() == aSinkId ) + { + // Remove sink from buffer + if ( iBuffer ) + { + iBuffer->RemoveSink( iSinks[i] ); + } + + // Delete sink + delete iSinks[i]; + iSinks[i] = NULL; + iSinks.Remove( i ); + LOG2( "CCRStreamingSession::DeleteSink(), deleted index: %d, aSinkId: %d", i, aSinkId ); + } + } + } + +// End of File