upnpmpxplugins/upnpplaybackplugins/src/upnpsingleton.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Fri, 17 Sep 2010 08:31:21 +0300
changeset 32 3785f754ee62
parent 0 7f85d04be362
permissions -rw-r--r--
Revision: 201035 Kit: 201037

/*
* Copyright (c) 2008 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:      Singleton class for main upnp related services
*
*/






// INCLUDES
#include <badesca.h>
#include "upnpavcontrollerfactory.h"
#include "upnpavcontroller.h"
#include "upnpavdevice.h"
#include "upnpavdevicelist.h"
#include "upnprendererselectorobserver.h"
#include "upnpsingleton.h"

// CONSTANTS
const TInt KDefaultGranularity = 5;
const TInt32 KRendererRequestTimeOut = 5000000;

_LIT( KComponentLogfile, "musicplugins.txt");
#include "upnplog.h"

// --------------------------------------------------------------------------
// Static members of CUPnPSingleton
// --------------------------------------------------------------------------
//

// reference count
TInt CUPnPSingleton::iInstanceCount = 0;

// reference count
CUPnPSingleton* CUPnPSingleton::iInstance = 0;

// default device index
TInt CUPnPSingleton::iDefaultRendererIndex;


// --------------------------------------------------------------------------
// CUPnPSingleton::GetInstanceL
// singleton constructor
// --------------------------------------------------------------------------
//
CUPnPSingleton* CUPnPSingleton::GetInstanceL()
    {
    if( iInstanceCount == 0 )
        {
        CUPnPSingleton* self = new(ELeave) CUPnPSingleton();
        CleanupStack::PushL( self );
        self->ConstructL();
        CleanupStack::Pop( self );
        iInstance = self;
        }

    ++iInstanceCount;
    return iInstance;
    }

// --------------------------------------------------------------------------
// CUPnPSingleton::CUPnPSingleton
// Default constructor.
// --------------------------------------------------------------------------
//
CUPnPSingleton::CUPnPSingleton()
    {
    }

// --------------------------------------------------------------------------
// CUPnPSingleton::ConstructL
// ConstructL.
// --------------------------------------------------------------------------
//
void CUPnPSingleton::ConstructL()
    {
    // Create timer for observing play time out.
    iPeriodizer = CUPnPMusicPeriodizer::NewL( *this,
        KRendererRequestTimeOut );

    // Create handle to AVController
    iAVController = UPnPAVControllerFactory::NewUPnPAVControllerL();
    iAVController->SetDeviceObserver( *this );
    CacheRendererListL();
    if ( iMediaRenderers.Count() > 0 )
        {
        iSelectorState = EStateReady;
        }
    else
        {
        iSelectorState = EStateWaiting;
        iPeriodizer->Start();
        }

    }

// --------------------------------------------------------------------------
// CUPnPSingleton::LoseInstance
// singleton desctuctor
// --------------------------------------------------------------------------
//
void CUPnPSingleton::LoseInstance( CUPnPSingleton* aInstance )
    {
    if( aInstance != 0 )
        {
        __ASSERTD( aInstance == iInstance,__FILE__, __LINE__ );
        __ASSERTD( iInstanceCount > 0,__FILE__, __LINE__ );
        --iInstanceCount;
        if( iInstanceCount == 0 )
            {
            delete iInstance;
            iInstance = 0;
            }
        }
    }

// --------------------------------------------------------------------------
// CUPnPSingleton::~CUPnPSingleton
// Destructor.
// --------------------------------------------------------------------------
//
CUPnPSingleton::~CUPnPSingleton()
    {
    __LOG("CUPnPSingleton::~CUPnPSingleton()");
    iMediaRenderers.ResetAndDestroy();
    delete iPeriodizer;
    if( iAVController )
        {
        iAVController->Release();
        }
    }

