vtengines/vtmediatorplugin/src/cvtmediatorplugin.cpp
author Pat Downey <patd@symbian.org>
Wed, 01 Sep 2010 12:29:12 +0100
branchRCL_3
changeset 35 779871d1e4f4
parent 34 f15ac8e65a02
permissions -rw-r--r--
Revert incorrect RCL_3 drop: Revision: 201033 Kit: 201035

/*
* 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:  Video Telephony mediator plugin header
*
*/


// INCLUDE FILES
#include <e32def.h>
#include <w32std.h>
#include <apacmdln.h>
#include <apaflrec.h>
#include <apgcli.h>
#include <MediatorDomainUIDs.h>
#include <eikdll.h>
#include <apgcli.h>
#include <apgwgnam.h>
#include <apgtask.h>
#include <mediatorcommandstotelephonyapi.h>
#include <videotelcontrolmediatorapi.h>
#include <videoteltophonecommandsapi.h>
#include "cvtmediatorplugin.h"


// CONSTANTS
#ifdef _DEBUG
#define TRACE(x) RDebug::Print( _L(x) );
#define TRACE2(x,y) RDebug::Print( _L(x),y );
#else
#define TRACE(x)
#define TRACE2(x,y)
#endif
                       
// This array's values are used in algorithm defining if video telephone
// application should be started. Previous state value is substracted from new 
// state value and if result is greater than zero, app is started.
// This tackles transitions where a state is for some reason skipped,
// e.g. idle -> connected (dialling/ringing/answering states were not detected).
// Negative value indicates call clearing.
static const TInt KVtCallStateActionArray[] = {
    0, //ECallStateUnknown
    0, //ECallStateIdle
    1, // ECallStateDialling
    0, // ECallStateEmergencyDialling (not valid video call state)
    1, // ECallStateRinging
    1, // ECallStateConnecting
    1, // ECallStateConnected
    0, // ECallStateHangingUp
    0, // ECallStateHeld (not valid video call state)
    1, // ECallStateAnswering
    0, // ECallStateRejecting
    0  // ECallStateDisconnecting
    };

static const TInt KVtAppNotReady = 5000;

static const TInt KVtEngMdtrCmdTimeout = 500000;

static const TInt KVtInitCallId = -1000;

// array granularity is 2 (use dataport, release dataport commands)
static const TInt KVtMdtrCmdArrayGranularity = 2;

const TUid KVtCmVideoTelUiUid = { 0x101F8681 };

static const TInt KRamNeededForVideoCalls = 4000000;

// VT application path 
_LIT( KVtCmVideoTelUiPath, "\\sys\\bin\\videotelui.exe" );


// -----------------------------------------------------------------------------
// CMediatorTestPlugin::CMediatorTestPlugin
// First phase construction.
// -----------------------------------------------------------------------------
CVtMediatorPlugin::CVtMediatorPlugin() : CMediatorPluginBase(),
    iCommandList( KVtMdtrCmdArrayGranularity ),
    iState( EWaitingAppLaunch ),
    iActiveVideoCallState( ECallStateUnknown ),
    iWaitingVideoCallState( ECallStateUnknown )
    
	{
	ClearData(iActiveVideoCallInfo, iActiveVideoCallState);
	ClearData(iWaitingVideoCallInfo, iWaitingVideoCallState);
	}
	
CMediatorPluginBase* CVtMediatorPlugin::NewL()
    {
    TRACE("CVtMediatorPlugin::NewL<")
    CVtMediatorPlugin* self = new (ELeave) CVtMediatorPlugin;
    TRACE("CVtMediatorPlugin::NewL>")
    return self;
    }

// -----------------------------------------------------------------------------
// Destructor.
// -----------------------------------------------------------------------------
CVtMediatorPlugin::~CVtMediatorPlugin()
	{
	TRACE("CVtMediatorPlugin::~CVtMediatorPlugin<")
    
	if ( iMediatorNotifications )
	    {
	    iMediatorNotifications->UnregisterNotificationObserver();
	    delete iMediatorNotifications;
	    }

	// ignore error
	if ( iEventConsumer )
	    {
	    iEventConsumer->UnsubscribeEvent(
	            KMediatorTelephonyDomain,
	            KCatEventsFromTelephony,
	            EPhoneEventCallData );     
	    delete iEventConsumer;
	    }
        
    // ignore error     
	if ( iEventProvider )
	    {
	    iEventProvider->UnregisterEvent(
	            KMediatorVideoTelephonyDomain,
	            KCatVideotelInternalEvents,
	            EVtMediatorEventVideoCallInformation );   
	    delete iEventProvider;
	    }
        
    // ignore error
	if ( iCommandResponder )
	    {
	    iCommandResponder->UnregisterCommand(
	                KMediatorVideoTelephonyDomain,
	                KCatPhoneToVideotelCommands,
	                iCommandList );
	    iCommandList.Close();
	    delete iCommandResponder;
	    }
	
	delete iCommandInitiator;
    
           
    if( iAppDeathActive )
        {
        delete iAppDeathActive;
        iAppThread.Close();
        }

    TRACE("CVtMediatorPlugin::~CVtMediatorPlugin>")
	}

