mmserv/tms/tmsserver/src/tmsserver.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Thu, 15 Jul 2010 19:13:36 +0300
branchRCL_3
changeset 17 60e492b28869
parent 12 2eb3b066cc7d
child 19 095bea5f582e
permissions -rw-r--r--
Revision: 201025 Kit: 2010127

/*
 * Copyright (c) 2009 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: Telephony Multimedia Service
 *
 */

#include <e32svr.h>
#include <e32uid.h>
#include <e32capability.h>
#include "tmsutility.h"
#include "tmsclientserver.h"
#include "tmstelephonycenrep.h"
#include "tmsservershutdown.h"
#include "tmsserversession.h"
#include "tmscallserverstartparam.h"
#include "tmscallserver.h"
#include "tmscallclisrv.h"
#include "tmsglobaleffectssettings.h"
#include "tmstareventhandler.h"
#include "tmscenrepaudiohandler.h"
#include "tmsserver.h"

using namespace TMS;

// CONSTANTS
const TInt KTMSShutDownDelayTime = 1000000; // 1 sec delay time
const TInt KOutputsArraySize = 10;

// -----------------------------------------------------------------------------
// TMSServer::NewL
//
// -----------------------------------------------------------------------------
//
TMSServer* TMSServer::NewLC()
    {
    TMSServer* self = new (ELeave) TMSServer;
    CleanupStack::PushL(self);
    self->ConstructL();
    return self;
    }

// -----------------------------------------------------------------------------
// TMSServer::TMSServer
//
// -----------------------------------------------------------------------------
//
TMSServer::TMSServer() :
    CServer2(CActive::EPriorityHigh, ESharableSessions),
    iSession(0)
    {
    }

// -----------------------------------------------------------------------------
// TMSServer::~TMSServer
//
// -----------------------------------------------------------------------------
//
TMSServer::~TMSServer()
    {
    TRACE_PRN_FN_ENT;

    delete iShutdownTimer;
    iTMSCallServList.ResetAndDestroy();
    iTMSCallServList.Close();
    iDnlCodecs.Reset();
    iDnlCodecs.Close();
    iUplCodecs.Reset();
    iUplCodecs.Close();
    delete iEffectSettings;
    delete iTarHandler;
    delete iAudioCenRepHandler;

    TRACE_PRN_FN_EXT;
    }

// -----------------------------------------------------------------------------
// TMSServer::NewSessionL
//
// -----------------------------------------------------------------------------
//
CSession2* TMSServer::NewSessionL(const TVersion& aVersion,
        const RMessage2& aMessage) const
    {
    TRACE_PRN_FN_ENT;

    if (!aMessage.HasCapability(ECapabilityMultimediaDD))
        {
        User::Leave(KErrPermissionDenied);
        }

    const TVersion version(KTMSServMajorVersionNumber,
            KTMSServMinorVersionNumber, KTMSServBuildVersionNumber);

    if (!User::QueryVersionSupported(version, aVersion))
        {
        User::Leave(KErrNotSupported);
        }

    TMSServerSession* session = TMSServerSession::NewL(*((TMSServer*) this));

    TRACE_PRN_FN_EXT;
    return session;
    }

// -----------------------------------------------------------------------------
// TMSServer::ConstructL
//
// -----------------------------------------------------------------------------
//
void TMSServer::ConstructL()
    {
    TRACE_PRN_FN_ENT;

    iShutdownTimer = TMSServerShutDown::NewL();
    StartL(KTMSServerName);
    RThread().SetPriority(EPriorityRealTime);
    iEffectSettings = TMSGlobalEffectsSettings::NewL();
    iTarHandler = NULL;
    iAudioCenRepHandler = NULL;
    iCurrentRouting = TMS_AUDIO_OUTPUT_PRIVATE;

    // We need it running for global volume change updates
    StartRoutingNotifierL();

    TRACE_PRN_FN_EXT;
    }

// -----------------------------------------------------------------------------
// TMSServer::AddSession
//
// -----------------------------------------------------------------------------
//
void TMSServer::AddSession()
    {
    iSession++;
    // If shutdown timer is active, cancel it here.
    iShutdownTimer->Cancel();

    TRACE_PRN_N1(_L("TMS->SRV: AddSession->Active Sessions: [%d]"), iSession);
    }

