mpx/playbackframework/playbackengine/src/mpxautoresumehandler.cpp
author Pat Downey <patd@symbian.org>
Wed, 01 Sep 2010 12:23:05 +0100
branchRCL_3
changeset 56 63223d4fd956
parent 55 6c1dfe4da5dd
permissions -rw-r--r--
Revert incorrect RCL_3 drop: Revision: 201033 Kit: 201035

/*
* Copyright (c) 2006 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: Implemention of the auto resume handler.
*
*/


#include <e32std.h>
#include <ctsydomainpskeys.h>
#include <mpxpskeywatcher.h>
#include <mpxlog.h>
#include "mpxplaybackengine.h"
#include "mpxautoresumehandler.h"

// CONSTANTS
const TInt KMPXErrDiedTimeout = 2000000;
// Time to wait before resume after call has ended.
const TInt KMPXResumeWaitTime = 3000000; // 3.0s

// TODO: the following constants and definitions are copied from nssvascoreconstant.h, which is not
// included directly because it is an App layer API. Way to fix this is to ask Speechsrv to move the header file to MW layer.
const TUid KSINDUID = {KUidSystemCategoryValue};
const TInt ERecognitionState=0;

// Recognition state values for the P&S key ERecognitionState
enum TRecognitionStateValues
    {
    ERecognitionStarted = 0, 
    ERecognitionSpeechEnd, 
    ERecognitionSuccess, 
    ERecognitionFail
    };
// End TODO


// ================= MEMBER FUNCTIONS =======================


// -----------------------------------------------------------------------------
// C++ constructor
// -----------------------------------------------------------------------------
//
CMPXAutoResumeHandler::CMPXAutoResumeHandler(
    CMPXPlaybackEngine& aEngine,
    TBool aMixerSupport) :
    iEngine(aEngine),
    iMixerSupport(aMixerSupport),
    iAutoResume(ETrue)
    {
    }

// -----------------------------------------------------------------------------
// Symbian OS default constructor
// -----------------------------------------------------------------------------
//
void CMPXAutoResumeHandler::ConstructL()
    {
    // Listen to call state changes
    iStateObserver = CMPXPSKeyWatcher::NewL(KPSUidCtsyCallInformation,
                                            KCTsyCallState,this);

    // Listen to call type changes
    iTypeObserver = CMPXPSKeyWatcher::NewL(KPSUidCtsyCallInformation,
                                           KCTsyCallType,this);
    
    iVoiceCmdObserver = CMPXPSKeyWatcher::NewL( KSINDUID, ERecognitionState, this );
    
    iResumeTimer = CPeriodic::NewL(CActive::EPriorityStandard);
    }

// -----------------------------------------------------------------------------
// Constructs a new entry with given values.
// -----------------------------------------------------------------------------
//
CMPXAutoResumeHandler* CMPXAutoResumeHandler::NewL(
                                         CMPXPlaybackEngine& aEngine,
                                         TBool aMixerSupport)
    {
    CMPXAutoResumeHandler* self =
        new (ELeave) CMPXAutoResumeHandler(aEngine, aMixerSupport);

    CleanupStack::PushL(self);
    self->ConstructL();
    CleanupStack::Pop( self );

    return self;
    }

// -----------------------------------------------------------------------------
// CMPXAutoResumeHandler::CMPXAutoResumeHandler()
// Destructor
// -----------------------------------------------------------------------------
//
CMPXAutoResumeHandler::~CMPXAutoResumeHandler()
    {
    delete iVoiceCmdObserver;
    delete iStateObserver;
    delete iTypeObserver;
    if ( iResumeTimer )
        {
        CancelResumeTimer();
        delete iResumeTimer;
        }
    }

// -----------------------------------------------------------------------------
// Open file completed
// -----------------------------------------------------------------------------
//
void CMPXAutoResumeHandler::HandleOpenFileComplete()
    {
    MPX_FUNC("CMPXAutoResumeHandler::HandleOpenFileComplete()");
    iPausedForCall = EFalse;
    }