// -----------------------------------------------------------------------------
// StartL.
// -----------------------------------------------------------------------------
void CVtMediatorPlugin::StartL()
	{
    TRACE("CVtMediatorPlugin.StartL<")
    
    // for monitoring VT app starting
    iMediatorNotifications = CMediatorNotifications::NewL();
    iMediatorNotifications->RegisterNotificationObserver( this );
    
    // consumer for call data events
    iEventConsumer = CMediatorEventConsumer::NewL( this );
    
    iCommandInitiator = CMediatorCommandInitiator::NewL( this );
    
    
    RegisterVtInternalEventL();
    
    RegisterDataportCommandL();       
          
    TRACE("CVtMediatorPlugin.StartL>")
	}

// -----------------------------------------------------------------------------
// MediatorEventL.
// -----------------------------------------------------------------------------
void CVtMediatorPlugin::MediatorEventL( TUid /*aDomain*/,
                             TUid aCategory,
                             TInt aEventId,
                             const TDesC8& aData )
    {
    TRACE("CVtMediatorPlugin.MediatorEventL<")
    if ( aCategory == KCatEventsFromTelephony &&
         aEventId == EPhoneEventCallData )
        {
        TTelephonyCallDataParamPackage pckg;
        pckg.Copy( aData );
        const TTelephonyCallDataParam telCallData = pckg();        
        HandleCallStateChangeL( telCallData );        
        }
    TRACE("CVtMediatorPlugin.MediatorEventL>")
    }
// -----------------------------------------------------------------------------
// CVtMediatorPlugin::MediatorEventsAddedL
//
// subscribes to CLI event when it is registered
// -----------------------------------------------------------------------------
//
void CVtMediatorPlugin::MediatorEventsAddedL( TUid aDomain/*aDomain*/,
                                   TUid aCategory,
                                   const REventList& aEvents )
    {
    TRACE("CVtMediatorPlugin.MediatorEventsAddedL<")
    
    if ( aCategory == KCatEventsFromTelephony )
        {
        ChangeCallDataEventSubscriptionL( aEvents, ETrue );
        }    
    TRACE("CVtMediatorPlugin.MediatorEventsAddedL>")
    }

// -----------------------------------------------------------------------------
// ?classname::?member_function
//
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CVtMediatorPlugin::MediatorCommandsAddedL( TUid /*aDomain*/,
                                     TUid aCategory,
                                     const RCommandList& /*aCommands*/ )
    {
    TRACE("CVtMediatorPlugin.MediatorCommandsAddedL<")
    if ( aCategory == KCatPhoneToVideotelCommands )
        {
        HandleVtCommandRegistrationL();
        }
    TRACE("CVtMediatorPlugin.MediatorCommandsAddedL>")
    }

// -----------------------------------------------------------------------------
// ?classname::?member_function
//
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CVtMediatorPlugin::MediatorCategoryRemovedL( TUid /*aDomain*/,
    TUid /*aCategory*/ )
    {
    }

// -----------------------------------------------------------------------------
// ?classname::?member_function
//
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CVtMediatorPlugin::MediatorEventsRemovedL( TUid /*aDomain*/,
                                     TUid aCategory,
                                     const REventList& aEvents )
    {
    TRACE("CVtMediatorPlugin.MediatorEventsRemovedL<")
    if ( aCategory == KCatEventsFromTelephony )
        {
        ChangeCallDataEventSubscriptionL( aEvents, EFalse );
        }    
    TRACE("CVtMediatorPlugin.MediatorEventsRemovedL>")
    }

// -----------------------------------------------------------------------------
// ?classname::?member_function
//
// (other items were commented in a header).
// -----------------------------------------------------------------------------
//
void CVtMediatorPlugin::MediatorCommandsRemovedL( TUid /*aDomain*/,
                                       TUid aCategory,
                                       const RCommandList& /*aCommands*/ )
    {
    TRACE("CVtMediatorPlugin.MediatorCommandsRemovedL<")  
    if ( aCategory == KCatPhoneToVideotelCommands )
        {
        // VT has unregistered commands, meaning it is shutting down
        HandleVtCommandUnregistrationL();
        }
    TRACE("CVtMediatorPlugin.MediatorCommandsRemovedL>")
    }

