internetradio2.0/streamsourcesrc/irstreamsource.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Mon, 19 Apr 2010 14:01:53 +0300
changeset 0 09774dfdd46b
permissions -rw-r--r--
Revision: 201011 Kit: 201015

/*
* 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;
	}