diff -r 000000000000 -r 71ca22bcf22a mmserv/voipaudioservices/VoIPServer/src/VoIPUplinkThread.cpp --- /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 +#include +#include +#include +#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 (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 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