// -----------------------------------------------------------------------------
// TMSServer::DropSession
//
// -----------------------------------------------------------------------------
//
void TMSServer::DropSession()
    {
    iSession--;

    // If session count is zero, start server shutdown
    if (iSession == 0)
        {
        iShutdownTimer->SetDelay(TTimeIntervalMicroSeconds32(
                KTMSShutDownDelayTime));
        }

    TRACE_PRN_N1(_L("TMS->DNL: DropSession->Active Sessions: [%d]"), iSession);
    }

// -----------------------------------------------------------------------------
// TMSServer::SessionCount
//
// -----------------------------------------------------------------------------
//
TInt TMSServer::SessionCount() const
    {
    return iSession;
    }

// -----------------------------------------------------------------------------
// TMSServer::SetDnLinkSession
//
// -----------------------------------------------------------------------------
//
void TMSServer::SetDnLinkSession(const TBool aSession)
    {
    iDnlinkSession = aSession;
    }

// -----------------------------------------------------------------------------
// TMSServer::SetUpLinkSession
//
// -----------------------------------------------------------------------------
//
void TMSServer::SetUpLinkSession(const TBool aSession)
    {
    iUplinkSession = aSession;
    }

// -----------------------------------------------------------------------------
// TMSServer::HasDnLinkSession
//
// -----------------------------------------------------------------------------
//
TBool TMSServer::HasDnLinkSession() const
    {
    return iDnlinkSession;
    }

// -----------------------------------------------------------------------------
// TMSServer::HasUpLinkSession
//
// -----------------------------------------------------------------------------
//
TBool TMSServer::HasUpLinkSession() const
    {
    return iUplinkSession;
    }

// -----------------------------------------------------------------------------
// TMSServer::GetNewTMSCallSessionHandleL
//
// -----------------------------------------------------------------------------
//
void TMSServer::GetNewTMSCallSessionHandleL(RHandleBase& aHandle)
    {
    TRACE_PRN_FN_ENT;

    TInt i = 0;
    while (i < iTMSCallServList.Count())
        {
        TMSStartAndMonitorTMSCallThread* callThread = iTMSCallServList[i];
        if (!callThread->IsActive())
            {
            iTMSCallServList.Remove(i);
            delete callThread;
            }
        else
            {
            i++;
            }
        }
    iTMSCallServList.Compress();

    TMSCallProxyLocal tmsCallSessionHandle;
    User::LeaveIfError(StartTMSCallServer(tmsCallSessionHandle));
    aHandle = tmsCallSessionHandle;

    TRACE_PRN_FN_EXT;
    }

// -----------------------------------------------------------------------------
// TMSServer::StartTMSCallServer
//
// -----------------------------------------------------------------------------
//
TInt TMSServer::StartTMSCallServer(TMSCallProxyLocal& aHandle)
    {
    TRACE_PRN_FN_ENT;

    TInt status = TMS_RESULT_SUCCESS;
    TMSStartAndMonitorTMSCallThread* callServerThread = NULL;
    TRAP(status, callServerThread =TMSStartAndMonitorTMSCallThread::NewL(
            const_cast<TMSServer*>(this)));
    if (status != TMS_RESULT_SUCCESS)
        {
        delete callServerThread;
        }
    else
        {
        status = iTMSCallServList.Append(callServerThread);
        if (callServerThread && status == TMS_RESULT_SUCCESS)
            {
            status = callServerThread->StartTMSCallServer(aHandle);
            TInt count = 0;
            count = iTMSCallServList.Count();

            iTMSCallServList[count - 1]->iTMSCallProxyLocal = aHandle;

            //cache global vol and global gain to call server thread.
            TInt volume;
            switch (iCurrentRouting)
                {
                case TMS_AUDIO_OUTPUT_PUBLIC:
                case TMS_AUDIO_OUTPUT_LOUDSPEAKER:
                    {
                    iEffectSettings->GetLoudSpkrVolume(volume);
                    }
                    break;
                default:
                    {
                    iEffectSettings->GetEarPieceVolume(volume);
                    }
                    break;
                }
            aHandle.SendToCallServer(TMS_EFFECT_GLOBAL_VOL_SET, volume);
            aHandle.SendToCallServer(TMS_EFFECT_GLOBAL_GAIN_SET,
                    iEffectSettings->Gain());
            }
        else
            {
            delete callServerThread;
            }
        }

    TRACE_PRN_FN_EXT;
    return status;
    }