// --------------------------------------------------------------------------
// CUPnPSingleton::GetRendererNamesL
// Get renderes from AVController and return the renderer names.
// --------------------------------------------------------------------------
//  
void CUPnPSingleton::GetRendererNamesL(
    MUPnPRendererSelectorObserver& aObserver )
    {
    __ASSERTD( iRendererselectorObserver == 0,__FILE__, __LINE__ );
    iRendererselectorObserver = &aObserver;

    switch( iSelectorState )
        {
        case EStateWaiting:
            {
            __LOG("GetRendererNames: waiting");
            // wait for something to happen
            }
            break;
        case EStateComplete:
            {
            __LOG("GetRendererNames: complete->ready");
            DeliverNamesToObserverL( ETrue );
            iSelectorState = EStateReady;
            }
            break;
        case EStateReady:
            {
            CacheRendererListL();
            if ( iMediaRenderers.Count() > 0 )
                {
                __LOG("GetRendererNames: ready");
                DeliverNamesToObserverL( ETrue );
                }
            else
                {
                __LOG("GetRendererNames: ready->waiting");
                iSelectorState = EStateWaiting;
                iPeriodizer->Start();
                }
            }
            break;
        case EStateError:
            {
            __LOG("GetRendererNames: error");
            DeliverNamesToObserverL( ETrue, KErrDisconnected );
            }
            break;
        default:
            {
            __PANICD(__FILE__, __LINE__ );
            }
            break;
        }
    }

// --------------------------------------------------------------------------
// CUPnPSingleton::CancelGetRendererNames
// --------------------------------------------------------------------------
//
void CUPnPSingleton::CancelGetRendererNames()
    {
    // just clear the observer -> no callbacks will occur.
    iRendererselectorObserver = 0;
    }

// --------------------------------------------------------------------------
// CUPnPSingleton::SelectRendererByIndexL
// Select renderer by given index.
// --------------------------------------------------------------------------
//
const CUpnpAVDevice* CUPnPSingleton::SelectRendererByIndexL( TInt aIndex )
    {
     if( iMediaRenderers.Count() <= aIndex || aIndex < 0 )
        {        
        __LOG("CUPnPSingl::SelectRendererByIndexL error: Wrong index");
        User::Leave( KErrArgument );
        }
        
    if ( iRendererselectorObserver != 0 )
        {
        DeliverNamesToObserverL( ETrue );
        }

    if ( !IsAvailable( *iMediaRenderers[aIndex] ) )
        {
        __LOG("CUPnPSingl::SelectRendererByIndexL error: disconnected");
        User::Leave( KErrDisconnected );
        }

    iDefaultRendererIndex = aIndex;

    return iMediaRenderers[aIndex];
    }

// --------------------------------------------------------------------------
// CUPnPSingleton::DefaultDevice
// Return return pointer of current renderer
// --------------------------------------------------------------------------
//
const CUpnpAVDevice* CUPnPSingleton::DefaultDevice()
    {
    if ( iDefaultRendererIndex >= 0 )
        {
        return iMediaRenderers[iDefaultRendererIndex];
        }
    else
        {
        return 0;
        }
    }

// --------------------------------------------------------------------------
// CUPnPSingleton::AVC
// Provides reference to the AVController resource
// --------------------------------------------------------------------------
//
MUPnPAVController& CUPnPSingleton::AVC()
    {
    return *iAVController;
    }

    
// --------------------------------------------------------------------------
// Method from MUPnPAVMediaObserver
// --------------------------------------------------------------------------

// --------------------------------------------------------------------------
// CUPnPSingleton::UPnPDeviceDiscovered
// Inform that new renderer device has discovered.
// --------------------------------------------------------------------------
//
void CUPnPSingleton::UPnPDeviceDiscovered( const CUpnpAVDevice& aDevice  )
    {
    // Check if device is media renderer
    if( aDevice.DeviceType() == CUpnpAVDevice::EMediaRenderer 
        && aDevice.AudioCapability() )
        {
        if ( iSelectorState == EStateWaiting ||
             iSelectorState == EStateComplete )
            {
            CUpnpAVDevice* dev = 0;
            TRAP_IGNORE( dev = CUpnpAVDevice::NewL( aDevice ) );
            if( dev )
                {
                iMediaRenderers.AppendL( dev );
                if ( iRendererselectorObserver != 0 )
                    {
                    TRAP_IGNORE( DeliverNamesToObserverL( EFalse ) );
                    }
                }
            }
        }
    else
        {
        // Do nothing with media servers
        }
    }

