mmserv/sts/stsproxy/src/rstssession.cpp
changeset 22 128eb6a32b84
child 36 73253677b50a
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mmserv/sts/stsproxy/src/rstssession.cpp	Thu May 27 13:20:50 2010 +0300
@@ -0,0 +1,321 @@
+/*
+ * Copyright (c) 2010 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:
+ * The file provides the implementation of the client side session
+ * to the STS Server.
+ */
+
+#include "rstssession.h"
+#include "stsclientservercommon.h"
+
+const TUint KNumSlots = 30;
+
+/*static*/TInt RStsSession::CallBackThreadMain(TAny* aSession)
+    {
+    TInt err = KErrNoMemory;
+
+    RThread myThread;
+    myThread.SetPriority(EPriorityAbsoluteHigh);
+    myThread.Close();
+
+    CTrapCleanup* cleanup = CTrapCleanup::New();
+
+    if (cleanup)
+        {
+        // Run the server and request a thread rendezvous.
+        TRAP( err, ((RStsSession*)aSession)->RunThreadL() );
+        delete cleanup;
+        }
+
+    return err;
+    }
+
+void RStsSession::RunThreadL()
+    {
+    iState = ERunning;
+    // Initialisation complete, now signal the client, if requested.
+    RThread::Rendezvous(KErrNone);
+    TRequestStatus queueStatus = KRequestPending;
+    iMsgQueue.NotifyDataAvailable(queueStatus);
+
+    RThread server;
+    TInt err = server.Open(iServerThreadId);
+    TRequestStatus serverStatus = KRequestPending;
+    server.Logon(serverStatus);
+
+    while (iState == ERunning)
+        {
+        TStsCallBack message;
+        // Using ReceiveBlocking here would block forever if the executive thread
+        // dies, so instead wait for either a data available notification or a
+        // notification that the executive thread has died.
+        User::WaitForRequest(queueStatus, serverStatus);
+
+        if (queueStatus != KRequestPending)
+            {
+            TInt err = iMsgQueue.Receive(message);
+            if (err == KErrNone)
+                {
+                HandleMessage(message);
+                }
+            else
+                {
+                //TODO:Log a message
+                }
+            queueStatus = KRequestPending;
+            iMsgQueue.NotifyDataAvailable(queueStatus);
+            }
+        if (serverStatus != KRequestPending && iState == ERunning)
+            {
+            //TODO: Log a message
+            //Restart the server
+            SignalObservers();
+            server.Close();
+            CreateServerSession();
+            TInt err = server.Open(iServerThreadId);
+            TRequestStatus serverStatus = KRequestPending;
+            server.Logon(serverStatus);
+            }
+        }
+
+    iMsgQueue.CancelDataAvailable();
+    server.LogonCancel(serverStatus);
+    server.Close();
+    }
+
+void RStsSession::HandleMessage(TStsCallBack& aMessage)
+    {
+    TStsCallBackType type = aMessage.callBackType;
+    if (type == EStsPlayAlarmComplete)
+        {
+        MStsPlayAlarmObserver* observer = aMessage.observer;
+        unsigned int context = aMessage.alarmContext;
+        iObserverMutex.Wait();
+        if (observer == iObserverMap[context])
+            {
+            observer->PlayAlarmComplete(aMessage.alarmContext);
+            }
+        else
+            {
+            //TODO: Log a message
+            }
+        iObserverMap.erase(context);
+        iObserverMutex.Signal();
+        }
+    else if (type == EStsShutdown)
+        {
+        iState = EStopping;
+        }
+    else
+        {
+        //TODO: Log error message
+        }
+    }
+
+TInt RStsSession::StartServer()
+    {
+    TInt err = KErrNone;
+
+    // Launch the server executable (i.e. in it its own process).
+
+    // Create a new server process. Simultaneous launching of two such processes 
+    // should be detected when the second one attempts to create the server 
+    // object, failing with KErrAlreadyExists.
+    RProcess server;
+    err = server.Create(KStsServerFile, KNullDesC);
+
+    if (err == KErrNone)
+        {
+        TRequestStatus rendezvousStatus;
+        server.Rendezvous(rendezvousStatus);
+        server.Resume();
+
+        // wait for start or death
+        User::WaitForRequest(rendezvousStatus);
+
+        // we can't use the 'exit reason' if the server panicked as this
+        // is the panic 'reason' and may be '0' which cannot be distinguished
+        // from KErrNone  
+        if (server.ExitType() == EExitPanic)
+            {
+            err = KErrGeneral;
+            }
+        else
+            {
+            err = rendezvousStatus.Int();
+            }
+        }
+    server.Close();
+
+    return err;
+    }
+
+TInt RStsSession::StartThread()
+    {
+    TInt result = iThread.Create(KNullDesC, RStsSession::CallBackThreadMain,
+            KDefaultStackSize, &User::Heap(), (TAny*) this);
+
+    if (result == KErrNone)
+        {
+        TRequestStatus rendezvousStatus = KRequestPending;
+
+        //  Register for rendezvous notification when thread is started.
+        iThread.Rendezvous(rendezvousStatus);
+
+        // Start the thread execution
+        iThread.Resume();
+
+        // Wait for thread to start.
+        User::WaitForRequest(rendezvousStatus);
+
+        result = rendezvousStatus.Int();
+
+        if (result != KErrNone)
+            {
+            iThread.Kill(result);
+            }
+        }
+
+    return result;
+    }
+
+TInt RStsSession::CreateServerSession()
+    {
+    // Try to create a session with the server
+    TInt result = CreateSession(KStsServerName, TVersion(
+            KStsServerMajorVersion, KStsServerMinorVersion, KStsServerBuild),
+            KNumSlots, EIpcSession_Sharable);
+
+    // If the server wasn't found, start the server and try creating a session again
+    if (result == KErrNotFound || result == KErrServerTerminated)
+        {
+        result = StartServer();
+        if (result == KErrNone || result == KErrAlreadyExists)
+            {
+            result = CreateSession(KStsServerName, TVersion(
+                    KStsServerMajorVersion, KStsServerMinorVersion,
+                    KStsServerBuild), KNumSlots, EIpcSession_Sharable);
+            }
+        }
+
+    if (result == KErrNone)
+        {
+        TPckg<TThreadId> idPckg(iServerThreadId);
+        result = SendReceive(StsMsg_RegisterMsgQueue, TIpcArgs(iMsgQueue,
+                &idPckg));
+        }
+
+    return result;
+    }
+
+TInt RStsSession::Connect()
+    {
+    iState = EInitializing;
+
+    // Create a nameless global message queue, then pass the handle to the queue to the server.
+    TInt result = iMsgQueue.CreateGlobal(KNullDesC, 30);
+
+    // Create thread for receiving asynch callbacks from the server
+    if (result == KErrNone)
+        {
+        result = CreateServerSession();
+        if (result == KErrNone)
+            {
+            result = StartThread();
+            if (result == KErrNone)
+                {
+                result = iObserverMutex.CreateLocal();
+                }
+            }
+        }
+
+    return result;
+    }
+
+void RStsSession::Close()
+    {
+    TRequestStatus logonStatus = KRequestPending;
+    iThread.Logon(logonStatus);
+    RSessionBase::Close();
+    User::WaitForRequest(logonStatus);
+    iThread.Close();
+    iMsgQueue.Close();
+    CleanUpObservers();
+    iObserverMutex.Close();
+    }
+
+void RStsSession::SendPlayTone(CSystemToneService::TToneType aTone)
+    {
+    TInt err = SendReceive(StsMsg_PlayTone, TIpcArgs(aTone));
+    if (err != KErrNone)
+        {
+        //TODO: Log a message
+        }
+    }
+
+void RStsSession::SendPlayAlarm(CSystemToneService::TAlarmType aAlarm,
+        unsigned int& aAlarmContext, MStsPlayAlarmObserver& aObserver)
+    {
+    TPckg<unsigned int> alarmContextPckg(aAlarmContext);
+    TInt err = SendReceive(StsMsg_PlayAlarm, TIpcArgs(aAlarm,
+            &alarmContextPckg, &aObserver));
+    if (err != KErrNone)
+        {
+        //TODO: Log a message
+        aObserver.PlayAlarmComplete(aAlarmContext);
+        }
+    else
+        {
+        iObserverMutex.Wait();
+        iObserverMap[aAlarmContext] = &aObserver;
+        iObserverMutex.Signal();
+        }
+    }
+
+void RStsSession::SendStopAlarm(unsigned int aAlarmContext)
+    {
+    iObserverMutex.Wait();
+    iObserverMap.erase(aAlarmContext);
+    iObserverMutex.Signal();
+    TInt err = SendReceive(StsMsg_StopAlarm, TIpcArgs(aAlarmContext));
+    if (err != KErrNone)
+        {
+        //TODO: Log a message
+        }
+    }
+
+void RStsSession::CleanUpObservers()
+    {
+    iObserverMutex.Wait();
+    while (!iObserverMap.empty())
+        {
+        //TODO: Add trace here
+        unsigned int context = iObserverMap.begin()->first;
+        iObserverMap.erase(context);
+        }
+    iObserverMutex.Signal();
+    }
+
+void RStsSession::SignalObservers()
+    {
+    iObserverMutex.Wait();
+    while (!iObserverMap.empty())
+        {
+        //TODO: Add trace here
+        unsigned int context = iObserverMap.begin()->first;
+        iObserverMap[context]->PlayAlarmComplete(context);
+        iObserverMap.erase(context);
+        }
+    iObserverMutex.Signal();
+    }