upnpframework/upnpcommand/src/upnpimagerenderingengine.cpp
branchnew development branch with rendering state machine and other goodies
changeset 38 5360b7ddc251
parent 0 7f85d04be362
--- a/upnpframework/upnpcommand/src/upnpimagerenderingengine.cpp	Fri Sep 17 08:31:21 2010 +0300
+++ b/upnpframework/upnpcommand/src/upnpimagerenderingengine.cpp	Mon Nov 01 12:37:49 2010 +0200
@@ -1,683 +1,693 @@
-/*
-* 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
+/*
+* 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
+#include "upnprenderingstatemachine.h"  // rendering state machine
+
+// command internal
+#include "upnpimagerenderingengineobserver.h"   // the observer interface
+#include "upnpimagerenderingengine.h"   // self
+#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;
+    iRenderingStateMachine = NULL;
+    iWlanActive = ETrue;
+    // set observer
+    iRenderingSession.SetObserver( *this );
+    }
+
+// --------------------------------------------------------------------------
+// Second phase constructor.
+// --------------------------------------------------------------------------
+//
+void CUpnpImageRenderingEngine::ConstructL()
+    {
+    __LOG( "[UpnpCommand]\t CUpnpImageRenderingEngine::ConstructL" );
+    iTimer = CUPnPPeriodic::NewL( CActive::EPriorityStandard );
+    iRenderingStateMachine = 
+                  CUpnpRenderingStateMachine::NewL( iRenderingSession );
+    iRenderingStateMachine->SetObserver( *this );
+    iRenderingStateMachine->SyncL();
+    }
+    
+// --------------------------------------------------------------------------
+// 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 ( iRenderingStateMachine )
+        {
+        iRenderingStateMachine->RemoveObserver();
+        delete iRenderingStateMachine;
+        iRenderingStateMachine = NULL;
+        }
+
+    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()
+    {
+    __LOG( "[UpnpCommand]\t CUpnpImageRenderingEngine::PlayL" );
+
+    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()
+    {
+    __LOG( "[UpnpCommand]\t CUpnpImageRenderingEngine::StopL" );
+
+    // 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:
+            {
+            // just cancel the sequence and do nothing
+            iState = EIdle;
+            break;
+            }
+        case ERendering: 
+            {
+            // Send stop action.
+            iRenderingStateMachine->CommandL( Upnp::EStop, 0, NULL );
+            break;
+            }
+        case EShuttingDown:
+            {
+            // command not allowed in this state
+            break;
+            }
+        default:
+            {
+            __PANIC( __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: 
+            {
+            StartResolvingL();
+            break;
+            }
+        case EResolvingItem: // fall through
+        case EResolveComplete: // fall through
+            {
+            // indicate that new image is being buffered. It will be popped
+            // from buffer in next callback.
+            iBufferingNewImage = ETrue;
+            break;
+            }
+        case ERendering:
+            {
+            // indicate that new image is being buffered. Send stop signal.
+            // new item will be handled after stop completed.
+            if( !iBufferingNewImage )
+                {
+                iBufferingNewImage = ETrue;
+                iRenderingStateMachine->CommandL( Upnp::EStop, 0, NULL );
+                }
+            else
+                {
+                // stop already sent, wait for response and do nothing
+                __LOG( "[UpnpCommand]\t CUpnpImageRenderingEngine::RunTimerL,\
+wait for stop" );
+                }
+            break;
+            }
+        case EShuttingDown:
+            {
+            // command not allowed in this state
+            break;
+            }
+        default:
+            {
+            __PANIC( __FILE__, __LINE__ );
+            break;
+            }
+        }
+    }
+
+// --------------------------------------------------------------------------
+// CUpnpImageRenderingEngine::RunError
+// Exception occurred in the timer body
+// --------------------------------------------------------------------------
+//
+TInt CUpnpImageRenderingEngine::RunError( TInt aError )
+    {
+    __LOG1( "[UpnpCommand]\t CUpnpImageRenderingEngine::\
+RunError aError %d", aError );
+    Cleanup();
+    SendRenderAck( aError );
+    return KErrNone;
+    }
+    
+// --------------------------------------------------------------------------
+// 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\
+ aError %d", aError );
+    
+    // if engine is shutting down, no need to check these
+    if ( iState == EResolvingItem )
+        {
+        __ASSERT( &aResolver == iCurrentResolver, __FILE__, __LINE__ );
+        
+        if( iBufferingNewImage )
+            {
+            TRAP( aError, StartResolvingL() );
+            }
+        else if( aError == KErrNone )
+            {
+            iState = ERendering;
+            const CUpnpItem& item = iCurrentResolver->Item();
+
+            if ( UPnPItemUtility::BelongsToClass( item, KClassImage ) )
+                {
+                __LOG1( "[UpnpCommand]\t play image item of resolver 0x%d", 
+                                                    TInt(iCurrentResolver) );
+                Cycle();
+                }
+            else if ( UPnPItemUtility::BelongsToClass( item, KClassVideo ) )
+                {
+                __LOG( "[UpnpCommand]\t video, inform observer to play it" );
+                aError = iObserver.RenderAck( KErrNotSupported, &item );
+                }
+            }
+            
+        // 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::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 aError %d", aError );
+ 
+    if ( iState == ERendering )
+        {
+        if( iBufferingNewImage && aError == KErrNone)
+            {
+            __LOG( "[UpnpCommand]\t CUpnpImageRenderingEngine::\
+SetURIResult - pass cancel to rendering state machine" );
+            iRenderingStateMachine->SetURIResult( KErrCancel );
+            }
+        else if( aError == KErrNone )
+            {
+            __LOG( "[UpnpCommand]\t CUpnpImageRenderingEngine::\
+SetURIResult - pass uri result to rendering state machine" );
+            iRenderingStateMachine->SetURIResult( aError );
+            }
+        }
+    else if ( iState == EShuttingDown )
+        {
+        // do nothing
+        }
+    }
+
+// --------------------------------------------------------------------------
+// CUpnpImageRenderingEngine::InteractOperationComplete
+// Called by UpnpAvController to indicate that play is complete.
+// --------------------------------------------------------------------------
+//
+void CUpnpImageRenderingEngine::InteractOperationComplete(
+    TInt aError,
+    TUPnPAVInteractOperation aOperation )
+    {
+    __LOG2( "[UpnpCommand]\t CUpnpImageRenderingEngine::\
+InteractOperationComplete aOperation %d aError %d", aOperation, aError );
+    if ( iState != EShuttingDown )
+        {
+        __LOG( "[UpnpCommand]\t CUpnpImageRenderingEngine::\
+InteractOperationComplete - pass operation to rendering state machine" );
+        iRenderingStateMachine->InteractOperationComplete( 
+            aError, aOperation );
+        }
+    }
+
+// --------------------------------------------------------------------------
+// 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::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()
+    {
+    __LOG1( "[UpnpCommand]\t CUpnpImageRenderingEngine::\
+IsWlanActive iWlanActive=%d ", iWlanActive );
+    return iWlanActive;
+    }
+
+// --------------------------------------------------------------------------
+// CUpnpImageRenderingEngine::Cycle
+// Cycles next item by checking resolver status. 
+// --------------------------------------------------------------------------
+//
+void CUpnpImageRenderingEngine::Cycle()
+    {
+    __LOG( "[UpnpCommand]\t CUpnpImageRenderingEngine::Cycle" );
+    
+    TRAPD( err, iRenderingStateMachine->CommandL( 
+            Upnp::EPlay, 0, &iCurrentResolver->Item() ) );
+            
+    if ( KErrNone != err )
+        {
+        SendRenderAck( err );
+        }
+    }
+    
+
+// --------------------------------------------------------------------------
+// CUpnpImageRenderingEngine::RendererSyncReady
+// Callback from rendering state machine when sync is ready.
+// --------------------------------------------------------------------------
+//
+void CUpnpImageRenderingEngine::RendererSyncReady( TInt aError,
+    Upnp::TState aState )
+    {
+    __LOG1( "[UpnpCommand]\t CUpnpImageRenderingEngine::\
+RendererSyncReady aError=%d ", aError );
+
+    if( aState != Upnp::EStopped )
+        {
+        // Renderer is used by another controlpoint. Cannot continue.
+        iState = EShuttingDown; // avoid all callbacks
+        iObserver.EngineShutdown( KErrInUse );
+        }
+    else if ( KErrNone != aError )
+        {
+        // notify observer if error. currently there will not
+        // any error from rendering state machine but may be
+        // in future. 
+        SendRenderAck( aError );
+        }
+    }
+
+// --------------------------------------------------------------------------
+// CUpnpImageRenderingEngine::RenderingStateChanged
+// Callback from rendering state machine when rendering state changes.
+// --------------------------------------------------------------------------
+//
+void CUpnpImageRenderingEngine::RenderingStateChanged( TInt aError, 
+    Upnp::TState aState , TBool aActionResponse, TInt /*aStateParam*/ )
+    {
+    __LOG( "[UpnpCommand]\t CUpnpImageRenderingEngine::\
+RenderingStateChanged" );
+
+    __LOG3( "[UpnpCommand]\t aError=%d aState=0x%x aActionResponse=%d",
+                                        aError, aState, aActionResponse );
+
+    if ( Upnp::EStopped == aState )
+        {
+        __LOG( "[UpnpCommand]\t CUpnpImageRenderingEngine::\
+RenderingStateChanged - image play stopped" );
+        
+        iState = EIdle;
+        
+        // new image waiting -> start resolving
+        if( iBufferingNewImage )
+            {
+            __LOG( "[UpnpCommand]\t CUpnpImageRenderingEngine::\
+RenderingStateChanged - start resolving new image");
+            TRAP( aError, StartResolvingL() );
+            }
+        }
+    else if ( Upnp::EPlaying == aState )
+        {
+        // new image waiting -> wait for stop
+        // stop has already been sent
+        if( iBufferingNewImage )
+            {
+            __LOG( "[UpnpCommand]\t CUpnpImageRenderingEngine::\
+RenderingStateChanged to play - new image -> wait for stop");
+            }
+            
+        // image playing -> inform observer  
+        else if( aActionResponse &&  KErrNone == aError )
+            {
+            __LOG( "[UpnpCommand]\t CUpnpImageRenderingEngine::\
+RenderingStateChanged - image play started ");
+            SendRenderAck( aError );
+            }
+        }    
+            
+    // Error handling       
+    if ( KErrNone != aError )
+        {
+        __LOG( "[UpnpCommand]\t CUpnpImageRenderingEngine::\
+RenderingStateChanged - Error situation" );
+        SendRenderAck( aError );
+        }
+    }
+
+// --------------------------------------------------------------------------
+// CUpnpImageRenderingEngine::RendererSyncReady
+// Callback from rendering state machine when rendering position is sync.
+// --------------------------------------------------------------------------
+//
+void CUpnpImageRenderingEngine::PositionSync( TInt /*aError*/, 
+        Upnp::TPositionMode /*aMode*/,
+        TInt /*aDuration*/,
+        TInt /*aPosition*/ )
+    {
+    __LOG( "[UpnpCommand]\t CUpnpImageRenderingEngine::\
+PositionSync" );
+    }
+    
+// End of File