mmserv/voipaudioservices/VoIPServer/src/VoIPUplinkThread.cpp
changeset 0 71ca22bcf22a
child 13 f5c5c82a163e
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mmserv/voipaudioservices/VoIPServer/src/VoIPUplinkThread.cpp	Tue Feb 02 01:08:46 2010 +0200
@@ -0,0 +1,828 @@
+/*
+ * Copyright (c) 2007-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:  VoIP Audio Services
+ *               Implements uplink thread object.
+ *
+ */
+
+#include <IlbcEncoderIntfc.h>
+#include <G711EncoderIntfc.h>
+#include <G729EncoderIntfc.h>
+#include <SpeechEncoderConfig.h>
+#include "debugtracemacros.h"
+#include "VoIPSharedData.h"
+#include "VoIPServerThread.h"
+
+// -----------------------------------------------------------------------------
+// CVoIPUplinkThread::CVoIPUplinkThread
+// Standard Constructor
+// -----------------------------------------------------------------------------
+//
+CVoIPUplinkThread::CVoIPUplinkThread(TSharedData& aData) :
+    iShared(aData)
+    {
+    }
+
+// -----------------------------------------------------------------------------
+// CVoIPUplinkThread::~CVoIPUplinkThread
+// Standard Constructor
+// -----------------------------------------------------------------------------
+//
+CVoIPUplinkThread::~CVoIPUplinkThread()
+    {
+    TRACE_PRN_FN_ENT;
+
+    Stop();
+    delete iSpeechEncoderConfig;
+    delete iG711EncoderIntfc;
+    delete iG729EncoderIntfc;
+    delete iIlbcEncoderIntfc;
+
+    TRACE_PRN_FN_EXT;
+    }
+
+// -----------------------------------------------------------------------------
+// CVoIPUplinkThread::NewL
+// Symbian two-phase constructor
+// -----------------------------------------------------------------------------
+//
+CVoIPUplinkThread* CVoIPUplinkThread::NewL(TSharedData& aData)
+    {
+    CVoIPUplinkThread* self = new (ELeave) CVoIPUplinkThread(aData);
+    CleanupStack::PushL(self);
+    self->ConstructL();
+    CleanupStack::Pop(self);
+    return self;
+    }
+
+// -----------------------------------------------------------------------------
+// CVoIPUplinkThread::ConstructL
+// Part two of Symbian two phase construction
+// -----------------------------------------------------------------------------
+//
+void CVoIPUplinkThread::ConstructL()
+    {
+    TRACE_PRN_FN_ENT;
+
+    InitThreadL();
+    iCodecID = iShared.iCodecSettings.iFourCC;
+    InitMsgQueuesL(KUpLinkQueue, KUpLinkThreadComQueue);
+
+    iShared.iMutex.Wait();
+    TRAPD(err, InitDevSoundL(EMMFStateRecording, iShared.iPriority,
+            iShared.iPreference));
+    iShared.iMutex.Signal();
+
+    if (err != KErrNone)
+        {
+        SendCmd(ECmdDnLinkError, err);
+        }
+    iMaxBufLen = DetermineMaxBufferLen();
+
+    // Client must set these before querying!
+    iG711CodecMode = CVoIPFormatIntfc::EG711ALaw;
+    iILBCCodecMode = CVoIPFormatIntfc::EiLBC20mSecFrame;
+
+    TRACE_PRN_FN_EXT;
+    }
+
+// -----------------------------------------------------------------------------
+// CVoIPUplinkThread::ThreadFunction
+// Thread Startup function
+// -----------------------------------------------------------------------------
+//
+TInt CVoIPUplinkThread::ThreadFunction(TAny* aData)
+    {
+    // get a pointer to the shared data object
+    TSharedData& shared = *((TSharedData*) aData);
+
+    // we can set the sync flag here
+    shared.iMutex.Wait();
+
+    // create a cleanup stack
+    CTrapCleanup* cleanupStack = CTrapCleanup::New();
+
+    if (!cleanupStack)
+        {
+        return KErrNoMemory;
+        }
+
+    CVoIPUplinkThread* thread = 0;
+    TRAPD(err, thread = CVoIPUplinkThread::NewL(shared));
+    if (err != KErrNone)
+        {
+        return err;
+        }
+
+    shared.iMutex.Signal();
+
+    // if we're still here, active scheduler has been constructed
+    // start wait loop which runs until it's time to end the thread
+    CActiveScheduler::Start();
+
+    // Termination cleanup
+    delete thread;
+    delete cleanupStack;
+
+    TRACE_PRN_N(_L("CVoIPUplinkThread::ThreadFunction : Thread CLOSED"));
+    return KErrNone;
+    }
+
+// -----------------------------------------------------------------------------
+// CVoIPUplinkThread::Start
+//
+// -----------------------------------------------------------------------------
+//
+void CVoIPUplinkThread::Start()
+    {
+    TRACE_PRN_FN_ENT;
+
+    TInt err = KErrNotReady;
+
+    if (iStatus == EReady)
+        {
+        TRAP(err, iDevSound->RecordInitL());
+        TRACE_PRN_IF_ERR(err);
+
+        if (err != KErrNone)
+            {
+            SendCmd(ECmdUpLinkError, err);
+            iStatus = EReady;
+            }
+#ifdef _DEBUG
+        else
+            {
+            iSamplesRecCount = 0;
+            }
+#endif
+        }
+
+    TRACE_PRN_FN_EXT;
+    }
+
+// -----------------------------------------------------------------------------
+// CVoIPUplinkThread::Stop
+//
+// -----------------------------------------------------------------------------
+//
+void CVoIPUplinkThread::Stop()
+    {
+    TRACE_PRN_FN_ENT;
+
+    if (iStatus == EStreaming)
+        {
+        iDevSound->Stop();
+        iStatus = EReady;
+        }
+
+    TRACE_PRN_FN_EXT;
+    }
+
+// -----------------------------------------------------------------------------
+// CVoIPUplinkThread::InitializeComplete
+// A callback from the DevSound indicating completion of the initialization.
+// It will send config data to the D/S and configure the encoder via CI.
+// If everything goes well, the state of the thread is set EReady.
+// The initialization completion message is sent back to the main thread.
+// -----------------------------------------------------------------------------
+//
+void CVoIPUplinkThread::InitializeComplete(TInt aError)
+    {
+    TRACE_PRN_FN_ENT;
+
+    TInt err = aError;
+
+    if (err == KErrNone)
+        {
+        TMMFCapabilities conf;
+        conf = iDevSound->Config();
+        conf.iRate = EMMFSampleRate8000Hz;
+        conf.iChannels = EMMFMono;
+        TRAP(err, iDevSound->SetConfigL(conf));
+        if (err == KErrNone)
+            {
+            // We are ready to stream even in case of later CI setting failure
+            iStatus = EReady;
+            TInt gain = iDevSound->MaxGain();
+            iShared.iMutex.Wait();
+            iShared.iMaxGain = gain;
+            iShared.iMutex.Signal();
+            }
+
+        // Init Custom Interface API to the Encoder
+        TRAPD(err0, SetCodecCiL());
+        if (err0 != KErrNone)
+            {
+            // DEBUG only
+            // Can ignore error - the encoder is not fully configured but
+            // can still run in the default mode.
+            TRACE_PRN_IF_ERR(err0);
+            }
+        }
+
+    // Notify the main thread
+    SendCmd(ECmdUplinkInitComplete, err);
+
+    TRACE_PRN_IF_ERR(err);
+    TRACE_PRN_FN_EXT;
+    }
+
+// -----------------------------------------------------------------------------
+// CVoIPUplinkThread::BufferToBeEmptied
+// From MDevSoundObserver
+// -----------------------------------------------------------------------------
+//
+void CVoIPUplinkThread::BufferToBeEmptied(CMMFBuffer* aBuffer)
+    {
+    //    TRACE_PRN_N1(_L("SAMPLES-RECORDED [%d]"), iSamplesRecCount++);
+
+    iDevSoundBufPtr = static_cast<CMMFDataBuffer*> (aBuffer);
+    TDes8& data = iDevSoundBufPtr->Data();
+
+#ifndef __WINSCW__
+    iBufLen = iDevSoundBufPtr->BufferSize();
+#else //__WINSCW__
+    // Buffer size is always 4kB in WINS (PCM). Since we are testing stub
+    // adaptaions of all other supported codecs, and WINS playback is not
+    // supported anyway, we can throw away generated frames and use only
+    // up to the max length of other codecs just to keep the loopback alive.
+    iBufLen = iMaxBufLen;
+    data.SetLength(iBufLen);
+#endif //__WINSCW__
+
+    TRACE_PRN_N1(_L("VoIP->UPL: BTBE->LEN [%d]"), iBufLen);
+
+    // Adjust/create RChunk if necessary
+    TInt err = DoChunk(KChunkUPL, iBufLen, iMaxBufLen);
+
+    if (err != KErrNone)
+        {
+        Stop();
+        iMsgBuffer.iStatus = err;
+        }
+    else
+        {
+        // Pass buffer parameters to the client
+        iMsgBuffer.iStatus = iChunk.Handle();
+        iMsgBuffer.iInt = iBufLen;
+
+        // Copy data over to RChunk
+        TPtr8 dataPtr(iChunk.Base(), iBufLen, iMaxBufLen);
+        dataPtr = data;
+        iStatus = EStreaming;
+        }
+
+    // Notify client there is buffer ready to be emptied
+    iMsgBuffer.iRequest = ECmdEmptyBuffer;
+    iMsgQueue.Send(iMsgBuffer);
+    }
+
+// -----------------------------------------------------------------------------
+// CVoIPUplinkThread::BufferEmptied
+//
+// -----------------------------------------------------------------------------
+//
+void CVoIPUplinkThread::BufferEmptied()
+    {
+    //    TRACE_PRN_N(_L("VoIP->UPL: BE"));
+
+    iDevSound->RecordData();
+    }
+
+// -----------------------------------------------------------------------------
+// CVoIPUplinkThread::RecordError
+// From MDevSoundObserver
+// Recording error is send to the main thread.
+// The state of recorder is rolled back to EReady.
+// -----------------------------------------------------------------------------
+//
+void CVoIPUplinkThread::RecordError(TInt aError)
+    {
+    TRACE_PRN_IF_ERR(aError);
+
+#ifdef _DEBUG
+    iSamplesRecCount = 0;
+#endif
+    iStatus = EReady;
+    SendCmd(ECmdUpLinkError, aError);
+    }
+
+// ---------------------------------------------------------------------------
+// CVoIPUplinkThread::SetCodecCiL
+//
+// ---------------------------------------------------------------------------
+//
+void CVoIPUplinkThread::SetCodecCiL()
+    {
+    TRACE_PRN_FN_ENT;
+
+    switch (iCodecID)
+        {
+        case KMccFourCCIdG711:
+            {
+            if (!iG711EncoderIntfc)
+                {
+                iG711EncoderIntfc = CG711EncoderIntfc::NewL(*iDevSound);
+                }
+            break;
+            }
+        case KMccFourCCIdG729:
+            {
+            if (!iG729EncoderIntfc)
+                {
+                iG729EncoderIntfc = CG729EncoderIntfc::NewL(*iDevSound);
+                }
+            break;
+            }
+        case KMccFourCCIdILBC:
+            {
+            if (!iIlbcEncoderIntfc)
+                {
+                iIlbcEncoderIntfc = CIlbcEncoderIntfc::NewL(*iDevSound);
+                }
+            break;
+            }
+        default:
+            {
+            break;
+            }
+        }
+
+    if (!iSpeechEncoderConfig && iCodecID != KMMFFourCCCodePCM16)
+        {
+        iSpeechEncoderConfig = CSpeechEncoderConfig::NewL(*iDevSound);
+        }
+
+    TRACE_PRN_FN_EXT;
+    }
+
+// -----------------------------------------------------------------------------
+// CVoIPUplinkThread::SetGain
+//
+// -----------------------------------------------------------------------------
+//
+void CVoIPUplinkThread::SetGain()
+    {
+    iShared.iMutex.Wait();
+    TInt gain = iShared.iInt;
+    iShared.iMutex.Signal();
+    iDevSound->SetGain(gain);
+    TRACE_PRN_N1(_L("VoIP->UPL: SetGain [%d]"), gain);
+    }
+
+// -----------------------------------------------------------------------------
+// CVoIPUplinkThread::GetGain
+//
+// -----------------------------------------------------------------------------
+//
+void CVoIPUplinkThread::GetGain()
+    {
+    TInt gain = iDevSound->Gain();
+    iShared.iMutex.Wait();
+    iShared.iInt = gain;
+    iShared.iMutex.Signal();
+    SendCmd(ECmdGetGainComplete);
+    }
+
+// -----------------------------------------------------------------------------
+// CVoIPUplinkThread::SetIlbcCodecMode
+//
+// -----------------------------------------------------------------------------
+//
+void CVoIPUplinkThread::SetIlbcCodecMode()
+    {
+    TInt err = KErrNotSupported;
+
+    if (iStatus == EReady)
+        {
+        iShared.iMutex.Wait();
+        iILBCCodecMode = iShared.iCodecSettings.iILBCCodecMode;
+        iShared.iMutex.Signal();
+
+        if (iIlbcEncoderIntfc && iCodecID == KMccFourCCIdILBC)
+            {
+            if (iILBCCodecMode == CVoIPFormatIntfc::EiLBC20mSecFrame)
+                {
+                err = iIlbcEncoderIntfc->SetEncoderMode(
+                        CIlbcEncoderIntfc::E20msFrame);
+                TRACE_PRN_0(
+                        _L("VoIP->CVoIPUplinkThread[0x%x]::SetIlbcCodecMode [20ms Frame]"));
+                }
+            else
+                {
+                if (iILBCCodecMode == CVoIPFormatIntfc::EiLBC30mSecFrame)
+                    {
+                    err = iIlbcEncoderIntfc->SetEncoderMode(
+                            CIlbcEncoderIntfc::E30msFrame);
+                    TRACE_PRN_0(
+                            _L("VoIP->CVoIPUplinkThread[0x%x]::SetIlbcCodecMode [30ms Frame]"));
+                    }
+                }
+            }
+        }
+
+    if (err != KErrNone)
+        {
+        SendCmd(ECmdUpLinkError, err);
+        }
+
+    TRACE_PRN_IF_ERR(err);
+    }
+
+// -----------------------------------------------------------------------------
+// CVoIPUplinkThread::GetIlbcCodecMode
+//
+// -----------------------------------------------------------------------------
+//
+void CVoIPUplinkThread::GetIlbcCodecMode()
+    {
+    // not available through CIs -> return local value
+    iShared.iMutex.Wait();
+    iShared.iCodecSettings.iILBCCodecMode = iILBCCodecMode;
+    iShared.iMutex.Signal();
+    SendCmd(ECmdGetIlbcCodecModeComplete);
+    }
+
+// -----------------------------------------------------------------------------
+// CVoIPUplinkThread::SetG711CodecMode
+//
+// -----------------------------------------------------------------------------
+//
+void CVoIPUplinkThread::SetG711CodecMode()
+    {
+    TInt err = KErrNotSupported;
+
+    if (iStatus == EReady)
+        {
+        iShared.iMutex.Wait();
+        iG711CodecMode = iShared.iCodecSettings.iG711CodecMode;
+        iShared.iMutex.Signal();
+
+        if (iG711EncoderIntfc && iCodecID == KMccFourCCIdG711)
+            {
+            if (iG711CodecMode == CVoIPFormatIntfc::EG711ALaw)
+                {
+                err = iG711EncoderIntfc->SetEncoderMode(
+                        CG711EncoderIntfc::EEncALaw);
+                TRACE_PRN_0(
+                        _L("VoIP->CVoIPUplinkThread[0x%x]::SetG711CodecMode [ALaw]"));
+                }
+            else
+                {
+                if (iG711CodecMode == CVoIPFormatIntfc::EG711uLaw)
+                    {
+                    err = iG711EncoderIntfc->SetEncoderMode(
+                            CG711EncoderIntfc::EEncULaw);
+                    TRACE_PRN_0(
+                            _L("VoIP->CVoIPUplinkThread[0x%x]::SetG711CodecMode [uLaw]"));
+                    }
+                }
+            }
+        }
+
+    if (err != KErrNone)
+        {
+        SendCmd(ECmdUpLinkError, err);
+        }
+
+    TRACE_PRN_IF_ERR(err);
+    }
+
+// -----------------------------------------------------------------------------
+// CVoIPUplinkThread::GetG711CodecMode
+//
+// -----------------------------------------------------------------------------
+//
+void CVoIPUplinkThread::GetG711CodecMode()
+    {
+    // not available through CIs -> return local value
+    iShared.iMutex.Wait();
+    iShared.iCodecSettings.iG711CodecMode = iG711CodecMode;
+    iShared.iMutex.Signal();
+    SendCmd(ECmdGetG711CodecModeComplete);
+    }
+
+// -----------------------------------------------------------------------------
+// CVoIPUplinkThread::GetSupportedBitrates
+//
+// -----------------------------------------------------------------------------
+//
+void CVoIPUplinkThread::GetSupportedBitrates()
+    {
+    TInt err = KErrNotSupported;
+
+    if (iSpeechEncoderConfig)
+        {
+        RArray<TUint> bitrates;
+        err = iSpeechEncoderConfig->GetSupportedBitrates(bitrates);
+        iShared.iMutex.Wait();
+        iShared.iCodecSettings.iArrBitrates = bitrates;
+        iShared.iMutex.Signal();
+        }
+
+    SendCmd(ECmdGetSupportedBitratesComplete, err);
+    TRACE_PRN_IF_ERR(err);
+    }
+
+// -----------------------------------------------------------------------------
+// CVoIPUplinkThread::SetBitrate
+//
+// -----------------------------------------------------------------------------
+//
+void CVoIPUplinkThread::SetBitrate()
+    {
+    TInt err = KErrNotSupported;
+    iShared.iMutex.Wait();
+    TUint bitrate = iShared.iCodecSettings.iBitrate;
+    iShared.iMutex.Signal();
+
+    if (iSpeechEncoderConfig)
+        {
+        err = iSpeechEncoderConfig->SetBitrate(bitrate);
+        TRACE_PRN_N1(_L("VoIP->UPL: SetBitrate [%d]"), bitrate);
+        }
+
+    if (err != KErrNone)
+        {
+        SendCmd(ECmdUpLinkError, err);
+        }
+
+    TRACE_PRN_IF_ERR(err);
+    }
+
+// -----------------------------------------------------------------------------
+// CVoIPUplinkThread::GetBitrate
+//
+// -----------------------------------------------------------------------------
+//
+void CVoIPUplinkThread::GetBitrate()
+    {
+    TInt err = KErrNotSupported;
+    TUint bitrate = 0;
+
+    if (iSpeechEncoderConfig)
+        {
+        err = iSpeechEncoderConfig->GetBitrate(bitrate);
+        }
+
+    iShared.iMutex.Wait();
+    iShared.iCodecSettings.iBitrate = bitrate;
+    iShared.iMutex.Signal();
+    SendCmd(ECmdGetBitrateComplete, err);
+    TRACE_PRN_IF_ERR(err);
+    }
+
+// -----------------------------------------------------------------------------
+// CVoIPUplinkThread::SetVad
+//
+// -----------------------------------------------------------------------------
+//
+void CVoIPUplinkThread::SetVad()
+    {
+    TInt err = KErrNotSupported;
+    iShared.iMutex.Wait();
+    TBool vad = iShared.iCodecSettings.iVad;
+    iShared.iMutex.Signal();
+
+    switch (iCodecID)
+        {
+        case KMccFourCCIdG711:
+            {
+            if (iG711EncoderIntfc)
+                {
+                err = iG711EncoderIntfc->SetVadMode(vad);
+                }
+            break;
+            }
+        case KMccFourCCIdG729:
+            {
+            if (iG729EncoderIntfc)
+                {
+                err = iG729EncoderIntfc->SetVadMode(vad);
+                }
+            break;
+            }
+        case KMccFourCCIdILBC:
+            {
+            if (iIlbcEncoderIntfc)
+                {
+                err = iIlbcEncoderIntfc->SetVadMode(vad);
+                }
+            break;
+            }
+        case KMccFourCCIdAMRNB:
+            {
+            if (iSpeechEncoderConfig)
+                {
+                err = iSpeechEncoderConfig->SetVadMode(vad);
+                }
+            break;
+            }
+        default:
+            {
+            break; //KErrNotSupported
+            }
+        }
+
+    if (err != KErrNone)
+        {
+        SendCmd(ECmdUpLinkError, err);
+        }
+
+    TRACE_PRN_IF_ERR(err);
+    }
+
+// -----------------------------------------------------------------------------
+// CVoIPUplinkThread::GetVad
+//
+// -----------------------------------------------------------------------------
+//
+void CVoIPUplinkThread::GetVad()
+    {
+    TInt err = KErrNotSupported;
+    TBool vad = EFalse;
+
+    switch (iCodecID)
+        {
+        case KMccFourCCIdG711:
+            {
+            if (iG711EncoderIntfc)
+                {
+                err = iG711EncoderIntfc->GetVadMode(vad);
+                }
+            break;
+            }
+        case KMccFourCCIdG729:
+            {
+            if (iG729EncoderIntfc)
+                {
+                err = iG729EncoderIntfc->GetVadMode(vad);
+                }
+            break;
+            }
+        case KMccFourCCIdILBC:
+            {
+            if (iIlbcEncoderIntfc)
+                {
+                err = iIlbcEncoderIntfc->GetVadMode(vad);
+                }
+            break;
+            }
+        case KMccFourCCIdAMRNB:
+            {
+            if (iSpeechEncoderConfig)
+                {
+                err = iSpeechEncoderConfig->GetVadMode(vad);
+                }
+            break;
+            }
+        default:
+            {
+            break; //KErrNotSupported
+            }
+        }
+
+    iShared.iMutex.Wait();
+    iShared.iCodecSettings.iVad = vad;
+    iShared.iMutex.Signal();
+    SendCmd(ECmdGetVadComplete, err);
+    TRACE_PRN_IF_ERR(err);
+    }
+
+// -----------------------------------------------------------------------------
+// CVoIPUplinkThread::SendCmd
+// Completes active object's request and sets shared data command value to
+// one of the user requested commands.
+// -----------------------------------------------------------------------------
+//
+void CVoIPUplinkThread::SendCmd(TUserCommand aCmd, TInt aError)
+    {
+    iShared.iMutex.Wait();
+
+    iShared.iCmd = aCmd;
+    TRequestStatus* status = iShared.iMnThreadStatus;
+
+    if (status)
+        {
+        if (status->Int() == KRequestPending)
+            {
+            RThread t;
+            TInt err = t.Open(iShared.iMainThreadID);
+            if (err == KErrNone)
+                {
+                t.RequestComplete(status, aError);
+                }
+            }
+        }
+
+    iShared.iMutex.Signal();
+    }
+
+// -----------------------------------------------------------------------------
+// CVoIPUplinkThread
+// From MQueueHandlerObserverSrv
+// -----------------------------------------------------------------------------
+//
+void CVoIPUplinkThread::Event(TInt aEventType, TInt /*aError*/)
+    {
+    switch (aEventType)
+        {
+        case ECmdStartUplink:
+            {
+            Start();
+            break;
+            }
+        case ECmdStopUplink:
+            {
+            if (iStatus == EStreaming)
+                {
+                Stop();
+                }
+            break;
+            }
+        case ECmdBufferEmptied:
+            {
+            BufferEmptied();
+            break;
+            }
+        case ECmdGetGain:
+            {
+            GetGain();
+            break;
+            }
+        case ECmdSetGain:
+            {
+            SetGain();
+            break;
+            }
+        case ECmdSetIlbcCodecMode:
+            {
+            SetIlbcCodecMode();
+            break;
+            }
+        case ECmdGetIlbcCodecMode:
+            {
+            GetIlbcCodecMode();
+            break;
+            }
+        case ECmdSetG711CodecMode:
+            {
+            SetG711CodecMode();
+            break;
+            }
+        case ECmdGetG711CodecMode:
+            {
+            GetG711CodecMode();
+            break;
+            }
+        case ECmdGetSupportedBitrates:
+            {
+            GetSupportedBitrates();
+            break;
+            }
+        case ECmdSetBitrate:
+            {
+            SetBitrate();
+            break;
+            }
+        case ECmdGetBitrate:
+            {
+            GetBitrate();
+            break;
+            }
+        case ECmdSetVad:
+            {
+            SetVad();
+            break;
+            }
+        case ECmdGetVad:
+            {
+            GetVad();
+            break;
+            }
+        case ECmdTerminateThread:
+        default:
+            {
+            if (iStatus == EStreaming)
+                {
+                Stop();
+                }
+            // if unknown exception is raised, just exit this thread
+            CActiveScheduler::Stop();
+            break;
+            }
+        }
+    }
+
+// End of file