// -----------------------------------------------------------------------------
// TMSServer::StartRoutingNotifierL
//
// -----------------------------------------------------------------------------
//
void TMSServer::StartRoutingNotifierL()
    {
    TRACE_PRN_FN_ENT;

    if (!iTarHandler)
        {
        iTarHandlerCount = 0;
        iTarHandler = TMSTarEventHandler::NewL((const_cast<TMSServer*> (this)));
        }
    iTarHandlerCount++;

    TRACE_PRN_FN_EXT;
    }

// -----------------------------------------------------------------------------
// TMSServer::CancelRoutingNotifier
//
// -----------------------------------------------------------------------------
//
void TMSServer::CancelRoutingNotifier()
    {
    if (--iTarHandlerCount < 1)
        {
        delete iTarHandler;
        iTarHandler = NULL;
        }
    }

// -----------------------------------------------------------------------------
// TMSServer::StartCenRepHandlerL
//
// -----------------------------------------------------------------------------
//
void TMSServer::StartCenRepHandlerL()
    {
    TRACE_PRN_FN_ENT;

#ifdef _USE_TELEPHONY_CENREP_
    if (!iAudioCenRepHandler)
        {
        iAudioCenRepHandlerCount = 0;
        iAudioCenRepHandler = TMSCenRepAudioHandler::NewL(
                (const_cast<TMSServer*> (this)));
        }
    iAudioCenRepHandlerCount++;
#endif

    TRACE_PRN_FN_EXT;
    }

// -----------------------------------------------------------------------------
// TMSServer::CancelCenRepHandler
//
// -----------------------------------------------------------------------------
//
void TMSServer::CancelCenRepHandler()
    {
    if (--iAudioCenRepHandlerCount <= 0)
        {
        delete iAudioCenRepHandler;
        iAudioCenRepHandler = NULL;
        }
    }

// -----------------------------------------------------------------------------
// TMSServer::SetOutput
//
// -----------------------------------------------------------------------------
//
TInt TMSServer::SetOutput(CSession2* /*sid*/, TInt output)
    {
    TRACE_PRN_FN_ENT;

    TInt status = SendMessageToCallServ(TMS_ROUTING_OUTPUT_SET, output);
    if (status == TMS_RESULT_SUCCESS)
        {
        iCurrentRouting = output;
        }

    TRACE_PRN_FN_EXT;
    return status;
    }

// -----------------------------------------------------------------------------
// TMSServer::GetOutput
//
// -----------------------------------------------------------------------------
//
TInt TMSServer::GetOutput(const RMessage2& aMessage)
    {
    TRACE_PRN_FN_ENT;

    TUint output;
    TInt i = 0;
    TInt status(TMS_RESULT_SUCCESS);
    while (i < iTMSCallServList.Count())
        {
        TMSStartAndMonitorTMSCallThread* callThread = iTMSCallServList[i];

        if (callThread)
            {
            status = callThread->iTMSCallProxyLocal.ReceiveFromCallServer(
                    TMS_ROUTING_OUTPUT_GET, output);
            if (status != TMS_RESULT_SUCCESS)
                {
                break;
                }
            }
        i++;
        }
    TPckgBuf<TInt> p(output);
    aMessage.Write(0, p);
    aMessage.Complete(TMS_RESULT_SUCCESS);

    TRACE_PRN_FN_EXT;
    return status;
    }

// -----------------------------------------------------------------------------
// TMSServer::GetPreviousOutput
//
// -----------------------------------------------------------------------------
//
TInt TMSServer::GetPreviousOutput(const RMessage2& aMessage)
    {
    TRACE_PRN_FN_ENT;

    TUint output;
    TInt i = 0;
    TInt status(TMS_RESULT_SUCCESS);
    while (i < iTMSCallServList.Count())
        {
        TMSStartAndMonitorTMSCallThread* callThread = iTMSCallServList[i];

        if (callThread)
            {
            status = callThread->iTMSCallProxyLocal.ReceiveFromCallServer(
                    TMS_ROUTING_PREVIOUSOUTPUT_GET, output);
            if (status != TMS_RESULT_SUCCESS)
                {
                break;
                }
            }
        i++;
        }
    TPckgBuf<TInt> p(output);
    aMessage.Write(0, p);
    aMessage.Complete(TMS_RESULT_SUCCESS);

    TRACE_PRN_FN_EXT;
    return status;
    }

