--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/upnpframework/upnpcommand/src/upnpimagerenderingengine.cpp Thu Dec 17 08:52:00 2009 +0200
@@ -0,0 +1,683 @@
+/*
+* Copyright (c) 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: Engine for rendering images remotely
+*
+*/
+
+
+// INCLUDE FILES
+// upnp stack api
+#include <upnpitem.h> // CUpnpItem
+#include <upnpobject.h> // CUpnpObject (cast)
+
+// upnpframework / avcontroller api
+#include "upnpavrenderingsession.h" // MUPnPAVRenderingSession
+#include "upnpavsessionobserverbase.h"
+
+// upnpframework / avcontroller helper api
+#include "upnpconstantdefs.h" // KFilterCommon
+#include "upnpitemresolver.h" // MUPnPItemResolver
+#include "upnpitemresolverobserver.h" // MUPnPItemResolverObserver
+#include "upnpitemresolverfactory.h" // UPnPItemResolverFactory
+#include "upnpitemutility.h" // UPnPItemUtility::BelongsToClass
+
+// upnpframework / commonui
+#include "upnpcommonui.h" // common UI for upnp video player dlg
+
+// command internal
+#include "upnpimagerenderingengineobserver.h" // the observer interface
+#include "upnpimagerenderingengine.h" // myself
+#include "upnpperiodic.h"
+
+_LIT( KComponentLogfile, "upnpcommand.log");
+#include "upnplog.h"
+
+// CONSTANT DEFINITIONS
+const TInt KReactionTimerMicrosec = 100000; // 100 millisec.
+
+
+// --------------------------------------------------------------------------
+// CUpnpImageRenderingEngine::NewL
+// --------------------------------------------------------------------------
+//
+CUpnpImageRenderingEngine* CUpnpImageRenderingEngine::NewL(
+ MUPnPAVController& aAVController,
+ MUPnPAVRenderingSession& aSession,
+ MUpnpImageRenderingEngineObserver& aObserver )
+ {
+ __LOG( "[UpnpCommand]\t CUpnpImageRenderingEngine::NewL" );
+
+ // Create instance
+ CUpnpImageRenderingEngine* self = NULL;
+ self = new (ELeave) CUpnpImageRenderingEngine(
+ aAVController, aSession, aObserver );
+ CleanupStack::PushL( self );
+ self->ConstructL( );
+ CleanupStack::Pop( self );
+ return self;
+ }
+
+// --------------------------------------------------------------------------
+// CUpnpImageRenderingEngine::CUpnpImageRenderingEngine
+// --------------------------------------------------------------------------
+//
+CUpnpImageRenderingEngine::CUpnpImageRenderingEngine(
+ MUPnPAVController& aAVController,
+ MUPnPAVRenderingSession& aSession,
+ MUpnpImageRenderingEngineObserver& aObserver )
+ : iAVController( aAVController )
+ , iRenderingSession( aSession )
+ , iObserver( aObserver )
+ {
+ __LOG( "[UpnpCommand]\t CUpnpImageRenderingEngine: Constructor" );
+
+ // Initialise member variables
+ iState = EIdle;
+ iCurrentResolver = 0;
+ iBufferedResolver = 0;
+
+ // set observer
+ iRenderingSession.SetObserver( *this );
+ }
+
+// --------------------------------------------------------------------------
+// Second phase constructor.
+// --------------------------------------------------------------------------
+//
+void CUpnpImageRenderingEngine::ConstructL()
+ {
+ __LOG( "[UpnpCommand]\t CUpnpImageRenderingEngine::ConstructL" );
+ iTimer = CUPnPPeriodic::NewL( CActive::EPriorityStandard );
+
+ iWlanActive = ETrue;
+ }
+
+// --------------------------------------------------------------------------
+// Destructor.
+// --------------------------------------------------------------------------
+//
+CUpnpImageRenderingEngine::~CUpnpImageRenderingEngine()
+ {
+ __LOG( "[UpnpCommand]\t CUpnpImageRenderingEngine: Destructor" );
+
+ Cleanup();
+
+ // Stop observing the rendering session
+ iRenderingSession.RemoveObserver();
+
+ __LOG( "[UpnpCommand]\t CUpnpImageRenderingEngine::~CUpnpImageRenderingEngine delete iCurrentResolver" );
+ MUPnPItemResolver* tempCurrentResolver = iCurrentResolver;
+ iCurrentResolver = NULL;
+ delete tempCurrentResolver;
+
+ if( iTimer )
+ {
+ iTimer->Cancel();
+ delete iTimer;
+ iTimer = 0;
+ }
+ }
+
+// --------------------------------------------------------------------------
+// CUpnpImageRenderingEngine::Cleanup
+// --------------------------------------------------------------------------
+//
+void CUpnpImageRenderingEngine::Cleanup()
+ {
+ __LOG( "[UpnpCommand]\t CUpnpImageRenderingEngine::Cleanup" );
+
+ // reset state
+ if ( iState != EShuttingDown )
+ {
+ iState = EIdle;
+ }
+
+ if( iTimer )
+ {
+ iTimer->Cancel();
+ }
+
+ iBufferingNewImage = EFalse;
+
+ // Delete resolvers
+ // Delete for resolvers is done using temporary variables so that we can
+ // first nullify the members and then delete the actual objects.
+ // This is because local resolver deletion uses active scheduler loops
+ // and therefore other asynchronous events may orrur. So we may end
+ // up here in Cleanup again, during the resolver is being deleted.
+ // if deletion is done the conventional way, the objects get deleted
+ // twice, which is not what we want. :-)
+
+ __LOG( "[UpnpCommand]\t CUpnpImageRenderingEngine::Cleanup delete iBufferedResolver" );
+ MUPnPItemResolver* tempBufferedResolver = iBufferedResolver;
+ iBufferedResolver = NULL;
+ delete tempBufferedResolver;
+
+ __LOG( "[UpnpCommand]\t CUpnpImageRenderingEngine::Cleanup end" );
+ }
+
+// --------------------------------------------------------------------------
+// CUpnpImageRenderingEngine::PlayL
+// --------------------------------------------------------------------------
+//
+void CUpnpImageRenderingEngine::PlayL()
+ {
+ __LOG1( "[UpnpCommand]\t CUpnpImageRenderingEngine::PlayL in state %d",
+ iState);
+
+ if ( iState != EShuttingDown )
+ {
+ if( iTimer->IsActive() )
+ {
+ __LOG( "[UpnpCommand]\t timer already active" );
+ }
+ else
+ {
+ TTimeIntervalMicroSeconds32 delay( KReactionTimerMicrosec );
+ iTimer->Start( delay, delay, TCallBack( Timer, this ) );
+ }
+ }
+ else
+ {
+ __LOG( "[UpnpCommand]\t not doing play in shutting down state" );
+ }
+ }
+
+// --------------------------------------------------------------------------
+// CUpnpImageRenderingEngine::StopL
+// --------------------------------------------------------------------------
+//
+void CUpnpImageRenderingEngine::StopL()
+ {
+ __LOG1( "[UpnpCommand]\t CUpnpImageRenderingEngine::StopL in state %d",
+ iState);
+
+ // cancel any timers that are going on
+ iTimer->Cancel();
+
+ // remove buffered images
+ iBufferingNewImage = EFalse;
+ delete iBufferedResolver;
+ iBufferedResolver = 0;
+
+ switch( iState )
+ {
+ case EIdle:
+ case EResolvingItem:
+ case EResolveComplete:
+ case ESettingUri: // fall through
+ {
+ // just cancel the sequence and do nothing
+ iState = EIdle;
+ break;
+ }
+ case EStartingPlay:
+ {
+ // wait for PLAY complete, then do STOP
+ // then wait for STOP complete
+ iState = EStopping;
+ break;
+ }
+ case EPlaying:
+ {
+ // Send stop action.
+ iRenderingSession.StopL();
+ iState = EStopping;
+ break;
+ }
+ case EStopping:
+ {
+ // already stopping - do nothing
+ break;
+ }
+ case EShuttingDown:
+ {
+ // command not allowed in this state
+ break;
+ }
+ default:
+ {
+ __PANICD( __FILE__, __LINE__ );
+ break;
+ }
+ }
+ }
+
+// --------------------------------------------------------------------------
+// CUpnpImageRenderingEngine::Timer
+// timer callback
+// --------------------------------------------------------------------------
+//
+TInt CUpnpImageRenderingEngine::Timer( TAny* aArg )
+ {
+ CUpnpImageRenderingEngine* self =
+ static_cast<CUpnpImageRenderingEngine*>( aArg );
+ TRAPD( error, self->RunTimerL() )
+ if ( error != KErrNone )
+ self->RunError( error );
+ return 0; // do not call again
+ }
+
+// --------------------------------------------------------------------------
+// CUpnpImageRenderingEngine::RunTimerL
+// Timer has triggered, start rendering media.
+// --------------------------------------------------------------------------
+//
+void CUpnpImageRenderingEngine::RunTimerL()
+ {
+ __LOG1( "[UpnpCommand]\t CUpnpImageRenderingEngine::RunTimerL, state %d",
+ iState );
+
+ iTimer->Cancel();
+
+ delete iBufferedResolver;
+ iBufferedResolver = iObserver.GetMedia();
+ if ( iBufferedResolver == 0 )
+ {
+ __LOG( "[UpnpCommand]\t resolver returned zero" );
+ User::Leave( KErrCancel );
+ }
+
+ switch( iState )
+ {
+ case EIdle: // fall through
+ {
+ StartResolvingL();
+ break;
+ }
+ case EResolvingItem: // fall through
+ case EResolveComplete:
+ case ESettingUri: // fall through
+ case EStartingPlay:
+ {
+ // indicate that new image is being buffered. It will be popped
+ // from buffer in next callback.
+ iBufferingNewImage = ETrue;
+ break;
+ }
+ case EPlaying:
+ {
+ // indicate that new image is being buffered. Send stop signal.
+ // new item will be handled after stop completed.
+ iBufferingNewImage = ETrue;
+ iRenderingSession.StopL();
+ iState = EStopping;
+ break;
+ }
+ case EStopping:
+ {
+ // indicate that new image is being buffered. It will be popped
+ // from buffer in next callback.
+ iBufferingNewImage = ETrue;
+ break;
+ }
+ case EShuttingDown:
+ {
+ // command not allowed in this state
+ break;
+ }
+ default:
+ {
+ __PANICD( __FILE__, __LINE__ );
+ break;
+ }
+ }
+ }
+
+// --------------------------------------------------------------------------
+// CUpnpImageRenderingEngine::StartResolvingL
+// Handles the start up of the item resolving.
+// --------------------------------------------------------------------------
+//
+void CUpnpImageRenderingEngine::StartResolvingL()
+ {
+ __LOG1( "[UpnpCommand]\t CUpnpImageRenderingEngine::StartResolvingL\
+ in state %d",
+ iState );
+
+ __ASSERTD( iBufferedResolver, __FILE__, __LINE__ );
+ if ( !iBufferedResolver )
+ {
+ // something is very wrong
+ User::Leave( KErrDisconnected );
+ }
+
+ // delete old resolver
+ // destruction takes time due to unsharing, so set to null first
+ // so that this wont be used else where
+ MUPnPItemResolver* tempCurrentResolver = iCurrentResolver;
+ iCurrentResolver = NULL;
+ delete tempCurrentResolver;
+
+ // take queued resolver in use
+ iCurrentResolver = iBufferedResolver;
+ iBufferedResolver = NULL;
+ iBufferingNewImage = EFalse;
+
+ // Update the state
+ iState = EResolvingItem;
+
+ // Start resolving the item
+ iCurrentResolver->ResolveL( *this );
+ }
+
+// --------------------------------------------------------------------------
+// CUpnpImageRenderingEngine::ResolveComplete
+// Indicates that resolving of an item is complete.
+// --------------------------------------------------------------------------
+//
+void CUpnpImageRenderingEngine::ResolveComplete(
+ const MUPnPItemResolver& aResolver,
+ TInt aError )
+ {
+ __LOG1( "[UpnpCommand]\t CUpnpImageRenderingEngine::ResolveComplete\
+ in state %d", iState );
+
+ // if engine is shutting down, no need to check these
+ if ( iState == EResolvingItem )
+ {
+ __ASSERTD( &aResolver == iCurrentResolver, __FILE__, __LINE__ );
+ if( iBufferingNewImage )
+ {
+ TRAP( aError, StartResolvingL() );
+ }
+ else if( aError == KErrNone )
+ {
+ iState = EResolveComplete;
+
+ // Now that we have the full metadata of the item available, we
+ // can start the rendering
+ TRAP( aError, InitiateShowingL() );
+ }
+ // error handling
+ if( aError != KErrNone && iState != EShuttingDown )
+ {
+ SendRenderAck( aError );
+ }
+ }
+ else if( iState == EShuttingDown )
+ {
+ // do nothing.
+ iState = EIdle;
+ }
+ else
+ {
+ __LOG( "[UpnpCommand]\t CUpnpImageRenderingEngine: state error." );
+ __PANICD( __FILE__, __LINE__ );
+ iState = EIdle;
+ }
+
+ }
+
+// --------------------------------------------------------------------------
+// CUpnpImageRenderingEngine::InitiateShowingL
+// Handles the initiation of rendering (SetUri or video player launching).
+// --------------------------------------------------------------------------
+void CUpnpImageRenderingEngine::InitiateShowingL()
+ {
+ __LOG1( "[UpnpCommand]\t CUpnpImageRenderingEngine::InitiateShowingL\
+ in state %d",
+ iState );
+ __ASSERTD( iCurrentResolver, __FILE__, __LINE__ );
+
+ if ( UPnPItemUtility::BelongsToClass(
+ iCurrentResolver->Item(), KClassImage ) )
+ {
+ // Send the setUri action
+ iRenderingSession.SetURIL(
+ iCurrentResolver->Resource().Value(),
+ iCurrentResolver->Item() );
+ // update the state
+ iState = ESettingUri;
+ }
+ else
+ {
+ User::Leave( KErrNotSupported );
+ }
+ }
+
+
+// --------------------------------------------------------------------------
+// CUpnpImageRenderingEngine::SetURIResult
+// UPnP AV Controller calls this method as a result for the 'set uri' request.
+// --------------------------------------------------------------------------
+//
+void CUpnpImageRenderingEngine::SetURIResult( TInt aError )
+ {
+ __LOG1( "[UpnpCommand]\t CUpnpImageRenderingEngine::SetURIResult\
+ in state %d",
+ iState );
+
+ if ( iState == ESettingUri )
+ {
+ //need check the aError in case of SetURIL cause a error.
+ if( aError != KErrNone )
+ {
+ Cleanup();
+ return;
+ }
+ __ASSERTD( iCurrentResolver, __FILE__, __LINE__ );
+ if( iBufferingNewImage )
+ {
+ TRAP( aError, StartResolvingL() );
+ }
+ else if( aError == KErrNone )
+ {
+ TRAP( aError, iRenderingSession.PlayL() );
+ if( aError == KErrNone )
+ {
+ // Update the state
+ iState = EStartingPlay;
+ }
+ }
+ // error handling
+ if( aError != KErrNone )
+ {
+ SendRenderAck( aError );
+ }
+ }
+ else if ( iState == EShuttingDown )
+ {
+ // do nothing
+ }
+ else
+ {
+ __LOG( "[UpnpCommand]\t CUpnpImageRenderingEngine: state error." );
+ __PANICD( __FILE__, __LINE__ );
+ iState = EIdle;
+ }
+
+ }
+
+// --------------------------------------------------------------------------
+// CUpnpImageRenderingEngine::InteractOperationComplete
+// Called by UpnpAvController to indicate that play is complete.
+// --------------------------------------------------------------------------
+//
+void CUpnpImageRenderingEngine::InteractOperationComplete(
+ TInt aError,
+ TUPnPAVInteractOperation aOperation )
+ {
+ __LOG2( "[UpnpCommand]\t CUpnpImageRenderingEngine::\
+InteractOperationComplete (%d) in state %d", aOperation, iState );
+
+ if ( iState == EStartingPlay )
+ {
+ __ASSERTD( iCurrentResolver, __FILE__, __LINE__ );
+ if( aOperation == EUPnPAVPlay && iBufferingNewImage )
+ {
+ // New image in buffer! call stop, then play new item.
+ TRAP( aError, iRenderingSession.StopL() );
+ if ( aError == KErrNone )
+ {
+ iState = EStopping;
+ }
+ }
+ else if ( aOperation == EUPnPAVPlay && aError == KErrNone )
+ {
+ // update status
+ iState = EPlaying;
+ // response for play request
+ SendRenderAck( KErrNone );
+ }
+ // error handling
+ if ( aError != KErrNone )
+ {
+ SendRenderAck( aError );
+ }
+ }
+ else if ( iState == EPlaying )
+ {
+ if( aOperation == EUPnPAVPlayUser )
+ {
+ // state change event notification
+ // no need to do anything here
+ }
+ else if( aOperation == EUPnPAVStopUser )
+ {
+ // user stop notification
+ // state to idle, so that no stop event will be sent
+ // if starting to process new item
+ iState = EIdle;
+ }
+ }
+ else if ( iState == EStopping )
+ {
+ __ASSERTD( iCurrentResolver, __FILE__, __LINE__ );
+ if( aOperation == EUPnPAVStop && iBufferingNewImage )
+ {
+ TRAP( aError, StartResolvingL() );
+ }
+ else if ( aOperation == EUPnPAVStop && aError == KErrNone )
+ {
+ // succesful stop - go IDLE
+ iState = EIdle;
+ }
+ // error handling
+ if ( aError != KErrNone )
+ {
+ SendRenderAck( aError );
+ }
+ }
+ else if ( iState == EShuttingDown )
+ {
+ if ( aOperation == EUPnPAVStop || aOperation == EUPnPAVPlay )
+ {
+ iState = EIdle;
+ }
+ }
+
+ __LOG( "[UpnpCommand]\t CUpnpImageRenderingEngine::InteractOperationComplete end " );
+ }
+
+
+
+
+// --------------------------------------------------------------------------
+// CUpnpImageRenderingEngine::MediaRendererDisappeared
+// Notifies that the Media Renderer we have a session with has disappeared.
+// Session is now unusable and must be closed.
+// --------------------------------------------------------------------------
+//
+void CUpnpImageRenderingEngine::MediaRendererDisappeared(
+ TUPnPDeviceDisconnectedReason aReason )
+ {
+ __LOG1( "[UpnpCommand]\t CUpnpImageRenderingEngine::\
+MediaRendererDisappeared in state %d", iState );
+
+ if( iState == EShuttingDown )
+ {
+ __LOG( "[UpnpCommand]\t CUpnpImageRenderingEngine::\
+ MediaRendererDisappeared engine already shutting down, do nothing" );
+ }
+ else
+ {
+ if( aReason == MUPnPAVSessionObserverBase::EWLANLost )
+ {
+ iWlanActive = EFalse;
+ }
+ iState = EShuttingDown; // avoid all callbacks
+ iObserver.EngineShutdown( KErrDisconnected );
+ }
+ }
+
+// --------------------------------------------------------------------------
+// CUpnpImageRenderingEngine::RunError
+// Exception occurred in the timer body
+// --------------------------------------------------------------------------
+//
+TInt CUpnpImageRenderingEngine::RunError( TInt aError )
+ {
+ __LOG2( "[UpnpCommand]\t CUpnpImageRenderingEngine::\
+RunError in state %d aError %d", iState, aError );
+ Cleanup();
+ SendRenderAck( aError );
+ return KErrNone;
+ }
+
+
+
+// --------------------------------------------------------------------------
+// CUpnpImageRenderingEngine::SendRenderAck
+// Exception occurred in the timer body
+// --------------------------------------------------------------------------
+//
+void CUpnpImageRenderingEngine::SendRenderAck( TInt aError )
+ {
+ __LOG1( "[UpnpCommand]\t CUpnpImageRenderingEngine::\
+SendRenderAck(%d)", aError );
+
+ // take a stack copy of some members
+ MUpnpImageRenderingEngineObserver& observer = iObserver;
+ const CUpnpItem* item = NULL;
+ if ( iCurrentResolver &&
+ !( iState == EIdle || iState == EResolvingItem ) )
+ {
+ item = &iCurrentResolver->Item();
+ }
+
+ // cleanup if this was an error
+ if ( aError != KErrNone )
+ {
+ __LOG1( "[UpnpCommand]\t CUpnpImageRenderingEngine::\
+SendRenderAck aError=%d -> Cleanup", aError );
+ Cleanup();
+ }
+
+ // call the observer
+ TInt resp = observer.RenderAck( aError, item );
+
+ // in case of disconnected error, do engine shutdown
+ if ( resp == KErrDisconnected )
+ {
+ __LOG1( "[UpnpCommand]\t CUpnpImageRenderingEngine::\
+SendRenderAck resp=%d -> EngineShutdown", resp );
+ iState = EShuttingDown;
+ observer.EngineShutdown( resp );
+ }
+
+ }
+
+
+// --------------------------------------------------------------------------
+// CUpnpImageRenderingEngine::IsWlanActive
+// If connection to renderer is lost, checks if wlan is still active
+// --------------------------------------------------------------------------
+//
+TBool CUpnpImageRenderingEngine::IsWlanActive()
+ {
+ return iWlanActive;
+ }
+
+// End of File