diff -r 000000000000 -r 3553901f7fa8 telephonyserverplugins/simtsy/src/CSimDtmf.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/telephonyserverplugins/simtsy/src/CSimDtmf.cpp Tue Feb 02 01:41:59 2010 +0200 @@ -0,0 +1,492 @@ +// Copyright (c) 2001-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: +// Implements the functionality required to provide DMTF transmission services. +// +// + +/** + @file +*/ + +#include +#include "CSimDtmf.h" +#include "CSimPhone.h" +#include "CSimVoiceCall.h" +#include "Simlog.h" + +const TInt KPauseDuration=2; //< The duration of a "pause" DTMF character. +const TInt KDtmfToneDuration=3; //< The duration of a standard DTMF character (tone or "pause"). + +CSimDtmf* CSimDtmf::NewL(CSimPhone* aPhone) +/** + * Standard two-phase constructor. + * @param aPhone The parent phone object. + * @return CSimDtmf The new signal strength class. + */ + { + CSimDtmf* self=new(ELeave) CSimDtmf(aPhone); + CleanupStack::PushL(self); + self->ConstructL(); + CleanupStack::Pop(); + return self; + } + +CSimDtmf::CSimDtmf(CSimPhone* aPhone) + : iPhone(aPhone) +/** + * Trivial first phase construction. + * @param aPhone The parent phone object. + */ + { + } + +void CSimDtmf::ConstructL() +/** + * Second phase construction. Create instances of the necessary heap-based + * objects and read in the DTMF information from the configuration file. + * + * Entries in the configuration file will take the following format: + * "XXX= , " + * A number of these entries may be included to create a signal strength profile + * for the duration of the test. + */ + { + iTimer=CSimTimer::NewL(iPhone); + } + +CSimDtmf::~CSimDtmf() +/** + * Standard destructor. Destroy the heap-based object owned by this object. + */ + { + delete iDtmfData; + delete iTimer; + } + +TInt CSimDtmf::GetDtmfCaps(TTsyReqHandle aReqHandle,TDes8* aPckg1) +/** + * Retrieve DMTF capability information. This function completes the + * client's request synchronously. + * + * @param aReqHandle The request handle associated with this request. + * @param aPckg1 The first parameter package. This will be populated with the + * capability data to be returned. + * @return TInt Standard error value. + */ + { + TPckg* dtmfCapsPckg=(TPckg*)aPckg1; + TUint32& dtmfCaps=(*dtmfCapsPckg)(); + + dtmfCaps= RMobilePhone::KCapsSendDTMFString | + RMobilePhone::KCapsSendDTMFSingleTone; + iPhone->ReqCompleted(aReqHandle,KErrNone); + return KErrNone; + } + +TInt CSimDtmf::NotifyDtmfCapsChange(TTsyReqHandle /*aReqHandle*/,TDes8* /*aPckg1*/) +/** + * Register a client's interest in being notified when the DMTF Caps change. + * Since the capabilities remain static, this request is not completed. + * + * @param aReqHandle The handle associated with this request. + * @param aPckg1 The first parameter package. This is populated with the changed + * capability information. + * @return TInt Standard error value. + */ + { + return KErrNone; + } + +void CSimDtmf::NotifyDtmfCapsChangeCancel(TTsyReqHandle aReqHandle) +/** + * Cancel a previous request to be notified of a change in DTMF capabilities. + */ + { + iPhone->ReqCompleted(aReqHandle,KErrCancel); + } + +TInt CSimDtmf::SendDTMFTones(TTsyReqHandle aReqHandle,TDes* aPckg1) +/** + * Send a series of DMTF tones. + * + * @param aReqHandle The request handle associated with this request. + * @param aPckg1 The first parameter package. This will be populated with the + * DTMF tone data to be sent. + * @return TInt Standard error value. + */ + { + TInt ret=SetDtmfCall(); + if(ret!=KErrNone) + { + iPhone->ReqCompleted(aReqHandle,KErrEtelCallNotActive); + return KErrNone; + } + + if(aPckg1->Length()==0) + { + iPhone->ReqCompleted(aReqHandle,KErrNone); + return KErrNone; + } + + iDtmfData=HBufC::New(aPckg1->Length()); + if(iDtmfData==NULL) + { + iPhone->ReqCompleted(aReqHandle,KErrNoMemory); + return KErrNone; + } + iDtmfData->Des().Copy(*aPckg1); + + iDtmfString=ETrue; + iDtmfStringIndex=0; + iDtmfStringReqPending=aReqHandle; + ret=ActionEvent(EEventStartDtmfString,(*iDtmfData)[iDtmfStringIndex]); + if(ret!=KErrNone) + { + CompleteDtmfStringTx(ret); + } + return KErrNone; + } + +TInt CSimDtmf::StartDTMFTone(TTsyReqHandle aReqHandle,TDes8* aPckg1) +/** + * Send a single DMTF tone. + * + * @param aReqHandle The request handle associated with this request. + * @param aPckg1 The first parameter package. This will be populated with the + * DTMF tone to be sent. + * @return TInt Standard error value. + */ + { + TInt ret=SetDtmfCall(); + if(ret!=KErrNone) + { + iPhone->ReqCompleted(aReqHandle,KErrEtelCallNotActive); + return KErrNone; + } + + TPckg* tonePckg=(TPckg*)aPckg1; + TChar& tone=(*tonePckg)(); + + ret=ActionEvent(EEventStartDtmfTone,tone); + iPhone->ReqCompleted(aReqHandle,ret); + return KErrNone; + } + +TInt CSimDtmf::StopDTMFTone(TTsyReqHandle aReqHandle) +/** + * Stop transmission of a single DMTF tone. + * + * @param aReqHandle The request handle associated with this request. + * @return TInt Standard error value. + */ + { + __ASSERT_ALWAYS(CheckForActiveVoiceCall(),SimPanic(EIllegalDtmfReq)); + TInt ret=ActionEvent(EEventStopDtmfTone); + iPhone->ReqCompleted(aReqHandle,ret); + return KErrNone; + } + +TInt CSimDtmf::NotifyStopInDTMFString(TTsyReqHandle aReqHandle) +/** + * Register a client's interest in being notified of when a stop tone is reached. + * @param aReqHandle The request handle associated with this request. + * @return TInt Standard error value. + */ + { + __ASSERT_ALWAYS(!iNotifyStopChar,SimPanic(EIllegalDtmfEvent)); + iNotifyStopChar=ETrue; + iNotifyStopReqHandle=aReqHandle; + return KErrNone; + } + +void CSimDtmf::NotifyStopInDTMFStringCancel() +/** + * Cancel a client's interest in being notified of when a stop tone is reach. + */ + { + if(iNotifyStopChar) + { + iNotifyStopChar=EFalse; + iPhone->ReqCompleted(iNotifyStopReqHandle,KErrCancel); + } + } + +TInt CSimDtmf::ContinueDtmfStringSending(TTsyReqHandle aReqHandle,TDes8* aPckg1) +/** + * Continue transmitting a DTMF String after a wait character has been hit. + * @param aPckg1 The first request package, which contains an indication of + * whether the request should be continued. + * @param aReqHandle The request handle associated with this request. + * @return TInt Standard error value. + */ + { + if(!CheckForActiveVoiceCall()) + { + iPhone->ReqCompleted(aReqHandle,KErrNotReady); + return KErrNone; + } + + TPckg* contPckg=(TPckg*)aPckg1; + TBool& cont=(*contPckg)(); + + if(cont) + { + TInt ret=ActionEvent(EEventContinueDtmf); + iPhone->ReqCompleted(aReqHandle,ret); + } + else + { + TInt ret=ActionEvent(EEventTerminateDtmf); + iPhone->ReqCompleted(aReqHandle,ret); + } + return KErrNone; + } + +TInt CSimDtmf::ActionEvent(TEvent aEvent) +/** + * Shell function for events that don't pass a DTMF tone character. + * @param aEvent The event to be actioned. + * @return TInt Standard error return. + */ + { + const TChar KNullChar(0); + return ActionEvent(aEvent,KNullChar); + } + +TInt CSimDtmf::ActionEvent(TEvent aEvent,const TChar& aTone) +/** + * Action a DTMF event. + * @param aEvent The event to be actioned. + * @param aTone Optionally, a tone associated with the event. + * @return TInt Standard error return. + */ + { + TInt ret = KErrNone; + switch(aEvent) + { + case EEventStartDtmfString: + if(iState==ETxTone) + return KErrInUse; + ret = ProcessTone(aTone,ETrue); + return ret; + + case EEventStartDtmfTone: + if(iState==ETxTone) + return KErrInUse; + ret = ProcessTone(aTone,EFalse); + return ret; + + case EEventTimer: + __ASSERT_ALWAYS(iState==ETxTone,SimPanic(EIllegalDtmfEvent)); + __ASSERT_ALWAYS(iDtmfString,SimPanic(EIllegalDtmfEvent)); + LOGMISC1("Completed sending DTMF Tone"); + iDtmfStringIndex++; + if(iDtmfStringIndexLength()) + ret = ProcessTone((*iDtmfData)[iDtmfStringIndex],ETrue); + else + { + iState=EIdle; + CompleteDtmfStringTx(KErrNone); + } + return ret; + + case EEventStopDtmfTone: + if(iDtmfString) + return KErrInUse; + if(iState!=ETxTone) // If there's been no StartDtmfTone, then return an error. + return KErrUnknown; + LOGMISC1("Stopping DTMF Tone"); + iState=EIdle; + return KErrNone; + + case EEventContinueDtmf: + if(iState!=EStopped) + return KErrUnknown; + __ASSERT_ALWAYS(iDtmfString,SimPanic(EIllegalDtmfEvent)); + LOGMISC1("Continuing Transmitting a DTMF string after a wait"); + iDtmfStringIndex++; + if(iDtmfStringIndexLength()) + ret = ProcessTone((*iDtmfData)[iDtmfStringIndex],ETrue); + else + { + iState=EIdle; + CompleteDtmfStringTx(KErrNone); + } + return ret; + + case EEventTerminateDtmf: + if(iState==EStopped) + { + __ASSERT_ALWAYS(iDtmfString,SimPanic(EIllegalDtmfEvent)); + iState=EIdle; + CompleteDtmfStringTx(KErrAccessDenied); + return KErrNone; + } + else + return KErrUnknown; + case EEventCallClosure: + if(iDtmfString) + { + iTimer->Cancel(); + CompleteDtmfStringTx(KErrEtelNoCarrier); + } + iState=EIdle; + return KErrNone; + } + + SimPanic(EIllegalDtmfEvent); + return KErrNone; // Dummy to stop compiler error. + } + +/** +Process a tone, i.e. check the tone's validity and, if necessary, start the timer. + +@param aTone The DTMF character to be processed. +@param aStartTimer A flag indicating whether the timer should be started. + The timer is not required for the single DTMF tone transmissions. +@return TInt Standard error return. +*/ +TInt CSimDtmf::ProcessTone(const TChar& aTone, TBool aStartTimer) + { + const TChar wait('w'); + const TChar pause('p'); + + if(aTone==wait) + { + LOGMISC1("Starting to perform a DTMF wait; character w"); + iState=EStopped; + CheckNotification(); + return KErrNone; + } + else if(aTone.IsDigit()||(aTone>='A')&&(aTone<='D')) + { + LOGMISC2("Starting to send DTMF Tone %c", TUint(aTone)); + iState=ETxTone; + if(aStartTimer) + { + iTimer->Start(KDtmfToneDuration,this); + } + return KErrNone; + } + else if(aTone==pause) + { + if(!aStartTimer) + { + return KErrArgument; // can't tx a single "pause" character + } + LOGMISC1("Starting to perform a DTMF pause; character p"); + iState=ETxTone; + iTimer->Start(KPauseDuration,this); + return KErrNone; + } + return KErrArgument; // Illegal DTMF character. + } + +void CSimDtmf::CompleteDtmfStringTx(TInt aStatus) +/** + * Complete a DTMF string transmission. + * @param aStatus Completion value. + */ + { + iDtmfString=EFalse; + delete iDtmfData; + iDtmfData=NULL; + iPhone->ReqCompleted(iDtmfStringReqPending,aStatus); + } + +void CSimDtmf::CheckNotification() +/** + * If pending, complete a DTMF "wait" command notification. + */ + { + if(iNotifyStopChar) + { + iNotifyStopChar=EFalse; + iPhone->ReqCompleted(iNotifyStopReqHandle,KErrNone); + } + } + +TInt CSimDtmf::SetDtmfCall() +/** + * Set a pointer to this class in the active voice call class, so that the call class + * can callback if the call becomes inactive. + * @return TInt Standard error return. + */ + { + CSimVoiceCall* call; + TInt ret=iPhone->FindActiveVoiceCall(call); + if(ret!=KErrNone) + return ret; + call->SetDtmfSession(this); + return ret; + } + +TBool CSimDtmf::CheckForActiveVoiceCall() +/** + * Check the active call DTMF pointer is pointing to this class. + * @return TBool ETrue if the call's pointer is correctly set. EFalse if not. + */ + { + CSimVoiceCall* call; + TInt ret=iPhone->FindActiveVoiceCall(call); + if(ret!=KErrNone) + return EFalse; + if(call->GetDtmfSession()==this) + return ETrue; + return EFalse; + } + + +void CSimDtmf::TimerCallBack(TInt /*aId*/) +/** + * The timer callback function. This function will be called when the timer + * completes. It indicates a DTMF tone completion. So, the action event function + * is called to advance the class' state. + * + * @param aId This parameter is unused. It is only required for CSimXxx classes + * that have more than one timer instance and need to identify which + * timer has expired. + */ + { + TInt ret=ActionEvent(EEventTimer); + __ASSERT_ALWAYS(ret==KErrNone,SimPanic(EIllegalDtmfEvent)); + } + +void CSimDtmf::CallClosureCallback() + { + TInt ret=ActionEvent(EEventCallClosure); + __ASSERT_ALWAYS(ret==KErrNone,SimPanic(EIllegalDtmfEvent)); + } + +const CTestConfigSection* CSimDtmf::CfgFile() +/** + * Returns a pointer to the current configuration file section. + * + * @return CTestConfigSection A pointer to the current configuration file section. + */ + { + return iPhone->CfgFile(); + } + +void CSimDtmf::SendDTMFTonesCancel() +/** +Cancels pending SendDTMFTone +*/ + { + iState=EIdle; + if(iTimer->Running()) + iTimer->Cancel(); + CompleteDtmfStringTx(KErrCancel); + + }