internetradio2.0/streamsourcesrc/iricyflowinitiator.cpp
changeset 0 09774dfdd46b
--- /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:
+*  <ccm_history>
+*
+*  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
+*
+*  </ccm_history>
+* ============================================================================
+*/
+
+#include <e32property.h>
+#include <es_sock.h>
+#include <in_sock.h>
+#include <uriutils.h>
+
+#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;
+    }
+