// -----------------------------------------------------------------------------
// TMSServer::GetAvailableOutputs
//
// -----------------------------------------------------------------------------
//
TInt TMSServer::GetAvailableOutputs(const RMessage2& aMessage)
    {
    TRAPD(status, GetAvailableOutputsL(aMessage));
    return status;
    }

// -----------------------------------------------------------------------------
// TMSServer::GetAvailableOutputsL
//
// -----------------------------------------------------------------------------
//
void TMSServer::GetAvailableOutputsL(const RMessage2& aMessage)
    {
    TRACE_PRN_FN_ENT;

    TInt status = TMS_RESULT_SUCCESS;
    OutputVector outputs;
    HBufC8* buf = HBufC8::NewLC(KOutputsArraySize * sizeof(TUint32));
    TPtr8 ptr = buf->Des();
    TPckgBuf<TInt> countpkg;
    TIpcArgs args;
    args.Set(0, &countpkg);
    args.Set(1, &ptr);

    TInt i = 0;

    while (i < iTMSCallServList.Count())
        {
        TMSStartAndMonitorTMSCallThread* callThread = iTMSCallServList[i];

        if (callThread)
            {
            status = callThread->iTMSCallProxyLocal.ReceiveFromCallServer(
                    TMS_ROUTING_AVAILABLE_OUTPUT_GET, args);
            if (status != TMS_RESULT_SUCCESS)
                {
                break;
                }
            }
        i++;
        }

    aMessage.WriteL(0, countpkg);
    aMessage.WriteL(1, buf->Des());
    aMessage.Complete(status);

    CleanupStack::PopAndDestroy(buf);

    TRACE_PRN_FN_EXT;
    }

// -----------------------------------------------------------------------------
// TMSServer::GetMaxLevel
//
// -----------------------------------------------------------------------------
//
TInt TMSServer::GetMaxLevel(const RMessage2& aMessage)
    {
    TRACE_PRN_FN_ENT;

    TInt status(TMS_RESULT_SUCCESS);
    TPckgBuf<TUint> pckg;

    pckg() = iEffectSettings->MaxVolume();
    if (status == TMS_RESULT_SUCCESS)
        {
        status = aMessage.Write(0, pckg);
        aMessage.Complete(status);
        }

    TRACE_PRN_FN_EXT;
    return status;
    }

// -----------------------------------------------------------------------------
// TMSServer::GetLevel
//
// -----------------------------------------------------------------------------
//
TInt TMSServer::GetLevel(const RMessage2& aMessage)
    {
    TRACE_PRN_FN_ENT;

    TInt status(TMS_RESULT_SUCCESS);
    TPckgBuf<TUint> pckg;
    TInt volume;

    switch (iCurrentRouting)
        {
        case TMS_AUDIO_OUTPUT_PUBLIC:
        case TMS_AUDIO_OUTPUT_LOUDSPEAKER:
            iEffectSettings->GetLoudSpkrVolume(volume);
            break;
        default:
            iEffectSettings->GetEarPieceVolume(volume);
            break;
        }

    pckg() = volume;
    if (status == TMS_RESULT_SUCCESS)
        {
        aMessage.Write(0, pckg);
        aMessage.Complete(status);
        }

    TRACE_PRN_FN_EXT;
    return status;
    }

