dvrengine/CommonRecordingEngine/src/CCRXpsSink.cpp
branchRCL_3
changeset 23 13a33d82ad98
parent 0 822a42b6c3f1
--- /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 <ipvideo/CDvrSdpParser.h>
+#include "CCRTimer.h"
+#include "CRtpPacket.h"
+#include "CRtpTsConverter.h"
+#include <CXPSPacketSink.h>
+
+// 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