diff -r 000000000000 -r 09774dfdd46b internetradio2.0/streamsourcesrc/iricyflowinitiator.cpp
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/internetradio2.0/streamsourcesrc/iricyflowinitiator.cpp Mon Apr 19 14:01:53 2010 +0300
@@ -0,0 +1,457 @@
+/*
+* Copyright (c) 2006-2007 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description: ICY flow initiator implementation
+*
+*/
+
+
+/* ---------------------------------------------------------------------------
+* Version history:
+* Template version:
+*
+*
+* Version: 3, Tue Mar 11 20:00:00 2008 by Rohit
+* Ref:
+* Merged IRv1.0 Engine code changes
+*
+* Version: 2, Tue Feb 28 18:00:00 2008 by Rohit/Kranthi
+* Ref:
+* Setting RawDataTransferredL() into DataTransferTracker for Byte Counter Impl
+*
+*
+* ============================================================================
+*/
+
+#include
+#include
+#include
+#include
+
+#include "iricyflowinitiator.h"
+#include "irdebug.h"
+#include "irnetworkcontroller.h"
+#include "irpubsubkeys.h"
+#include "irstationconnection.h"
+#include "irstreamsourceerrors.h"
+#include "irstreamsourceliterals.h"
+
+// Constants
+const TInt KIRFITimeOutValue = 10000000;
+const TInt KIRHeaderMaxSize = 256;
+_LIT8( KIRUriComponentSeparator, "/" );
+const TInt KFour = 4;
+const TInt KSixtyFour=64;
+const TInt KTwoZeroFourEight=2048;
+// ---------------------------------------------------------------------------
+// CIRIcyFlowInitiator::NewL
+// ---------------------------------------------------------------------------
+//
+CIRIcyFlowInitiator* CIRIcyFlowInitiator::NewL( RSocket& aSocket, const TDesC& aUri,
+ CIRStationConnection& aOwner, TChannelInfo& aChannelInfo )
+ {
+ CIRIcyFlowInitiator* self = new ( ELeave ) CIRIcyFlowInitiator( aSocket,
+ aUri, aOwner, aChannelInfo );
+ CleanupStack::PushL(self);
+ self->ConstructL();
+ CleanupStack::Pop(self);
+ return self;
+ }
+
+// ---------------------------------------------------------------------------
+// CIRIcyFlowInitiator::CIRIcyFlowInitiator
+// ---------------------------------------------------------------------------
+//
+CIRIcyFlowInitiator::CIRIcyFlowInitiator( RSocket& aSocket, const TDesC& aUri,
+ CIRStationConnection& aOwner, TChannelInfo& aChannelInfo ) :
+ CActive( CActive::EPriorityStandard ), iState( EIRIdle ),
+ iSocket( aSocket ), iUri( aUri ), iOwner( aOwner ), iChannelInfo( aChannelInfo )
+ {
+ }
+
+// ---------------------------------------------------------------------------
+// CIRIcyFlowInitiator::ConstructL
+// ---------------------------------------------------------------------------
+//
+void CIRIcyFlowInitiator::ConstructL()
+ {
+ IRLOG_DEBUG( "CIRIcyFlowInitiator::ConstructL." );
+ CActiveScheduler::Add( this );
+ iSocketTimer = CIRSocketTimeOutTimer::NewL(CActive::EPriorityHigh,*this);
+
+ iNetworkControllerHandle = CIRNetworkController::OpenL();
+ iUAProfString.CreateL( *iNetworkControllerHandle->GetUAProfString() );
+
+ iBuffer.CreateL( KIRHeaderMaxSize );
+ iReadBuffer.CreateL( 1 );
+ if ( !ExtractUriComponentsL() )
+ {
+ User::Leave( KErrCorrupt );
+ }
+ IRLOG_DEBUG( "CIRIcyFlowInitiator::ConstructL - Exiting." );
+ }
+
+// ---------------------------------------------------------------------------
+// CIRIcyFlowInitiator::~CIRIcyFlowInitiator
+// ---------------------------------------------------------------------------
+//
+CIRIcyFlowInitiator::~CIRIcyFlowInitiator()
+ {
+ Cancel();
+ iHost.Close();
+ iPath.Close();
+
+ iBuffer.Close();
+ iReadBuffer.Close();
+ iUAProfString.Close();
+
+ delete iSocketTimer;
+ if(iNetworkControllerHandle)
+ {
+ iNetworkControllerHandle->Close();
+ }
+ }
+
+// ---------------------------------------------------------------------------
+// CIRIcyFlowInitiator::ExtractUriComponentsL
+// ---------------------------------------------------------------------------
+//
+TBool CIRIcyFlowInitiator::ExtractUriComponentsL()
+ {
+ IRLOG_DEBUG( "CIRIcyFlowInitiator::ExtractUriComponentsL" );
+
+ TBool retMe = EFalse;
+
+ if( !UriUtils::HasInvalidChars( iUri ) )
+ {
+ TUriParser uriParser;
+ uriParser.Parse( iUri );
+
+ iHost.Close();
+ iHost.CreateL( uriParser.Extract( EUriHost ).Size() );
+ iHost.Copy( uriParser.Extract( EUriHost ) );
+ iPath.Close();
+ iPath.CreateL( uriParser.Extract( EUriPath ).Size() );
+ iPath.Copy( uriParser.Extract( EUriPath ) );
+
+ if ( iPath.Length() == 0 )
+ {
+ iPath.Close();
+ iPath.CreateL( KIRUriComponentSeparator );
+ }
+ retMe = ETrue;
+ }
+ IRLOG_DEBUG( "CIRIcyFlowInitiator::ExtractUriComponentsL - Exiting." );
+ return retMe;
+ }
+
+// ---------------------------------------------------------------------------
+// CIRIcyFlowInitiator::RequestFlow
+// ---------------------------------------------------------------------------
+//
+void CIRIcyFlowInitiator::RequestFlow()
+ {
+ IRLOG_DEBUG( "CIRIcyFlowInitiator::RequestFlow" );
+ Cancel();
+
+ iBuffer.ReAlloc(iPath.Length() + iHost.Length() + iUAProfString.Length()
+ + KIcyRequest().Length());
+ iBuffer.Format( KIcyRequest, &iPath, &iHost, &iUAProfString );
+
+ // Cancel any pending timer requests
+ iSocketTimer->Cancel();
+ iSocketTimer->After( KIRFITimeOutValue );
+
+ iState = EIRSending;
+
+ IRDEBUGCODE(
+ RBuf requestCopy;
+ if ( requestCopy.Create( iBuffer.Length() ) == KErrNone )
+ {
+ requestCopy.Copy( iBuffer );
+ IRLOG_DEBUG2( "CIRIcyFlowInitiator::RequestFlow - request= %S", &requestCopy );
+ requestCopy.Close();
+ }
+ )
+
+ // HTTP GET METHOD sent to server
+ iSocket.Send( iBuffer, 0, iStatus );
+ SetActive();
+ IRLOG_DEBUG( "CIRIcyFlowInitiator::RequestFlow - Exiting." );
+ }
+
+// ---------------------------------------------------------------------------
+// CIRIcyFlowInitiator::RunL
+// ---------------------------------------------------------------------------
+//
+void CIRIcyFlowInitiator::RunL()
+ {
+ IRLOG_INFO3( "CIRIcyFlowInitiator::RunL - iStatus=%d, iState=%d", iStatus.Int(), iState );
+
+ if( iStatus == KErrNone )
+ {
+ switch( iState )
+ {
+ case EIRSending:
+ iSocketTimer->Cancel();
+ iSocketTimer->After( KIRFITimeOutValue );
+
+ // Byte Counter Impl
+ iNetworkControllerHandle->DataTransferTracker().RawDataTransferredL(
+ iBuffer.Size(),0, MIRDataTransferTracker::EIRTransferCategoryAudio);
+
+ iBuffer.Zero();
+ iBuffer.ReAlloc( KIRHeaderMaxSize );
+ iState = EIRReceiving;
+ iSocket.Read( iReadBuffer, iStatus );
+ SetActive();
+ break;
+ case EIRReceiving:
+ iSocketTimer->Cancel();
+ if ( iBuffer.MaxLength() <= ( iBuffer.Length() + iReadBuffer.Length() ) )
+ {
+ iBuffer.ReAlloc( iBuffer.MaxLength() + KSixtyFour );
+ }
+ // Byte Counter Impl
+ iNetworkControllerHandle->DataTransferTracker().RawDataTransferredL( 0,
+ iBuffer.Size(), MIRDataTransferTracker::EIRTransferCategoryAudio);
+ iBuffer.Append(iReadBuffer);
+ iReadBuffer.Zero();
+
+ // Check if we got the full header and if not, read more from the socket.
+ if ( iBuffer.Find( KHeaderEnd ) == KErrNotFound )
+ {
+ // if we have received 2kb's of headers, Then there is propably
+ // some sort error and its time to abort
+ if ( iBuffer.Length() >= KTwoZeroFourEight )
+ {
+ IRLOG_ERROR( "CIRIcyFlowInitiator::RunL - EIRReceiving. Got 2kb's of headers." );
+ // Cancel the timer if active
+ iSocketTimer->Cancel();
+ iOwner.ConnectionError( KIRStreamSourceReadError );
+ iState = EIRIdle;
+ break;
+ }
+
+ iSocket.Read( iReadBuffer, iStatus );
+ SetActive();
+ iSocketTimer->After( KIRFITimeOutValue );
+ break;
+ }
+ ParseChannelInfoL();
+ if ( ValidateChannelServer() )
+ {
+ TInt bitRateInt(0);
+ TLex8 bitvariable( iChannelInfo.iBitRate );
+ bitvariable.Val( bitRateInt );
+ RProperty::Set( KUidActiveInternetRadioApp,
+ KIRPSBitrate, bitRateInt );
+ iOwner.FlowReady();
+ iState = EIRFinished;
+ }
+ else
+ {
+ IRLOG_ERROR( "CIRIcyFlowInitiator::RunL - Invalid server" );
+ iOwner.ConnectionError( KIRStreamSourceInvalidUrl );
+ iState = EIRIdle;
+ }
+
+ break;
+ default:
+ __ASSERT_DEBUG( EFalse, User::Invariant() );
+ break;
+ }
+ }
+ else // An error has occurred
+ {
+ switch( iState )
+ {
+ case EIRSending:
+ IRLOG_ERROR( "CIRIcyFlowInitiator::RunL - EIRSending" );
+ // Cancel the timer if active
+ iSocketTimer->Cancel();
+ // Error in sending data to channel server
+ iOwner.ConnectionError( KIRStreamSourceWriteError );
+ break;
+ case EIRReceiving:
+ IRLOG_ERROR( "CIRIcyFlowInitiator::RunL - EIRReceiving" );
+ // Cancel the timer if active
+ iSocketTimer->Cancel();
+ //Error in response from channel server
+ if( iStatus.Int() == KErrEof )
+ {
+ iOwner.ConnectionError( KIRStreamSourceNoResponse );
+ }
+ else
+ {
+ iOwner.ConnectionError( KIRStreamSourceReadError );
+ }
+ break;
+ default:
+ IRLOG_FATAL2( "CIRIcyFlowInitiator::RunL - Error in unexpected state (%d)", iStatus.Int() );
+ __ASSERT_DEBUG( EFalse, User::Invariant() );
+ break;
+ }
+ }
+ IRLOG_DEBUG( "CIRIcyFlowInitiator::RunL - Exiting." );
+ }
+
+// ---------------------------------------------------------------------------
+// CIRIcyFlowInitiator::RunError
+// ---------------------------------------------------------------------------
+//
+TInt CIRIcyFlowInitiator::RunError( TInt aError )
+ {
+ IRLOG_ERROR2( "CIRIcyFlowInitiator::RunError - aError=%d", aError );
+ iOwner.ConnectionError( aError );
+ return KErrNone;
+ }
+
+// ---------------------------------------------------------------------------
+// CIRIcyFlowInitiator::DoCancel
+// ---------------------------------------------------------------------------
+//
+void CIRIcyFlowInitiator::DoCancel()
+ {
+ IRLOG_DEBUG2( "CIRIcyFlowInitiator::DoCancel - iState = %d.", iState );
+ iSocket.CancelAll();
+ iSocketTimer->Cancel();
+ iState = EIRIdle;
+ }
+
+// ---------------------------------------------------------------------------
+// CIRIcyFlowInitiator::TimerExpired
+// ---------------------------------------------------------------------------
+//
+void CIRIcyFlowInitiator::TimerExpired()
+ {
+ IRLOG_ERROR( "CIRIcyFlowInitiator::TimerExpired." );
+ Cancel();
+ iOwner.ConnectionError( KIRStreamSourceTimeOut );
+ IRLOG_DEBUG( "CIRIcyFlowInitiator::TimerExpired - Exiting." );
+ }
+
+// ---------------------------------------------------------------------------
+// CIRIcyFlowInitiator::ValidateChannelServer
+// ---------------------------------------------------------------------------
+//
+TBool CIRIcyFlowInitiator::ValidateChannelServer()
+ {
+ IRLOG_DEBUG( "CIRIcyFlowInitiator::ValidateChannelServer" );
+ TBool retMe = EFalse;
+
+ if ( iChannelInfo.iContentType.Match(KValidContentType) != KErrNotFound )
+ {
+ retMe = ETrue;
+ }
+ IRLOG_DEBUG2( "CIRIcyFlowInitiator::ValidateChannelServer - Exiting (%d).", retMe );
+ return retMe;
+ }
+
+
+// ---------------------------------------------------------------------------
+// CIRIcyFlowInitiator::ParseChannelInfoL
+// ---------------------------------------------------------------------------
+//
+void CIRIcyFlowInitiator::ParseChannelInfoL()
+ {
+ IRLOG_DEBUG( "CIRIcyFlowInitiator::ParseChannelInfoL" );
+
+ TInt offsetPositionStart( 0 );
+ offsetPositionStart = iBuffer.Find( KHeaderEnd );
+ if ( offsetPositionStart == KErrNotFound )
+ {
+ IRLOG_ERROR( "CIRIcyFlowInitiator::ParseChannelInfoL - Header delimiter not found." );
+ User::Leave( KIRStreamSourceApplicationProtocolError );
+ }
+ offsetPositionStart += KFour;
+ TPtrC8 start = iBuffer.Mid( offsetPositionStart );
+ iChannelInfo.iAudioDataOffset = start.Length();
+ // Call ExtractMetaInfo function for each Meta Field
+ ExtractMetaInfoL( KIcyName, iChannelInfo.iStationName );
+ ExtractMetaInfoL( KIcyGenre, iChannelInfo.iGenre );
+ ExtractMetaInfoL( KIcyBitrate, iChannelInfo.iBitRate );
+ // Extract the Content-Type header
+ ExtractMetaInfoL( KContentType, iChannelInfo.iContentType );
+ // Extract the content-type header ( invalid header name handling )
+ ExtractMetaInfoL( KContentTypeInvalid, iChannelInfo.iContentType );
+ RBuf8 metaIntervalBuf;
+ metaIntervalBuf.CreateL( KMAXMETABUFLENGTH );
+ metaIntervalBuf.CleanupClosePushL();
+
+ ExtractMetaInfoL( KIcyMetaint, metaIntervalBuf );
+
+ TLex8 convert( metaIntervalBuf );
+ convert.Val( iChannelInfo.iMetaInterval );
+
+ if ( iChannelInfo.iMetaInterval <= 0 ) // Invalid meta interval specified, the stream is corrupt and cannot be played.
+ {
+ IRLOG_ERROR( "CIRIcyFlowInitiator::ParseChannelInfoL - Invalid metainterval." );
+ User::Leave( KIRStreamSourceApplicationProtocolError );
+ }
+ CleanupStack::PopAndDestroy();
+
+ IRLOG_DEBUG( "CIRIcyFlowInitiator::ParseChannelInfoL - Exiting." );
+ }
+
+
+// ---------------------------------------------------------------------------
+// CIRIcyFlowInitiator::ExtractMetaInfoL
+// ---------------------------------------------------------------------------
+//
+TBool CIRIcyFlowInitiator::ExtractMetaInfoL(const TDesC8& aMetaField, TDes8 &aBuffer ) const
+ {
+ IRLOG_DEBUG2( "CIRIcyFlowInitiator::ExtractMetaInfoL - aMetaField = %S", &aMetaField );
+ // This function contains the logic for parsing the
+ // buffer obtained from RecieveMetaInfo() and
+ // appends the Meta info into the ChannelInfo structure
+ TInt offsetPositionStart( 0 );
+ TInt offsetPositionEnd( 0 );
+ TPtr8 startPos( NULL, 0 );
+
+ offsetPositionStart = iBuffer.Find( aMetaField );
+
+ if ( offsetPositionStart < 0 )
+ {
+ IRLOG_DEBUG( "CIRIcyFlowInitiator::ExtractMetaInfoL - Field not found, Exiting." );
+ return EFalse;
+ }
+ // Increment the offset by the length of meta field
+ offsetPositionStart += aMetaField.Length();
+
+ TPtrC8 start = iBuffer.Mid( offsetPositionStart );
+
+ offsetPositionEnd = start.Find( KCarReturn );
+
+ if ( offsetPositionEnd == KErrNotFound )
+ {
+ IRLOG_ERROR( "CIRIcyFlowInitiator::ExtractMetaInfoL - Field delimiter not found." );
+ User::Leave( KIRStreamSourceApplicationProtocolError );
+ }
+ // Extract the actual data
+ TPtrC8 data = start.Left( offsetPositionEnd );
+
+ // too large field for this implementation.
+ if (data.Length() > aBuffer.MaxLength() )
+ {
+ IRLOG_ERROR3( "CIRIcyFlowInitiator::ExtractMetaInfoL - Received field was too large (%d, allowed maximum = %d)",
+ data.Length(), aBuffer.Length() );
+ User::Leave( KIRStreamSourceApplicationProtocolError );
+ }
+
+ aBuffer.Copy( data );
+ aBuffer.TrimAll();
+ IRLOG_DEBUG( "CIRIcyFlowInitiator::ExtractMetaInfoL - Exiting." );
+ return ETrue;
+ }
+