diff -r 826cea16efd9 -r 13a33d82ad98 dvrengine/CommonRecordingEngine/src/CCRXpsSink.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dvrengine/CommonRecordingEngine/src/CCRXpsSink.cpp Wed Sep 01 12:20:37 2010 +0100 @@ -0,0 +1,858 @@ +/* +* 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 that takes packet from the buffer and forward them thrue* +*/ + + + + +// INCLUDES +#include "CCRXpsSink.h" +#include "CCRPacketBuffer.h" +#include "CCRStreamingSession.h" +#include +#include "CCRTimer.h" +#include "CRtpPacket.h" +#include "CRtpTsConverter.h" +#include + +// CONSTANTS +_LIT( KCRXpsServerName, "IpVideoXps" ); +_LIT8( KAttributeDefRange, "a=range:npt=0-86400.0" ); +#ifdef VIA_FEA_IPTV_USE_IPDC +_LIT8( KMtvAvc, "X-MTV-AVC" ); +_LIT8( KHxAvc1, "X-HX-AVC1" ); +#endif // VIA_FEA_IPTV_USE_IPDC +const TInt KRangeIdentifierLen( 8 ); +const TInt KXpsBufferedPackets( 300 ); // about 3s +const TInt KXpsOverflowDelay( 300 * 1000 ); // 300ms + +// ============================ MEMBER FUNCTIONS =============================== + +// ----------------------------------------------------------------------------- +// CCRXpsSink::NewL +// Two-phased constructor. +// ----------------------------------------------------------------------------- +// +CCRXpsSink* CCRXpsSink::NewL( + CCRStreamingSession::TCRSinkId aSinkId, + CCRStreamingSession& aOwningSession ) + { + CCRXpsSink* self = new( ELeave ) + CCRXpsSink( aSinkId, aOwningSession ); + CleanupStack::PushL( self ); + self->ConstructL(); + CleanupStack::Pop( self ); + return self; + } + +// ----------------------------------------------------------------------------- +// CCRXpsSink::CCRXpsSink +// C++ default constructor can NOT contain any code, that might leave. +// ----------------------------------------------------------------------------- +// +CCRXpsSink::CCRXpsSink( + CCRStreamingSession::TCRSinkId aSinkId, + CCRStreamingSession& aOwningSession ) + : CCRPacketSinkBase( aOwningSession, aSinkId ), + iWaitPlayer( KErrNotFound ), + iRequested( KErrNotFound ), + iXpsResetOk( EFalse ), + iAudioStreamId( KErrNotFound ), + iVideoStreamId( KErrNotFound ), + iTitleStreamId( KErrNotFound ) + { + // None + } + +// ----------------------------------------------------------------------------- +// CCRXpsSink::ConstructL +// 2nd phase. +// ----------------------------------------------------------------------------- +// +void CCRXpsSink::ConstructL() + { + LOG( "CCRXpsSink::ConstructL() in" ); + + iRtpPacket = CRtpPacket::NewL(); + iPacketSink = CXPSPacketSink::New(); + LOG1( "CCRXpsSink::ConstructL(), iPacketSink: %d", iPacketSink ); + User::LeaveIfNull( iPacketSink ); + TInt err( iPacketSink->Init( KCRXpsServerName, this ) ); + if ( err ) + { + LOG1( "CCRXpsSink::ConstructL(), iPacketSink->Init() err: %d", err ); + User::Leave( err ); + } + + LOG( "CCRXpsSink::ConstructL() out" ); + } + +// ----------------------------------------------------------------------------- +// CCRXpsSink::~CCRXpsSink +// Destructor. +// ----------------------------------------------------------------------------- +// +CCRXpsSink::~CCRXpsSink() + { + LOG( "CCRXpsSink::~CCRXpsSink()" ); + + // Delete variables + StopTimer(); + delete iPacketSink; + delete iAudioConv; + delete iVideoConv; + delete iTitleConv; + delete iRtpPacket; + +#ifdef VIA_FEA_IPTV_USE_IPDC + delete iVideoDepacketizer; +#endif // VIA_FEA_IPTV_USE_IPDC + } + +// ----------------------------------------------------------------------------- +// CCRXpsSink::SetSdpL +// Sets SDP, parses it and initiates XPS. +// ----------------------------------------------------------------------------- +// +void CCRXpsSink::SetSdpL( const TDesC8& aSdp ) + { + LOG1( "CCRXpsSink::SetSdpL(), SDP len: %d", aSdp.Length() ); + +#if defined( LIVE_TV_RDEBUG_TRACE ) || defined( LIVE_TV_FILE_TRACE ) + LOG( "CCRXpsSink::SetSdpL(), SDP content:" ); + TName d( KNullDesC ); + for ( TInt i( 0 ); i < aSdp.Length(); i++ ) + { + TChar c = aSdp[i]; + d.Append( c ); + if ( ( i > 0 ) && ( i % 80 ) == 0 ) + { + LOG1( ">%S<", &d ); + d.Zero(); + } + } + + LOG1( ">%S<", &d ); +#endif // LIVE_TV_RDEBUG_TRACE || LIVE_TV_FILE_TRACE + + if ( iWaitPlayer != KErrNotFound ) + { + LOG( "CCRXpsSink::SetSdpL(), SDP already set !" ); + return; + } + + // SDP parser + CDvrSdpParser* sdpParser = CDvrSdpParser::NewLC(); + sdpParser->TryParseL( aSdp ); + + // TS converter + delete iAudioConv; iAudioConv = NULL; + iAudioConv = CRtpTsConverter::NewL( sdpParser->AudioTimerGranularity() ); + LOG1( "CCRXpsSink::SetSdpL(), AudioTimerGranularity: %d", + sdpParser->AudioTimerGranularity() ); + + delete iVideoConv; iVideoConv = NULL; + iVideoConv = CRtpTsConverter::NewL( sdpParser->VideoTimerGranularity() ); + LOG1( "CCRXpsSink::SetSdpL(), VideoTimerGranularity: %d", + sdpParser->VideoTimerGranularity() ); + + delete iTitleConv; iTitleConv = NULL; + + // Streams count + TInt streams( 0 ); + const CDvrSdpParser::TDvrPacketProvidings providings( + sdpParser->SupportedContent() ); + if ( providings == CDvrSdpParser::EDvrAudioOnly || + providings == CDvrSdpParser::EDvrVideoOnly ) + { + streams = 1; + } + if ( providings == CDvrSdpParser::EDvrBothAudioAndVideo ) + { + streams = 2; + } + + // Stream ids + iAudioStreamId = sdpParser->AudioStreamId(); + iVideoStreamId = sdpParser->VideoStreamId(); + LOG2( "CCRXpsSink::SetSdpL(), iAudioStreamId: %d, iVideoStreamId: %d", + iAudioStreamId, iVideoStreamId ); + // Verify/update range + if ( aSdp.FindC( + KAttributeDefRange().Left( KRangeIdentifierLen ) ) == KErrNotFound ) + { + LOG( "CCRXpsSink::SetSdpL(), setting default range" ); + iRangeKnown = EFalse; + sdpParser->NewLineL( KErrNotFound, KAttributeDefRange ); + } + else + { + LOG( "CCRXpsSink::SetSdpL() sdp already did contain range, not changed" ); + iRangeKnown = ETrue; + } + + // Get SDP data + TPtrC8 sdp( NULL, 0 ); + User::LeaveIfError( sdpParser->GetSdp( sdp ) ); + HBufC8* tmpSdpData = NULL; + + // See if recorded from ISMA crypted content +#ifdef VIA_FEA_IPTV_USE_IPDC + TInt mimePos( sdp.Find( KMtvAvc ) ); + if ( mimePos != KErrNotFound || sdp.Find( KHxAvc1 ) != KErrNotFound ) + { + LOG( "CCRXpsSink::SetSdpL(), Playback of ISMA clip.." ); + delete iVideoDepacketizer; iVideoDepacketizer = NULL; + iVideoDepacketizer = CH264Mpeg4GenrToFileformat::New(); + User::LeaveIfNull( iVideoDepacketizer ); + HBufC8* fmtp = FindFmtpLC( sdp ); + TInt err( iVideoDepacketizer->Init( *fmtp ) ); + CleanupStack::PopAndDestroy( fmtp ); + if ( err ) + { + delete iVideoDepacketizer; iVideoDepacketizer = NULL; + LOG1( "CCRXpsSink::SetSdpL(), Depacketizer Init() failed: %d", err ); + } + else + { + // Change MIME type from X-MTV-AVC to X-HX-AVC1 for playback + // KMtvAvc mime prevents Helix crash in non DVB-H phones + if ( mimePos != KErrNotFound ) + { + tmpSdpData = HBufC8::NewLC( sdp.Length() - + KMtvAvc().Length() + KHxAvc1().Length() ); + TPtr8 ptr( tmpSdpData->Des() ); + ptr.Copy( sdp.Left( mimePos ) ); + ptr.Append( KHxAvc1 ); + ptr.Append( sdp.Mid( mimePos + KMtvAvc().Length() ) ); + sdp.Set( ptr ); + } + } + } +#endif // VIA_FEA_IPTV_USE_IPDC + + // Pass SDP to XPS + LOG( "CCRXpsSink::SetSdpL(), iPacketSink->SetSessionDescription.." ); + User::LeaveIfError( iPacketSink->SetSessionDescription( sdp, streams ) ); + if ( tmpSdpData != NULL ) + { + CleanupStack::PopAndDestroy( tmpSdpData ); + } + + // Config streams + for ( TInt i( 0 ); i < streams; i++ ) + { + LOG2( "CCRXpsSink::SetSdpL(), iPacketSink->ConfigStream: %d, KXpsBufferedPackets: %d", + i, KXpsBufferedPackets ); + User::LeaveIfError( iPacketSink->ConfigStream( i, KXpsBufferedPackets ) ); + } + + CleanupStack::PopAndDestroy( sdpParser ); + iWaitPlayer = KErrNone; + } + +// ----------------------------------------------------------------------------- +// CCRXpsSink::NewPacketAvailable +// From CCRPacketSinkBase. +// ----------------------------------------------------------------------------- +// +void CCRXpsSink::NewPacketAvailable() + { + // Kill flow timer + StopTimer(); + + // Ok to enqueue? + if ( iBuffer ) + { + if ( iWaitPlayer == KErrNone ) + { + // Enqueue packet + if ( SendPacket() ) + { + // Keep buffer size reasonable + iBuffer->HandleBufferSize(); + } + + if ( iBuffer->ContinousStream() ) + { + // Make sure all will be sent from the buffer in continous stream case + if ( iBuffer->PacketsCount( iSinkId ) > KErrNotFound ) + { + StartTimer( 0 ); + } + } + else + { + // Group done, need request more + if ( !iBuffer->MoreComing() ) + { + StartTimer( 0 ); + } + } + } + else + { + iBuffer->HandleBufferSize(); + // Make sure that process never end + if ( !iBuffer->ContinousStream() ) + { + StartTimer( KXpsOverflowDelay ); + } + } + } + } + +// ----------------------------------------------------------------------------- +// CCRXpsSink::BufferResetting +// From CCRPacketSinkBase. +// ----------------------------------------------------------------------------- +// +void CCRXpsSink::BufferResetDone() + { + StopTimer(); + iWaitPlayer = KErrNone; + iRequested = KErrNotFound; + + // XPS reset possible? + if ( iXpsResetOk ) + { + LOG( "CCRXpsSink::BufferResetDone(), Resets XPS.." ); + iPacketSink->Reset(); + iXpsResetOk = EFalse; + } + + // Uninit TS converters + LOG( "CCRXpsSink::BufferResetDone(), Uninitiates TS converters.." ); + if ( iAudioConv ) + { + iAudioConv->UnInitiate(); + } + if ( iVideoConv ) + { + iVideoConv->UnInitiate(); + } + if ( iTitleConv ) + { + iTitleConv->UnInitiate(); + } + +#if defined( LIVE_TV_RDEBUG_TRACE ) || defined( LIVE_TV_FILE_TRACE ) + iLogXps = 0; +#endif // LIVE_TV_RDEBUG_TRACE || LIVE_TV_FILE_TRACE + } + +// ----------------------------------------------------------------------------- +// CCRXpsSink::TimerExpired +// From MCRTimerObserver. +// ----------------------------------------------------------------------------- +// +void CCRXpsSink::TimerExpired( CCRTimer* /*aTimer*/ ) + { + RestoreSink(); + } + +// ----------------------------------------------------------------------------- +// CCRXpsSink::RestorePacketSupply +// From CCRPacketSinkBase. +// ----------------------------------------------------------------------------- +// +void CCRXpsSink::RestorePacketSupply( TUint aStreamId ) + { +#if defined( LIVE_TV_RDEBUG_TRACE ) || defined( LIVE_TV_FILE_TRACE ) + if ( iLogXps < 5 ) + { + iLogXps++; + LOG2( "CCRXpsSink::RestorePacketSupply(), aStreamId: %d, iWaitPlayer: %d", + aStreamId, iWaitPlayer ); + } +#endif // LIVE_TV_RDEBUG_TRACE || LIVE_TV_FILE_TRACE + + if ( iWaitPlayer != TInt( ETrue ) ) + { + if ( iBuffer->ContinousStream() ) + { + iRequested = aStreamId; + iWaitPlayer = KErrNone; + RestoreSink(); + } + else + { + iWaitPlayer = KErrNone; + StartTimer( KXpsOverflowDelay ); + } + } + } + +// ----------------------------------------------------------------------------- +// CCRXpsSink::RestoreSink +// ----------------------------------------------------------------------------- +// +void CCRXpsSink::RestoreSink() + { + if ( iBuffer ) + { + // See if more waits in packet buffer + if ( iBuffer->PacketsCount( iSinkId ) > KErrNotFound ) + { + NewPacketAvailable(); + } + else + { + StopTimer(); + // This is only for non continous stream, like .rtp clip + iOwningSession.SourceRestore(); + } + } + } + +// ----------------------------------------------------------------------------- +// CCRXpsSink::SendPacket +// Initialises time stamp converter for audio and video stream and passes RTP +// packets with adjusted time stamp to XPS interface. All packets before +// converter has beeen initialized are dumbed. +// ----------------------------------------------------------------------------- +// +TBool CCRXpsSink::SendPacket() + { + TBool packetSent( ETrue ); + MCRPacketSource::TCRPacketStreamId bufferId( MCRPacketSource::EStreamIdCount ); + const TInt book( iBuffer->GetStream( iSinkId, bufferId ) ); + TPtr8 packet( NULL, 0 ); + + // Packet type related action + TInt err( KErrNone ); + switch ( bufferId ) + { + case MCRPacketSource::EAudioStream: + if ( iAudioConv->Initiated() ) + { + iBuffer->GetPacket( book, packet ); + if ( iRequested == KErrNotFound || iRequested == iAudioStreamId ) + { + iRequested = KErrNotFound; + err = SendAudioPacket( packet ); + } + else + { + LOG( "CCRXpsSink::SendPacket(), Audio packet DROPPED after XPS overflow !" ) + } + } + else + { + packetSent = EFalse; + SearchForControlStreamPackets(); + } + break; + + case MCRPacketSource::EAudioControlStream: + { + iBuffer->GetPacket( book, packet ); + if ( !iAudioConv->Initiated() ) + { + iAudioConv->Init( packet ); + LOG1( "CCRXpsSink::SendPacket(), Audio TS initiated, status: %d", + iAudioConv->Initiated() ) + } + } + break; + + case MCRPacketSource::EVideoStream: + if ( iVideoConv->Initiated() ) + { + iBuffer->GetPacket( book, packet ); + if ( iRequested == KErrNotFound || iRequested == iVideoStreamId ) + { + iRequested = KErrNotFound; + err = SendVideoPacket( packet ); + } + else + { + LOG( "CCRXpsSink::SendPacket(), Video packet DROPPED after XPS overflow !" ) + } + } + else + { + packetSent = EFalse; + SearchForControlStreamPackets(); + } + break; + + case MCRPacketSource::EVideoControlStream: + { + iBuffer->GetPacket( book, packet ); + if ( !iVideoConv->Initiated() ) + { + iVideoConv->Init( packet ); + LOG1( "CCRXpsSink::SendPacket(), Video TS initiated, status: %d", + iVideoConv->Initiated() ) + } + } + break; + + case MCRPacketSource::ESubTitleStream: + if ( iTitleConv->Initiated() ) + { + iBuffer->GetPacket( book, packet ); + err = SendTitlePacket( packet ); + } + else + { + packetSent = EFalse; + SearchForControlStreamPackets(); + } + break; + + case MCRPacketSource::ESubTitleControlStream: + { + iBuffer->GetPacket( book, packet ); + if ( !iTitleConv->Initiated() ) + { + iTitleConv->Init( packet ); + LOG1( "CCRXpsSink::SendPacket(), Title TS initiated, status: %d", + iTitleConv->Initiated() ) + } + } + break; + + case MCRPacketSource::EDisContinousStream: + { + LOG( "CCRXpsSink::SendPacket(), EDiscontinousStream" ); + // Just wait player's "MvloLoadingStartedL" event, + // PlayCommand( -1.0, -1.0 ) will then handle pause packet + iWaitPlayer = ETrue; + // Used packet out from the buffer + iBuffer->GetPacket( book, packet ); + } + break; + + case MCRPacketSource::EStreamEndTag: + LOG1( "CCRXpsSink::SendPacket(), EStreamEndTag, iRangeKnown: %d", iRangeKnown ); + if ( iRangeKnown ) + { + if ( iAudioStreamId > KErrNotFound ) + { + iPacketSink->StreamEnd( iAudioStreamId ); + } + if ( iVideoStreamId > KErrNotFound ) + { + iPacketSink->StreamEnd( iVideoStreamId ); + } + } + //else + // { + // Just wait player's "MvloLoadingStartedL" event, + // Play ends with PlayCommand( -1.0, -1.0 ) in .rtp clip case and/or + // VIA will stop the play if play position goes beond the clip's lenght + // } + + // Used packet out from the buffer + iBuffer->GetPacket( book, packet ); + break; + + default: + LOG1( "CCRXpsSink::SendPacket(), Bad bufferId: %d", bufferId ); + // Used packet out from the buffer + iBuffer->GetPacket( book, packet ); + break; + } + + // Stop sink if error? + if ( err ) + { + LOG2( "CCRXpsSink::SendPacket(), error: %d, bufferId: %d", err, bufferId ); + LOG2( "CCRXpsSink::SendPacket(), iAudioStreamId: %d, iVideoStreamId: %d", + iAudioStreamId, iVideoStreamId ); + iOwningSession.SinkStops( Id() ); + } + + return packetSent; + } + +// ----------------------------------------------------------------------------- +// CCRXpsSink::SendAudioPacket +// Adjust RTP timestamp and enqueue the packet. +// ----------------------------------------------------------------------------- +// +TInt CCRXpsSink::SendAudioPacket( const TDesC8& aPacket ) + { + // Parse packet + TInt err( iRtpPacket->ParseRtp( aPacket ) ); + if ( err ) + { + LOG1( "CCRXpsSink::SendAudioPacket(), Parsing error: %d", err ); + return err; + } + + // Adjust time stamp + iRtpPacket->SetTimeStamp( + iAudioConv->ConvertTs( iRtpPacket->iRtpRecvHeader.iTimestamp ) ); + + // Send to player + return EnqueuePacket( iAudioStreamId ); + } + +// ----------------------------------------------------------------------------- +// CCRXpsSink::SendVideoPacket +// Adjust RTP timestamp and enqueue the packet. +// ----------------------------------------------------------------------------- +// +TInt CCRXpsSink::SendVideoPacket( const TDesC8& aPacket ) + { + TPtrC8 packet( aPacket ); + +#ifdef VIA_FEA_IPTV_USE_IPDC + // Do ISMA Depacketizer + if ( iVideoDepacketizer != NULL ) + { + TInt result( iVideoDepacketizer->PushPacket( packet ) ); + if ( result != KErrCompletion ) // KErrCompletion means Ok + { + return KErrNone; + } + + // Next packet should be available + TInt err( iVideoDepacketizer->NextFrame( packet ) ); + if ( err ) + { + LOG1( "CCRXpsSink::SendVideoPacket(), NextFrame error: %d", err ); + return err; + } + } +#endif // VIA_FEA_IPTV_USE_IPDC + + // Parse packet + TInt err( iRtpPacket->ParseRtp( packet ) ); + if ( err ) + { + LOG1( "CCRXpsSink::SendVideoPacket(), Parsing error: %d", err ); + return err; + } + + // Adjust time stamp + iRtpPacket->SetTimeStamp( + iVideoConv->ConvertTs( iRtpPacket->iRtpRecvHeader.iTimestamp ) ); + + // Send to player + return EnqueuePacket( iVideoStreamId ); + } + +// ----------------------------------------------------------------------------- +// CCRXpsSink::SendTitlePacket +// Adjust RTP timestamp and enqueue the packet. +// ----------------------------------------------------------------------------- +// +TInt CCRXpsSink::SendTitlePacket( const TDesC8& /*aPacket*/ ) + { + // Title implementation unknown + return KErrNotSupported; + } + +// ----------------------------------------------------------------------------- +// CCRXpsSink::EnqueuePacket +// Sends packet to the player. +// ----------------------------------------------------------------------------- +// +TInt CCRXpsSink::EnqueuePacket( const TUint aStreamId ) + { + TInt err( iPacketSink->Enqueue( + aStreamId, iRtpPacket->iRtpRecvHeader, iRtpPacket->iPayload ) ); + +#if defined( LIVE_TV_RDEBUG_TRACE ) || defined( LIVE_TV_FILE_TRACE ) + if ( err && ( iLogXps < 5 || err != KErrOverflow ) ) + { + LOG3( "CCRXpsSink::EnqueuePacket(), aStreamId: %d, err: %d, payload len: %d", + aStreamId, err, iRtpPacket->iPayload.Length() ); + } +#endif // LIVE_TV_RDEBUG_TRACE || LIVE_TV_FILE_TRACE + + if ( err == KErrOverflow ) + { + iWaitPlayer = err; + return KErrNone; + } + + // XPS reset can not be done before first packet is enqued + iXpsResetOk = ETrue; + return err; + } + +// ----------------------------------------------------------------------------- +// CCRXpsSink::SearchForControlStreamPackets +// Checks buffer for control stream packets. +// ----------------------------------------------------------------------------- +// +void CCRXpsSink::SearchForControlStreamPackets() + { + // Check if RTCP packet already in buffer + if ( CheckBufferForControlStreamPackets() ) + { + iBuffer->AdjustBuffer(); + } + else + { + // Get more packets if group not contains any RTCP packet(s) + if ( !iBuffer->ContinousStream() && !iBuffer->MoreComing() ) + { + iBuffer->AdjustBuffer(); + iOwningSession.SourceRestore(); + } + } + } + +// ----------------------------------------------------------------------------- +// CCRXpsSink::CheckBufferForControlStreamPackets +// Checks buffer for control stream packets. +// ----------------------------------------------------------------------------- +// +TBool CCRXpsSink::CheckBufferForControlStreamPackets() + { + TBool audioOk( iAudioConv->Initiated() || iAudioStreamId == KErrNotFound ); + TBool videoOk( iVideoConv->Initiated() || iVideoStreamId == KErrNotFound ); + + // Loop packets, oldest first + for ( TInt offset( iBuffer->PacketsCount( iSinkId ) - 1 ); + ( !audioOk || !videoOk ) && offset >= 0; offset-- ) + { + MCRPacketSource::TCRPacketStreamId streamId( MCRPacketSource::EStreamIdCount ); + const TInt book( iBuffer->GetStream( iSinkId, offset, streamId ) ); + TPtr8 packet( NULL, 0 ); + + switch ( streamId ) + { + case MCRPacketSource::EAudioControlStream: + if ( !iAudioConv->Initiated() ) + { + audioOk = ETrue; + iBuffer->PeekPacket( book, packet, offset ); + iAudioConv->Init( packet ); + LOG1( "CCRXpsSink::CheckBufferForControlStreamPackets(), Audio TS initiated, status: %d", + iAudioConv->Initiated() ) + } + break; + + case MCRPacketSource::EVideoControlStream: + if ( !iVideoConv->Initiated() ) + { + videoOk = ETrue; + iBuffer->PeekPacket( book, packet, offset ); + iVideoConv->Init( packet ); + LOG1( "CCRXpsSink::CheckBufferForControlStreamPackets(), Video TS initiated, status: %d", + iVideoConv->Initiated() ) + } + break; + + case MCRPacketSource::ESubTitleControlStream: + if ( !iTitleConv->Initiated() ) + { + iBuffer->PeekPacket( book, packet, offset ); + iTitleConv->Init( packet ); + LOG1( "CCRXpsSink::CheckBufferForControlStreamPackets(), Title TS initiated, status: %d", + iTitleConv->Initiated() ) + } + break; + + default: + break; + } + } + + return ( audioOk && videoOk ); + } + +// ----------------------------------------------------------------------------- +// CCRXpsSink::StartTimer +// Starts packet flow timer. +// ----------------------------------------------------------------------------- +// +void CCRXpsSink::StartTimer( const TInt& aInterval ) + { + StopTimer(); + TRAPD( err, iFlowTimer = CCRTimer::NewL( + CActive::EPriorityLow, *this ) ); + if ( !err ) + { + iFlowTimer->After( aInterval ); + } + else + { + LOG1( "CCRXpsSink::StartTimer(), Flowtimer err: %d", err ); + iOwningSession.SinkStops( Id() ); + } + } + +// ----------------------------------------------------------------------------- +// CCRXpsSink::StopTimer +// Starts packet flow timer. +// ----------------------------------------------------------------------------- +// +void CCRXpsSink::StopTimer() + { + delete iFlowTimer; iFlowTimer = NULL; + } + +#ifdef VIA_FEA_IPTV_USE_IPDC +// ----------------------------------------------------------------------------- +// CCRXpsSink::FindFmtpL +// Finds the fmtp string. +// ----------------------------------------------------------------------------- +// +HBufC8* CCRXpsSink::FindFmtpLC( const TDesC8& aSdpData ) + { + LOG( "CCRXpsSink::FindFmtpLC() in" ); + _LIT8( KCRStr, "\r" ); + _LIT8( KLFStr, "\n" ); + _LIT8( KHxAVCfmtp, "a=hxavcfmtp:" ); + + // Get the video fmtp string + HBufC8* fmtp = NULL; + TInt pos = aSdpData.Find( KHxAVCfmtp ); + if ( pos > KErrNotFound ) + { + // Extract the right most from the fist char after KHxAVCfmtp + TPtrC8 rightPtr( aSdpData.Mid( pos + KHxAVCfmtp().Length() ) ); + + // We need the first line of rightPtr + TInt posLFStr( rightPtr.Find( KLFStr ) ); + TInt posCRStr( rightPtr.Find( KCRStr ) ); + if ( posLFStr > 0 && posCRStr > 0 ) + { + fmtp = rightPtr.Left( Min( posLFStr, posCRStr ) ).AllocLC(); + } + else if ( posLFStr > 0 ) + { + fmtp = rightPtr.Left( posLFStr ).AllocLC(); + } + else if ( posCRStr > 0 ) + { + fmtp = rightPtr.Left( posCRStr ).AllocLC(); + } + else + { + fmtp = rightPtr.AllocLC(); + } + } + + User::LeaveIfNull( fmtp ); +#if defined( LIVE_TV_RDEBUG_TRACE ) || defined( LIVE_TV_FILE_TRACE ) + HBufC* buf = HBufC::NewL( fmtp->Length() ); + TPtr ptr( buf->Des() ); ptr.Copy( *fmtp ); + LOG1( "CCRXpsSink::FindFmtpLC() out, Fmtp: %S", &ptr ); +#endif // LIVE_TV_RDEBUG_TRACE || LIVE_TV_FILE_TRACE + return fmtp; + } + +#endif // VIA_FEA_IPTV_USE_IPDC + + // End of File