internetradio2.0/streamsourcesrc/irstreamsource.cpp
changeset 0 09774dfdd46b
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/internetradio2.0/streamsourcesrc/irstreamsource.cpp	Mon Apr 19 14:01:53 2010 +0300
@@ -0,0 +1,425 @@
+/*
+* 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:  Stream source main class implementation
+*
+*/
+
+
+#include <e32property.h>
+#include "irpubsubkeys.h"
+
+#include "irdebug.h"
+#include "irnetworkcontroller.h"
+#include "irstreamsource.h"
+#include "irstreamsourceerrors.h"
+#include "irstreamsourceobserver.h"
+#include "irstationconnection.h"
+
+
+// Constants
+const TInt KIRSCConnectionCleanupDelay = 10000000;
+const TInt KHundred = 100;
+
+// ---------------------------------------------------------------------------
+//  CIRStreamSource::ConnectToServerL
+// ---------------------------------------------------------------------------
+//
+EXPORT_C void CIRStreamSource::ConnectToServerL( const TDesC& aUrl )
+    {
+    IRLOG_INFO2( "CIRStreamSource::ConnectToServerL - aUrl=%S", &aUrl );
+	#ifndef __WINS__
+	 					 	 
+    //Connecting for the first time
+ /*****************************testing*****************/
+    	/*if ( iCurrentConnection )	
+	    {
+	    iCurrentConnection->Close();
+	    }
+	AsyncCleanupConnection( iCurrentConnection );
+    iCurrentConnection = NULL;*/
+/*****************************************************/
+   	
+   		#endif //__WINS__
+    if ( iNetworkControllerHandle->GetNetworkStatus() )
+        {
+        iReConnecting = EFalse;
+        DoConnectL( aUrl );    
+        }
+    else
+	    {
+		iStreamSourceObserver.ErrorConnecting( KIRStreamSourceConnectionError );
+	    }
+    IRLOG_DEBUG( "CIRStreamSource::ConnectToServerL - Exiting." );
+	}
+
+// ---------------------------------------------------------------------------
+//  CIRStreamSource::ReconnectL
+// ---------------------------------------------------------------------------
+//
+EXPORT_C void CIRStreamSource::ReconnectL( const TDesC& aUrl )
+    {
+    IRLOG_INFO( "CIRStreamSource::ReconnectL" );
+	if ( iNetworkControllerHandle->GetNetworkStatus() )
+	    {
+        iReConnecting = ETrue;
+        DoConnectL( aUrl );
+	    }
+	else
+		{
+		iStreamSourceObserver.ErrorConnecting( KIRStreamSourceConnectionError );
+		}
+    IRLOG_DEBUG( "CIRStreamSource::ReconnectL - Exiting." );
+	}
+	
+// ---------------------------------------------------------------------------
+//  CIRStreamSource::DoConnectL
+//  Creates the connection object which initiates the connection
+//  to the channel server
+// ---------------------------------------------------------------------------
+//
+void CIRStreamSource::DoConnectL( const TDesC& aUrl )
+	{
+    IRLOG_INFO2( "CIRStreamSource::DoConnectL iCurrentConn=%d", iCurrentConnection );	
+
+    AsyncCleanupConnection( iNewConnection );
+    iNewConnection = NULL;        
+    StaticConnectionCleanupCallback( this ); // delete it (and them) now
+
+    CIRStationConnection* connection = CIRStationConnection::NewL( *this, *this );
+    CleanupStack::PushL( connection );
+    iConnections.AppendL( connection );
+    CleanupStack::Pop( connection );
+    iNewConnection = connection;
+    
+    iNewConnection->ConnectL( aUrl );
+    
+	IRLOG_INFO2( "CIRStreamSource::DoConnectL - Exiting, iNewConnection=%d.", iNewConnection );
+	}
+
+// ---------------------------------------------------------------------------
+//  CIRStreamSource::CIRStreamSource
+//  Default Constructor
+// ---------------------------------------------------------------------------
+//
+CIRStreamSource::CIRStreamSource( MIRStreamSourceObserver &aObserver ):
+	iStreamSourceObserver( aObserver )
+    {
+	// no implementation
+    }
+
+// ---------------------------------------------------------------------------
+// CIRStreamSource::~CIRStreamSource
+// Default Destructor
+// ---------------------------------------------------------------------------
+//
+CIRStreamSource::~CIRStreamSource()
+    {    
+    IRLOG_DEBUG( "CIRStreamSource::~CIRStreamSource" );
+	
+    // close the network controller handle	
+	if( iNetworkControllerHandle )
+		{
+		iNetworkControllerHandle->Close();	
+        }
+	delete iSocketTimer;
+    
+    delete iConnectionCleanupTimer;
+    
+    iConnections.ResetAndDestroy();
+    iConnections.Close();
+    }
+
+// --------------------------------------------------------------------------- 
+//  CIRStreamSource::NewL
+// ---------------------------------------------------------------------------
+//
+EXPORT_C CIRStreamSource *CIRStreamSource::NewL( MIRStreamSourceObserver   &aObserver )
+    {
+    CIRStreamSource *self = new( ELeave ) CIRStreamSource( aObserver );
+    CleanupStack::PushL( self );
+    self->ConstructL();
+    CleanupStack::Pop( self );
+    return self;
+    }
+
+// ---------------------------------------------------------------------------
+// CIRStreamSource::ConstructL
+// ---------------------------------------------------------------------------
+//
+void CIRStreamSource::ConstructL()
+    {
+    // Open handle to network controller
+    iNetworkControllerHandle = CIRNetworkController::OpenL();
+    // create a timer for timeouts
+    iSocketTimer = CIRSocketTimeOutTimer::NewL( CActive::EPriorityHigh,	*this ); 
+    }
+
+// --------------------------------------------------------------------------- 
+//  CIRStreamSource::FilltheBuffer
+// ---------------------------------------------------------------------------
+//
+EXPORT_C void CIRStreamSource::FilltheBuffer( TDes8& aInputBuffer )
+    {
+    IRLOG_DEBUG( "CIRStreamSource::FilltheBuffer" );
+
+    if( iCurrentConnection )
+    	{
+   	 	iCurrentConnection->FillBuffer( aInputBuffer );
+    	}
+    else
+    	{
+    	iReConnecting = ETrue;
+    	iStreamSourceObserver.ErrorConnecting( KIRStreamSourceNoResponse );
+    	}
+    IRLOG_DEBUG( "CIRStreamSource::FilltheBuffer - Exiting." );
+    }
+
+// ---------------------------------------------------------------------------
+// CIRStreamSource::TimerExpired
+// ---------------------------------------------------------------------------
+//
+void CIRStreamSource::TimerExpired()
+	{
+	// CancelRequest gets called by UI.We could of course call it here, but you never
+	// know what it would cause in UI without thorough testing.
+	iStreamSourceObserver.ErrorConnecting( KIRStreamSourceTimeOut );
+	}
+
+// ---------------------------------------------------------------------------
+// CIRStreamSource::TimerExpired
+// ---------------------------------------------------------------------------
+//
+void CIRStreamSource::MetadataReceived( const CIRMetaData& aMetaData )
+    {
+    TRAP_IGNORE( iStreamSourceObserver.HandleMetaDataReceivedL( aMetaData ) )
+    }
+
+// ---------------------------------------------------------------------------
+// CIRStreamSource::AudioDataEvent
+// ---------------------------------------------------------------------------
+//
+void CIRStreamSource::AudioDataEvent( const TInt aResponseCode,	TInt aValue )
+	{
+	IRLOG_DEBUG3( "CIRStreamSource::AudioDataEvent - aResponseCode=%d, aFeedValue=%d", aResponseCode, aValue );
+	switch( aResponseCode )
+		{
+		case EBufferFilled:
+			{
+			IRLOG_DEBUG( "CIRStreamSource::AudioDataEvent - EBufferFilled" );
+			// Indicate the observer
+			if( !iReConnecting )
+				{
+				iStreamSourceObserver.PlayNow();
+				}
+			else
+				{
+				iStreamSourceObserver.Play();	
+				}
+			}
+			break;
+		case EOpenComplete:
+			{
+			IRLOG_DEBUG( "CIRStreamSource::AudioDataEvent - EOpenComplete" );
+			// Indicate the observer that streamsource buffering complete	
+			iStreamSourceObserver.OpenComplete();
+			}
+			break;
+		case EBufferPercentage:
+			{
+			// Indicate buffering progress to observer
+			iStreamSourceObserver.UpdateProgress( aValue );
+			if ( aValue == KHundred )
+				{
+			    IRLOG_INFO( "CIRStreamSource::AudioDataEvent - 100 percent EBufferPercentage" );				
+				iSocketTimer->Cancel();
+				} 
+			}
+			break;
+		default:
+			{
+			__ASSERT_DEBUG( EFalse, User::Invariant() );
+			}
+			break;	
+		}
+	IRLOG_DEBUG( "CIRStreamSource::AudioDataEvent - Exiting." );	
+	}
+	
+// ---------------------------------------------------------------------------
+//  CIRStreamSource::ContentTypeL
+// ---------------------------------------------------------------------------
+//
+EXPORT_C const TDesC8& CIRStreamSource::ContentTypeL()
+	{
+    __ASSERT_ALWAYS( iCurrentConnection, User::Leave( KErrNotReady ) );
+
+    return iCurrentConnection->ContentType();
+	}
+
+// ---------------------------------------------------------------------------
+// CIRStreamSource::CancelRequest
+// ---------------------------------------------------------------------------
+//
+EXPORT_C void CIRStreamSource::CancelRequest()
+	{
+	IRLOG_INFO3( "CIRStreamSource::CancelRequest - iNewConnection=%d, iCurrentConnection=%d", iNewConnection, iCurrentConnection );	
+	iSocketTimer->Cancel();
+		
+    if ( iNewConnection )		
+        {
+        iNewConnection->Close();
+        AsyncCleanupConnection( iNewConnection );
+        iNewConnection = NULL;
+        }
+    else
+        {
+		if ( iCurrentConnection )
+		    {
+		    iCurrentConnection->Close();		    
+		    }
+		AsyncCleanupConnection( iCurrentConnection );
+		iCurrentConnection = NULL;
+        }        
+	IRLOG_DEBUG( "CIRStreamSource::CancelRequest - Exiting." );	
+	}
+
+// ---------------------------------------------------------------------------
+// CIRStreamSource::ConnectionSuccessfulL
+// ---------------------------------------------------------------------------
+//
+void CIRStreamSource::ConnectionSuccessful( CIRStationConnection* aConnection )
+	{
+	IRLOG_INFO3( "CIRStreamSource::ConnectionSuccessful aConnection=%d, iCurrentConn=%d", 
+	             aConnection, iCurrentConnection );	
+	__ASSERT_DEBUG( aConnection->ConnectionType() == CIRStationConnection::EIRCandidate,
+	                User::Invariant() );
+	                
+    // publish the url
+    RProperty::Set( KUidActiveInternetRadioApp, KIRPSChannelUrl, aConnection->Uri() );	
+
+	if( !iReConnecting )
+		{
+		iStreamSourceObserver.StopBuffering();
+	    }	
+	    
+	if ( iCurrentConnection )	
+	    {
+	    iCurrentConnection->Close();
+	    }
+	AsyncCleanupConnection( iCurrentConnection );
+    iCurrentConnection = NULL;
+
+    aConnection->SetConnectionType( CIRStationConnection::EIRPermanent );
+    iCurrentConnection = aConnection;
+    iNewConnection = NULL;
+
+    iStreamSourceObserver.ConnectionEstablished();
+    // Buffering starts now, so let's set the timer.
+	TTimeIntervalMicroSeconds32 timeOut( KBufferingTimeOut );
+	iSocketTimer->Cancel();
+	iSocketTimer->After( timeOut );
+
+	IRLOG_DEBUG( "CIRStreamSource::ConnectionSuccessful - Exiting." );	
+	}
+
+// ---------------------------------------------------------------------------
+// CIRStreamSource::ConnectionError
+// ---------------------------------------------------------------------------
+//
+void CIRStreamSource::ConnectionError( CIRStationConnection* aConnection, TInt aErrorCode )
+	{
+	IRLOG_ERROR3( "CIRStreamSource::ConnectionError - aConnection=%d, aErrorCode=%d", aConnection, aErrorCode );
+    
+	if ( aConnection->ConnectionType() == CIRStationConnection::EIRCandidate )
+	    {
+        AsyncCleanupConnection( aConnection );
+        iNewConnection = NULL; // To Do: implement more sophisticated pending connection handling.	    
+		iReConnecting = ETrue;        
+	    }
+    else
+        {
+        if ( aErrorCode == KIRStreamSourceDisconnected )
+            {
+			CancelRequest();            
+            }
+        }	    
+	iStreamSourceObserver.ErrorConnecting( aErrorCode );
+	IRLOG_DEBUG( "CIRStreamSource::ConnectionError - Exiting." );
+	}
+
+// ---------------------------------------------------------------------------
+// CIRStreamSource::AsyncCleanupConnection
+// ---------------------------------------------------------------------------
+//
+void CIRStreamSource::AsyncCleanupConnection( CIRStationConnection* aConnection )
+    {
+    IRLOG_DEBUG2( "CIRStreamSource::AsyncCleanupConnection - aConnection=%d.", aConnection );    
+    // let's not double-add any connections.
+    if ( aConnection )
+        {
+        IRLOG_INFO2( "CIRStreamSource::AsyncCleanupConnection - Scheduled deletion of connection %d.", aConnection );            
+        delete iConnectionCleanupTimer;
+        iConnectionCleanupTimer = NULL;
+        TRAPD( err, iConnectionCleanupTimer = CPeriodic::NewL( CActive::EPriorityStandard ) )
+        if ( err == KErrNone )
+            {
+            iConnectionCleanupTimer->Start( KIRSCConnectionCleanupDelay, 0,
+            			 TCallBack( StaticConnectionCleanupCallback, this ) );
+            }
+        else
+            {
+            IRLOG_ERROR2( "CIRStreamSource::AsyncCleanupConnection - CPeriodic creation left with %d.", err );
+            // delete the existing dying connections.
+            StaticConnectionCleanupCallback( this );    
+            }
+        aConnection->SetConnectionType( CIRStationConnection::EIRDying );                    
+        }
+    IRLOG_DEBUG( "CIRStreamSource::AsyncCleanupConnection - Exiting." );                    
+    }
+
+// ---------------------------------------------------------------------------
+// CIRStreamSource::StaticConnectionCleanupCallback
+// ---------------------------------------------------------------------------
+//
+TInt CIRStreamSource::StaticConnectionCleanupCallback( TAny* aSelfPtr )
+	{
+	CIRStreamSource* self = reinterpret_cast<CIRStreamSource*>( aSelfPtr );
+	if ( self )
+		{
+	IRRDEBUG2("CIRStreamSource::StaticConnectionCleanupCallback - Entering", KNullDesC );
+
+        IRLOG_DEBUG( "CIRStreamSource::StaticConnectionCleanupCallback." );
+		delete self->iConnectionCleanupTimer;
+		self->iConnectionCleanupTimer = NULL;
+		TInt it = self->iConnections.Count() - 1;
+		while ( it >= 0 )
+		    {
+		    if ( self->iConnections[it]->ConnectionType() == CIRStationConnection::EIRDying )
+		        {
+		 IRRDEBUG2("CIRStreamSource::StaticConnectionCleanupCallback - Entering1", KNullDesC );
+        IRLOG_INFO2( "CIRStreamSource::StaticConnectionCleanupCallback - Deleting connection %d.", 
+                self->iConnections[it] );		    		        
+        delete self->iConnections[it];
+        self->iConnections.Remove( it );
+		 IRRDEBUG2("CIRStreamSource::StaticConnectionCleanupCallback - Exiting1", KNullDesC );
+
+		        }
+		    it--;
+		    }
+	IRRDEBUG2("CIRStreamSource::StaticConnectionCleanupCallback - Exiting", KNullDesC );
+
+        IRLOG_DEBUG( "CIRStreamSource::StaticConnectionCleanupCallback - Exiting." );		    
+		}
+	return KErrNone;
+	}
+