diff -r 798ee5f1972c -r 826cea16efd9 dvrengine/CommonRecordingEngine/src/CCRRtpRecordSink.cpp --- a/dvrengine/CommonRecordingEngine/src/CCRRtpRecordSink.cpp Thu Aug 19 10:54:18 2010 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,623 +0,0 @@ -/* -* 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 buffer and does not put them* -*/ - - - - -// INCLUDES -#include "CCRRtpRecordSink.h" -#include "CCRPacketBuffer.h" -#include "CCRStreamingSession.h" -#include "MCRConnectionObserver.h" -#include -#include -#include -#include "CRtpTsConverter.h" -#include "CRtpPacket.h" -#include -#include "videoserviceutilsLogger.h" - -// CONSTANTS -const TInt KDefaultBitRate( 256 + 64 ); // 320 kbps -const TInt KDefGroupSize( 70 * 1024 ); // 70k -const TInt KMaxGroupSize( 140 * 1024 ); // 140k -const TInt KMaxGrouplength( 3000 ); // 3 s -const TInt KGroupHeaderSize( KGroupHeaderBytes + KPacketsCountBytes ); -const TInt KGroupLenghtAccuracy( 20 ); // 20ms - -// ============================ MEMBER FUNCTIONS =============================== - -// ----------------------------------------------------------------------------- -// CCRRtpRecordSink::NewL -// Two-phased constructor. -// ----------------------------------------------------------------------------- -// - -CCRRtpRecordSink* CCRRtpRecordSink::NewL( - const SCRRecordParams& aRecordParams, - CCRStreamingSession::TCRSinkId aSinkId, - CCRStreamingSession& aOwningSession, - MCRConnectionObserver* aObserver, - CRtpClipHandler*& aClipHandler ) - { - CCRRtpRecordSink* self = new( ELeave ) - CCRRtpRecordSink( aSinkId, aOwningSession, aObserver, aClipHandler ); - CleanupStack::PushL( self ); - self->ConstructL( aRecordParams ); - CleanupStack::Pop( self ); - return self; - } - -// ----------------------------------------------------------------------------- -// CCRRtpRecordSink::CCRRtpRecordSink -// C++ default constructor can NOT contain any code, that might leave. -// ----------------------------------------------------------------------------- -// -CCRRtpRecordSink::CCRRtpRecordSink( - CCRStreamingSession::TCRSinkId aSinkId, - CCRStreamingSession& aOwningSession, - MCRConnectionObserver* aObserver, - CRtpClipHandler*& aClipHandler ) - : CCRPacketSinkBase( aOwningSession, aSinkId ), - iObserver( aObserver ), - iClipHandler( aClipHandler ), - iGroupPointer( NULL, 0 ), - iGroupSize( KGroupHeaderSize ), - iPacketsCount( 0 ), - iWantedGroup( KMaxTInt ), - iOldestTs( KMaxTUint ), - iLatestAudio( NULL, 0 ), - iSaveMode( MRtpFileWriteObserver::ESaveNormal ), - iGroupMode( MRtpFileWriteObserver::ESaveIdle ) - { - // None - } - -// ----------------------------------------------------------------------------- -// CCRRtpRecordSink::ConstructL -// 2nd phase. -// ----------------------------------------------------------------------------- -// -void CCRRtpRecordSink::ConstructL( const SCRRecordParams& aRecordParams ) - { - LOG( "CCRRtpRecordSink::ConstructL()" ); - - // Params - iRecParams.iClipPath = aRecordParams.iFileName; - iRecParams.iSdpData.Set( aRecordParams.iSdpData ); - iRecParams.iService.Set( aRecordParams.iServiceName ); - iRecParams.iProgram.Set( aRecordParams.iProgramName ); - iRecParams.iPostRule = aRecordParams.iPostRule; - iRecParams.iParental = aRecordParams.iParental; - iRecParams.iEndTime = aRecordParams.iEndTime; - - if ( aRecordParams.iFormat == ECRRecordTimeShift ) - { - iRecParams.iStartTime = 0; - iRecParams.iEndTime = KDvrMaximumTimeShift * 1e6; - iSaveMode = MRtpFileWriteObserver::ESaveTimeShift; - } - -#if defined( LIVE_TV_RDEBUG_TRACE ) || defined( LIVE_TV_FILE_TRACE ) - LOG1( "CCRRtpRecordSink::ConstructL(), iClipPath: %S", &iRecParams.iClipPath ); - TName buf( KNullDesC ); iRecParams.iStartTime.FormatL( buf, KTimeDateFormat ); - LOG1( "CCRRtpRecordSink::ConstructL(), iStartTime: %S", &buf ); - iRecParams.iEndTime.FormatL( buf, KTimeDateFormat ); - LOG1( "CCRRtpRecordSink::ConstructL(), iEndTime: %S", &buf ); -#endif // LIVE_TV_RDEBUG_TRACE || LIVE_TV_FILE_TRACE - - // Clip handler and group buffer - User::LeaveIfNull( iClipHandler ); - iGroupBuffer = HBufC8::NewL( 0 ); - iGroupPointer.Set( iGroupBuffer->Des() ); - } - -// ----------------------------------------------------------------------------- -// CCRRtpRecordSink::~CCRRtpRecordSink -// Destructor. -// ----------------------------------------------------------------------------- -// -CCRRtpRecordSink::~CCRRtpRecordSink() - { - LOG( "CCRRtpRecordSink::~CCRRtpRecordSink()" ); - - if ( iClipHandler ) - { - iClipHandler->StopRecording( KErrCancel ); - } - - delete iGroupBuffer; - delete iAudioConv; - } - -// ----------------------------------------------------------------------------- -// CCRRtpRecordSink::SetSdpL -// Sets SDP, parses it and initiates XPS. -// ----------------------------------------------------------------------------- -// -void CCRRtpRecordSink::SetSdpL( const TDesC8& aSdp ) - { - TInt initiated( iRecParams.iSdpData.Length() ); - LOG2( "CCRRtpRecordSink::SetSdpL(), aSdp len: %d, initiated: %d", - aSdp.Length(), initiated ); - if ( !initiated && iClipHandler ) - { - iRecParams.iSdpData.Set( aSdp ); - iClipHandler->RegisterWriteObserver( this ); - iClipHandler->StartRecordingL( iRecParams, iSaveMode ); - - // SDP parser - CDvrSdpParser* sdpParser = CDvrSdpParser::NewLC(); - sdpParser->TryParseL( aSdp ); - - // Bit rates - TUint total( sdpParser->VideoBitrate() + sdpParser->AudioBitrate() ); - TReal angle( TReal( total ) / KDefaultBitRate ); - iWantedGroup = TInt( angle * KDefGroupSize ); - LOG1( "SetSdpL::SetSdpL(), iWantedGroup: %d", iWantedGroup ); - iGroupBuffer = iGroupBuffer->ReAllocL( iWantedGroup + KGroupHeaderSize ); - iGroupPointer.Set( iGroupBuffer->Des() ); - - // TS converter - delete iAudioConv; iAudioConv = NULL; - iAudioConv = CRtpTsConverter::NewL( sdpParser->AudioTimerGranularity() ); - LOG1( "CCRRtpRecordSink::SetSdpL(), AudioTimerGranularity: %d", - sdpParser->AudioTimerGranularity() ); - CleanupStack::PopAndDestroy( sdpParser ); - - // Recording can start - iGroupMode = MRtpFileWriteObserver::ESaveNormal; - iObserver->ConnectionStatusChange( iOwningSession.SourceChecksum(), - MCRConnectionObserver::ECRRecordingStarted, KErrNone ); - } - } - -// ----------------------------------------------------------------------------- -// CCRRtpRecordSink::NewPacketAvailable -// From CCRPacketSinkBase. New packet(s) to a group. -// ----------------------------------------------------------------------------- -// -void CCRRtpRecordSink::NewPacketAvailable() - { - // Keep group buffer untouch during clip writing - if ( iBuffer && iClipHandler && !iClipHandler->WritingActive() ) - { - if ( iGroupMode == MRtpFileWriteObserver::ESaveNormal ) - { - // New packets to a group - AddToGroup(); - - // Group size big enougth to write to clip? - if ( iGroupSize >= iWantedGroup ) - { - SaveGroup( iGroupMode ); - } - - // Keep buffer size reasonable - iBuffer->HandleBufferSize(); - } - else - { - if ( iGroupMode != MRtpFileWriteObserver::ESaveIdle ) - { - AddToGroup(); - - // Handle user pause - if ( iGroupMode == MRtpFileWriteObserver::ESavePause ) - { - AddPausePacket(); - } - - SaveGroup( iGroupMode ); - iGroupMode = MRtpFileWriteObserver::ESaveIdle; - } - } - } - } - -// ----------------------------------------------------------------------------- -// CCRRtpRecordSink::BufferResetting -// From CCRPacketSinkBase. -// ----------------------------------------------------------------------------- -// -void CCRRtpRecordSink::BufferResetDone() - { - AddPausePacket(); - if ( iClipHandler && !iClipHandler->WritingActive() ) - { - SaveGroup( MRtpFileWriteObserver::ESavePause ); - } - } - -// ----------------------------------------------------------------------------- -// CCRRtpRecordSink::Pause -// ----------------------------------------------------------------------------- -// -TInt CCRRtpRecordSink::Pause() - { - LOG1( "CCRRtpRecordSink::Pause(), iGroupMode: %d", iGroupMode ); - - TInt err( KErrCompletion ); - if ( iClipHandler ) - { - if ( iSaveMode == MRtpFileWriteObserver::ESaveNormal ) - { - // Normal pause - err = KErrNone; - iGroupMode = MRtpFileWriteObserver::ESavePause; - } - else - { - // Time shift pause - TRAP( err, iClipHandler->TimeShiftPauseL() ); - } - } - - return err; - } - -// ----------------------------------------------------------------------------- -// CCRRtpRecordSink::Restore -// ----------------------------------------------------------------------------- -// -TInt CCRRtpRecordSink::Restore() - { - LOG1( "CCRRtpRecordSink::Restore(), iGroupMode: %d", iGroupMode ); - - iGroupMode = MRtpFileWriteObserver::ESaveNormal; - return KErrNone; - } - -// ----------------------------------------------------------------------------- -// CCRRtpRecordSink::Stop -// ----------------------------------------------------------------------------- -// -void CCRRtpRecordSink::Stop() - { - LOG1( "CCRRtpRecordSink::Stop(), iGroupMode: %d", iGroupMode ); - - iGroupMode = MRtpFileWriteObserver::ESaveEnd; - if ( iClipHandler && !iClipHandler->WritingActive() ) - { - iWantedGroup = KMaxTInt; - SaveGroup( iGroupMode ); - } - } - -// ----------------------------------------------------------------------------- -// CCRRtpRecordSink::GroupSaved -// From MRtpFileWriteObserver. -// ----------------------------------------------------------------------------- -// -void CCRRtpRecordSink::GroupSaved() - { - ResetGroupVariables(); - if ( iGroupMode != MRtpFileWriteObserver::ESaveNormal ) - { - SaveGroup( iGroupMode ); - iGroupMode = MRtpFileWriteObserver::ESaveIdle; - } - } - -// ----------------------------------------------------------------------------- -// CCRRtpRecordSink::WriteStatus -// From MRtpFileWriteObserver. -// ----------------------------------------------------------------------------- -// -void CCRRtpRecordSink::WriteStatus( const TInt aStatus ) - { - LOG1( "CCRRtpRecordSink::WriteStatus(), aStatus: %d", aStatus ); - - ForceStopRecording( aStatus ); - } - -// ----------------------------------------------------------------------------- -// CCRRtpRecordSink::AddToGroup -// Initialises time stamp converter for audio stream and adds packets to a group. -// ----------------------------------------------------------------------------- -// -void CCRRtpRecordSink::AddToGroup() - { - const TInt packets( iBuffer->PacketsCount( iSinkId ) ); - for ( TInt i( packets ); i > KErrNotFound; i-- ) - { - // Packet - TPtr8 packet( NULL, 0 ); - MCRPacketSource::TCRPacketStreamId streamId( - MCRPacketSource::EStreamIdCount ); - const TInt book( iBuffer->GetStream( iSinkId, streamId ) ); - iBuffer->GetPacket( book, packet ); - - // TS converter - if ( streamId == MCRPacketSource::EAudioControlStream && - iAudioConv && !iAudioConv->Initiated() ) - { - iAudioConv->Init( packet ); - } - - // Type valid - MRtpFileWriteObserver::TRtpType type( MRtpFileWriteObserver::ERtpNone ); - if ( packet.Length() && StreamToType( streamId, type ) ) - { - TRAPD( err, AddPacketToGroupL( packet, type ) ); - if ( err ) - { - LOG1( "CCRRtpRecordSink::AddToGroup(), AddPacketToGroupL leaved: %d", err ); - ForceStopRecording( err ); - } - } - } - } - -// ----------------------------------------------------------------------------- -// CCRRtpRecordSink::AddPacketToGroupL -// ----------------------------------------------------------------------------- -// -void CCRRtpRecordSink::AddPacketToGroupL( - const TDesC8& aPacket, - const MRtpFileWriteObserver::TRtpType& aType ) - { - const TUint total( KPacketSizeBytesLen + - KPacketTypeBytesLen + aPacket.Length() ); - iGroupSize += total; - if ( iGroupSize > iGroupPointer.MaxLength() ) - { - iGroupBuffer = iGroupBuffer->ReAllocL( iGroupSize ); - iGroupPointer.Set( iGroupBuffer->Des() ); - LOG1( "CCRRtpRecordSink::AddPacketToGroupL(), New iGroupSize: %d", iGroupSize ); - } - - // Packet length (PTL), type and data - TBuf8 header; - CRtpUtil::MakeBytesL( total, header ); - header.Append( KCharSpace ); - header[KPacketTypeBytePoint] = ( TUint8 )( aType ); - iGroupPointer.Append( header ); - iGroupPointer.Append( aPacket ); - iPacketsCount++; - -#ifdef CR_ALL_LOGS - const TUint8* pointer( &aPacket[2] ); - TInt seq( BigEndian::Get16( pointer ) ); - LOG3( "CCRRtpRecordSink::AddPacketToGroupL(), type: %d, packet: %d, seq: %d", - aType, aPacket.Length(), seq ); - //RFileLogger::WriteFormat( _L( "livetv" ), _L( "record.log" ), EFileLoggingModeAppend, - // _L( "AddPacketToGroupL(), type: %d, packet: %d, seq: %d" ), aType, aPacket.Length(), seq ); - -#endif // CR_ALL_LOGS - - // Variables for TS delta - if ( aType == MRtpFileWriteObserver::ERtpAudio && - iAudioConv && iAudioConv->Initiated() ) - { - if ( iOldestTs == KMaxTUint ) - { - iOldestTs = TsFromPacketL( aPacket ); - } - else - { - iLatestAudio.Set( iGroupPointer.Right( aPacket.Length() ) ); - } - } - } - -// ----------------------------------------------------------------------------- -// CCRRtpRecordSink::SaveGroup -// Saves RTP packets group to a clip. -// ----------------------------------------------------------------------------- -// -void CCRRtpRecordSink::SaveGroup( MRtpFileWriteObserver::TRtpSaveAction aAction ) - { - TRAPD( err, SaveGroupL( aAction ) ); - if ( err ) - { - ForceStopRecording( err ); - } - } - -// ----------------------------------------------------------------------------- -// CCRRtpRecordSink::SaveGroup -// Saves RTP packets group to a clip. -// ----------------------------------------------------------------------------- -// -void CCRRtpRecordSink::SaveGroupL( MRtpFileWriteObserver::TRtpSaveAction aAction ) - { - // TS delta - TBool forceSave( aAction != MRtpFileWriteObserver::ESaveNormal ); - TInt length( TReal( iGroupSize ) / iWantedGroup * KNormalRecGroupLength ); - if ( iOldestTs != KMaxTUint ) - { - length = TsFromPacketL( iLatestAudio ) - iOldestTs; - } - if ( length >= ( KNormalRecGroupLength - KGroupLenghtAccuracy ) ) - { - forceSave = ETrue; - if ( length <= ( KNormalRecGroupLength + KGroupLenghtAccuracy ) ) - { - iWantedGroup = ( iWantedGroup + iGroupSize ) / 2; - } - else - { - TReal angle( TReal( iGroupSize ) / length ); - TInt wanted( TReal( KNormalRecGroupLength ) * angle ); - if ( wanted > ( KDefGroupSize / 2 ) && wanted < KMaxGroupSize ) - { - iWantedGroup = ( iWantedGroup + wanted ) / 2; - } - } - } - - // Group ok to save? - if ( forceSave || iGroupSize > KMaxGroupSize ) - { - // Group packets count (PTC) - HBufC8* bytes = CRtpUtil::MakeBytesLC( iPacketsCount ); - iGroupPointer.Insert( 0, bytes->Des() ); - CleanupStack::PopAndDestroy( bytes ); - - // Make sure that nasty length not end to the clip in case TS overflow - length = ( length <= KMaxGrouplength )? length: KMaxGrouplength; - - // Save to clip - TInt err( KErrNotReady ); - if ( iClipHandler ) - { - TRAP( err, iClipHandler->SaveNextGroupL( iGroupPointer, - length, aAction ) ); - } - if ( err ) - { - LOG1( "CCRRtpRecordSink::SaveGroup(), SaveNextGroupL Leaved: %d", err ); - ForceStopRecording( err ); - } - - LOG3( "CCRRtpRecordSink::SaveGroup(), iPacketsCount: %d, length: %u, iWantedGroup: %d", - iPacketsCount, length, iWantedGroup ); - } - } - -// ----------------------------------------------------------------------------- -// CCRRtpRecordSink::StreamToType -// ----------------------------------------------------------------------------- -// -TBool CCRRtpRecordSink::StreamToType( - const MCRPacketSource::TCRPacketStreamId& aStream, - MRtpFileWriteObserver::TRtpType& aType ) - { - switch ( aStream ) - { - case MCRPacketSource::EAudioStream: - aType = MRtpFileWriteObserver::ERtpAudio; - break; - - case MCRPacketSource::EAudioControlStream: - aType = MRtpFileWriteObserver::ERtcpAudio; - break; - - case MCRPacketSource::EVideoStream: - aType = MRtpFileWriteObserver::ERtpVideo; - break; - - case MCRPacketSource::EVideoControlStream: - aType = MRtpFileWriteObserver::ERtcpVideo; - break; - - case MCRPacketSource::ESubTitleStream: - aType = MRtpFileWriteObserver::ERtpSubTitle; - break; - - case MCRPacketSource::ESubTitleControlStream: - aType = MRtpFileWriteObserver::ERtcpSubTitle; - break; - - case MCRPacketSource::EDisContinousStream: - LOG( "CCRRtpRecordSink::StreamToType(), ERtpClipPause" ); - aType = MRtpFileWriteObserver::ERtpClipPause; - break; - - case MCRPacketSource::EStreamEndTag: - LOG( "CCRRtpRecordSink::StreamToType(), ERtpClipEnd" ); - aType = MRtpFileWriteObserver::ERtpClipEnd; - break; - - default: - return EFalse; - } - - return ETrue; - } - -// ----------------------------------------------------------------------------- -// CCRRtpRecordSink::TsFromPacketL -// ----------------------------------------------------------------------------- -// -TUint CCRRtpRecordSink::TsFromPacketL( const TDesC8& aPacket ) - { - CRtpPacket* rtpPacket = CRtpPacket::NewLC(); - TUint ts( KMaxTUint ); - if ( !rtpPacket->ParseRtp( aPacket ) ) - { - ts = iAudioConv->ConvertTs( rtpPacket->iRtpRecvHeader.iTimestamp, ETrue ); - } - - CleanupStack::PopAndDestroy( rtpPacket ); - return ts; - } - -// ----------------------------------------------------------------------------- -// CCRRtpRecordSink::AddPausePacket -// Wrapper for AddPausePacketL(). -// ----------------------------------------------------------------------------- -// -void CCRRtpRecordSink::AddPausePacket() - { - LOG( "CCRRtpRecordSink::AddPausePacket()"); - - TRAPD( err, AddPausePacketL() ); - if ( err ) - { - ForceStopRecording( err ); - } - } - -// ----------------------------------------------------------------------------- -// CCRRtpRecordSink::AddPausePacketL -// Adds pause packet to the group. -// ----------------------------------------------------------------------------- -// -void CCRRtpRecordSink::AddPausePacketL() - { - HBufC8* data = CRtpUtil::MakeBytesLC( KMaxTUint ); - AddPacketToGroupL( data->Des(), MRtpFileWriteObserver::ERtpClipPause ); - CleanupStack::PopAndDestroy( data ); - } - -// ----------------------------------------------------------------------------- -// CCRRtpRecordSink::ForceStopRecording -// Stops recording on clip handler and destroys the sink. -// ----------------------------------------------------------------------------- -// -void CCRRtpRecordSink::ForceStopRecording( const TInt& aStatus ) - { - LOG2( "CCRRtpRecordSink::ForceStopRecording(), iGroupMode: %d, aStatus: %d", - iGroupMode, aStatus ); - iGroupMode = MRtpFileWriteObserver::ESaveIdle; - - if ( iClipHandler ) - { - iClipHandler->StopRecording( aStatus ); - } - - iObserver->ConnectionStatusChange( iOwningSession.SourceChecksum(), - MCRConnectionObserver::ECRRecordingEnded, aStatus ); - iOwningSession.SinkStops( Id() ); - } - -// ----------------------------------------------------------------------------- -// CCRRtpRecordSink::ResetGroupVariables -// -// ----------------------------------------------------------------------------- -// -void CCRRtpRecordSink::ResetGroupVariables() - { - iGroupSize = KGroupHeaderSize; // Room for group header and packets count - iPacketsCount = 0; - iGroupPointer.Zero(); - iOldestTs = KMaxTUint; - iLatestAudio.Set( NULL, 0 ); - } - -// End of File