// -----------------------------------------------------------------------------
// TMSServer::SetLevel
//
// -----------------------------------------------------------------------------
//
TInt TMSServer::SetLevel(CSession2* /*sid*/, TBool tmsclient, TInt level)
    {
    TRACE_PRN_FN_ENT;

    TInt status = SendMessageToCallServ(TMS_EFFECT_GLOBAL_VOL_SET, level);
    if (status == TMS_RESULT_SUCCESS)
        {
        switch (iCurrentRouting)
            {
            case TMS_AUDIO_OUTPUT_PUBLIC:
            case TMS_AUDIO_OUTPUT_LOUDSPEAKER:
                {
                if (tmsclient && iAudioCenRepHandler)
                    {
                    iAudioCenRepHandler->SetLoudSpeakerVol(level);
                    }
                iEffectSettings->SetLoudSpkrVolume(level);
                }
                break;
            case TMS_AUDIO_OUTPUT_NONE:
            case TMS_AUDIO_OUTPUT_PRIVATE:
            case TMS_AUDIO_OUTPUT_HANDSET:
            case TMS_AUDIO_OUTPUT_WIRED_ACCESSORY:
            case TMS_AUDIO_OUTPUT_ACCESSORY:
            case TMS_AUDIO_OUTPUT_ETTY:
                {
                if (tmsclient && iAudioCenRepHandler)
                    {
                    iAudioCenRepHandler->SetEarPieceVol(level);
                    }
                iEffectSettings->SetEarPieceVolume(level);
                }
                break;
            default:
                break;
            }

        iSessionIter.SetToFirst();
        TMSServerSession* serverSession =
                static_cast<TMSServerSession*> (iSessionIter++);

        while (serverSession != NULL)
            {
            serverSession->HandleGlobalEffectChange(
                    TMS_EVENT_EFFECT_VOL_CHANGED, level, EFalse,
                    iCurrentRouting);

            serverSession = static_cast<TMSServerSession*> (iSessionIter++);
            }
        }

    TRACE_PRN_FN_EXT;
    return status;
    }

// -----------------------------------------------------------------------------
// TMSServer::GetMaxGain
//
// -----------------------------------------------------------------------------
//
TInt TMSServer::GetMaxGain(const RMessage2& aMessage)
    {
    TRACE_PRN_FN_ENT;

    TInt status(TMS_RESULT_SUCCESS);
    TPckgBuf<TUint> pckg;
    pckg() = iEffectSettings->MaxGain();
    if (status == TMS_RESULT_SUCCESS)
        {
        status = aMessage.Write(0, pckg);
        aMessage.Complete(status);
        }

    TRACE_PRN_FN_EXT;
    return status;
    }

// -----------------------------------------------------------------------------
// TMSServer::GetGain
//
// -----------------------------------------------------------------------------
//
TInt TMSServer::GetGain(const RMessage2& aMessage)
    {
    TRACE_PRN_FN_ENT;

    TInt status(TMS_RESULT_SUCCESS);
    TPckgBuf<TUint> pckg;
    pckg() = iEffectSettings->Gain();
    if (status == TMS_RESULT_SUCCESS)
        {
        status = aMessage.Write(0, pckg);
        aMessage.Complete(status);
        }

    TRACE_PRN_FN_EXT;
    return status;
    }

// -----------------------------------------------------------------------------
// TMSServer::SetGain
//
// -----------------------------------------------------------------------------
//
TInt TMSServer::SetGain(CSession2* /*sid*/, TInt level)
    {
    TRACE_PRN_FN_ENT;

    TInt status = SendMessageToCallServ(TMS_EFFECT_GLOBAL_GAIN_SET, level);
    if (status == TMS_RESULT_SUCCESS)
        {
        iAudioCenRepHandler->SetMuteState(level);
        iEffectSettings->SetGain(level);
        iSessionIter.SetToFirst();

        TMSServerSession* serverSession =
                static_cast<TMSServerSession*> (iSessionIter++);

        while (serverSession != NULL)
            {
            serverSession->HandleGlobalEffectChange(
                    TMS_EVENT_EFFECT_GAIN_CHANGED, level);
            serverSession = static_cast<TMSServerSession*> (iSessionIter++);
            }
        }

    TRACE_PRN_FN_EXT;
    return status;
    }

// -----------------------------------------------------------------------------
// TMSServer::GetSupportedCodecs
//
// -----------------------------------------------------------------------------
//
TInt TMSServer::GetSupportedCodecs(const TMSStreamType strmType,
        RArray<TFourCC>*& aCodecs)
    {
    TRACE_PRN_FN_ENT;

    if (strmType == TMS_STREAM_UPLINK)
        {
        aCodecs = &iUplCodecs;
        }
    else if (strmType == TMS_STREAM_DOWNLINK)
        {
        aCodecs = &iDnlCodecs;
        }

    TRACE_PRN_FN_EXT;
    return TMS_RESULT_SUCCESS;
    }