// --------------------------------------------------------------------------
// CUPnPSingleton::UPnPDeviceDisappeared
// Inform that renderer device has disappeared.
// --------------------------------------------------------------------------
//   
void CUPnPSingleton::UPnPDeviceDisappeared( const CUpnpAVDevice& aDevice )
    {
    // Check if device is media renderer
    if( aDevice.DeviceType() == CUpnpAVDevice::EMediaRenderer 
        && aDevice.AudioCapability() )
        {
        if ( iSelectorState == EStateWaiting ||
             iSelectorState == EStateComplete )
            {
            // In monitoring state. Remove the renderer from cache.
            TInt count = iMediaRenderers.Count();
            for( TInt i = 0; i < count; i++ )
                {
                if( aDevice.Uuid().Compare(
                    iMediaRenderers[i]->Uuid() ) == 0 )
                    {
                    iMediaRenderers.Remove(i);
                    // we removed an renderer from the list so we want to 
                    // continue the loop with the same i.
                    // Could break here if absolutely sure that there are 
                    // no duplicates in iMediaRenderers.
                    count--;
                    i--; 
                    }
                }
            if ( iRendererselectorObserver != 0 )
                {
                TRAP_IGNORE( DeliverNamesToObserverL( EFalse ) );
                }
            }
        else if ( iSelectorState == EStateReady )
            {
            // Device disappears in ready state. Can't remove from cache
            // (because we use indexing to select to renderers)
            // instead mark the renderer unusable.
            __LOG( "Singleton: renderer disappeared in Ready state" );
            TInt count = iMediaRenderers.Count();
            TBool done = EFalse;
            for( TInt i = 0; i < count && !done; i++ )
                {
                if( aDevice.Uuid().Compare(
                    iMediaRenderers[i]->Uuid() ) == 0 )
                    {
                    SetAvailable( *iMediaRenderers[i], EFalse );
                    done = ETrue;
                    }
                }
            }
        }
    else
        {
        // Do nothing with media servers
        }
    }

// --------------------------------------------------------------------------
// CUPnPSingleton::WLANConnectionLost
// Inform that renderer device has disappeared.
// --------------------------------------------------------------------------
// 
void CUPnPSingleton::WLANConnectionLost()
    {
    iMediaRenderers.ResetAndDestroy();
    if ( iSelectorState == EStateWaiting )
        {
        iPeriodizer->Stop();
        }

    iSelectorState = EStateError;

    if ( iRendererselectorObserver != 0 )
        {
        TRAP_IGNORE( DeliverNamesToObserverL( ETrue, KErrDisconnected ) );
        }
    }

// --------------------------------------------------------------------------
// Methods of MUPnPMusicPeriodizerObserver
// --------------------------------------------------------------------------

// --------------------------------------------------------------------------
// CUPnPSingleton::HandlePeriod
// Action when timer has expired.
// --------------------------------------------------------------------------
// 
void CUPnPSingleton::HandlePeriod()
    {
    __ASSERTD( iSelectorState == EStateWaiting,__FILE__, __LINE__ );

    if ( iMediaRenderers.Count() > 0 )
        {
        __LOG("GetRendererNames: timeout->complete");
        iSelectorState = EStateComplete;
        if ( iRendererselectorObserver != 0 )
            {
            __LOG("GetRendererNames: complete->ready");
            iSelectorState = EStateReady;
            TRAP_IGNORE( DeliverNamesToObserverL( ETrue ) );
            }
        }
    else
        {
        __LOG("GetRendererNames: timeout->continue timer");
        iPeriodizer->Continue();
        if ( iRendererselectorObserver != 0 )
            {
            TRAP_IGNORE( DeliverNamesToObserverL( ETrue ) );
            }
        }
    }

// --------------------------------------------------------------------------
// Private methods of CUPnPRendererSelector
// --------------------------------------------------------------------------

