diff -r 14979e23cb5e -r 3de6c4cf6b67 mpxmusicplayer/mediakeyhandler/src/mpxmediakeyhandlerimp.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mpxmusicplayer/mediakeyhandler/src/mpxmediakeyhandlerimp.cpp Wed Sep 01 12:32:02 2010 +0100 @@ -0,0 +1,1422 @@ +/* +* 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: Implementation of media key handler +* +*/ + + +// INCLUDE FILES +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef UPNP_INCLUDED +#include +#endif + + +#include // AknErrorNote +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mpxmetadatahandler.h" +#include +#include +#include "mpxmediakeyhandlerimp.h" +#include "mpxremconkeyresponse.h" +#include "mpxnotifierdialog.h" + + +// CONSTANTS +const TInt KFirstTimerExpiryInterval( 1 ); // Expire immediately +const TInt KTimerExpiryInterval( KAknStandardKeyboardRepeatRate ); +const TInt KMPXOneSecInMilliSecs( 1000 ); +const TInt KMPXMinVolume(0); +const TInt KMPXMaxVolume(100); // Max volume used in volume popup +const TInt KMPXVolumeSteps(1); +const TInt KTenStepsVolume = 10; +const TInt KTwentyStepsVolume = 20; +const TInt KVolumePopupSynchInterval = 300000; // 300 ms +const TInt KFilterEventInterval( 6000 ); //6ms +const TRemConCoreApiOperationId KSupportedCoreFeatures[] = { + ERemConCoreApiVolumeUp, + ERemConCoreApiVolumeDown, + ERemConCoreApiPlay, + ERemConCoreApiStop, + ERemConCoreApiPause, + ERemConCoreApiRewind, + ERemConCoreApiFastForward, + ERemConCoreApiForward, + ERemConCoreApiBackward, + ERemConCoreApiPausePlayFunction +}; + +_LIT( KMPXMediaKeyHandlerRscPath, "mpxmediakeyhandler.rsc" ); + + +// ======== MEMBER FUNCTIONS ======== + +// --------------------------------------------------------------------------- +// C++ default constructor can NOT contain any code, that +// might leave. +// --------------------------------------------------------------------------- +// +CMPXMediaKeyHandlerImp::CMPXMediaKeyHandlerImp( + MMPXMediaKeyHandlerObserver* aObserver ) : + iObserver( aObserver ), + iEnable( ETrue ), + iCurrentVol( KErrNotFound ), + iVolumeSteps(KMPXMaxVolume), + iPreviousVol( KErrNotFound ) + { + } + +// --------------------------------------------------------------------------- +// Symbian 2nd phase constructor can leave. +// --------------------------------------------------------------------------- +// +void CMPXMediaKeyHandlerImp::ConstructL( + TMPXMediaKeyPopupFlags aFlags ) + { + ASSERT( iObserver ); + CCoeEnv* coeEnv = CEikonEnv::Static(); + TParse parse; + parse.Set( KMPXMediaKeyHandlerRscPath, &KDC_APP_RESOURCE_DIR, NULL ); + TFileName resourceFile( parse.FullName() ); + User::LeaveIfError( MPXUser::CompleteWithDllPath( resourceFile ) ); + BaflUtils::NearestLanguageFile( coeEnv->FsSession(), resourceFile ); + iResourceOffset = coeEnv->AddResourceFileL( resourceFile ); + + // Register to remote control framework + iInterfaceSelector = CRemConInterfaceSelector::NewL(); + + // For AVRCP 1.4 support, pass the core features to the target API. + TInt entrySize = sizeof( KSupportedCoreFeatures[0] ); + TRemConCoreApiOperationId* entries = (TRemConCoreApiOperationId*) &KSupportedCoreFeatures[0]; + TInt count = sizeof( KSupportedCoreFeatures ) / entrySize; + RArray coreFeatures( entrySize, entries, count ); + iCoreTarget = CRemConCoreApiTarget::NewL( *iInterfaceSelector, *this, coreFeatures ); + + // For handling AVRCP 1.3 metadata + iMetaDataHandler = MMPXMetaDataHandler::NewL(*iInterfaceSelector); + + // For AVRCP 1.4 support, make the player named. + HBufC* avsrcname = StringLoader::LoadLC( R_MPX_AVSRC_NAME_TEXT ); + HBufC8* avsrcname8 = CnvUtfConverter::ConvertFromUnicodeToUtf8L( avsrcname->Des() ); + CleanupStack::PushL( avsrcname8 ); + iInterfaceSelector->OpenTargetL(ERemConAudioPlayer, ERemConNoSubType, *avsrcname8); + CleanupStack::PopAndDestroy( avsrcname8 ); + CleanupStack::PopAndDestroy( avsrcname ); + iResponseHandler = CMPXRemConKeyResponse::NewL( *iCoreTarget ); + + // Timer for implementing repeat + iTimer = CPeriodic::NewL( CActive::EPriorityStandard ); + + // Get the playback utility instance from engine. + iPlaybackUtility = MMPXPlaybackUtility::UtilityL( KPbModeDefault ); + iPlaybackUtility->AddObserverL( *this ); + // get the current Volume and Max Volume + iPlaybackUtility->PropertyL(*this, EPbPropertyVolume); + iPlaybackUtility->PropertyL(*this, EPbPropertyMute); + CMMFDevSound* devsound = CMMFDevSound::NewL(); + MPX_DEBUG2( "CMPXMediaKeyHandlerImp::Constructdevsound->MaxVolume()%d",devsound->MaxVolume()); + iVolumeSteps = KTenStepsVolume; //Default 10 steps + if ( devsound && devsound->MaxVolume() >= KTwentyStepsVolume ) + { + // set 20-steps volume + iVolumeSteps = KTwentyStepsVolume; + } + delete devsound; + if ( aFlags & EDisplayVolumePopup ) + { + // Popup volume control + iVolPopup = CAknVolumePopup::NewL(NULL, ETrue); + iVolPopup->SetObserver(this); + iVolPopup->SetRange(KMPXMinVolume, iVolumeSteps); + iVolPopup->SetStepSize(KMPXVolumeSteps); + // Ensure that initial value is set to popup. If not initialized, CAknVolumePopup::Value() returns 0 + // but the control appears unmuted and allows volume to be decreased out of range (panics also with Avkon 6 in UDEB) + iVolPopup->SetValue( 0 ); + + HBufC* popupText = StringLoader::LoadLC( R_MPX_VOLUME_POPUP_TEXT ); + iVolPopup->SetTitleTextL( *popupText ); + CleanupStack::PopAndDestroy( popupText ); + } + + if ( aFlags & EDisplayMediaPopup ) + { + // Playback popup + iPlaybackPopup = CMPXNotifierDialog::NewL(); + } + + MMPXSource* s = iPlaybackUtility->Source(); + if ( s ) + { + RArray attrs; + CleanupClosePushL(attrs); + attrs.Append( KMPXMediaGeneralTitle ); + s->MediaL( attrs.Array(), *this ); + CleanupStack::PopAndDestroy( &attrs ); + } + else + { + // No current track. + // This is constructed so that the first popup will display + // it doesn't hold anything. + iTrackTitle = HBufC::NewL( 1 ); + } +#ifdef UPNP_INCLUDED + if (!iUpnpCopyCommand ) + { + MPX_TRAPD ( error, iUpnpCopyCommand = CUpnpCopyCommand::NewL() ); + if ( error == KErrNone ) + { + iUpnpFrameworkSupport = ETrue; + } + else + { + iUpnpFrameworkSupport = EFalse; + iUpnpCopyCommand = NULL; + } + } +#endif + iVolumePopupSynchTimer = CPeriodic::NewL( CActive::EPriorityStandard ); + iFilterEventTimer = CPeriodic::NewL( CActive::EPriorityStandard ); + } + +// --------------------------------------------------------------------------- +// Two-phased constructor. +// --------------------------------------------------------------------------- +// +MMPXMediaKeyHandler* CMPXMediaKeyHandlerImp::NewL( + TMPXMediaKeyPopupFlags aFlags, + MMPXMediaKeyHandlerObserver* aObserver ) + { + CMPXMediaKeyHandlerImp* self = + new(ELeave)CMPXMediaKeyHandlerImp( aObserver ); + CleanupStack::PushL( self ); + self->ConstructL( aFlags ); + CleanupStack::Pop(); + + return self; + } + +// --------------------------------------------------------------------------- +// Destructor +// --------------------------------------------------------------------------- +// +CMPXMediaKeyHandlerImp::~CMPXMediaKeyHandlerImp() + { + if ( iFilterEventTimer ) + { + iFilterEventTimer->Cancel(); + delete iFilterEventTimer; + } + if ( iVolumePopupSynchTimer ) + { + iVolumePopupSynchTimer->Cancel(); + delete iVolumePopupSynchTimer; + } + if ( iPlaybackUtility ) + { + TRAP_IGNORE( iPlaybackUtility->RemoveObserverL( *this ) ); + iPlaybackUtility->Close(); + } + + delete iMetaDataHandler; + + delete iResponseHandler; + delete iInterfaceSelector; + + if( iTimer ) + { + iTimer->Cancel(); + delete iTimer; + } + + if ( iResourceOffset ) + { + CEikonEnv::Static()->DeleteResourceFile( iResourceOffset ); + } + + delete iTrackTitle; + delete iVolPopup; + delete iPlaybackPopup; +#ifdef UPNP_INCLUDED + if ( iUpnpCopyCommand) + { + delete iUpnpCopyCommand; + } +#endif + } + +// --------------------------------------------------------------------------- +// Filter and send command to playback utility. +// --------------------------------------------------------------------------- +// +void CMPXMediaKeyHandlerImp::FilterAndSendCommand( + TMPXPlaybackCommand aCommandId ) + { + MPX_FUNC( "CMPXMediaKeyHandlerImp::FilterAndSendCommand" ); + TRAP_IGNORE( DoFilterAndSendCommandL( aCommandId ) ); + } + +// --------------------------------------------------------------------------- +// Help filter and send command to playback utility. +// --------------------------------------------------------------------------- +// +void CMPXMediaKeyHandlerImp::DoFilterAndSendCommandL( + TMPXPlaybackCommand aCommandId ) + { + MPX_FUNC( "CMPXMediaKeyHandlerImp::DoFilterAndSendCommandL" ); + // Only send media key events if the media key component is enabled + if( iEnable ) + { + TBool forwardCommand = ETrue; + if ( iUpnpFrameworkSupport ) + { + switch ( aCommandId ) + { + case EPbCmdStartSeekForward: + case EPbCmdStartSeekBackward: + { + if ( IsUpnpVisibleL() ) + { + TFileName subPlayerName; + TMPXPlaybackPlayerType currentPlayerType = EPbLocal; + GetSubPlayerInfoL(subPlayerName, currentPlayerType); + + if ( currentPlayerType != EPbLocal) + { + //show error note + HBufC* dialogText = StringLoader::LoadLC(R_MPX_MEDIA_KEY_NOT_SUPPORTED); + CAknErrorNote* errNote = new(ELeave) CAknErrorNote(ETrue); + errNote->SetTimeout(CAknNoteDialog::ELongTimeout); + errNote->ExecuteLD( *dialogText ); + CleanupStack::PopAndDestroy( dialogText ); + forwardCommand = EFalse; + } + } + break; + } + default: + { + //do nothing + break; + } + } + } + + if ( forwardCommand ) + { + TInt volume(0); + TFileName subPlayerName; + TMPXPlaybackPlayerType currentPlayerType = EPbLocal; + GetSubPlayerInfoL(subPlayerName, currentPlayerType); + + if ( currentPlayerType == EPbRemote ) + { + volume = iUpnpVolume % ( KPbPlaybackVolumeLevelMax / iVolumeSteps ) + + iCurrentVol * KPbPlaybackVolumeLevelMax / iVolumeSteps; + } + else + { + volume = iCurrentVol * KPbPlaybackVolumeLevelMax/iVolumeSteps; + iPreviousVol = iCurrentVol; + } + + if ( volume < KMPXMinVolume ) + { + volume = KMPXMinVolume; + } + if ( volume > KMPXMaxVolume ) + { + volume = KMPXMaxVolume; + } + + MPX_DEBUG3( "CMPXMediaKeyHandlerImp::DoFilterAndSendCommandL: aCommandId(%d), volume(%d)" , aCommandId, volume ); + iObserver->HandleMediaKeyCommand( aCommandId, volume ); + } + } + } + +// --------------------------------------------------------------------------- +// Handle playback message. +// --------------------------------------------------------------------------- +// +void CMPXMediaKeyHandlerImp::DoHandlePlaybackMessageL( + const CMPXMessage& aMessage ) + { + MPX_FUNC( "CMPXMediaKeyHandlerImp::DoHandlePlaybackMessageL(CMPXMessage)"); + + TMPXMessageId id( aMessage.ValueTObjectL( KMPXMessageGeneralId ) ); + if ( KMPXMessagePbMediaChanged == id ) + { + if ( aMessage.IsSupported( KMPXMessagePbMedia ) ) + { + CMPXMedia* media( aMessage.Value( KMPXMessagePbMedia ) ); + User::LeaveIfNull( media ); + iPlaybackPosition = 0; + DoHandleMediaL( *media, KErrNone ); + } + } + else if ( KMPXMessageGeneral == id ) + { + TInt type( aMessage.ValueTObjectL( KMPXMessageGeneralType )); + TInt data( aMessage.ValueTObjectL( KMPXMessageGeneralData )); + switch ( aMessage.ValueTObjectL( KMPXMessageGeneralEvent ) ) + { + case TMPXPlaybackMessage::EPropertyChanged: + { + TMPXPlaybackProperty property( + static_cast( type ) ); + TInt error( KErrNone ); + + DoHandlePropertyL( property, data, error ); + break; + } + case TMPXPlaybackMessage::EStateChanged: + { + MPX_DEBUG2( "CMPXMediaKeyHandlerImp::HandlePlaybackMessageL - EStateChanged(%d)", type ); + + TMPXPlaybackState state = + static_cast( type ); + DoHandleStateChangedL( state ); + break; + } + case TMPXPlaybackMessage::EMediaChanged: + { + MMPXSource* s = iPlaybackUtility->Source(); + if ( s ) + { + RArray attrs; + CleanupClosePushL(attrs); + attrs.Append( KMPXMediaGeneralTitle ); + MPX_DEBUG1( "CMPXMediaKeyHandlerImp::HandlePlaybackMessageL Media changed, calling MediaL to refresh" ); + s->MediaL( attrs.Array(), *this ); + CleanupStack::PopAndDestroy( &attrs ); + } + break; + } + case TMPXPlaybackMessage::ECommandReceived: + { + MPX_DEBUG2( "CMPXMediaKeyHandlerImp::HandlePlaybackMessageL - ECommandReceived(%d)", type ); + break; + } + case TMPXPlaybackMessage::ESkipping: + { + iSkipping = ETrue; + break; + } + case TMPXPlaybackMessage::ESkipEnd: + { + iSkipping = EFalse; + break; + } + default: + { + break; + } + } + } + } + +// --------------------------------------------------------------------------- +// Handle playback property. +// --------------------------------------------------------------------------- +// +void CMPXMediaKeyHandlerImp::DoHandlePropertyL( + TMPXPlaybackProperty aProperty, + TInt aValue, + TInt aError ) + { + MPX_FUNC( "CMPXMediaKeyHandlerImp::DoHandlePropertyL" ); + MPX_DEBUG4( "CMPXMediaKeyHandlerImp::HandlePropertyL - Property(%d); Value(%d); Error(%d)", aProperty, aValue, aError ); + + iUpnpVolume = aValue; + if ( KErrNone == aError ) + { + switch ( aProperty ) + { + case EPbPropertyPosition: + { + iPlaybackPosition = aValue / KMPXOneSecInMilliSecs; + ShowPlaybackPopupL( EMPXPopupShowIfVisible ); + break; + } + case EPbPropertyMute: + { + iMuted = aValue; + StartVolumePopupSynchTimer(); + break; + } + case EPbPropertyVolume: + { + // Avkon Volume has 10 steps, but the rest of the framework + // has 100 steps. Need to scale it to 10 steps. + if ( aValue > 0 ) + { + aValue = aValue * iVolumeSteps; + aValue = aValue / KPbPlaybackVolumeLevelMax; + if ( aValue > iVolumeSteps ) + { + aValue = iVolumeSteps; + } + } + + //if aValue equal to iPreviousVol, MediaKey should not set Volume again. + TBool OkToSetVolume = ( aValue != iPreviousVol ); + iPreviousVol = KErrNotFound; + + if( iMuted && aValue > 0 ) // unmute + { + iMuted = EFalse; + iCurrentVol = aValue; + } + else if( aValue == 0 ) // mute + { + if( !iMuted ) + { + iMuted = ETrue; + } + } + else if ( aValue != iCurrentVol ) + { + if ( aValue != 0 && OkToSetVolume && ( iResponseHandler->iCountOfVolumeCommands == 0 ) ) + { + // if we are processing remcon events we shouldn't change the current volume value + iCurrentVol = aValue; + } + } + + if ( iCurrentVol == KErrNotFound ) // muted by some other application before launching Music Player + { + iCurrentVol = aValue; + } + + if ( OkToSetVolume ) + { + StartVolumePopupSynchTimer(); + } + + // send a command to UI to display Volume bar on device when controlling volume via UPnP + if ( IsUpnpVisibleL() && iPlayerState != EPbStateNotInitialised ) + { + TFileName subPlayerName; + TMPXPlaybackPlayerType currentPlayerType = EPbLocal; + GetSubPlayerInfoL( subPlayerName, currentPlayerType ); + + if ( currentPlayerType != EPbLocal ) + { + iObserver->HandleMediaKeyCommand( EPbCmdSetVolume, iUpnpVolume ); + } + } + + if ( iUpnpFrameworkSupport ) + { + SetVolumePopupTitleL(); + } + + break; + } + default: + { + break; + } + } + } + else + { + switch ( aProperty ) + { + case EPbPropertyVolume: + case EPbPropertyMute: + { + if ( iVolPopup && iShowPopups & EDisplayVolumePopup ) + { + //show error note + HBufC* dialogText = StringLoader::LoadLC(R_MPX_VOLUME_KEYS_NOT_SUPPORTED); + CAknErrorNote* errNote = new(ELeave) CAknErrorNote(ETrue); + errNote->SetTimeout(CAknNoteDialog::ELongTimeout); + errNote->ExecuteLD( *dialogText ); + CleanupStack::PopAndDestroy( dialogText ); + } + break; + } + default: + { + break; + } + } + } + } + +// --------------------------------------------------------------------------- +// Handle media properties. +// Notes: The client is responsible for delete the object of aProperties. +// --------------------------------------------------------------------------- +// +void CMPXMediaKeyHandlerImp::DoHandleMediaL( + const CMPXMedia& aMedia, + TInt aError ) + { + MPX_FUNC( "CMPXMediaKeyHandlerImp::DoHandleMediaL" ); + + // Delete old title no matter there's error or not + if ( iTrackTitle ) + { + delete iTrackTitle; + iTrackTitle = NULL; + } + + if ( KErrNone == aError ) + { + // Keep track of the current track's title + iTrackTitle = aMedia.ValueText( KMPXMediaGeneralTitle ).AllocL(); + + // Update popup if visible + if ( iShowPopups & EDisplayMediaPopup ) + { + MPX_DEBUG1( "CMPXMediaKeyHandlerImp::DoHandleMediaL EMPXPopupTimeout" ); + ShowPlaybackPopupL( EMPXPopupTimeout ); + } + else + { + ShowPlaybackPopupL( EMPXPopupShowIfVisible ); + } + } + } + +// --------------------------------------------------------------------------- +// Handle playback state changed. +// --------------------------------------------------------------------------- +// +void CMPXMediaKeyHandlerImp::DoHandleStateChangedL( + TMPXPlaybackState aState ) + { + MPX_FUNC( "CMPXMediaKeyHandlerImp::DoHandleStateChangedL" ); + switch ( aState ) + { + case EPbStateStopped: + { + iPlayerState = aState; + ShowPlaybackPopupL( EMPXPopupShowIfVisible ); + break; + } + case EPbStatePlaying: + case EPbStatePaused: + { + iPlayerState = aState; + // Start the time if needed, otherwise, update content if visible + if ( iShowPopups & EDisplayMediaPopup ) + { + MPX_DEBUG1( "CMPXMediaKeyHandlerImp::DoHandleStateChangedL EMPXPopupTimeout" ); + ShowPlaybackPopupL( EMPXPopupTimeout ); + } + else + { + ShowPlaybackPopupL( EMPXPopupShowIfVisibleRestartTimer ); + } + break; + } + default: + { + // do nothing + break; + } + } + } + +// --------------------------------------------------------------------------- +// Callback for timer +// --------------------------------------------------------------------------- +// +TInt CMPXMediaKeyHandlerImp::TimerCallback( TAny* aPtr ) + { + static_cast( aPtr )->HandleRepeatEvent(); + return KErrNone; + } + +// --------------------------------------------------------------------------- +// Handle repeat event +// --------------------------------------------------------------------------- +// +void CMPXMediaKeyHandlerImp::HandleRepeatEvent() + { + UpdateVolume(); + FilterAndSendCommand( iCommandId ); + } + +// ----------------------------------------------------------------------------- +// CMPXMediaKeyHandlerImp::GetSubPlayerInfoL +// Retrieves the current player name and sets the volume popup title +// ----------------------------------------------------------------------------- +// +void CMPXMediaKeyHandlerImp::GetSubPlayerInfoL( + TDes& aSubPlayerName, + TMPXPlaybackPlayerType& aCurrentPlayerType ) + { + aCurrentPlayerType = EPbLocal; + aSubPlayerName = KNullDesC; + +//#ifdef __UPNP_FRAMEWORK_2_0_ + if ( iUpnpFrameworkSupport ) + { + MMPXPlayerManager& manager = iPlaybackUtility->PlayerManager(); + TUid currentlyUsedPlayer; + TInt currentlyUsedSubPlayer; + HBufC* subPlayerName = NULL; + TRAP_IGNORE( manager.GetSelectionL( aCurrentPlayerType, + currentlyUsedPlayer, + currentlyUsedSubPlayer, + subPlayerName ) ); + if ( subPlayerName ) + { + aSubPlayerName = (*subPlayerName); + delete subPlayerName; + } + } +//#endif + } + +// ----------------------------------------------------------------------------- +// CMPXMediaKeyHandlerImp::SetVolumePopupTitleL +// Retrieves the current player name and sets the volume popup title +// ----------------------------------------------------------------------------- +// +void CMPXMediaKeyHandlerImp::SetVolumePopupTitleL() + { + if ( iUpnpFrameworkSupport && IsUpnpVisibleL() ) + { + TFileName subPlayerName; + TMPXPlaybackPlayerType currentPlayerType = EPbLocal; + + GetSubPlayerInfoL(subPlayerName, currentPlayerType); + if ( currentPlayerType != EPbLocal) + { + iVolPopup->SetTitleTextL( subPlayerName ); + } + else // need to restore original title + { + HBufC* popupText = StringLoader::LoadLC( R_MPX_VOLUME_POPUP_TEXT ); + iVolPopup->SetTitleTextL( *popupText ); + CleanupStack::PopAndDestroy( popupText ); + } + } + } + +// ----------------------------------------------------------------------------- +// CMPXMediaKeyHandlerImp::IsUpnpVisibleL +// Taken from Gallery upnp support implementation +// ----------------------------------------------------------------------------- +// +TBool CMPXMediaKeyHandlerImp::IsUpnpVisibleL() + { + MPX_FUNC( "CMPXMediaKeyHandlerImp::IsUpnpVisible" ); + TBool returnValue = EFalse; +#ifdef UPNP_INCLUDED + if ( iUpnpCopyCommand && iUpnpFrameworkSupport ) + { + returnValue = iUpnpCopyCommand->IsAvailableL(); + } +#endif + return returnValue; + } + +// --------------------------------------------------------------------------- +// Updates the volume and the volume command +// --------------------------------------------------------------------------- +// +void CMPXMediaKeyHandlerImp::UpdateVolume() + { + // Current volume level is not yet initialised + if( iCurrentVol < 0 ) + { + MPX_DEBUG1( "CMPXMediaKeyHandlerImp::UpdateVolume not initialised"); + return; + } + + if ( iIncreaseVol ) + { + if ( iMuted ) + { + iMuted = EFalse; + iCommandId = EPbCmdUnMuteVolume; + if ( iCurrentVol == 0 ) // prevent muting again when HandleControlEvent is called next time + { + iCurrentVol = 1; // "1" is the first step of 20-step volume + } + iVolPopup->SetValue( iCurrentVol ); + } + else + { + iCommandId = EPbCmdSetVolume; + iCurrentVol = iCurrentVol < iVolumeSteps ? (iCurrentVol + 1) : iCurrentVol; + iVolPopup->SetValue( iCurrentVol ); + } + } + else + { + if ( iCurrentVol == 1 ) + { + iMuted = ETrue; + iCommandId = EPbCmdMuteVolume; + iVolPopup->SetValue( 0 ); + } + else if ( iMuted ) // Muted && volume > 1 + { + iMuted = EFalse; + iCommandId = EPbCmdUnMuteVolume; + iVolPopup->SetValue( iCurrentVol ); + } + else + { + iCommandId = EPbCmdSetVolume; + iCurrentVol = iCurrentVol - 1; + iVolPopup->SetValue( iCurrentVol ); + } + } + } + +// --------------------------------------------------------------------------- +// From MMPXMediaKeyHandler +// Show playback popup. +// --------------------------------------------------------------------------- +// +void CMPXMediaKeyHandlerImp::ShowPlaybackPopupL( + TMPXPlaybackPopupModes aMode ) + { + MPX_FUNC( "CMPXMediaKeyHandlerImp::ShowPlaybackPopupL" ); + + // Check to see is it ok to display popup + if ( !iPlaybackPopup || !iTrackTitle ) + { + return; + } + + switch ( aMode ) + { + case EMPXPopupShowIfVisibleRestartTimer: + case EMPXPopupTimeout: + { + iShowPopups &= ~EDisplayMediaPopup; + break; + } + case EMPXPopupNoTimeout: + { + iShowPopups |= EDisplayMediaPopup; + break; + } + case EMPXPopupShowIfVisible: + { + if ( iShowPopups & EDisplayMediaPopup ) + { + aMode = EMPXPopupNoTimeout; + } + break; + } + default: + { + break; + } + } + + CMPXNotifierDialog::TMPXPlaybackPopupIcons icon( + CMPXNotifierDialog::EMPXPopupNoneIcon ); + TMPXPlaybackState playerState( EPbStateNotInitialised ); + + // Get current playback state from playback utility + playerState = iPlaybackUtility->StateL(); + switch ( playerState ) + { + case EPbStatePlaying: + { + icon = CMPXNotifierDialog::EMPXPopupPlayIcon; + break; + } + case EPbStatePaused: + { + icon = CMPXNotifierDialog::EMPXPopupPauseIcon; + break; + } + case EPbStateSeekingForward: + icon = CMPXNotifierDialog::EMPXPopupFFIcon; + break; + case EPbStateSeekingBackward: + { + icon = CMPXNotifierDialog::EMPXPopupFRIcon; + break; + } + case EPbStateStopped: + { + // no icon if in stopped state + break; + } + default: + { + // not to display popup in other states + return; + } + } + + if ( iTrackTitle->Length() ) + { + MPX_DEBUG2( "CMPXMediaKeyHandlerImp::ShowPlaybackPopupL aMode = %d", aMode ); + iPlaybackPopup->ShowInfoPopupL( + icon, *iTrackTitle, iSkipping ? KErrNotFound : iPlaybackPosition, aMode ); + } + } + +// --------------------------------------------------------------------------- +// From MMPXMediaKeyHandler +// Show Volume popup +// --------------------------------------------------------------------------- +// +void CMPXMediaKeyHandlerImp::ShowVolumePopupL() + { + MPX_FUNC( "CMPXMediaKeyHandlerImp::ShowVolumePopupL" ); + if ( iVolPopup ) + { + iShowPopups |= EDisplayVolumePopup; + iVolPopup->ShowVolumePopupL(); + } + } + +// --------------------------------------------------------------------------- +// From MMPXMediaKeyHandler +// Dismiss notifier popup. +// --------------------------------------------------------------------------- +// +void CMPXMediaKeyHandlerImp::DismissNotifier( + TMPXMediaKeyPopupFlags aFlags ) + { + MPX_FUNC( "CMPXMediaKeyHandlerImp::DismissNotifier" ); + if ( aFlags & EDisplayMediaPopup && iPlaybackPopup ) + { + iPlaybackPopup->CancelInfoPopup(); + iShowPopups &= ~EDisplayMediaPopup; + } + + if ( aFlags & EDisplayVolumePopup && iVolPopup ) + { + iVolPopup->CloseVolumePopup(); + iShowPopups &= ~EDisplayVolumePopup; + } + } + +// --------------------------------------------------------------------------- +// From MMPXMediaKeyHandler +// Enable or disable media keys +// --------------------------------------------------------------------------- +// +void CMPXMediaKeyHandlerImp::SetEnableMediaKeys( TBool aEnable ) + { + iEnable = aEnable; + } + +// --------------------------------------------------------------------------- +// From MMPXMediaKeyHandler +// Gets called when orientation change begins +// --------------------------------------------------------------------------- +// +void CMPXMediaKeyHandlerImp::NotifyOrientationChangeBegin() + { + iPlaybackPopup->NotifyOrientationChangeBegin(); + } + +// From MMPXPlaybackObserver +// Handle playback message. +// --------------------------------------------------------------------------- +// +void CMPXMediaKeyHandlerImp::HandlePlaybackMessage( + CMPXMessage* aMessage, TInt aError ) + { + if ( aError == KErrNone && aMessage ) + { + TRAP_IGNORE( DoHandlePlaybackMessageL( *aMessage ) ); + } + } + +// --------------------------------------------------------------------------- +// From MMPXPlaybackCallback +// Handle playback property. +// --------------------------------------------------------------------------- +// +void CMPXMediaKeyHandlerImp::HandlePropertyL( + TMPXPlaybackProperty aProperty, + TInt aValue, + TInt aError ) + { + TRAP_IGNORE( DoHandlePropertyL( aProperty, aValue, aError ) ); + } + +// --------------------------------------------------------------------------- +// From MMPXPlaybackCallback +// Method is called continously until aComplete=ETrue, signifying that +// it is done and there will be no more callbacks +// Only new items are passed each time +// --------------------------------------------------------------------------- +// +void CMPXMediaKeyHandlerImp::HandleSubPlayerNamesL( + TUid /* aPlayer */, + const MDesCArray* /* aSubPlayers */, + TBool /* aComplete */, + TInt /* aError */ ) + { + MPX_FUNC( "CMPXMediaKeyHandlerImp::HandleSubPlayerNamesL" ); + } + +// --------------------------------------------------------------------------- +// From MMPXPlaybackCallback +// Handle media properties. +// Notes: The client is responsible for delete the object of aMedia. +// --------------------------------------------------------------------------- +// +void CMPXMediaKeyHandlerImp::HandleMediaL( + const CMPXMedia& aMedia, + TInt aError ) + { + MPX_FUNC( "CMPXMediaKeyHandlerImp::HandleMediaL" ); + TRAP_IGNORE( DoHandleMediaL( aMedia, aError ) ); + } + +// --------------------------------------------------------------------------- +// A 'play' command has been received. +// --------------------------------------------------------------------------- +// +void CMPXMediaKeyHandlerImp::MrccatoPlay( + TRemConCoreApiPlaybackSpeed /* aSpeed */, + TRemConCoreApiButtonAction aButtonAct ) + { + MPX_DEBUG2( "-->CMPXMediaKeyHandlerImp::MrccatoPlay(aButtonAct=%d)", aButtonAct ); + + if ( ( aButtonAct == ERemConCoreApiButtonClick ) || + ( aButtonAct == ERemConCoreApiButtonPress ) ) + { + FilterAndSendCommand( EPbCmdPlay ); + } + iResponseHandler->CompleteAnyKey( ERemConCoreApiPlay ); + MPX_DEBUG1( "<--CMPXMediaKeyHandlerImp::MrccatoPlay"); + } + +// --------------------------------------------------------------------------- +// A command has been received. +// --------------------------------------------------------------------------- +// +void CMPXMediaKeyHandlerImp::MrccatoCommand( + TRemConCoreApiOperationId aOperationId, + TRemConCoreApiButtonAction aButtonAct ) + { + MPX_DEBUG3( "CMPXMediaKeyHandlerImp::MrccatoCommand(aOperationId=%d, aButtonAct=%d)", aOperationId, aButtonAct ); + + switch (aOperationId) + { + case ERemConCoreApiPausePlayFunction: + { + if ( aButtonAct == ERemConCoreApiButtonClick ) + { + FilterAndSendCommand( EPbCmdPlayPause ); + } + break; + } + case ERemConCoreApiPlay: + { + if ( ( aButtonAct == ERemConCoreApiButtonClick ) || + ( aButtonAct == ERemConCoreApiButtonPress ) ) + { + FilterAndSendCommand( EPbCmdPlay ); + } + break; + } + case ERemConCoreApiStop: + { + if ( ( aButtonAct == ERemConCoreApiButtonClick ) || + ( aButtonAct == ERemConCoreApiButtonPress ) ) + { + FilterAndSendCommand( EPbCmdStop ); + } + break; + } + case ERemConCoreApiPause: + { + if ( ( aButtonAct == ERemConCoreApiButtonClick ) || + ( aButtonAct == ERemConCoreApiButtonPress ) ) + { + FilterAndSendCommand( EPbCmdPause ); + } + break; + } + case ERemConCoreApiRewind: + { + switch ( aButtonAct ) + { + case ERemConCoreApiButtonPress: + { + FilterAndSendCommand( EPbCmdStartSeekBackward ); + break; + } + case ERemConCoreApiButtonRelease: + { + FilterAndSendCommand( EPbCmdStopSeeking ); + break; + } + default: + { + break; + } + } + break; + } + case ERemConCoreApiFastForward: + { + switch ( aButtonAct ) + { + case ERemConCoreApiButtonPress: + { + FilterAndSendCommand( EPbCmdStartSeekForward ); + break; + } + case ERemConCoreApiButtonRelease: + { + FilterAndSendCommand( EPbCmdStopSeeking ); + break; + } + default: + { + break; + } + } + break; + } + case ERemConCoreApiBackward: + { + if ( ( aButtonAct == ERemConCoreApiButtonClick ) || + ( aButtonAct == ERemConCoreApiButtonRelease ) ) + { + FilterAndSendCommand( EPbCmdPrevious ); + } + break; + } + case ERemConCoreApiForward: + { + if ( ( aButtonAct == ERemConCoreApiButtonClick ) || + ( aButtonAct == ERemConCoreApiButtonRelease ) ) + { + FilterAndSendCommand( EPbCmdNext ); + } + break; + } + case ERemConCoreApiVolumeUp: + case ERemConCoreApiVolumeDown: + { + iResponseHandler->iCountOfVolumeCommands++; + iTimer->Cancel(); + MMPXPlaybackUtility* pbUtil( NULL ); + MPX_TRAPD( err, pbUtil = MMPXPlaybackUtility::UtilityL( KPbModeActivePlayer )); + if( err != KErrNone ) + { + MPX_DEBUG2( "CMPXMediaKeyHandlerImp::MrccatoCommand ERemConCoreApiVolumeDown leave err%d", err ); + break; + } + TMPXPlaybackState playerState( EPbStateNotInitialised ); + TRAP_IGNORE( playerState = pbUtil->StateL()); + pbUtil->Close(); + pbUtil = NULL; + + if( playerState == EPbStatePlaying || IsAppForeground() ) + { + iIncreaseVol = (aOperationId == ERemConCoreApiVolumeUp ? ETrue: EFalse); + switch (aButtonAct) + { + case ERemConCoreApiButtonPress: + { + //Start Timer + iTimer->Start( + KFirstTimerExpiryInterval, + KTimerExpiryInterval, + TCallBack( TimerCallback, this ) ); + break; + } + case ERemConCoreApiButtonClick: + { + UpdateVolume(); + FilterAndSendCommand( iCommandId ); + break; + } + case ERemConCoreApiButtonRelease: + default: + { + break; + } + } + } + break; + } + default: + { + break; + } + } + iResponseHandler->CompleteAnyKey( aOperationId ); + MPX_DEBUG1( "<--CMPXMediaKeyHandlerImp::MrccatoCommand"); + } + +// --------------------------------------------------------------------------- +// A 'tune function' command has been received. +// --------------------------------------------------------------------------- +// +void CMPXMediaKeyHandlerImp::MrccatoTuneFunction( + TBool /* aTwoPart */, + TUint /* aMajorChannel */, + TUint /* aMinorChannel */, + TRemConCoreApiButtonAction /* aButtonAct */ ) + { + iResponseHandler->CompleteAnyKey( + ERemConCoreApiTuneFunction ); + } + +// --------------------------------------------------------------------------- +// A 'select disk function' has been received. +// --------------------------------------------------------------------------- +// +void CMPXMediaKeyHandlerImp::MrccatoSelectDiskFunction( + TUint /* aDisk */, + TRemConCoreApiButtonAction /* aButtonAct */ ) + { + iResponseHandler->CompleteAnyKey( + ERemConCoreApiSelectDiskFunction ); + } + +// --------------------------------------------------------------------------- +// A 'select AV input function' has been received. +// --------------------------------------------------------------------------- +// +void CMPXMediaKeyHandlerImp::MrccatoSelectAvInputFunction( + TUint8 /* aAvInputSignalNumber */, + TRemConCoreApiButtonAction /* aButtonAct */ ) + { + iResponseHandler->CompleteAnyKey( + ERemConCoreApiSelectAvInputFunction ); + } + +// --------------------------------------------------------------------------- +// A 'select audio input function' has been received. +// --------------------------------------------------------------------------- +// +void CMPXMediaKeyHandlerImp::MrccatoSelectAudioInputFunction( + TUint8 /* aAudioInputSignalNumber */, + TRemConCoreApiButtonAction /* aButtonAct */ ) + { + iResponseHandler->CompleteAnyKey( + ERemConCoreApiSelectAudioInputFunction ); + } + +// ---------------------------------------------------------------------------- +// void CMPlayerBaseView::HandleControlEventL +// ---------------------------------------------------------------------------- +// +void CMPXMediaKeyHandlerImp::HandleControlEventL( CCoeControl* aControl, TCoeEvent aEventType ) + { + MPX_FUNC("CMPXMediaKeyHandlerImp::HandleControlEventL"); + if ( !AknLayoutUtils::PenEnabled() ) + { + return; + } + + if( (aEventType == EEventStateChanged) && (aControl == iVolPopup) ) + { + TInt vol = iVolPopup->Value(); + + MPX_DEBUG4( "CMPXMediaKeyHandlerImp::HandleControlEventL: vol(%d), iCurrentVol(%d), iMuted(%d)", vol, iCurrentVol, iMuted ); + + if ( vol == iCurrentVol && vol != 0 ) + { + if ( iMuted ) + { + iMuted = EFalse; + FilterAndSendCommand( EPbCmdUnMuteVolume ); + } + else + { + return; + } + } + + if ( vol == 0 ) + { + if ( iMuted ) + { + return; + } + else + { + iMuted = ETrue; + FilterAndSendCommand( EPbCmdMuteVolume ); + } + } + else + { + if ( iMuted ) + { + iMuted = EFalse; + + if ( iCurrentVol == 0 ) // setting volume to 0 would reapply mute, use slider value instead + { + iCurrentVol = vol; + } + + iVolPopup->SetValue( iCurrentVol ); + FilterAndSendCommand( EPbCmdUnMuteVolume ); + } + else + { + iCurrentVol = vol; + //VolPopup CallBack functon is frequently called, + //But Music Palyer deals with the event slowly + //Thus VolPopup will not display smoothly. + //So Music Player needs timer to filter some events. + if ( !iFilterEventTimer->IsActive() ) + { + iFilterEventTimer->Start( KFilterEventInterval, + KFilterEventInterval, + TCallBack( FilterEventTimerCallback, this ) ); + } + } + } + } + } + +// --------------------------------------------------------------------------- +// Check the mpx app is foreground. +// --------------------------------------------------------------------------- +// +TBool CMPXMediaKeyHandlerImp::IsAppForeground() + { + TBool isForeground( EFalse ); + // Gets the window group id of the app in foreground + RWsSession& wsSession = CCoeEnv::Static()->WsSession(); + TInt windowGroupId = wsSession.GetFocusWindowGroup(); + if ( windowGroupId >= 0 ) + { + TRAP_IGNORE( + { + CApaWindowGroupName* wgName = CApaWindowGroupName::NewL( + wsSession, windowGroupId ); + + isForeground = ( wgName->AppUid() == KAppUidMusicPlayerX ); + delete wgName; + } ); + } + + return isForeground; + } + +// --------------------------------------------------------------------------- +// CMPXMediaKeyHandlerImp::VolumePopupSynchTimerCallback +// --------------------------------------------------------------------------- +// +TInt CMPXMediaKeyHandlerImp::VolumePopupSynchTimerCallback( TAny* aPtr ) + { + static_cast( aPtr )->DoVolumePopupSynch(); + return KErrNone; + } + +// --------------------------------------------------------------------------- +// CMPXMediaKeyHandlerImp::DoVolumePopupSynch +// --------------------------------------------------------------------------- +// +void CMPXMediaKeyHandlerImp::DoVolumePopupSynch() + { + MPX_FUNC("CMPXMediaKeyHandlerImp::DoVolumePopupSynch"); + + iVolumePopupSynchTimer->Cancel(); + + TInt popupValue = iVolPopup->Value(); + + MPX_DEBUG4("CMPXMediaKeyHandlerImp::DoVolumePopupSynch: popupValue(%d), iMuted(%d), iCurrentVol(%d)", + popupValue, iMuted, iCurrentVol ); + + if ( iMuted ) + { + if ( popupValue != 0 ) + { + MPX_DEBUG1("CMPXMediaKeyHandlerImp::DoVolumePopupSynch: popup out of synch (muted)" ); + iVolPopup->SetValue( 0 ); + } + } + else + { + if ( iCurrentVol != popupValue ) + { + MPX_DEBUG1("CMPXMediaKeyHandlerImp::DoVolumePopupSynch: popup out of synch" ); + iVolPopup->SetValue( iCurrentVol ); + } + } + } + +// --------------------------------------------------------------------------- +// CMPXMediaKeyHandlerImp::StartVolumePopupSynchTimer +// --------------------------------------------------------------------------- +// +void CMPXMediaKeyHandlerImp::StartVolumePopupSynchTimer() + { + iVolumePopupSynchTimer->Cancel(); + iVolumePopupSynchTimer->Start( KVolumePopupSynchInterval, + KVolumePopupSynchInterval, + TCallBack( VolumePopupSynchTimerCallback, this ) ); + + } + +// --------------------------------------------------------------------------- +// CMPXMediaKeyHandlerImp::FilterEventTimerCallback +// --------------------------------------------------------------------------- +// +TInt CMPXMediaKeyHandlerImp::FilterEventTimerCallback( TAny* aPtr ) + { + static_cast( aPtr )->DoFilterEventTimer(); + return KErrNone; + } + +// --------------------------------------------------------------------------- +// CMPXMediaKeyHandlerImp::FilterEventTimerCallback +// --------------------------------------------------------------------------- +// +void CMPXMediaKeyHandlerImp::DoFilterEventTimer() + { + MPX_FUNC("CMPXMediaKeyHandlerImp::DoFilterEventTimer"); + iFilterEventTimer->Cancel(); + FilterAndSendCommand( EPbCmdSetVolume ); + } +// End of File