--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/mpx/playbackframework/playbackserver/src/mpxplaybackserver.cpp Thu Dec 17 08:55:47 2009 +0200
@@ -0,0 +1,525 @@
+/*
+* Copyright (c) 2004 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: Playback server
+*
+*/
+
+
+#include <e32std.h>
+#include <e32svr.h>
+#ifdef RD_TSP_CLIENT_MAPPER
+#include <tspclientmapper.h>
+#endif
+#include <mpxclientlist.h>
+#include <mpxpluginmonitor.h>
+#include <mpxlog.h>
+#include "mpxplaybackserverdefs.h"
+#include "mpxplaybackengine.h"
+#include "mpxplaybackserversession.h"
+#include "mpxplaybackserver.h"
+
+// CONSTANTS
+
+// Server Security Policy
+const TUint KMPXPlaybackServerRangeCount = 2;
+const TInt KMPXPlaybackServerRanges[KMPXPlaybackServerRangeCount] =
+ {
+ 0, //range is [0-EPbsServerOpEnd)
+ EPbsServerOpEnd, //range is [EPbsServerOpEnd-KMaxTInt]
+ };
+const TUint8 KMPXPlaybackSeverElementsIndex[KMPXPlaybackServerRangeCount] =
+ {
+ 0, //applies to range [0-EPbsServerOpEnd)
+ CPolicyServer::ENotSupported, //applies to range [EPbsServerOpEnd-KMaxTInt]
+ };
+
+const CPolicyServer::TPolicyElement KMPXPlaybackServerPolicyElements[] =
+ {
+ {_INIT_SECURITY_POLICY_C1(ECapability_None),
+ CPolicyServer::EFailClient},
+ };
+
+const CPolicyServer::TPolicy KMPXPlaybackServerPolicy =
+ {
+ CPolicyServer::EAlwaysPass, //specifies all connect attempts should pass
+ KMPXPlaybackServerRangeCount,
+ KMPXPlaybackServerRanges,
+ KMPXPlaybackSeverElementsIndex,
+ KMPXPlaybackServerPolicyElements,
+ };
+
+// ----------------------------------------------------------------------------
+// Start playback server
+//
+LOCAL_C void StartServerL()
+ {
+ User::LeaveIfError(User::RenameThread(KMPXPlaybackServerName));
+ CActiveScheduler* scheduler = new(ELeave)CActiveScheduler;
+ CleanupStack::PushL(scheduler);
+ CActiveScheduler::Install(scheduler);
+ CMPXPlaybackServer* server = CMPXPlaybackServer::NewL();
+ CleanupStack::PushL(server);
+ RProcess::Rendezvous(KErrNone);
+ CActiveScheduler::Start();
+ CActiveScheduler::Install(NULL);
+ CleanupStack::PopAndDestroy(server);
+ CleanupStack::PopAndDestroy(scheduler);
+ }
+
+// ============================ MEMBER FUNCTIONS ==============================
+
+// ----------------------------------------------------------------------------
+// Two-phased constructor.
+// ----------------------------------------------------------------------------
+//
+CMPXPlaybackServer* CMPXPlaybackServer::NewL()
+ {
+ CMPXPlaybackServer *pS = new(ELeave) CMPXPlaybackServer(
+ CActive::EPriorityStandard,
+ KMPXPlaybackServerPolicy);
+ CleanupStack::PushL(pS);
+ pS->ConstructL();
+ CleanupStack::Pop(pS);
+ return pS;
+ }
+
+// ----------------------------------------------------------------------------
+// C++ constructor can NOT contain any code that might leave.
+// ----------------------------------------------------------------------------
+//
+CMPXPlaybackServer::CMPXPlaybackServer(TInt aPriority, const TPolicy &aPolicy)
+ : CPolicyServer(aPriority, aPolicy)
+ {}
+
+// ----------------------------------------------------------------------------
+// Destructor
+// ----------------------------------------------------------------------------
+//
+CMPXPlaybackServer::~CMPXPlaybackServer()
+ {
+ iPlayers.ResetAndDestroy();
+ delete iPluginMonitor;
+#ifdef RD_TSP_CLIENT_MAPPER
+ delete iClientMapper;
+#endif
+ }
+
+// ----------------------------------------------------------------------------
+// Symbian 2nd phase constructor can leave.
+// ----------------------------------------------------------------------------
+//
+void CMPXPlaybackServer::ConstructL()
+ {
+ StartL(KMPXPlaybackServerName);
+ iPluginMonitor = CMPXPluginMonitor::NewL(KMPXPlaybackInterfaceUid);
+#ifdef RD_TSP_CLIENT_MAPPER
+ iClientMapper = CTspClientMapper::NewL();
+#endif
+ }
+
+// ----------------------------------------------------------------------------
+// Increments number of sessions this server holds
+// ----------------------------------------------------------------------------
+//
+void CMPXPlaybackServer::AddClient()
+ {
+ iClients++;
+ }
+
+
+// ----------------------------------------------------------------------------
+// Find the player that has client aName, and remove it from that player; if
+// that player has no clients, then delete that player. If the server has no
+// more client sessions, then stop the server.
+// ----------------------------------------------------------------------------
+//
+void CMPXPlaybackServer::RemoveClient(const CMPXMessageQueue& aMsgQueue)
+ {
+ MPX_DEBUG2("CMPXPlaybackServer::RemoveClient from %d",
+ iPlayers.Count());
+ for (TInt i=iPlayers.Count();--i>=0;)
+ {
+ CMPXPlaybackEngine* p=iPlayers[i];
+ CMPXClientList* cl=p->ClientList();
+ TInt index(cl->Find(aMsgQueue));
+ if (KErrNotFound != index)
+ {
+ MPX_DEBUG1("CMPXPlaybackServer::RemoveClient found client");
+ cl->RemoveClient(index);
+ if (cl->ClientCount()==0)
+ {
+ MPX_DEBUG1("CMPXPlaybackServer::RemoveClient delete a player");
+ delete p;
+ iPlayers.Remove(i);
+ }
+ break;
+ }
+ }
+ iClients--;
+ ASSERT(iClients>=0);
+ if (iClients==0)
+ {
+ CActiveScheduler::Stop();
+ }
+ }
+
+// ----------------------------------------------------------------------------
+// Return last active process id
+// ----------------------------------------------------------------------------
+//
+TProcessId CMPXPlaybackServer::LastActiveProcessId()
+ {
+ TProcessId id(KNullProcessId);
+ if (iPlayers.Count())
+ {
+ id = iPlayers[0]->LastActiveProcessId();
+ }
+ return id;
+ }
+
+// ----------------------------------------------------------------------------
+// Creates a brand new player to the player list with this client name and TID,
+// and whether it's the music player.
+// ----------------------------------------------------------------------------
+//
+CMPXPlaybackEngine* CMPXPlaybackServer::AddNewPlayerL(
+ TThreadId aClientId,
+ const TUid& aModeId,
+ CMPXMessageQueue* aMsgQueue,
+ const TInt aCategory)
+ {
+ CMPXPlaybackEngine* p =
+ CMPXPlaybackEngine::NewL(*iPluginMonitor,*this,this,aModeId, aCategory);
+ MPX_DEBUG2("CMPXPlaybackServer::AddNewPlayerL 0x%08x", p);
+ CleanupStack::PushL(p);
+ p->ClientList()->AddClientL(aClientId, aModeId.iUid, aMsgQueue, aCategory);
+ iPlayers.AppendL(p);
+ CleanupStack::Pop(p);
+ return p;
+ }
+
+// ----------------------------------------------------------------------------
+// Create player according to the mode:
+// ----------------------------------------------------------------------------
+//
+CMPXPlaybackEngine* CMPXPlaybackServer::CreatePlayerL(
+ const TUid& aModeId,
+ const TInt aCategory,
+ TThreadId aClientId,
+ CMPXMessageQueue* aMsgQueue)
+ {
+ CMPXPlaybackEngine* p=NULL;
+ if (aModeId == KPbModeDefault)
+ {
+ // Add the new client to the player created by another client running
+ // in the same thread. If there isn't one, then create the first player
+ // for this thread
+ //
+ p=AddToDefaultPlayerL(aClientId,aMsgQueue,aCategory);
+ if(!p)
+ {
+
+ p=AddNewPlayerL(aClientId, aModeId, aMsgQueue, aCategory);
+ }
+ }
+ //
+ else if (aModeId == KPbModeNewPlayer)
+ {
+ //
+ // Create a brand new player for this client
+ //
+ p=AddNewPlayerL(aClientId, aModeId, aMsgQueue, aCategory);
+ }
+ else if (aModeId == KPbModeActivePlayer)
+ {
+ TInt index = IndexOfRecentActivePlayer(aCategory);
+ if (KErrNotFound != index)
+ {
+ p = iPlayers[index]; // active & matching category
+ }
+ if (!p && iPlayers.Count()>0)
+ { //no recent activeplayer, attach to the first player with matching category
+ TInt count = iPlayers.Count();
+ for(TInt i = 0; i < count; i++)
+ {
+ if(iPlayers[i]->Category() == aCategory)
+ {
+ p = iPlayers[i]; // not active, first matching category
+ break;
+ }
+ }
+ }
+ if (p)
+ {
+ p->ClientList()->AddClientL(aClientId,aModeId.iUid,aMsgQueue, aCategory);
+ }
+ else
+ { // no player available (no active player with matching category)
+ MPX_DEBUG1("CMPXPlaybackServer::CreatePlayerL create a new player");
+ p=AddNewPlayerL(aClientId, aModeId, aMsgQueue, aCategory);
+ }
+ }
+ else
+ {
+ //
+ // Add the new client to the player created by one application. If
+ // there isn't one, then create the first player for the application
+ //
+ for (TInt i=iPlayers.Count();--i>=0;)
+ {
+ if (iPlayers[i]->ModeId() == aModeId)
+ {
+ p = iPlayers[i];
+ p->ClientList()->AddClientL(aClientId,
+ aModeId.iUid, aMsgQueue, aCategory);
+ break;
+ }
+ }
+
+ if (!p)
+ {
+ p=AddNewPlayerL(aClientId, aModeId, aMsgQueue, aCategory);
+ }
+ }
+ return p;
+ }
+
+// ----------------------------------------------------------------------------
+// Add the new client (defined by it's TID) to the player
+// associated with the Tid aExistingClientId
+// ----------------------------------------------------------------------------
+//
+CMPXPlaybackEngine* CMPXPlaybackServer::AddToDefaultPlayerL(
+ TThreadId aClientId,
+ CMPXMessageQueue* aMsgQueue,
+ const TInt aCategory)
+ {
+ CMPXPlaybackEngine* p=NULL;
+ for (TInt i=0; i < iPlayers.Count(); ++i)
+ {
+ p=iPlayers[i];
+ CMPXClientList* cl=p->ClientList();
+ TInt index = cl->Find(aClientId);
+ if (KErrNotFound != index)
+ {
+ // if the player is an active player, change mode from default
+ // to activeplayer. Default mode always uses the mode of first client
+ TInt mode = (cl->ClientMode(index) == KPbModeActivePlayer.iUid) ?
+ KPbModeActivePlayer.iUid : KPbModeDefault.iUid;
+ MPX_DEBUG3("CMPXPlaybackServer::AddToDefaultPlayerL mode 0x%08x, engine 0x%08x",
+ mode, p);
+ cl->AddClientL(aClientId,mode,aMsgQueue, aCategory);
+ break;
+ }
+ }
+ return p;
+ }
+
+// ----------------------------------------------------------------------------
+// Return the index of an active player. If there is no active player, return
+// the index to the player in paused state which may be interrupted.
+// ----------------------------------------------------------------------------
+//
+TInt CMPXPlaybackServer::IndexOfRecentActivePlayer(TInt aCategory)
+ {
+ TInt ret(KErrNotFound);
+ for (TInt i=0; i<iPlayers.Count(); ++i)
+ {
+ CMPXPlaybackEngine* p = iPlayers[i];
+ if (p->IsPlayerActive() && aCategory == p->Category())
+ { // Found active player
+ ret = i;
+ break;
+ }
+ else if (EPbStatePaused == p->State() && KErrNotFound == ret && aCategory == p->Category())
+ { // first paused player
+ ret = i;
+ }
+ }
+ return ret;
+ }
+
+TInt CMPXPlaybackServer::IndexOfRecentActivePlayer()
+ {
+ TInt ret(KErrNotFound);
+ for (TInt i=0; i<iPlayers.Count(); ++i)
+ {
+ CMPXPlaybackEngine* p = iPlayers[i];
+ if (p->IsPlayerActive())
+ { // Found active player
+ ret = i;
+ break;
+ }
+ else if (EPbStatePaused == p->State() && KErrNotFound == ret)
+ { // first paused player
+ ret = i;
+ }
+ }
+ return ret;
+ }
+
+// ----------------------------------------------------------------------------
+// Handle active player changed evnet.
+// Notify all clients of EPbModeActivePlayer mode in inactive engines
+// ----------------------------------------------------------------------------
+//
+void CMPXPlaybackServer::HandleActiveEngineL(
+ const CMPXPlaybackEngine* aEngine,
+ TBool aActive)
+ {
+ MPX_DEBUG3("CMPXPlaybackServer::HandleActiveEngineL Engine: 0x%08x, Active %d",
+ aEngine, aActive);
+ TInt i(0);
+ TInt indexOfActive = iPlayers.Find(aEngine);
+ ASSERT(KErrNotFound!=indexOfActive);
+ if (!aActive)
+ {
+#ifdef RD_TSP_CLIENT_MAPPER
+ iClientMapper->SetTspTargetClientToOtherType(
+ CTspClientMapper::EStoppedClients,
+ aEngine->LastActiveProcessId());
+ MPX_DEBUG2("CMPXPlaybackServer::HandleActiveEngineL(): Adding to stopped client %d",
+ TUint( aEngine->LastActiveProcessId()));
+
+#endif
+ if (EPbStatePaused != aEngine->State())
+ {
+ indexOfActive = IndexOfRecentActivePlayer();
+ }
+ else
+ { // else no need to rebind. if the player is interruptted by other player
+ // there must be another HandleActiveEngineL callback with aActive = ETrue
+ indexOfActive = KErrNotFound;
+ }
+ }
+ else
+ {// else aEngine is active player
+#ifdef RD_TSP_CLIENT_MAPPER
+ iClientMapper->SetTspTargetClientToOtherType(
+ CTspClientMapper::EPlayingClients,
+ aEngine->LastActiveProcessId());
+ MPX_DEBUG2("CMPXPlaybackServer::HandleActiveEngineL(): Adding to playing client %d",
+ TUint( aEngine->LastActiveProcessId()));
+#endif
+ }
+
+ if (KErrNotFound != indexOfActive)
+ {
+ // Move the active player engine to the top of player list
+ CMPXPlaybackEngine* player(NULL);
+ if (indexOfActive)
+ { // not 0
+ player = iPlayers[indexOfActive];
+ iPlayers.Remove(indexOfActive);
+ iPlayers.Insert(player, 0);
+ }
+
+ // Active engine changed, notify all clients who are instrested.
+ // e.g. KPbModeActivePlayer
+ for (i=1; i < iPlayers.Count(); ++i)
+ {
+ player = iPlayers[i];
+ if (player == aEngine && aActive)
+ {
+ continue;
+ }
+ MPX_DEBUG2("CMPXPlaybackServer::HandleActiveEngineL Player: 0x%08x", player);
+ CMPXClientList* cl = player->ClientList();
+ for (TInt j = cl->ClientCount(); --j>=0;)
+ {
+ if ((KPbModeActivePlayer.iUid == cl->ClientMode(j)) &&
+ (aEngine->Category() == cl->ClientCategory(j)))
+ {
+ MPX_DEBUG2(
+ "CMPXPlaybackServer notify %d client player changed", j);
+ player->ClientList()->SendMsgL(
+ j,
+ TMPXPlaybackMessage(
+ TMPXPlaybackMessage::EActivePlayerChanged,
+ 1, aActive));
+ }
+ }
+ }
+ }
+ }
+
+// ----------------------------------------------------------------------------
+// Observe client change event
+// ----------------------------------------------------------------------------
+//
+void CMPXPlaybackServer::HandleClientChange(
+ const TProcessId& aPid,
+ MMPXClientlistObserver::TChangeType aChangeType)
+ {
+#ifdef RD_TSP_CLIENT_MAPPER
+ if (MMPXClientlistObserver::EAdd == aChangeType)
+ {
+ iClientMapper->SetTspTargetClient(
+ CTspClientMapper::EPlayingClients,
+ aPid);
+ MPX_DEBUG2("CMPXPlaybackServer::HandleClientChange(): Adding to registered client %d",
+ TUint( aPid ));
+ }
+ else
+ {
+ iClientMapper->RemoveTspTargetClient(
+ CTspClientMapper::EPlayingClients,
+ aPid);
+ MPX_DEBUG2("CMPXPlaybackServer::HandleClientChange(): Adding to EPlayingClients client %d",
+ TUint( aPid ));
+ }
+#else
+ (void)aPid;
+ (void)aChangeType;
+#endif
+ }
+
+// ----------------------------------------------------------------------------
+// Create a new session
+// ----------------------------------------------------------------------------
+//
+CSession2* CMPXPlaybackServer::NewSessionL(const TVersion& aVersion,
+ const RMessage2& /*aMessage*/) const
+ {
+ TVersion v(KMPXPlaybackServerMajorVersionNumber,
+ KMPXPlaybackServerMinorVersionNumber,
+ KMPXPlaybackServerBuildVersionNumber);
+ if (!User::QueryVersionSupported(v,aVersion))
+ User::Leave(KErrNotSupported);
+ CMPXPlaybackSession* session = CMPXPlaybackSession::NewL();
+ const_cast<CMPXPlaybackServer*>(this)->AddClient();
+ return session;
+ }
+
+// ----------------------------------------------------------------------------
+// Server exe entry
+// ----------------------------------------------------------------------------
+//
+TInt E32Main()
+ {
+ __UHEAP_MARK;
+ //
+ CTrapCleanup* cleanup=CTrapCleanup::New();
+ TInt r=KErrNoMemory;
+ if (cleanup)
+ {
+ TRAP(r,StartServerL());
+ }
+
+ delete cleanup;
+ __UHEAP_MARKEND;
+ return r;
+ }
+
+// End of file