// --------------------------------------------------------------------------
// CUPnPSingleton::CacheRendererListL
// Refreshes the renderer cache from AVController
// --------------------------------------------------------------------------
// 
void CUPnPSingleton::CacheRendererListL()
    {
    // Clean old devices array and device names
    iDefaultRendererIndex = KErrNotFound;

    // Get media renderers
    CUpnpAVDeviceList* devices = iAVController->GetMediaRenderersL();
    CleanupStack::PushL( devices );

    // go through current renderer list
    for ( TInt i = 0; i < iMediaRenderers.Count(); ++i )
        {
        CUpnpAVDevice* renderer = iMediaRenderers[ i ];
        TBool exists = EFalse;
        for ( TInt j = 0; j < devices->Count() && !exists; ++j )
            {
            CUpnpAVDevice* device = (*devices)[j];
            if ( renderer->Uuid() == device->Uuid())
                {
                // renderer still exists.
                delete device;
                devices->Remove( j );
                SetAvailable( *renderer, ETrue );
                --j;
                exists = ETrue;
                }
            }
        if ( !exists )
            {
            // renderer has disappeared
            delete renderer;
            iMediaRenderers.Remove( i );
            --i;
            }
        }

    // Remaining devices are all new. Add them to end of the list.
    while ( devices->Count() > 0 )
        {
         __LOG("CacheRendererListL::Remaining devices are all new.");
        CUpnpAVDevice* device = (*devices)[ 0 ];
        if( device->AudioCapability() )
            {
            iMediaRenderers.AppendL( device );
            }
        devices->Remove( 0 );
        }

    CleanupStack::PopAndDestroy( devices ); 
    }

// --------------------------------------------------------------------------
// CUPnPSingleton::DeliverNamesToObserverL
// Delivers current names in cached list to observer
// --------------------------------------------------------------------------
// 
void CUPnPSingleton::DeliverNamesToObserverL( TBool aCompleted,
    TInt aError )
    {
    __ASSERTD( iRendererselectorObserver != 0,__FILE__, __LINE__ );

    // Create an array for names
    CDesCArrayFlat* deviceNames = new(ELeave) CDesCArrayFlat( 
        KDefaultGranularity );
    CleanupStack::PushL( deviceNames );

    TInt count = iMediaRenderers.Count();
    for( TInt i = 0; i < count; i++ )
        {
        HBufC* buf = HBufC::NewL(
            iMediaRenderers[i]->FriendlyName().Length() );
        CleanupStack::PushL( buf );
        buf->Des().Copy( iMediaRenderers[i]->FriendlyName() );
        deviceNames->AppendL( *buf ); // Transfer ownership
        CleanupStack::PopAndDestroy( buf );
        }

    // Call back current renderer names
    __LOG1( "DeliverNamesToObserver: count=%d", count );
    MUPnPRendererSelectorObserver& obs = *iRendererselectorObserver;
    iRendererselectorObserver = 0;
    obs.HandleSubPlayerNames( deviceNames, aCompleted, aError );

    CleanupStack::PopAndDestroy( deviceNames );
    }

// --------------------------------------------------------------------------
// CUPnPSingleton::IsAvailable
// checks if the device type is renderer
// --------------------------------------------------------------------------
// 
TBool CUPnPSingleton::IsAvailable( const CUpnpAVDevice& aDevice ) const
    {
    return aDevice.DeviceType() == CUpnpAVDevice::EMediaRenderer;
    }

// --------------------------------------------------------------------------
// CUPnPSingleton::SetAvailable
// sets the device type to an illegal unrecognized type
// --------------------------------------------------------------------------
// 
void CUPnPSingleton::SetAvailable(
    CUpnpAVDevice& aDevice, TBool aAvailable ) const
    {
    if ( aAvailable && !IsAvailable( aDevice ) )
        {
        __LOG1( "CUPnPSingleton: renderer available: %S",
            &aDevice.FriendlyName() );
        aDevice.SetDeviceType(
            CUpnpAVDevice::EMediaRenderer );
        }
    else if ( !aAvailable && IsAvailable ( aDevice ) )
        {
        __LOG1( "CUPnPSingleton: renderer not available: %S",
            &aDevice.FriendlyName() );
        aDevice.SetDeviceType(
            (CUpnpAVDevice::TUpnpAVDeviceType)KErrUnknown );
        }
    }