// -----------------------------------------------------------------------------
// CVtMediatorPlugin::MediatorCommandL
//
// 
// -----------------------------------------------------------------------------
//
void CVtMediatorPlugin::MediatorCommandL( TUid aDomain,
                                 TUid aCategory, 
                                 TInt aCommandId,
                                 TVersion /*aVersion*/, 
                                 const TDesC8& aData )
    {
    TRACE("CVtMediatorPlugin.MediatorCommandL<") 
    if ( aCategory == KCatPhoneToVideotelCommands )
        {
        if ( aCommandId == EVtCmdUseDataport )
            {
#ifdef _DEBUG           
            // error in responding is ignored but printed on debug build
            const TInt err =
#endif            
            iCommandResponder->IssueResponse( 
                aDomain, aCategory, aCommandId, KErrNone, KNullDesC8() );
            TRACE2("CVtMediatorPlugin.MediatorCommandL EVtCmdUseDataport err=%d", err )
            HandleDataportCommandL( aData );
            }
        else if ( aCommandId == EVtCmdReleaseDataport )
            {
            if ( EReady == iState )
                {
                const TVersion version( 
                        KVideotelMdtrCommandsVersionMajor,
                        KVideotelMdtrCommandsVersionMinor,
                        KVideotelMdtrCommandsVersionBuild );

#ifdef _DEBUG           
            // error in responding is ignored but printed on debug build
            const TInt err =
#endif                          
                iCommandInitiator->IssueCommand(
                        KMediatorVideoTelephonyDomain,
                        KCatVideotelInternalCommands,
                        EVtMediatorReleaseDataport,
                        version,
                        KNullDesC8() );
            TRACE2("CVtMediatorPlugin.MediatorCommandL EVtCmdReleaseDataport, send to VT err=%d", err )
                
                }
            else
                {
#ifdef _DEBUG           
                // error in responding is ignored but printed on debug build
                const TInt err =
#endif            
                iCommandResponder->IssueResponse( 
                        aDomain, 
                        aCategory, 
                        aCommandId, 
                        KErrNone, 
                        KNullDesC8() );
                TRACE2("CVtMediatorPlugin.MediatorCommandL EVtCmdReleaseDataport, just Resp err=%d", err ) 
                }
           
            }
        }
    TRACE("CVtMediatorPlugin.MediatorCommandL>")
    }

// -----------------------------------------------------------------------------
// CVtMediatorPlugin::CommandResponseL
//
// 
// -----------------------------------------------------------------------------
//
void CVtMediatorPlugin::CommandResponseL( TUid aDomain, TUid aCategory, 
    TInt aCommandId, TInt /*aStatus*/, const TDesC8& /*aData*/ )
    {
    TRACE("CVtMediatorPlugin.CommandResponseL<")
    if( ( aDomain == KMediatorVideoTelephonyDomain ) &&
        ( aCategory == KCatVideotelInternalCommands ) )
        {
        TInt res =
        iCommandResponder->IssueResponse( 
                KMediatorVideoTelephonyDomain,
                KCatPhoneToVideotelCommands,
                EVtCmdReleaseDataport, 
                KErrNone, 
                KNullDesC8() );         
         TRACE2("CVtMediatorPlugin.CommandResponseL, IssueResponse res: %d", res )  
         User::LeaveIfError( res );      
        }
    TRACE("CVtMediatorPlugin.CommandResponseL>")
    }

// -----------------------------------------------------------------------------
// CVtMediatorPlugin::CancelMediatorCommand
//
// no-op
// -----------------------------------------------------------------------------
//
void CVtMediatorPlugin::CancelMediatorCommand( TUid /*aDomain*/,
                                      TUid /*aCategory*/, 
                                      TInt /*aCommandId*/ )
    {
    }