// -----------------------------------------------------------------------------
// CMPXAutoResumeHandler::MPlayerStateChanged
// -----------------------------------------------------------------------------
//
void CMPXAutoResumeHandler::HandlePlaybackStateChange(TMPXPlaybackState aState)
    {
    MPX_DEBUG2("CMPXAutoResumeHandler::HandlePlaybackStateChange(%d) entering", aState);

    // Any state change means that possible waiting resume is not to be done
    // anymore.
    CancelResumeTimer();

    if (aState != EPbStatePaused)
        {
        iPausedForCall = EFalse;
        }
    MPX_DEBUG1("CMPXAutoResumeHandler::HandlePlaybackStateChange() exiting");
    }

// -----------------------------------------------------------------------------
// CMPXAutoResumeHandler::MPlayerPlayComplete
// -----------------------------------------------------------------------------
//
void CMPXAutoResumeHandler::HandlePlaybackComplete(TInt aError)
    {
    MPX_DEBUG2("CMPXAutoResumeHandler::HandlePlaybackComplete(%d) entering", aError);
    iPausedForCall = EFalse;
    if ( KErrDied == aError ||
         KErrAccessDenied == aError || 
         KErrInUse == aError )
        {
        iKErrDiedTime.HomeTime();

        TInt callType = EPSCTsyCallTypeNone;
        TInt callState = EPSCTsyCallStateNone;
        TInt voiceCmdState(0);
        
        if (!iTypeObserver->GetValue(callType) &&
            !iStateObserver->GetValue(callState))
            {
            if ((callState == EPSCTsyCallStateRinging && iMixerSupport) ||
                 ShouldPause())
                {
                // Getting a play complete with KErrDied here
                // means Audio Policy terminated our playback,
                // due to phone call being connected. Enable
                // autoresume.
                iPausedForCall = ETrue;
                }
            }
        
        if ( !iPausedForCall && !iVoiceCmdObserver->GetValue( voiceCmdState ) ) // key exist if voice commanding is in progress
            {
            // Paused due voice command activity
            iPausedForVoiceCmd = ETrue;
            }
        }
    
    MPX_DEBUG3("CMPXAutoResumeHandler::HandlePlaybackComplete() exiting: iPausedForCall=%d, iPausedForVoiceCmd=%d",
               iPausedForCall, iPausedForVoiceCmd);
    }

// -----------------------------------------------------------------------------
// CMPXAutoResumeHandler::CancelResumeTimer
// -----------------------------------------------------------------------------
//
void CMPXAutoResumeHandler::CancelResumeTimer()
    {
    if ( iResumeTimer )
        {
        iResumeTimer->Cancel();
        }
    }

// -----------------------------------------------------------------------------
// CMPXAutoResumeHandler::HandlePSEvent
// -----------------------------------------------------------------------------
//
void CMPXAutoResumeHandler::HandlePSEvent(TUid aUid, TInt /*aKey*/)
    {
    MPX_FUNC("CMPXAutoResumeHandler::HandlePSEvent()");
    
    if ( aUid == KSINDUID )
        {
        DoHandleVoiceCmdChange();
        }
    else
        {
        TRAP_IGNORE(DoHandleStateChangeL());
        }
    }

