/*
* 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: This class launchs music player, then send play command
* to the player at 2 seconds timeout.
*
*/
// INCLUDE FILES
#include <apacmdln.h>
#include <apgcli.h>
#include <e32property.h>
#include <remconcoreapitarget.h>
#include "btrccplayerstarter.h"
#include "btaudioremconpskeys.h"
#include "debug.h"
// MODULE DATA STRUCTURES
// mpx playeris name is mpx.exe in 5.0.
// it is musicplayer.exe in 3.2.
_LIT(KMpxPlayerExeName, "mpx.exe");
_LIT(KMpxPlayerSearchPatternBySID, "*102072c3*");
_LIT(KVideoPlayerSearchPatternBySID, "*200159B2*");
static const TInt KPlayCmdToPlayerDelay = 6000000; // value will be tuned later
// ================= MEMBER FUNCTIONS =======================
// -----------------------------------------------------------------------------
// CPlayerStarter::NewL
// Two-phased constructor.
// -----------------------------------------------------------------------------
//
CPlayerStarter* CPlayerStarter::NewL()
{
CPlayerStarter* self = new (ELeave) CPlayerStarter();
CleanupStack::PushL(self);
self->ConstructL();
CleanupStack::Pop(self);
return self;
}
void CPlayerStarter::SetCoreTarget(CRemConCoreApiTarget& aTarget)
{
iCoreTarget = &aTarget;
}
// -----------------------------------------------------------------------------
// CPlayerStarter::CPlayerStarter
// C++ constructor.
// -----------------------------------------------------------------------------
//
CPlayerStarter::CPlayerStarter()
:CActive(EPriorityNormal)
{
CActiveScheduler::Add(this);
}
// -----------------------------------------------------------------------------
// CPlayerStarter::ConstructL
// Symbian 2nd phase constructor.
// -----------------------------------------------------------------------------
//
void CPlayerStarter::ConstructL()
{
TRACE_FUNC
iTimer.CreateLocal();
}
// -----------------------------------------------------------------------------
// Destructor.
// -----------------------------------------------------------------------------
//
CPlayerStarter::~CPlayerStarter()
{
TRACE_FUNC
// Starting player is not finished yet, send play command. Just wish the player
// can receive it.
if (IsActive() && iState != ERespondPlayNok)
{
RProperty::Set(KBTAudioRemCon, KBTAudioPlayerControl,
EBTAudioResumePlayer);
}
Cancel();
iTimer.Close();
}
// -----------------------------------------------------------------------------
// CPlayerStarter::RunL
// -----------------------------------------------------------------------------
//
void CPlayerStarter::RunL()
{
TRACE_INFO((_L("CPlayerStarter::RunL() state %d, status %d"), iState, iStatus.Int()));
if (iStatus != KErrNone)
{
iState = EIdle;
return;
}
switch (iState)
{
case ERespondPlayOk:
{
// Response OK has been sent to the remote device, start timer waiting
// for player's initialization.
iTimer.After(iStatus, KPlayCmdToPlayerDelay);
SetActive();
iState = EPlayMusicTiming;
TRACE_INFO(_L("schedule PLAY command ..."));
break;
}
case EPlayMusicTiming:
{
// Player should have fully up and running. Send PLAY command to it
// through our internal Play API.
RProperty::Set(KBTAudioRemCon, KBTAudioPlayerControl,
EBTAudioResumePlayer);
TRACE_INFO(_L("PLAY command sent to btmonobearer"));
iState = EIdle;
break;
}
default:
{
iState = EIdle;
break;
}
}
}
// -----------------------------------------------------------------------------
// CPlayerStarter::RunError
// -----------------------------------------------------------------------------
//
TInt CPlayerStarter::RunError(TInt aError)
{
TRACE_FUNC
(void) aError;
return KErrNone;
}
// -----------------------------------------------------------------------------
// CPlayerStarter::DoCancel
// -----------------------------------------------------------------------------
//
void CPlayerStarter::DoCancel()
{
TRACE_FUNC
switch (iState)
{
case ERespondPlayOk:
case ERespondPlayNok:
{
// This cancel won't cancel the response sending to the remote
// device. (RemCon FW's cancel mechanism is only completing client's request.
// the real operation in its server side won't be stopped.)
iCoreTarget->Cancel();
break;
}
case EPlayMusicTiming:
{
iTimer.Cancel();
break;
}
}
}
// ---------------------------------------------------------------------------
// A 'play' command has been received.
// ---------------------------------------------------------------------------
//
void CPlayerStarter::MrccatoPlay(
TRemConCoreApiPlaybackSpeed /* aSpeed */,
TRemConCoreApiButtonAction aButtonAct )
{
TRACE_FUNC
if ( ( aButtonAct == ERemConCoreApiButtonClick ) ||
( aButtonAct == ERemConCoreApiButtonPress ) )
{
StartPlayIfNeeded();
}
}
// ---------------------------------------------------------------------------
// A command has been received.
// ---------------------------------------------------------------------------
//
void CPlayerStarter::MrccatoCommand(
TRemConCoreApiOperationId aOperationId,
TRemConCoreApiButtonAction aButtonAct )
{
TRACE_INFO((_L("CPlayerStarter::MrccatoCommand opId %d, button %d"),
aOperationId, aButtonAct));
switch (aOperationId)
{
case ERemConCoreApiPlay:
{
if ( ( aButtonAct == ERemConCoreApiButtonClick ) ||
( aButtonAct == ERemConCoreApiButtonPress ) )
{
StartPlayIfNeeded();
}
break;
}
case ERemConCoreApiStop:
case ERemConCoreApiPause:
{
if ( ( aButtonAct == ERemConCoreApiButtonClick ) ||
( aButtonAct == ERemConCoreApiButtonPress ) )
{
// if starting player is ongoing, possibly PLAY command has been scheduled
// need to abort it.
Cancel();
}
break;
}
default:
{
break;
}
}
}
// -----------------------------------------------------------------------------
// CPlayerStarter::StartPlayIfNeeded
// -----------------------------------------------------------------------------
//
void CPlayerStarter::StartPlayIfNeeded()
{
TRACE_FUNC
// unfinished business ongoing, eat the event.
if (IsActive())
{
return;
}
if (!IsMusicPlayerRunning() && !IsVideoPlayerRunning())
{
TRAPD(err, LaunchMusicPlayerL());
// Send the response of play command to remote device
iCoreTarget->PlayResponse(iStatus, err);
SetActive();
iState = (err) ? ERespondPlayNok : ERespondPlayOk;
}
}
TBool CPlayerStarter::IsMusicPlayerRunning()
{
TRACE_FUNC
// Music player is running if we can find a thread whose name contains
// S60 Music Player's SID.
TFindThread findt(KMpxPlayerSearchPatternBySID);
TFullName result;
TBool running(EFalse);
if (!findt.Next(result))
{
TRACE_INFO((_L("Thread '%S'is found"), &result));
running = ETrue;
}
return running;
}
TBool CPlayerStarter::IsVideoPlayerRunning()
{
TRACE_FUNC
// Video player is running if we can find a thread whose name contains
// Video Player's SID.
TFindThread findt(KVideoPlayerSearchPatternBySID);
TFullName result;
TBool running(EFalse);
if (!findt.Next(result))
{
TRACE_INFO((_L("Thread '%S'is found"), &result));
running = ETrue;
}
return running;
}
void CPlayerStarter::LaunchMusicPlayerL()
{
RApaLsSession ls;
User::LeaveIfError(ls.Connect());
CleanupClosePushL(ls);
CApaCommandLine* cmd = CApaCommandLine::NewL();
CleanupStack::PushL(cmd);
cmd->SetExecutableNameL( KMpxPlayerExeName );
cmd->SetCommandL( EApaCommandOpen );
User::LeaveIfError(ls.StartApp( *cmd ));
CleanupStack::PopAndDestroy(2); // cmd, ls
}
// End of File