// -----------------------------------------------------------------------------
// CVtMediatorPlugin::ChangeCallDataEventSubscriptionL
//
// Takes care of 'call data' event subscription.
// -----------------------------------------------------------------------------
//
void CVtMediatorPlugin::ChangeCallDataEventSubscriptionL(
    const REventList& aEvents,
    const TBool aEventRegistered )
    {
    TRACE("CVtMediatorPlugin.ChangeCLIEventSubscription<")
   
    TInt res( KErrNone );
    TInt eventCount = aEvents.Count();
    while ( eventCount-- )
        {
        const TEvent& aEvent = aEvents[ eventCount ];
        if ( aEvent.iEventId == EPhoneEventCallData )
            {
            if ( aEventRegistered )
                {
                // Phone has registered Call data event => subscribe it                
                const TVersion version(
                    KTelephonyEventsVersionMajor,
                    KTelephonyEventsVersionMinor,
                    KTelephonyEventsVersionBuild );
                res = iEventConsumer->SubscribeEvent(
                    KMediatorTelephonyDomain,
                    KCatEventsFromTelephony,
                    EPhoneEventCallData, version );
                }
            else
                {
                // Phone has unregistered Call data event => unsubscribe it
                res = iEventConsumer->UnsubscribeEvent(
                    KMediatorTelephonyDomain,
                    KCatEventsFromTelephony,
                    EPhoneEventCallData );
                }
            TRACE2("   (un)subscribe result=%d", res )
            eventCount = 0; // break loop
            }
        }
    
    TRACE2("CVtMediatorPlugin.ChangeCLIEventSubscription result=%d>", res )
    User::LeaveIfError( res );
    }
    
// -----------------------------------------------------------------------------
// CVtMediatorPlugin::HandleVtCommandRegistrationL
//
// 
// -----------------------------------------------------------------------------
//
void CVtMediatorPlugin::HandleVtCommandRegistrationL()
    {
    TRACE("CVtMediatorPlugin.HandleVtCommandRegistrationL<" )
    if ( iState == EWaitingEventRegistration )
        {
        // VT app registered commands => it can also receive events
        // NOTE: it is expected that VT application first subscribes
        // to internal events and only after that registers commands to
        // avoid timing problems.
        iState = EReady;
        delete iCallBack;
        iCallBack = NULL;
        TCallBack cb( &EventRaiserCallback, this );
        iCallBack = new ( ELeave ) CAsyncCallBack( cb, 
            CActive::EPriorityStandard );        
        TRACE("CVtMediatorPlugin enque async callback" )
        iCallBack->CallBack();        
        }
    TRACE("CVtMediatorPlugin.HandleVtCommandRegistrationL>" )
    }

TInt CVtMediatorPlugin::EventRaiserCallback( TAny* aAny )
    {
    TRACE("CVtMediatorPlugin.EventRaiserCallback<" )
    CVtMediatorPlugin* plugin = reinterpret_cast<CVtMediatorPlugin*>( aAny );
    delete plugin->iCallBack;
    plugin->iCallBack = NULL;
    TRAP_IGNORE( plugin->RaiseVtEventL() );
    TRACE("CVtMediatorPlugin.EventRaiserCallback>" )
    return KErrNone;
    }

// -----------------------------------------------------------------------------
// CVtMediatorPlugin::
//
// 
// -----------------------------------------------------------------------------
//
void CVtMediatorPlugin::HandleVtCommandUnregistrationL()
    {
    // unregistration means that VT app is shutting down.    
    TRACE("CVtMediatorPlugin.HandleVtCommandUnregistrationL<" )
    ClearData(iActiveVideoCallInfo, iActiveVideoCallState);
    //ClearData(iWaitingVideoCallInfo);
    TRACE("CVtMediatorPlugin.HandleVtCommandUnregistrationL>" )
    }