// -----------------------------------------------------------------------------
// CMPXAutoResumeHandler::DoHandleStateChangeL
// -----------------------------------------------------------------------------
//
void CMPXAutoResumeHandler::DoHandleStateChangeL()
    {
    MPX_FUNC("CMPXAutoResumeHandler::DoHandleStateChangeL()");
    MPX_DEBUG2("CMPXAutoResumeHandler::DoHandleStateChangeL(): iPausedForCall = %d", iPausedForCall);
    MPX_DEBUG2("CMPXAutoResumeHandler::DoHandleStateChangeL(): engineState = %d", iEngine.State());
    // if autoresume is disabled, do nothing
    if ( !iAutoResume )
        {
        return;
        }
    
    TBool shouldPause = ShouldPause();
    if (shouldPause &&
        !iPausedForCall &&
        iEngine.State() == EPbStatePlaying)
        {
        iEngine.HandleCommandL(EPbCmdPause);
        iPausedForCall = ETrue;
        }
    else if ( shouldPause &&
            !iPausedForCall &&
            ( iEngine.State() == EPbStateSeekingForward ||
            iEngine.State() == EPbStateSeekingBackward ) )
        {
        iEngine.HandleCommandL( EPbCmdStopSeeking );
        if ( iEngine.State() == EPbStatePlaying )
            {
            iEngine.HandleCommandL( EPbCmdPause );
            iPausedForCall = ETrue;
            }
        }
    else if(!shouldPause &&
            iPausedForCall &&
            iEngine.State() == EPbStatePaused)
        {
        MPX_DEBUG1("CMPXAutoResumeHandler::DoHandleStateChangeL(): starting resume timer");
        if ( iResumeTimer->IsActive() )
            iResumeTimer->Cancel();
        iResumeTimer->Start(
            KMPXResumeWaitTime,
            KMPXResumeWaitTime,
            TCallBack(ResumeTimerCallback, this) );
        iPausedForCall = EFalse;
        }
    else if ( shouldPause &&
             iEngine.State() == EPbStatePaused &&
             !iPausedForCall &&
             iKErrDiedTime.Int64())
        {
        // Check if we recently got a playcomplete with KErrDied,
        // it was most likely caused by an active call
        TTime now;
        now.HomeTime();
        TInt64 deltaTime = now.MicroSecondsFrom(iKErrDiedTime).Int64();
        if ( deltaTime > 0 &&
             deltaTime < KMPXErrDiedTimeout)
            {
            iResumeTimer->Cancel();
            iPausedForCall = ETrue;
            }
        }
    
    if ( shouldPause && iVoiceCmdResumeOngoing )
        {
        // Resume timer has been started after a voice command, cancel it now
        // so that playback is not resumed while calling
        if ( iResumeTimer->IsActive() )
            {
            iResumeTimer->Cancel();
            }
        iVoiceCmdResumeOngoing = EFalse;
        iPausedForCall = ETrue; // resume playback once call has been ended
        }
    
    MPX_DEBUG2("CMPXAutoResumeHandler::DoHandleStateChangeL(): iPausedForCall = %d", iPausedForCall);
    }

// -----------------------------------------------------------------------------
// CMPXAutoResumeHandler::ShouldPause
// -----------------------------------------------------------------------------
//
TBool CMPXAutoResumeHandler::ShouldPause()
    {
    MPX_DEBUG1("CMPXAutoResumeHandler::ShouldPause() entering");
    TBool ret = EFalse;

    if ( !IsPlaybackRemote() )
        {
        TInt callType;
        TInt callState;
        iTypeObserver->GetValue(callType);
        iStateObserver->GetValue(callState);
        MPX_DEBUG3("CMPXAutoResumeHandler::ShouldPause(): type = %d, state = %d", callType, callState);

        if (callType == EPSCTsyCallTypeCSVoice ||
            callType == EPSCTsyCallTypeH324Multimedia ||
            callType == EPSCTsyCallTypeVoIP ||
            callType == EPSCTsyCallTypeUninitialized)
            {
            switch (callState)
                {
                case EPSCTsyCallStateAnswering:
                case EPSCTsyCallStateAlerting:
                case EPSCTsyCallStateConnected:
                case EPSCTsyCallStateDialling:
                case EPSCTsyCallStateHold:
                case EPSCTsyCallStateDisconnecting:
                    {
                    ret = ETrue;
                    break;
                    }
                case EPSCTsyCallStateRinging:
                    {
                    if (iPausedForCall)
                       {
                       ret = ETrue;
                       }
                    else
                        {
                        // Pause playback if we cannot mix music playback
                        // with ringing tone.
                        ret = !iMixerSupport;
                        }
                    break;
                    }
                default:
                    {
                    // Default is no pause
                    break;
                    }
                }
            }
        }
    MPX_DEBUG2("CMPXAutoResumeHandler::ShouldPause() exiting: %d", ret);
    return ret;
    }

