diff -r 000000000000 -r 7f85d04be362 upnpmpxplugins/upnpplaybackplugins/src/upnpsingleton.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/upnpmpxplugins/upnpplaybackplugins/src/upnpsingleton.cpp Thu Dec 17 08:52:00 2009 +0200 @@ -0,0 +1,548 @@ +/* +* 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 +#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.Append( 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.Append( 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 ); + } + }