// -----------------------------------------------------------------------------
// CVtMediatorPlugin::
//
// 
// -----------------------------------------------------------------------------
//
void CVtMediatorPlugin::LaunchVtAppL()
    {
        
    TRACE("CVtMediatorPlugin.LaunchVtAppL<" )
    
    if ( !IsEnoughMemory() )
        {
        const TVersion KTelephonyCmdVersion(
                KTelephonyCommandsVersionMajor,
                KTelephonyCommandsVersionMinor,
                KTelephonyCommandsVersionBuild );
        const TInt res =
        iCommandInitiator->IssueCommand(
                KMediatorTelephonyDomain,
                KCatVideoTelToPhoneCommands,
                EVtCmdLowMemory,
                KTelephonyCmdVersion,
                KNullDesC8() );
        ClearData(iActiveVideoCallInfo, iActiveVideoCallState);
        ClearData(iWaitingVideoCallInfo, iWaitingVideoCallState);
        TRACE("CVtMediatorPlugin.LaunchVtAppL, Insufficient Memory" )
        return;
        }

    iAppDeathActive = new ( ELeave ) CAppDeathActive( *this, iAppThread );
       
    RWsSession wsSession;
    User::LeaveIfError( wsSession.Connect() );
    CleanupClosePushL( wsSession );

    TInt wgId = 0;
    TBool found = EFalse;

    // Check if there is already application running. Then we do not 
    // start new one - rather we just monitor the existing one.
    while ( ( wgId != KErrNotFound ) && !found )
        {
        CApaWindowGroupName::FindByAppUid( 
            KVtCmVideoTelUiUid, 
            wsSession, 
            wgId );

        TApaTask task( wsSession );
        task.SetWgId( wgId );
        if ( task.Exists() )
            {
            if ( iAppThread.Open( task.ThreadId() ) == KErrNone )
                {
                TExitType exitType = iAppThread.ExitType();
                found = ( exitType == EExitPending );

                if ( found )
                    {
                    iAppThreadId = task.ThreadId();
                    }
                }
            }
            
        if ( !found )
            {
            iAppThread.Close();
             }
        }
    CleanupStack::PopAndDestroy(); // CleanupClosePushL
    
    // If application was not found, then launch new application.
    if ( !found )
        {
        TThreadId threadId;
#ifndef SYMBIAN_SUPPORT_UI_FRAMEWORKS_V1
        CApaCommandLine* cmd = CApaCommandLine::NewLC();
        cmd->SetExecutableNameL( KVtCmVideoTelUiPath );
#else // !SYMBIAN_SUPPORT_UI_FRAMEWORKS_V1
        CApaCommandLine* cmd = CApaCommandLine::NewLC( KVtCmVideoTelUiPath );
#endif // SYMBIAN_SUPPORT_UI_FRAMEWORKS_V1
        cmd->SetCommandL( EApaCommandBackground );
            
        RApaLsSession session;
        User::LeaveIfError( session.Connect() );
        CleanupClosePushL( session );
            
        TInt err = session.StartApp( *cmd, threadId );
        if ( err > KErrNone )
            {
            err = KErrGeneral;
            }
        User::LeaveIfError( err );
        CleanupStack::PopAndDestroy( 2, cmd ); // CleanupClosePushL, cmd
        User::LeaveIfError( iAppThread.Open( threadId ) );
        iAppThreadId = threadId;
        }

    // Start active objects.
    iState = EWaitingEventRegistration;
    iAppDeathActive->Start();
    TRACE("CVtMediatorPlugin.LaunchVtAppL>" )
    }


// -----------------------------------------------------------------------------
// CVtMediatorPlugin::
//
// 
// -----------------------------------------------------------------------------
//
void CVtMediatorPlugin::SaveCallData( const TTelephonyCallDataParam& aData, TVtVideoTelephonyCallInformation& iVtCallInfo )
    {
    TRACE("CVtMediatorPlugin.SaveCallData<" )
    iVtCallInfo.iDisplayText = aData.iCLIText.Left(
        TVtVideoTelephonyCallInformation::TDisplayTextMaxLength );
        
    TRACE2("CVtMediatorPlugin.SaveCallData iDisplayText=%S",
        &iVtCallInfo.iDisplayText );
                
    iVtCallInfo.iCallId = aData.iCallId;
    
    if ( KNullDesC() != aData.iRemotePhoneNumber )
        {
        iVtCallInfo.iVoiceCallPossible = ETrue;
        }
    iVtCallInfo.iEventDataValidity |= 
        TVtVideoTelephonyCallInformation::EDisplayTextValid;
    TRACE2("CVtMediatorPlugin.SaveCallData data saved=%d>",
        aData.iCallType == ECallTypeVideo )
    }

                     
// -----------------------------------------------------------------------------
// CVtMediatorPlugin::
//
// 
// -----------------------------------------------------------------------------
//
void CVtMediatorPlugin::HandleDataportCommandL( const TDesC8& aData )
    {
    TRACE("CVtMediatorPlugin.HandleDataportCommandL<" ) 
    TDataPortPackage pckg;
    pckg.Copy( aData );
    iActiveVideoCallInfo.iDataport = pckg();
    iActiveVideoCallInfo.iEventDataValidity |= 
        TVtVideoTelephonyCallInformation::EDataportValid;     
    RaiseVtEventL();
    TRACE("CVtMediatorPlugin.HandleDataportCommandL>" )
    }

                         
// -----------------------------------------------------------------------------
// CVtMediatorPlugin::ClearData
//
// 
// -----------------------------------------------------------------------------
//
void CVtMediatorPlugin::ClearData(TVtVideoTelephonyCallInformation& aVtCallInfo, TCallState& aCallState)
    {
    TRACE("CVtMediatorPlugin.ClearData<" )
    if ( aVtCallInfo.iCallId == iActiveVideoCallInfo.iCallId )
        {
        iState = EWaitingAppLaunch;
        }
    aVtCallInfo.iEventDataValidity = 0;
    aVtCallInfo.iDataport.Zero();
    aVtCallInfo.iVoiceCallPossible = EFalse;
    //for video call, it should be 9/10
    //for other call, it will be from -1 to 8
    aVtCallInfo.iCallId = KVtInitCallId;
    aVtCallInfo.iDisplayText.Zero();
    aCallState = ECallStateIdle;
    TRACE("CVtMediatorPlugin.ClearData>" )
    }