// -----------------------------------------------------------------------------
// TMSServer::SendMessageToCallServ
//
// -----------------------------------------------------------------------------
//
TInt TMSServer::SendMessageToCallServ(TInt func, TInt value)
    {
    TRACE_PRN_FN_ENT;

    TInt status(TMS_RESULT_SUCCESS);
    TInt i = 0;
    while (i < iTMSCallServList.Count())
        {
        TMSStartAndMonitorTMSCallThread* callThread = iTMSCallServList[i];

        if (callThread)
            {
            if (!callThread->IsActive())
                {
                iTMSCallServList.Remove(i);
                delete callThread;
                }
            else
                {
                status = callThread->iTMSCallProxyLocal.SendToCallServer(
                        func, value);
                if (status != TMS_RESULT_SUCCESS)
                    {
                    break;
                    }
                }
            }
        i++;
        }

    TRACE_PRN_FN_EXT;
    return status;
    }

// -----------------------------------------------------------------------------
// TMSServer::SendMessageToCallServ
//
// -----------------------------------------------------------------------------
//
TInt TMSServer::SendMessageToCallServ(TInt func, TIpcArgs args)
    {
    TRACE_PRN_FN_ENT;

    TInt status(TMS_RESULT_SUCCESS);
    TInt i = 0;
    while (i < iTMSCallServList.Count())
        {
        TMSStartAndMonitorTMSCallThread* callThread = iTMSCallServList[i];

        if (callThread)
            {
            if (!callThread->IsActive())
                {
                iTMSCallServList.Remove(i);
                delete callThread;
                }
            else
                {
                status = callThread->iTMSCallProxyLocal.SendToCallServer(
                        func, args);
                if (status != TMS_RESULT_SUCCESS)
                    {
                    break;
                    }
                }
            }
        i++;
        }

    TRACE_PRN_FN_EXT;
    return status;
    }

// -----------------------------------------------------------------------------
// TMSServer::NotifyTarClients
//
// -----------------------------------------------------------------------------
//
TInt TMSServer::NotifyTarClients(TRoutingMsgBufPckg routingpckg)
    {
    TRACE_PRN_FN_ENT;

    TInt vol;
    iCurrentRouting = routingpckg().iOutput;
    if (iCurrentRouting == TMS_AUDIO_OUTPUT_PUBLIC ||
            iCurrentRouting == TMS_AUDIO_OUTPUT_LOUDSPEAKER)
        {
        iEffectSettings->GetLoudSpkrVolume(vol);
        }
    else
        {
        iEffectSettings->GetEarPieceVolume(vol);
        }

    TInt status = SendMessageToCallServ(TMS_EFFECT_GLOBAL_VOL_SET, vol);

    iSessionIter.SetToFirst();
    TMSServerSession* serverSession =
            static_cast<TMSServerSession*> (iSessionIter++);
    while (serverSession != NULL)
        {
        // Send only if there is a subscriber to TMS routing notifications.
        if (iTarHandlerCount > 1)
            {
            serverSession->HandleRoutingChange(routingpckg);
            }
        serverSession->HandleGlobalEffectChange(TMS_EVENT_EFFECT_VOL_CHANGED,
                vol, ETrue, iCurrentRouting);
        serverSession = static_cast<TMSServerSession*> (iSessionIter++);
        }

    TRACE_PRN_FN_EXT;
    return status;
    }

// -----------------------------------------------------------------------------
// TMSServer::RunServerL
//
// -----------------------------------------------------------------------------
//
void TMSServer::RunServerL()
    {
    TRACE_PRN_N(_L("TMS->RunServerL"));

    // Naming the server thread after the server helps to debug panics
    User::LeaveIfError(User::RenameThread(KTMSServerName));

    // Create and install the active scheduler we need
    CActiveScheduler* scheduler = new (ELeave) CActiveScheduler;
    CleanupStack::PushL(scheduler);
    CActiveScheduler::Install(scheduler);

    // Create the server (leave it on the cleanup stack)
    TMSServer* server = TMSServer::NewLC();

    // Initialisation complete, now signal the client
    RProcess::Rendezvous(TMS_RESULT_SUCCESS);

    // Start the scheduler and wait for client requests
    CActiveScheduler::Start();

    // Ready to exit.
    // Cleanup scheduler and delete the server
    CleanupStack::PopAndDestroy(server);
    CleanupStack::PopAndDestroy(scheduler);

    TRACE_PRN_N(_L("TMS->RunServerL - TMS server closed"));
    }

