mmserv/sts/stsimplementation/src/rstssession.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Fri, 14 May 2010 16:22:35 +0300
changeset 16 43d09473c595
parent 14 80975da52420
permissions -rw-r--r--
Revision: 201017 Kit: 201019

/*
 * 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()
    {
    // Initialisation complete, now signal the client, if requested.
    RThread::Rendezvous(KErrNone);

    while (true)
        {
        TStsCallBack message;
        iMsgQueue.ReceiveBlocking(message);
        TStsCallBackType type = message.callBackType;
        if (type == EStsPlayAlarmComplete)
            {
            message.observer->PlayAlarmComplete(message.alarmContext);
            }
        else if (type == EStsShutdown)
            {
            break;
            }
        else
            {
            //TODO: Log error message
            }
        }
    }

TInt RStsSession::StartMsgQueue()
    {
    // Create a nameless global message queue, then pass the handle to the queue to the server.
    TInt err = iMsgQueue.CreateGlobal(KNullDesC, 30);
    if (err == KErrNone)
        {
        err = SendReceive(StsMsg_RegisterMsgQueue, TIpcArgs(iMsgQueue));
        }
    return err;
    }

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::Connect()
    {
    // 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 = StartServer();
        if (result == KErrNone || result == KErrAlreadyExists)
            {
            result = CreateSession(KStsServerName, TVersion(
                    KStsServerMajorVersion, KStsServerMinorVersion,
                    KStsServerBuild), KNumSlots, EIpcSession_Sharable);
            }
        }

    // Create thread for receiving asynch callbacks from the server
    if (result == KErrNone)
        {
        result = StartMsgQueue();
        if (result == KErrNone)
            {
            result = StartThread();
            }
        }

    return result;
    }

void RStsSession::Close()
    {
    TRequestStatus logonStatus = KRequestPending;
    iThread.Logon(logonStatus);
    RSessionBase::Close();
    User::WaitForRequest(logonStatus);
    iThread.Close();
    iMsgQueue.Close();
    }

TInt RStsSession::SendPlayTone(CSystemToneService::TToneType aTone)
    {
    return SendReceive(StsMsg_PlayTone, TIpcArgs(aTone));
    }

TInt RStsSession::SendPlayAlarm(CSystemToneService::TAlarmType aAlarm,
        unsigned int& aAlarmContext, MStsPlayAlarmObserver& aObserver)
    {
    TPckg<unsigned int> alarmContextPckg(aAlarmContext);
    return SendReceive(StsMsg_PlayAlarm, TIpcArgs(aAlarm, &alarmContextPckg,
            &aObserver));
    }

TInt RStsSession::SendStopAlarm(unsigned int aAlarmContext)
    {
    return SendReceive(StsMsg_StopAlarm, TIpcArgs(aAlarmContext));
    }