// -----------------------------------------------------------------------------
// CVtMediatorPlugin::RegisterVtInternalEventL
//
// 
// -----------------------------------------------------------------------------
//
void CVtMediatorPlugin::RegisterVtInternalEventL()
    {
    TRACE("CVtMediatorPlugin.RegisterVtInternalEventL<" )
    iEventProvider = CMediatorEventProvider::NewL();
    
    TVersion version(
        KVideotelMdtrEventVersionMajor,
        KVideotelMdtrEventVersionMinor,
        KVideotelMdtrEventVersionBuild );

    TCapabilitySet capSet;
    capSet.SetEmpty();
    capSet.AddCapability( ECapabilityReadDeviceData );
            
    const TInt err = iEventProvider->RegisterEvent(
        KMediatorVideoTelephonyDomain,
        KCatVideotelInternalEvents,
        EVtMediatorEventVideoCallInformation,
        version,
        capSet );
          
   
    TRACE2("CVtMediatorPlugin.RegisterVtInternalEventL err=%d>", err )
    User::LeaveIfError( err );
    }

// -----------------------------------------------------------------------------
// CVtMediatorPlugin::RegisterDataportCommandL
//
// 
// -----------------------------------------------------------------------------
//
void CVtMediatorPlugin::RegisterDataportCommandL()
    {
    TRACE("CVtMediatorPlugin.RegisterDataportCommandL<" )
    iCommandResponder = CMediatorCommandResponder::NewL( this );
    
    TCapabilitySet capSet;
    capSet.SetEmpty();
    capSet.AddCapability( ECapabilityWriteDeviceData );
    MediatorService::TCommand command;
    
    command.iCaps = capSet;
    command.iVersion = TVersion( 
            KPhoneToVideotelCmdVersionMajor, 
            KPhoneToVideotelCmdVersionMinor,
            KPhoneToVideotelCmdVersionBuild );
    command.iTimeout = KVtEngMdtrCmdTimeout;
        
    // enable microphone command
    command.iCommandId = EVtCmdUseDataport;
    iCommandList.Append( command );
        
    // Releasedataport command
    capSet.SetEmpty();
    capSet.AddCapability( ECapabilityPowerMgmt );
    command.iCommandId = EVtCmdReleaseDataport;
    iCommandList.Append( command );
    
    const TInt err = iCommandResponder->RegisterCommand( 
        KMediatorVideoTelephonyDomain,
        KCatPhoneToVideotelCommands,
        iCommandList );    
    
    TRACE2("CVtMediatorPlugin.RegisterDataportCommandL err=%d>", err )
    User::LeaveIfError( err );
    }

// -----------------------------------------------------------------------------
// CVtMediatorPlugin::RaiseVtEventL
//
// Raises VT call info event if in suitable state, i.e. VT app has subscribed 
// the event.
// -----------------------------------------------------------------------------
//
void CVtMediatorPlugin::RaiseVtEventL()
    {
    TRACE("CVtMediatorPlugin.RaiseVtEventL<" )
    TInt result = KVtAppNotReady;  // does not cause leave
    TRACE2("CVtMediatorPlugin.RaiseVtEventL iState=%d>", 
            iState )
    TRACE2("CVtMediatorPlugin.RaiseVtEventL iActiveVideoCallState=%d>", 
            iActiveVideoCallState )            
    if ( iState == EReady && // application subscribed to the event
    
        // don't send event if video call is not starting/ongoing
         ( iActiveVideoCallState >= ECallStateDialling &&
         iActiveVideoCallState <= ECallStateConnected ) )
        {
        const TVersion version(
            KVideotelMdtrEventVersionMajor,
            KVideotelMdtrEventVersionMinor,
            KVideotelMdtrEventVersionBuild );            
            
        const TVtMediatorInfoPackage pckg( iActiveVideoCallInfo );
        result = iEventProvider->RaiseEvent(
            KMediatorVideoTelephonyDomain,
            KCatVideotelInternalEvents,
            EVtMediatorEventVideoCallInformation,
            version,
            pckg
            );
        }
    TRACE2("CVtMediatorPlugin.RaiseVtEventL result=%d>", result )
    User::LeaveIfError( result );
    }