// -----------------------------------------------------------------------------
// TMSStartAndMonitorTMSCallThread::TMSStartAndMonitorTMSCallThread
// Perhaps we need to move this to a .cpp?
// -----------------------------------------------------------------------------
//
TMSStartAndMonitorTMSCallThread::TMSStartAndMonitorTMSCallThread(
        TMSServer* aServer) :
    CActive(EPriorityStandard),
    iTMSServer(aServer)
    {
    TRACE_PRN_FN_ENT;
    CActiveScheduler::Add(this);
    TRACE_PRN_FN_EXT;
    }

// -----------------------------------------------------------------------------
// TMSStartAndMonitorTMSCallThread::~TMSStartAndMonitorTMSCallThread
//
// -----------------------------------------------------------------------------
//
TMSStartAndMonitorTMSCallThread::~TMSStartAndMonitorTMSCallThread()
    {
    TRACE_PRN_FN_ENT;
    Cancel();
    TRACE_PRN_FN_EXT;
    }

// -----------------------------------------------------------------------------
// TMSStartAndMonitorTMSCallThread::NewL
//
// -----------------------------------------------------------------------------
//
TMSStartAndMonitorTMSCallThread* TMSStartAndMonitorTMSCallThread::NewL(
        TMSServer* aServer)
    {
    TRACE_PRN_FN_ENT;

    TMSStartAndMonitorTMSCallThread* self =
            new (ELeave) TMSStartAndMonitorTMSCallThread(aServer);
    CleanupStack::PushL(self);
    self->ConstructL();
    CleanupStack::Pop(self);

    TRACE_PRN_FN_EXT;
    return self;
    }

// -----------------------------------------------------------------------------
// TMSStartAndMonitorTMSCallThread::ConstructL
//
// -----------------------------------------------------------------------------
//
void TMSStartAndMonitorTMSCallThread::ConstructL()
    {
    TRACE_PRN_FN_ENT;
    TRACE_PRN_FN_EXT;
    }

// -----------------------------------------------------------------------------
// TMSStartAndMonitorTMSCallThread::StartTMSCallServer
//
// -----------------------------------------------------------------------------
//
TInt TMSStartAndMonitorTMSCallThread::StartTMSCallServer(
        TMSCallProxyLocal& aHndl)
    {
    TRACE_PRN_FN_ENT;

    TInt status(TMS_RESULT_SUCCESS);
    TMSCallServerStartParam start(iTMSServer, iCallSrvrHndl);
    const TUidType serverUid(KNullUid, KNullUid, KUidTMSCallServerUid3);
    TThreadFunction serverFunc = TMSCallServer::StartThread;

    status = iServerThread.Create(_L(""),
                                  serverFunc,
                                  KTMSCallServerStackSize,
                                  KTMSCallServerInitHeapSize,
                                  KTMSCallServerMaxHeapSize,
                                  &start,
                                  EOwnerProcess);

    if (status != TMS_RESULT_SUCCESS)
        {
        return status;
        }

    //NOTE: set priority to EPriorityRealTime or speech codec audio will choke.
    iServerThread.SetPriority(EPriorityRealTime);

    // Synchronise with the server
    TRequestStatus reqStatus;
    iServerThread.Rendezvous(reqStatus);

    if (reqStatus != KRequestPending)
        {
        iServerThread.Kill(0);
        }
    else
        {
        // Start the test harness
        iServerThread.Resume();
        // Server will call the reciprocal static synchronise call
        }

    User::WaitForRequest(reqStatus); // wait for start or death
    if (reqStatus.Int() != TMS_RESULT_SUCCESS)
        {
        iServerThread.Close();
        iCallSrvrHndl.Close();
        return reqStatus.Int();
        }
    status = aHndl.Open(iCallSrvrHndl);

    if (status != TMS_RESULT_SUCCESS)
        {
        iServerThread.Close();
        iCallSrvrHndl.Close();
        return status;
        }
    aHndl.ShareProtected();
    iStatus = KRequestPending;
    iServerThread.Logon(iStatus);
    SetActive();

    TRACE_PRN_FN_EXT;
    return TMS_RESULT_SUCCESS;
    }