// -----------------------------------------------------------------------------
// CMPXAutoResumeHandler::HandleResumeTimerCallback
// -----------------------------------------------------------------------------
//
void CMPXAutoResumeHandler::HandleResumeTimerCallback()
    {
    MPX_FUNC("CMPXAutoResumeHandler::HandleResumeTimerCallback() entering");

    iVoiceCmdResumeOngoing = EFalse;
    
    CancelResumeTimer();
    TRAP_IGNORE( iEngine.HandleCommandL( EPbCmdPlayWithFadeIn ));
    }

// -----------------------------------------------------------------------------
// CMPXAutoResumeHandler::ResumeTimerCallbackL
// -----------------------------------------------------------------------------
//
TInt CMPXAutoResumeHandler::ResumeTimerCallback(TAny* aPtr)
    {
    MPX_FUNC("CMPXAutoResumeHandler::ResumeTimerCallback()");

    CMPXAutoResumeHandler* ptr =
        static_cast<CMPXAutoResumeHandler*>(aPtr);
    ptr->HandleResumeTimerCallback();

    return KErrNone;
    }

// -----------------------------------------------------------------------------
// CMPXAutoResumeHandler::IsPlaybackRemote
// -----------------------------------------------------------------------------
//
TBool CMPXAutoResumeHandler::IsPlaybackRemote()
    {
    MPX_DEBUG1("CMPXAutoResumeHandler::IsPlaybackRemote() entering");
    TBool isRemote = EFalse;

    if ( iEngine.State() == EPbStatePlaying )
        {
        TMPXPlaybackPlayerType type( EPbLocal );
        TUid uid;
        TInt index;
        TPtrC subPlayerName( KNullDesC );
        iEngine.PluginHandler()->GetSelection( type, uid,
                                               index, subPlayerName );

        if ( type != EPbLocal )
            {
            isRemote = ETrue;
            }
        }

    MPX_DEBUG2("CMPXAutoResumeHandler::IsPlaybackRemote() exiting: %d", isRemote);
    return isRemote;
    }

// -----------------------------------------------------------------------------
// Set autoresume value
// -----------------------------------------------------------------------------
//
void CMPXAutoResumeHandler::SetAutoResume(TBool aAutoResume)
    {
    MPX_DEBUG2("CMPXAutoResumeHandler::SetAutoResume(): AutoResume = %d", aAutoResume);
    iAutoResume = aAutoResume;
    }

// -----------------------------------------------------------------------------
// CMPXAutoResumeHandler::DoHandleVoiceCmdChange
// -----------------------------------------------------------------------------
//
void CMPXAutoResumeHandler::DoHandleVoiceCmdChange()
    {
    MPX_FUNC("CMPXAutoResumeHandler::DoHandleVoiceCmdChange()");
    
    TInt voiceCmdState( 0 );
    TInt err( iVoiceCmdObserver->GetValue( voiceCmdState ) );
    
    MPX_DEBUG4("CMPXAutoResumeHandler::DoHandleVoiceCmdChange(): iPausedForVoiceCmd = %d, err=%d, state=%d", 
                    iPausedForVoiceCmd, err, voiceCmdState);
    
    if ( iPausedForVoiceCmd && !iPausedForCall )
        {
        if ( err == KErrNotFound ) // voice command has been finished once the P&S key is deleted 
            {
            if ( iResumeTimer->IsActive() )
                  iResumeTimer->Cancel();
            
            iResumeTimer->Start( KMPXResumeWaitTime, KMPXResumeWaitTime, TCallBack(ResumeTimerCallback, this) );
            
            iPausedForVoiceCmd = EFalse;
            
            iVoiceCmdResumeOngoing = ETrue; // flag for cancelling resume timer due to a call
            }
        }
    
    if ( iPausedForCall ) // ensure that not interfering with call handling in any circumstances
        {
        iPausedForVoiceCmd = EFalse;
        }
    }

//  End of File