// -----------------------------------------------------------------------------
// CVtMediatorPlugin::HandleCallStateChangeL
//
// Compares previous and new video call states and resolves based on result
// if Video telephone applicaton should be launched.
// -----------------------------------------------------------------------------
//
void CVtMediatorPlugin::HandleCallStateChangeL(
    const TTelephonyCallDataParam& aData )
    {
    TRACE("CVtMediatorPlugin.HandleCallStateChangeL<" )    
    
    TRACE2("CVtMediatorPlugin.HandleCallStateChangeL calltype=%d>", 
            aData.iCallType )
    TRACE2("CVtMediatorPlugin.HandleCallStateChangeL saved Activecallid=%d>", 
            iActiveVideoCallInfo.iCallId )
    TRACE2("CVtMediatorPlugin.HandleCallStateChangeL saved Waitingcallid=%d>", 
            iWaitingVideoCallInfo.iCallId )
    TRACE2("CVtMediatorPlugin.HandleCallStateChangeL callid=%d>", 
            aData.iCallId )   
    TRACE2("CVtMediatorPlugin.HandleCallStateChangeL ActiveCallOldState=%d>", 
            iActiveVideoCallState )
    TRACE2("CVtMediatorPlugin.HandleCallStateChangeL WaitingCallOldState=%d>", 
            iWaitingVideoCallState )
    TRACE2("CVtMediatorPlugin.HandleCallStateChangeL NewState=%d>",
            aData.iCallState )
            
    //if the call is waitingcall, just save/clear
    if ( aData.iCallType == ECallTypeVideo ||       
        // check also call id because in call clearing states call type may
        // be unspecified but call id is saved in call setup and we can
        // compare to it.
         iActiveVideoCallInfo.iCallId == aData.iCallId  ||
         iWaitingVideoCallInfo.iCallId == aData.iCallId )
        {
        TBool isWaitingCall = ETrue;
        
        /**
         * firstly we should check the callid to identify if it is a waitingcal/activecall
         * imagine the usecase that long press endkey to shutdown both calls.
         * after that checking iState
         */
        if ( iWaitingVideoCallInfo.iCallId == aData.iCallId )
            {
            isWaitingCall =  ETrue;
            }
        else if ( iActiveVideoCallInfo.iCallId == aData.iCallId )
            {
            isWaitingCall = EFalse;
            }
        //no vt app launched, this happens while vt first launching or end key to shutdown both calls
        else if ( iState == EWaitingAppLaunch )
            {
            isWaitingCall =  EFalse;
            }
        
        TRACE2("CVtMediatorPlugin.HandleCallStateChangeL isWaitingCall=%d>",
                isWaitingCall)
        
        TCallState& callState = isWaitingCall?iWaitingVideoCallState:iActiveVideoCallState;
        TVtVideoTelephonyCallInformation& vtCallInfo = isWaitingCall?iWaitingVideoCallInfo:iActiveVideoCallInfo;
            
        TBool launchNeeded = KVtCallStateActionArray[ aData.iCallState ] -
                    KVtCallStateActionArray[callState] > 0;
        if ( isWaitingCall )
            {
            launchNeeded = EFalse;
            }
        callState = aData.iCallState;
            
        switch ( callState )
            {
            case ECallStateDialling:
            case ECallStateRinging:
            case ECallStateConnecting:
            case ECallStateConnected:
                SaveCallData( aData,  vtCallInfo);
                break;
            default:
                // data becomes invalid in other states (=call clearing/idle)
                ClearData(vtCallInfo, callState);
                break;
            }
        if ( launchNeeded )
            {
            LaunchVtAppL();
            }
        if ( !isWaitingCall )
            {
            RaiseVtEventL();
            }
        }
        
    TRACE("CVtMediatorPlugin.HandleCallStateChangeL>" )
    }

// -----------------------------------------------------------------------------
// CVtMediatorPlugin::IsEnoughMemory
//
// Check if there is enough memory to launch
// -----------------------------------------------------------------------------
//
TBool CVtMediatorPlugin::IsEnoughMemory()
    {
    TRACE("CVtMediatorPlugin::IsEnoughMemory<" )    
    // Fetch amount of free memory.
    TMemoryInfoV1Buf memory;
    UserHal::MemoryInfo( memory );
    TInt freeRam = (TInt)( memory().iFreeRamInBytes );
    TRACE2("CVtMediatorPlugin::IsEnoughMemory: freeRam = %d", freeRam )
    
    TBool enoughRam = ETrue;

    if ( freeRam < KRamNeededForVideoCalls )
        {
        FreeRam();
        freeRam = (TInt)( memory().iFreeRamInBytes );
        TRACE2("CVtMediatorPlugin::IsEnoughMemory: after free, freeRam = %d", freeRam )
        if ( freeRam < KRamNeededForVideoCalls )
            {
            enoughRam = EFalse;
            TRACE ("CVtMediatorPlugin::IsEnoughMemory : Not enough RAM")
                
            }
        }
    TRACE("CVtMediatorPlugin::IsEnoughMemory>" )    
    return enoughRam;
    }  