// -----------------------------------------------------------------------------
// TMSStartAndMonitorTMSCallThread::RunL
// From CActive
// -----------------------------------------------------------------------------
//
void TMSStartAndMonitorTMSCallThread::RunL()
    {
    TRACE_PRN_FN_ENT;
    iServerThread.Close();
    //NOTE: This is causing a panic when closing down TMS server.
    //iCallSrvrHndl.Close();
    TRACE_PRN_FN_EXT;
    }

// -----------------------------------------------------------------------------
// TMSStartAndMonitorTMSCallThread::DoCancel
// From CActive
// -----------------------------------------------------------------------------
//
void TMSStartAndMonitorTMSCallThread::DoCancel()
    {
    TRACE_PRN_FN_ENT;
    if (iServerThread.Handle())
        {
        iServerThread.LogonCancel(iStatus);
        User::WaitForRequest(iStatus);
        }
    TRACE_PRN_FN_EXT;
    }

// -----------------------------------------------------------------------------
// TMSCallProxyLocal::Open
// Perhaps we need to move this to a .cpp?
// -----------------------------------------------------------------------------
TInt TMSCallProxyLocal::Open(RServer2& aTMSCallServerHandle)
    {
    TRACE_PRN_FN_ENT;

    TInt status(KErrNotSupported);
    status = CreateSession(aTMSCallServerHandle,
                           TVersion(KTMSCallServerMajorVersionNumber,
                                    KTMSCallServerMinorVersionNumber,
                                    KTMSCallServerBuildVersionNumber),
                           -1,
                           EIpcSession_GlobalSharable);
    TRACE_PRN_FN_EXT;
    return status;
    }

// -----------------------------------------------------------------------------
// TMSCallProxyLocal::SendToCallServer
//
// -----------------------------------------------------------------------------
//
TInt TMSCallProxyLocal::SendToCallServer(TInt aFunc, TUint value)
    {
    TInt status(TMS_RESULT_SUCCESS);
    status = SendReceive(aFunc, TIpcArgs(value));
    return status;
    }

// -----------------------------------------------------------------------------
// TMSCallProxyLocal::SendToCallServer
//
// -----------------------------------------------------------------------------
//
TInt TMSCallProxyLocal::SendToCallServer(TInt aFunc, TIpcArgs args)
    {
    TInt status(TMS_RESULT_SUCCESS);
    status = SendReceive(aFunc, args);
    return status;
    }

// -----------------------------------------------------------------------------
// TMSCallProxyLocal::ReceiveFromCallServer
//
// -----------------------------------------------------------------------------
//
TInt TMSCallProxyLocal::ReceiveFromCallServer(TInt aFunc, TUint& value)
    {
    TInt status(TMS_RESULT_SUCCESS);
    TPckgBuf<TUint> pckg;
    TIpcArgs args(&pckg);
    status = SendReceive(aFunc, args);
    if (status == TMS_RESULT_SUCCESS)
        {
        value = pckg();
        }
    return status;
    }

// -----------------------------------------------------------------------------
// TMSCallProxyLocal::ReceiveFromCallServer
//
// -----------------------------------------------------------------------------
//
TInt TMSCallProxyLocal::ReceiveFromCallServer(TInt aFunc, TIpcArgs args)
    {
    TInt status(TMS_RESULT_SUCCESS);
    status = SendReceive(aFunc, args);
    return status;
    }

// -----------------------------------------------------------------------------
// E32Main
// Entry point for the server
// -----------------------------------------------------------------------------
//
TInt E32Main()
    {
    __UHEAP_MARK;
    CTrapCleanup* cleanup = CTrapCleanup::New();
    TInt r = KErrNoMemory;
    if (cleanup)
        {
        TRAP(r, TMSServer::RunServerL());
        delete cleanup;
        }
    __UHEAP_MARKEND;
    return r;
    }

// End of file