sl@0: //mmfaudioserver.cpp sl@0: sl@0: // Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies). sl@0: // All rights reserved. sl@0: // This component and the accompanying materials are made available sl@0: // under the terms of "Eclipse Public License v1.0" sl@0: // which accompanies this distribution, and is available sl@0: // at the URL "http://www.eclipse.org/legal/epl-v10.html". sl@0: // sl@0: // Initial Contributors: sl@0: // Nokia Corporation - initial contribution. sl@0: // sl@0: // Contributors: sl@0: // sl@0: // Description: sl@0: // Portions Copyright Nokia-Symbian * Nokia Core OS * sl@0: // INCLUDE FILES sl@0: // sl@0: sl@0: #include sl@0: #include sl@0: sl@0: #include "mmfaudioserver.h" sl@0: #include "mmfaudioserverdecs.h" sl@0: #include "mmfdevsoundsession.h" sl@0: #include "mmfaudioserversession.h" sl@0: #include "mmfdevsoundserver.h" sl@0: #include "mmfdevsoundserverstart.h" sl@0: #include "mmfaudioserverfactory.h" sl@0: #include "devsoundsvrthreadpriorityconsts.h" sl@0: sl@0: #ifdef _DEBUG sl@0: #include "e32debug.h" sl@0: #define SYMBIAN_DEBPRN0(str) RDebug::Print(str, this) sl@0: #else sl@0: #define SYMBIAN_DEBPRN0(str) sl@0: #endif //_DEBUG sl@0: sl@0: sl@0: // Time delay that the audio server wait before shutdown itself when is detected that the last DevSoundSession is closed sl@0: const TInt KAudioServerShutDownDelay = 50000000; //50 sec sl@0: sl@0: // ======== LOCAL FUNCTIONS ======== sl@0: sl@0: void Panic(TInt aPanicCode) sl@0: { sl@0: _LIT(KAudioServerPanicCategory, "mmfaudioserver"); sl@0: User::Panic(KAudioServerPanicCategory, aPanicCode); sl@0: } sl@0: sl@0: // ============================ MEMBER FUNCTIONS =============================== sl@0: sl@0: // ----------------------------------------------------------------------------- sl@0: // CMMFAudioServer::NewL sl@0: // Two-phased constructor. sl@0: // ----------------------------------------------------------------------------- sl@0: // sl@0: CMMFAudioServer* CMMFAudioServer::NewL() sl@0: { sl@0: CMMFAudioServer* self = new(ELeave) CMMFAudioServer(); sl@0: CleanupStack::PushL(self); sl@0: self->ConstructL(); sl@0: CleanupStack::Pop(self); sl@0: return self; sl@0: } sl@0: sl@0: // ----------------------------------------------------------------------------- sl@0: // CMMFAudioServer::CMMFAudioServer sl@0: // C++ default constructor can NOT contain any code, that sl@0: // might leave. sl@0: // ----------------------------------------------------------------------------- sl@0: // sl@0: CMMFAudioServer::CMMFAudioServer() sl@0: : CMmfIpcServer(EPriorityStandard) sl@0: { sl@0: } sl@0: sl@0: // ----------------------------------------------------------------------------- sl@0: // CMMFAudioServer::ConstructL sl@0: // Symbian 2nd phase constructor can leave. sl@0: // ----------------------------------------------------------------------------- sl@0: // sl@0: void CMMFAudioServer::ConstructL() sl@0: { sl@0: SYMBIAN_DEBPRN0(_L("CMMFAudioServer[0x%x]::ConstructL - enter")); sl@0: sl@0: SetPinClientDescriptors(ETrue); sl@0: // Call base class to Start server sl@0: StartL(KAudioServerName); sl@0: sl@0: iFourCCConvertor = CFourCCConvertor::NewL(); sl@0: iDelayAudioServerShutDown = CDelayAudioServerShutDown::NewL(); sl@0: sl@0: iFactory = CMMFAudioServerFactory::NewL(); sl@0: iFactory->StartL(*this); sl@0: sl@0: SYMBIAN_DEBPRN0(_L("CMMFAudioServer[0x%x]::ConstructL - exit")); sl@0: } sl@0: sl@0: // ----------------------------------------------------------------------------- sl@0: // CMMFAudioServer::~CMMFAudioServer sl@0: // Destructor sl@0: // ----------------------------------------------------------------------------- sl@0: // sl@0: CMMFAudioServer::~CMMFAudioServer() sl@0: { sl@0: if (iDelayAudioServerShutDown) sl@0: { sl@0: iDelayAudioServerShutDown->Cancel(); sl@0: delete iDelayAudioServerShutDown; sl@0: iDelayAudioServerShutDown = NULL; sl@0: } sl@0: sl@0: for(TInt i=(iDevSoundServList.Count()-1); i >=0 ; i--) sl@0: { sl@0: CStartAndMonitorDevSoundThread* devSoundMonitorThread = iDevSoundServList[i]; sl@0: iDevSoundServList.Remove(i); sl@0: delete devSoundMonitorThread; sl@0: } sl@0: iDevSoundServList.Close(); sl@0: delete iFourCCConvertor; sl@0: if (iFactory) sl@0: { sl@0: iFactory->Stop(*this); sl@0: delete iFactory; sl@0: } sl@0: } sl@0: sl@0: // ----------------------------------------------------------------------------- sl@0: // CMMFAudioServer::NewSessionL sl@0: // Creates a new session to handle requests by the client and returns it to the sl@0: // client server framework. sl@0: // ----------------------------------------------------------------------------- sl@0: // sl@0: CMmfIpcSession* CMMFAudioServer::NewSessionL(const TVersion& aVersion) const sl@0: { sl@0: SYMBIAN_DEBPRN0(_L("CMMFAudioServer[0x%x]::NewSessionL - enter")); sl@0: sl@0: TVersion v(KMMFAudioServerVersion, sl@0: KMMFAudioServerMinorVersionNumber, sl@0: KMMFAudioServerBuildVersionNumber); sl@0: if(!User::QueryVersionSupported(v, aVersion)) sl@0: { sl@0: User::Leave(KErrNotSupported); sl@0: } sl@0: sl@0: for(TInt i=(iDevSoundServList.Count()-1); i >=0 ; i--) sl@0: { sl@0: CStartAndMonitorDevSoundThread* devSoundMonitorThread = iDevSoundServList[i]; sl@0: sl@0: if(!devSoundMonitorThread->IsActive()) sl@0: { sl@0: iDevSoundServList.Remove(i); sl@0: delete devSoundMonitorThread; sl@0: } sl@0: iDevSoundServList.Compress(); sl@0: } sl@0: sl@0: RMMFDevSoundServerProxy devSoundSessionHandle; sl@0: User::LeaveIfError(StartDevSoundServer(devSoundSessionHandle)); sl@0: CMMFAudioServerSession* audioServerSession = CMMFAudioServerSession::NewL(devSoundSessionHandle); sl@0: SYMBIAN_DEBPRN0(_L("CMMFAudioServer[0x%x]::NewSessionL - session created")); sl@0: return audioServerSession; sl@0: } sl@0: sl@0: // ----------------------------------------------------------------------------- sl@0: // CMMFAudioServer::IncrementSessionId sl@0: // Increment the session Id. sl@0: // ----------------------------------------------------------------------------- sl@0: // sl@0: void CMMFAudioServer::IncrementSessionId() sl@0: { sl@0: iAudioServerSessionId++; sl@0: } sl@0: sl@0: // ----------------------------------------------------------------------------- sl@0: // CMMFAudioServer::DecrementSessionId sl@0: // Decrement the session Id. sl@0: // ----------------------------------------------------------------------------- sl@0: // sl@0: void CMMFAudioServer::DecrementSessionId() sl@0: { sl@0: iAudioServerSessionId--; sl@0: } sl@0: sl@0: // ----------------------------------------------------------------------------- sl@0: // CMMFAudioServer::IncrementDevSoundCount sl@0: // Increment the DevSound server counter. If there is atleast one DevSound sl@0: // server, it will cancel its shutdown timer. sl@0: // ----------------------------------------------------------------------------- sl@0: // sl@0: void CMMFAudioServer::IncrementDevSoundCount() sl@0: { sl@0: iDevSoundCount++; sl@0: //in the case we started the shutdown due to no more DevSound sl@0: if(iDevSoundCount) sl@0: { sl@0: ASSERT(iDelayAudioServerShutDown); sl@0: if (iDelayAudioServerShutDown) sl@0: { sl@0: iDelayAudioServerShutDown->Cancel(); sl@0: } sl@0: } sl@0: } sl@0: sl@0: // ----------------------------------------------------------------------------- sl@0: // CMMFAudioServer::DecrementDevSoundCount sl@0: // Decrement the DevSound server counter. Once the number of DevSound server's sl@0: // instances becomes zero, Audio Server will start its shutdown routine. sl@0: // ----------------------------------------------------------------------------- sl@0: // sl@0: void CMMFAudioServer::DecrementDevSoundCount() sl@0: { sl@0: iDevSoundCount--; sl@0: if (iDevSoundCount == 0) sl@0: { sl@0: ASSERT(iDelayAudioServerShutDown); sl@0: if (iDelayAudioServerShutDown) sl@0: { sl@0: iDelayAudioServerShutDown->SetDelay(TTimeIntervalMicroSeconds32(KAudioServerShutDownDelay)); sl@0: } sl@0: } sl@0: } sl@0: sl@0: // ----------------------------------------------------------------------------- sl@0: // CMMFAudioServer::SendEventToClient sl@0: // Sends Event to DevSound client. sl@0: // ----------------------------------------------------------------------------- sl@0: // sl@0: void CMMFAudioServer::SendEventToClient(TInt aSessionToAlert, TInt /*aSessionToBeLaunched*/) sl@0: { sl@0: // For the session requested, send event to client sl@0: iSessionIter.SetToFirst(); sl@0: CMMFAudioServerSession* session = static_cast(iSessionIter++); sl@0: while (session) sl@0: { sl@0: if (session->AudioServerSessionId() == aSessionToAlert) sl@0: { sl@0: break; // Finished sl@0: } sl@0: sl@0: session = static_cast(iSessionIter++); sl@0: } sl@0: } sl@0: sl@0: // ----------------------------------------------------------------------------- sl@0: // CMMFAudioServer::LaunchRequest sl@0: // Launches the DevSound servers waiting for Audio Policy. sl@0: // ----------------------------------------------------------------------------- sl@0: // sl@0: void CMMFAudioServer::LaunchRequest(TInt aSessionId) sl@0: { sl@0: iSessionIter.SetToFirst(); sl@0: CMMFAudioServerSession* session = static_cast(iSessionIter++); sl@0: sl@0: while (session) sl@0: { sl@0: if (session->AudioServerSessionId() == aSessionId) sl@0: { sl@0: break; // Finished sl@0: } sl@0: session = static_cast(iSessionIter++); sl@0: } sl@0: } sl@0: sl@0: // ----------------------------------------------------------------------------- sl@0: // CMMFAudioServer::StartDevSoundServer sl@0: // Starts a new DevSound server instance. sl@0: // ----------------------------------------------------------------------------- sl@0: // sl@0: TInt CMMFAudioServer::StartDevSoundServer(RMMFDevSoundServerProxy& aDevSoundSessionHandle) const sl@0: { sl@0: SYMBIAN_DEBPRN0(_L("CMMFAudioServer[0x%x]::StartDevSoundServer - enter")); sl@0: sl@0: RMessage2 message(Message()); sl@0: CStartAndMonitorDevSoundThread* monitorDevSound = NULL; sl@0: sl@0: TRAPD(err, monitorDevSound = CStartAndMonitorDevSoundThread::NewL(const_cast(this))); sl@0: if(err != KErrNone) sl@0: { sl@0: delete monitorDevSound; sl@0: return err; sl@0: } sl@0: sl@0: err = iDevSoundServList.Append(monitorDevSound); sl@0: if(err != KErrNone) sl@0: { sl@0: delete monitorDevSound; sl@0: return err; sl@0: } sl@0: sl@0: SYMBIAN_DEBPRN0(_L("CMMFAudioServer[0x%x]::StartDevSoundServer - exit")); sl@0: return monitorDevSound->StartDevSoundServer(message, aDevSoundSessionHandle); sl@0: sl@0: } sl@0: sl@0: // ----------------------------------------------------------------------------- sl@0: // CMMFAudioServer::CDelayAudioServerShutDown::NewL sl@0: // Two-phased constructor. sl@0: // ----------------------------------------------------------------------------- sl@0: // sl@0: CMMFAudioServer::CDelayAudioServerShutDown* sl@0: CMMFAudioServer::CDelayAudioServerShutDown::NewL() sl@0: { sl@0: CDelayAudioServerShutDown* self = new(ELeave) CDelayAudioServerShutDown; sl@0: CleanupStack::PushL(self); sl@0: self->ConstructL(); sl@0: CleanupStack::Pop(self); sl@0: return self; sl@0: } sl@0: sl@0: // ----------------------------------------------------------------------------- sl@0: // Constructor. sl@0: // ----------------------------------------------------------------------------- sl@0: // sl@0: CMMFAudioServer::CDelayAudioServerShutDown::CDelayAudioServerShutDown() sl@0: : CActive(0) sl@0: { sl@0: } sl@0: sl@0: // ----------------------------------------------------------------------------- sl@0: // CMMFAudioServer::CDelayAudioServerShutDown::ConstructL sl@0: // ----------------------------------------------------------------------------- sl@0: // sl@0: void CMMFAudioServer::CDelayAudioServerShutDown::ConstructL() sl@0: { sl@0: User::LeaveIfError(iShutDownTimer.CreateLocal()); sl@0: CActiveScheduler::Add(this); sl@0: } sl@0: sl@0: // ----------------------------------------------------------------------------- sl@0: // CMMFAudioServer::CDelayAudioServerShutDown::~CDelayAudioServerShutDown sl@0: // ----------------------------------------------------------------------------- sl@0: // sl@0: CMMFAudioServer::CDelayAudioServerShutDown::~CDelayAudioServerShutDown() sl@0: { sl@0: Cancel(); sl@0: iShutDownTimer.Close(); sl@0: } sl@0: sl@0: // ----------------------------------------------------------------------------- sl@0: // CMMFAudioServer::CDelayAudioServerShutDown::SetDelay sl@0: // Request a timeout after aDelay sl@0: // ----------------------------------------------------------------------------- sl@0: // sl@0: void CMMFAudioServer::CDelayAudioServerShutDown::SetDelay( sl@0: TTimeIntervalMicroSeconds32 aDelay) sl@0: { sl@0: __ASSERT_ALWAYS(!IsActive(), Panic(EMMFAudioServerIsActive)); sl@0: iShutDownTimer.After(iStatus, aDelay); sl@0: SetActive(); sl@0: } sl@0: sl@0: // ----------------------------------------------------------------------------- sl@0: // CMMFAudioServer::CDelayAudioServerShutDown::RunL sl@0: // Called by Active object framework when timer times out. sl@0: // ----------------------------------------------------------------------------- sl@0: // sl@0: void CMMFAudioServer::CDelayAudioServerShutDown::RunL() sl@0: { sl@0: CActiveScheduler::Stop(); sl@0: } sl@0: sl@0: // ----------------------------------------------------------------------------- sl@0: // CMMFAudioServer::CDelayAudioServerShutDown::DoCancel sl@0: // Called by the Active object framework when user cancels active object. sl@0: // ----------------------------------------------------------------------------- sl@0: // sl@0: void CMMFAudioServer::CDelayAudioServerShutDown::DoCancel() sl@0: { sl@0: iShutDownTimer.Cancel(); sl@0: } sl@0: sl@0: // ----------------------------------------------------------------------------- sl@0: // CStartAndMonitorDevSoundThread::NewL sl@0: // ----------------------------------------------------------------------------- sl@0: // sl@0: CStartAndMonitorDevSoundThread* CStartAndMonitorDevSoundThread::NewL( sl@0: CMMFAudioServer* aAudioServer) sl@0: { sl@0: CStartAndMonitorDevSoundThread* self = new(ELeave) CStartAndMonitorDevSoundThread(aAudioServer); sl@0: CleanupStack::PushL(self); sl@0: self->ConstructL(); sl@0: CleanupStack::Pop(self); sl@0: return self; sl@0: } sl@0: sl@0: // ----------------------------------------------------------------------------- sl@0: // CStartAndMonitorDevSoundThread::ConstructL sl@0: // ----------------------------------------------------------------------------- sl@0: // sl@0: void CStartAndMonitorDevSoundThread::ConstructL() sl@0: { sl@0: CActiveScheduler::Add(this); sl@0: } sl@0: sl@0: // ----------------------------------------------------------------------------- sl@0: // CStartAndMonitorDevSoundThread::StartDevSoundServer sl@0: // Starts a new DevSound server. sl@0: // ----------------------------------------------------------------------------- sl@0: // sl@0: TInt CStartAndMonitorDevSoundThread::StartDevSoundServer( sl@0: RMessage2& aMessage, sl@0: RMMFDevSoundServerProxy& aDevSoundSessionHandle) sl@0: { sl@0: SYMBIAN_DEBPRN0(_L("CStartAndMonitorDevSoundThread[0x%x]::StartDevSoundServer - enter")); sl@0: sl@0: RThread clientThread; sl@0: TInt err(KErrNone); sl@0: sl@0: // Open handle to client thread sl@0: err = aMessage.Client(clientThread); sl@0: if (err != KErrNone) sl@0: { sl@0: clientThread.Close(); sl@0: return err; sl@0: } sl@0: // Open a process-relative handle to the process which owns clientThread. sl@0: RProcess clientProcess; sl@0: err = clientThread.Process(clientProcess); sl@0: sl@0: if (err != KErrNone) sl@0: { sl@0: // Close client thread handle and return error sl@0: clientThread.Close(); sl@0: return err; sl@0: } sl@0: sl@0: // Get the client process id sl@0: TProcessId clientProcessId(clientProcess.Id()); sl@0: sl@0: // Close client thread and client process handles sl@0: clientThread.Close(); sl@0: clientProcess.Close(); sl@0: sl@0: RServer2 devSoundServerHandle; sl@0: devSoundServerHandle.SetReturnedHandle(0); sl@0: sl@0: //Pass to DevSoundServer the clien't process ID sl@0: TDevSoundServerStart start(iAudioServer, sl@0: clientProcessId, sl@0: devSoundServerHandle); sl@0: sl@0: TThreadFunction serverFunc=CMMFDevSoundServer::StartThread; sl@0: sl@0: // To deal with the unique thread (+semaphore!) naming in EPOC, sl@0: // and that we may be trying to restart a server that has just sl@0: // exited we attempt to create a unique thread name for the server. sl@0: #ifdef SYMBIAN_USE_SEPARATE_HEAPS sl@0: err = iServer.Create(KNullDesC,serverFunc,KDevSoundServerStackSize*2, sl@0: KDevSoundServerInitHeapSize, sl@0: KDevSoundServerMaxHeapSize, sl@0: &start, sl@0: EOwnerProcess); sl@0: #else sl@0: err = iServer.Create(KNullDesC, sl@0: serverFunc, sl@0: (KDevSoundServerStackSize*2), sl@0: NULL, sl@0: &start, sl@0: EOwnerProcess); sl@0: #endif // SYMBIAN_USE_SEPARATE_HEAPS sl@0: if(err != KErrNone) sl@0: { sl@0: return err; sl@0: } sl@0: iServer.SetPriority(KDevsoundSvrPriority); sl@0: sl@0: // Synchronise with the server sl@0: TRequestStatus reqStatus; sl@0: iServer.Rendezvous(reqStatus); sl@0: sl@0: if (reqStatus!=KRequestPending) sl@0: { sl@0: iServer.Kill(0); sl@0: } sl@0: else sl@0: { sl@0: // Start the test harness sl@0: iServer.Resume(); sl@0: // Server will call the reciprocal static synchronise call sl@0: } sl@0: sl@0: // note devSoundServerHandle really "owned" by client thread - just copied here sl@0: sl@0: User::WaitForRequest(reqStatus); // wait for start or death sl@0: if(reqStatus.Int() != KErrNone) sl@0: { sl@0: // close our handle to the thread. If we reach here, the thread should have sl@0: // closed anyway as continue Rendezvous is always KErrNone() sl@0: iServer.Close(); sl@0: return reqStatus.Int(); sl@0: } sl@0: sl@0: err = aDevSoundSessionHandle.Open(devSoundServerHandle); sl@0: sl@0: if(err != KErrNone) sl@0: { sl@0: // close our handle to the thread. If we reach here, this means that NewSessionL() failed sl@0: // on server, and that action itself will asynchronously stop the thread sl@0: iServer.Close(); sl@0: return err; sl@0: } sl@0: sl@0: aDevSoundSessionHandle.ShareProtected(); sl@0: iServer.Logon(iStatus); sl@0: SetActive(); sl@0: sl@0: iAudioServer->IncrementDevSoundCount(); sl@0: sl@0: SYMBIAN_DEBPRN0(_L("CStartAndMonitorDevSoundThread[0x%x]::StartDevSoundServer - exit")); sl@0: return KErrNone; sl@0: } sl@0: sl@0: // ----------------------------------------------------------------------------- sl@0: // CStartAndMonitorDevSoundThread::CStartAndMonitorDevSoundThread sl@0: // Constructor sl@0: // ----------------------------------------------------------------------------- sl@0: // sl@0: CStartAndMonitorDevSoundThread::CStartAndMonitorDevSoundThread( sl@0: CMMFAudioServer* aAudioServer) sl@0: : CActive(EPriorityStandard),iAudioServer(aAudioServer) sl@0: { sl@0: sl@0: } sl@0: sl@0: // Desctructor sl@0: CStartAndMonitorDevSoundThread::~CStartAndMonitorDevSoundThread() sl@0: { sl@0: Cancel(); sl@0: } sl@0: sl@0: // ----------------------------------------------------------------------------- sl@0: // CStartAndMonitorDevSoundThread::RunL sl@0: // Called by Active Object framework when DevSound server is destroyed. sl@0: // ----------------------------------------------------------------------------- sl@0: // sl@0: void CStartAndMonitorDevSoundThread::RunL() sl@0: { sl@0: iServer.Close(); sl@0: iAudioServer->DecrementDevSoundCount(); sl@0: } sl@0: sl@0: // ----------------------------------------------------------------------------- sl@0: // CStartAndMonitorDevSoundThread::DoCancel sl@0: // Called by Active Object framework when client cancels active object. sl@0: // ----------------------------------------------------------------------------- sl@0: // sl@0: void CStartAndMonitorDevSoundThread::DoCancel() sl@0: { sl@0: iServer.LogonCancel(iStatus); sl@0: } sl@0: sl@0: sl@0: // ----------------------------------------------------------------------------- sl@0: // RMMFDevSoundServerProxy::Open sl@0: // Creates new audio server session for the devsound server. sl@0: // ----------------------------------------------------------------------------- sl@0: // sl@0: TInt RMMFDevSoundServerProxy::Open(RServer2& aDevSoundServerHandle) sl@0: { sl@0: SYMBIAN_DEBPRN0(_L("RMMFDevSoundServerProxy[0x%x]::Open - enter")); sl@0: TInt err = CreateSession(aDevSoundServerHandle, TVersion(KMMFDevSoundServerVersion, sl@0: KMMFDevSoundServerMinorVersionNumber, sl@0: KMMFDevSoundServerBuildVersionNumber), sl@0: -1, EIpcSession_GlobalSharable); sl@0: sl@0: SYMBIAN_DEBPRN0(_L("RMMFDevSoundServerProxy[0x%x]::Open - exit")); sl@0: return err; sl@0: } sl@0: sl@0: // End of File