// -----------------------------------------------------------------------------
// CVtMediatorPlugin::FreeRam
// Try to free memory to match the memory usage of VT
// -----------------------------------------------------------------------------
//
void CVtMediatorPlugin::FreeRam()
    {
    TRACE("CVtMediatorPlugin.FreeRam()<")
    User::CompressAllHeaps();
    TRACE("CVtMediatorPlugin.FreeRam()>")
    }

// -----------------------------------------------------------------------------
// CVtMediatorPlugin::StopDeathActiveL
// -----------------------------------------------------------------------------
//
void CVtMediatorPlugin::StopDeathActiveL()
    {
    TRACE("CVtMediatorPlugin.StopDeathActive<")
    delete iAppDeathActive;
    iAppThread.Close();
    //if there is a waiting call, check if we need to launch it
    TRACE2("CVtMediatorPlugin.StopDeathActive WaitintCallID=%d>",
            iWaitingVideoCallInfo.iCallId)
    if ( iWaitingVideoCallInfo.iCallId != KVtInitCallId )
        {
        iActiveVideoCallInfo = iWaitingVideoCallInfo;
        iActiveVideoCallState = iWaitingVideoCallState;
        ClearData(iWaitingVideoCallInfo, iWaitingVideoCallState);
        
        if ( iActiveVideoCallState == ECallStateDialling ||
                iActiveVideoCallState ==  ECallStateRinging ||
                iActiveVideoCallState == ECallStateConnecting ||
                iActiveVideoCallState == ECallStateConnected ||
                iActiveVideoCallState == ECallStateAnswering )
                {
                LaunchVtAppL();
                RaiseVtEventL();
                }
        }
    TRACE("CVtMediatorPlugin.StopDeathActive>")
    }
// -----------------------------------------------------------------------------
// CVtMediatorPlugin::CAppDeathActive::CAppDeathActive
// -----------------------------------------------------------------------------
//
CVtMediatorPlugin::CAppDeathActive::CAppDeathActive( 
        CVtMediatorPlugin& aMediatorPlugin,
        RThread& aAppThread
    )
    : CActive( CActive::EPriorityStandard ),
      iMediatorPlugin( aMediatorPlugin ),
      iAppThread( aAppThread )
      
    {
    CActiveScheduler::Add( this );
    }

// -----------------------------------------------------------------------------
// CVtMediatorPlugin::CAppDeathActive::~CAppDeathActive
// -----------------------------------------------------------------------------
//
CVtMediatorPlugin::CAppDeathActive::~CAppDeathActive()
    {
    TRACE("CVtMediatorPlugin.~CAppDeathActive")
    Cancel();
    }

// -----------------------------------------------------------------------------
// CVtMediatorPlugin::CAppDeathActive::Start
// -----------------------------------------------------------------------------
//
void CVtMediatorPlugin::CAppDeathActive::Start()
    {
    TRACE("CVtMediatorPlugin.Start<")
    Cancel();
    iAppThread.Logon( iStatus );
    SetActive();
    TRACE("CVtMediatorPlugin.Start>")
    }

// -----------------------------------------------------------------------------
// CVtMediatorPlugin::CAppDeathActive::RunL
// -----------------------------------------------------------------------------
//
void CVtMediatorPlugin::CAppDeathActive::RunL()
    {
    //do something here
    TRACE("CVtMediatorPlugin.RunL<")
    iMediatorPlugin.StopDeathActiveL();
    TRACE("CVtMediatorPlugin.RunL>")
      
    }
        
// -----------------------------------------------------------------------------
// CVtMediatorPlugin::CAppDeathActive::DoCancel
// -----------------------------------------------------------------------------
//
void CVtMediatorPlugin::CAppDeathActive::DoCancel()
    {
    iAppThread.LogonCancel( iStatus );
    }
        
// -----------------------------------------------------------------------------
// CVtMediatorPlugin::CAppDeathActive::RunError
// -----------------------------------------------------------------------------
//
TInt CVtMediatorPlugin::CAppDeathActive::RunError( TInt /*aError*/ )
    {
    return KErrNone;
    }