// 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:// This file contains the implementation of the Simulator TSY Voice Call functionality. // The Call classes process the Call-based requests made by ETel clients // and passed down to the TSY by the ETel Server.// ///** @file*/#include <testconfigfileparser.h>#include "CSimVoiceCall.h"#include "CSimPhone.h"#include "CSimDtmf.h"#include "Simlog.h"#include "CSimTsyMode.h"CSimVoiceCall* CSimVoiceCall::NewL(CSimLine* aLine,const TDesC& aName, CSimPhone* aPhone)/*** Standard two phase constructor.** @param aLine pointer to the Line object.* @param aName name of the call to be constructed* @return CSimVoiceCall pointer to the voice call object created* @leave Leaves if no memory or object is not created for any reason*/ { CSimVoiceCall* voiceCall=new(ELeave) CSimVoiceCall(aLine,aName,aPhone); TCleanupItem newCallVoiceClose(CloseCall,voiceCall); CleanupStack::PushL(newCallVoiceClose); voiceCall->ConstructL(); CleanupStack::Pop(); return voiceCall; }CSimVoiceCall::CSimVoiceCall(CSimLine* aLine,const TDesC& aName, CSimPhone* aPhone) : CSimCall(aLine,aName,aPhone)/*** Trivial constructor. Calls CSimCall to initialise its members*/ { }void CSimVoiceCall::ConstructL()/*** Second phase of 2-Phase Constructor* Retrieves all the pausing duration tags from the config file** @param aName name of the voice call to be constructed*/ { LOGVOICE1("Starting to parse Voice Call config parameters..."); iCaps=Caps(); iDiallingPause=iLine->CfgFile()->ItemValue(KDiallingPauseDuration,KDefaultDiallingPauseDuration); iConnectingPause=iLine->CfgFile()->ItemValue(KConnectingPauseDuration,KDefaultConnectingPauseDuration); iDisconnectingPause=iLine->CfgFile()->ItemValue(KDisconnectingPauseDuration,KDefaultDisconnectingPauseDuration); iAnswerIncomingPause=iLine->CfgFile()->ItemValue(KAnswerIncomingPauseDuration,KDefaultAnswerIncomingPauseDuration); iRemoteHangupPause=iLine->CfgFile()->ItemValue(KRemoteHangupPauseDuration,KDefaultRemoteHangupPauseDuration); iTimer=CSimTimer::NewL(iLine->iPhone); CSimCall::ConstructL(); //If present read in remote party info tag TPtrC8 callingname, remotenumber; TInt delay=0; const CTestConfigItem* item=NULL; item=iLine->CfgFile()->Item(KNotifyRemotePartyInfo); TInt ret; if (item) { ret=CTestConfig::GetElement(item->Value(),KStdDelimiter,0,delay); if(ret!=KErrNone) { LOGPARSERR("delay",ret,0,&KNotifyRemotePartyInfo); } ret=CTestConfig::GetElement(item->Value(),KStdDelimiter,1,callingname); if(ret!=KErrNone) { LOGPARSERR("callingname",ret,1,&KNotifyRemotePartyInfo); } ret=CTestConfig::GetElement(item->Value(),KStdDelimiter,2,remotenumber); if(ret!=KErrNone) { LOGPARSERR("remotenumber",ret,2,&KNotifyRemotePartyInfo); } iNotifyRemotePartyInfoTimer->iDelay = delay; iNotifyRemotePartyInfoTimer->iRemotePartyInfoV1.iDirection = RMobileCall::EDirectionUnknown; iNotifyRemotePartyInfoTimer->iRemotePartyInfoV1.iCallingName.Copy(callingname); iNotifyRemotePartyInfoTimer->iRemotePartyInfoV1.iRemoteNumber.iTelNumber.Copy(remotenumber); iNotifyRemotePartyInfoTimer->iRemotePartyInfoV1.iRemoteNumber.iTypeOfNumber = RMobilePhone::EInternationalNumber; iNotifyRemotePartyInfoTimer->iRemotePartyInfoV1.iRemoteNumber.iNumberPlan = RMobilePhone::EIsdnNumberPlan; iNotifyRemotePartyInfoTimer->iRemotePartyInfoV1.iRemoteIdStatus = RMobileCall::ERemoteIdentityAvailable; } else { iNotifyRemotePartyInfoTimer->iRemotePartyInfoV1.iRemoteIdStatus = RMobileCall::ERemoteIdentityUnknown; } LOGVOICE1("...Finished parsing Voice Call config parameters..."); }CSimVoiceCall::~CSimVoiceCall()/*** Destroy all the objects constructed.* CSimTimer and CSimSysAgent objects are destroyed here*/ { delete iTimer; if(iAnswerIncomingCall.iNotifyPending) iLine->ResetAutoAnswerCallObject(this); }TInt CSimVoiceCall::ExtFunc(const TTsyReqHandle aTsyReqHandle,const TInt aIpc,const TDataPackage& aPackage)/*** ExtFunc is called by the server when it has a "extended", i.e. non-core ETel request * for the TSY to process* A request handle, request type and request data are passed to the TSY** @param aTsyReqHandle* @param aIpc IPc number representing the request* @param aPackage data for the request* @return KErrNone*/ { TAny* dataPtr=aPackage.Ptr1(); // The request data has to extracted from TDataPackage and the TAny* pointers have to // be "cast" to the expected request data type switch (aIpc) { // // No Flow Control NOR Multiple Completion // case EMobileCallGetMobileCallCaps: return GetMobileCallCaps(aTsyReqHandle,aPackage.Des1n()); case EMobileCallGetMobileCallStatus: return GetMobileCallStatus(aTsyReqHandle, REINTERPRET_CAST(RMobileCall::TMobileCallStatus*,dataPtr)); case EMobileCallGetMobileCallInfo: return GetMobileCallInfo(aTsyReqHandle,aPackage.Des1n()); case EMobileCallDialEmergencyCall: return DialEmergencyCall(aTsyReqHandle,aPackage.Des1u()); case EMobileCallHold: return Hold(aTsyReqHandle); case EMobileCallResume: return Resume(aTsyReqHandle); case EMobileCallSwap: return Swap(aTsyReqHandle); case EMobileCallDialISV: return DialISV(aTsyReqHandle, aPackage.Des1n(), aPackage.Des2u()); case EMobileCallAnswerISV: TInt retVal; TRAPD(errVal, retVal=AnswerIncomingCallISVL(aTsyReqHandle, aPackage.Des1n())); if (errVal != KErrNone) { return errVal; } else { return retVal; } // // Multiple Completion Services with Immediate Server Repost // (Usually Notifications) // case EMobileCallNotifyMobileCallStatusChange: return NotifyMobileCallStatusChange(aTsyReqHandle, REINTERPRET_CAST(RMobileCall::TMobileCallStatus*, dataPtr)); case EMobileCallNotifyMobileCallCapsChange: return NotifyMobileCallCapsChange(aTsyReqHandle, aPackage.Des1n()); case EMobileCallNotifyRemotePartyInfoChange: return NotifyRemotePartyInfoChange(aTsyReqHandle, aPackage.Des1n()); default: break; } return KErrNotSupported; }TInt CSimVoiceCall::CancelService(const TInt aIpc,const TTsyReqHandle aTsyReqHandle)/** * Cancel an outstanding request. * @param aIpc The IPC number of the request that must be cancelled. Note: this is not the * IPC number of the cancel request itself. * @param aTsyReqHandle The TSY Request Handle of the request to be cancelled. */ { switch(aIpc) { case EMobileCallNotifyMobileCallStatusChange: return NotifyMobileCallStatusChangeCancel(aTsyReqHandle); case EMobileCallNotifyMobileCallCapsChange: return NotifyMobileCallCapsChangeCancel(aTsyReqHandle); case EMobileCallDialEmergencyCall: return DialEmergencyCallCancel(aTsyReqHandle); case EMobileCallHold: return HoldCancel(aTsyReqHandle); case EMobileCallResume: return ResumeCancel(aTsyReqHandle); case EMobileCallSwap: return SwapCancel(aTsyReqHandle); case EMobileCallNotifyRemotePartyInfoChange: return NotifyRemotePartyInfoChangeCancel(); case EMobileCallDialISV: return DialISVCancel(aTsyReqHandle); case EMobileCallAnswerISV: return AnswerIncomingCallISVCancel(aTsyReqHandle); default: break; } return CCallBase::CancelService(aIpc,aTsyReqHandle); }TInt CSimVoiceCall::DialEmergencyCall(const TTsyReqHandle aTsyReqHandle,TDesC* aTelNumber)/*** Process a client's emergency call request.** @param aTsyReqHandle* @param aTelNumber The telephone number to dial* @return KErrNone*/ { return Dial(aTsyReqHandle,NULL,aTelNumber); }TInt CSimVoiceCall::DialEmergencyCallCancel(const TTsyReqHandle aTsyReqHandle)/*** Cancels an emergency call request.** @param aTsyReqHandle* @return KErrNone if successfully cancelled*/ { return DialCancel(aTsyReqHandle); }TInt CSimVoiceCall::Dial(const TTsyReqHandle aTsyReqHandle,const TDesC8* aCallParams,TDesC* /*aTelNumber*/)/*** Process a client's dial request.** @param aTsyReqHandle* @param aCallParams the call parameters* @param aTelNumber The telephone number to dial* @return KErrNone*/ { LOGVOICE1(">>CSimVoiceCall::Dial"); // Note: The telephone number and call parameters should be validated against config file // values here. //see where the dial request has orignated from if(aCallParams) { RCall::TCallParamsPckg* callparamsPckg=reinterpret_cast<RCall::TCallParamsPckg*>(const_cast<TDesC8*>(aCallParams)); RCall::TCallParams& callparams=(*callparamsPckg)(); if(callparams.ExtensionId() == RMobileCall::KETel3rdPartyCallParamsV1) { LOGVOICE1("<<CSimVoiceCall::Dial request from Etel 3rd Party client."); } } iDialRequestHandle=aTsyReqHandle; TInt ret; ret = ActionEvent(ECallEventDial,KErrNone); LOGVOICE1("<<CSimVoiceCall::Dial"); return ret; }TInt CSimVoiceCall::DialCancel(const TTsyReqHandle /*aTsyReqHandle*/)/*** Cancels a dial Request** @param aTsyReqHandle* @return KErrNone if successfully cancelled*/ { LOGVOICE1(">>CSimVoiceCall::DialCancel"); switch(iState) { case RMobileCall::EStatusIdle: SimPanic(EIllegalCancelRequest); // A DialCancel should never reach the TSY in this state. break; case RMobileCall::EStatusDialling: case RMobileCall::EStatusConnecting: iTimer->DoCancel(); // Can ignore for cancel TInt err; err = KErrNone; TRAP(err, (void)ChangeStateL(RMobileCall::EStatusIdle,EFalse,EFalse)); if (err != KErrNone) { ReqCompleted(iDialRequestHandle, err); } else { ReqCompleted(iDialRequestHandle, KErrCancel); } break; case RMobileCall::EStatusConnected: SimPanic(EIllegalCancelRequest); // A DialCancel should never reach the TSY in this state. break; default: break; } LOGVOICE1("<<CSimVoiceCall::DialCancel"); return KErrNone; }TInt CSimVoiceCall::DialISV(const TTsyReqHandle aTsyReqHandle,const TDesC8* aCallParams,TDesC* /*aTelNumber*/)/*** Process an EtelISV client's dial request.** @param aTsyReqHandle* @param aCallParams the call parameters* @param aTelNumber The telephone number to dial* @return KErrNone*/ { LOGVOICE1(">>CSimVoiceCall::DialISV"); // Note: The telephone number and call parameters should be validated against config file // values here. //see where the dial request has orignated from if(aCallParams) { RCall::TCallParamsPckg* callparamsPckg=reinterpret_cast<RCall::TCallParamsPckg*>(const_cast<TDesC8*>(aCallParams)); RCall::TCallParams& callparams=(*callparamsPckg)(); if(callparams.ExtensionId() == RMobileCall::KETel3rdPartyCallParamsV1) { LOGVOICE1("<<CSimVoiceCall::Dial request from Etel 3rd Party client."); } } iDialRequestHandle=aTsyReqHandle; TInt ret; ret = ActionEvent(ECallEventDial,KErrNone); LOGVOICE1("<<CSimVoiceCall::DialISV"); return ret; }TInt CSimVoiceCall::DialISVCancel(const TTsyReqHandle /*aTsyReqHandle*/)/*** Cancels an EtelISV originated dial Request** @param aTsyReqHandle* @return KErrNone if successfully cancelled*/ { LOGVOICE1(">>CSimVoiceCall::DialISVCancel"); switch(iState) { case RMobileCall::EStatusIdle: SimPanic(EIllegalCancelRequest); // A DialCancel should never reach the TSY in this state. break; case RMobileCall::EStatusDialling: case RMobileCall::EStatusConnecting: iTimer->DoCancel(); // Can ignore for cancel TInt err; err = KErrNone; TRAP(err, (void)ChangeStateL(RMobileCall::EStatusIdle,EFalse,EFalse)); if (err != KErrNone) { ReqCompleted(iDialRequestHandle, err); } else { ReqCompleted(iDialRequestHandle, KErrCancel); } break; case RMobileCall::EStatusConnected: SimPanic(EIllegalCancelRequest); // A DialCancel should never reach the TSY in this state. break; default: break; } LOGVOICE1("<<CSimVoiceCall::DialISVCancel"); return KErrNone; }TInt CSimVoiceCall::AnswerIncomingCall(const TTsyReqHandle aTsyReqHandle,const TDesC8* aCallParams)/*** Register a client's interest in answering the next incoming call.* First register interest in incoming calls with the line, then, if a call* is already ringing, start the answer procedure.** @param aTsyReqHandle* @param aCallParams the call parameters* @return KErrNone*/ { LOGVOICE3(">>CSimVoiceCall::AnswerIncomingCall 0x%08x, state %d entry ",this,iState); //see where the answer request has orignated from if(aCallParams) { RCall::TCallParamsPckg* callparamsPckg=reinterpret_cast<RCall::TCallParamsPckg*>(const_cast<TDesC8*>(aCallParams)); RCall::TCallParams& callparams=(*callparamsPckg)(); if(callparams.ExtensionId() == RMobileCall::KETel3rdPartyCallParamsV1) { LOGVOICE1("<<CSimVoiceCall::AnswerIncomingCall request from Etel 3rd Party client."); } } TInt ret=iLine->SetAutoAnswerCallObject(this); if(ret!=KErrNone) { ReqCompleted(aTsyReqHandle,ret); return KErrNone; } iAnswerIncomingCall.iNotifyPending=ETrue; iAnswerIncomingCall.iNotifyHandle=aTsyReqHandle; if(iState==RMobileCall::EStatusRinging) ret = ActionEvent(ECallEventAnswerIncoming,KErrNone); else if(iLine->iState==RMobileCall::EStatusRinging) { TRAPD(errVal, ret=ChangeStateL(RMobileCall::EStatusRinging,EFalse,EFalse)); if (errVal != KErrNone) { ret = errVal; } if(ret==KErrNone) ret = ActionEvent(ECallEventAnswerIncoming,KErrNone); } LOGVOICE3("<<CSimVoiceCall::AnswerIncomingCall 0x%08x, state %d exit",this,iState); return ret; }TInt CSimVoiceCall::AnswerIncomingCallCancel(const TTsyReqHandle /*aTsyReqHandle*/)/*** Cancels a AnswerIncomingCall Request** @param aTsyReqHandle* @return KErrNone if successfully cancelled*/ { LOGVOICE1(">>CSimVoiceCall::AnswerIncomingCallCancel"); if(iAnswerIncomingCall.iNotifyPending) { iAnswerIncomingCall.iNotifyPending=EFalse; iLine->ResetAutoAnswerCallObject(this); ReqCompleted(iAnswerIncomingCall.iNotifyHandle,KErrCancel); } LOGVOICE1("<<CSimVoiceCall::AnswerIncomingCallCancel"); return KErrNone; }TInt CSimVoiceCall::AnswerIncomingCallISVL(const TTsyReqHandle aTsyReqHandle,const TDesC8* aCallParams)/*** Register an EtelISV client's interest in answering the next incoming call.* First register interest in incoming calls with the line, then, if a call* is already ringing, start the answer procedure.** @param aTsyReqHandle* @param aCallParams the call parameters* @return KErrNone*/ { LOGVOICE3(">>CSimVoiceCall::AnswerIncomingCallISV 0x%08x, state %d entry ",this,iState); //see where the answer request has orignated from if(aCallParams) { RCall::TCallParamsPckg* callparamsPckg=reinterpret_cast<RCall::TCallParamsPckg*>(const_cast<TDesC8*>(aCallParams)); RCall::TCallParams& callparams=(*callparamsPckg)(); if(callparams.ExtensionId() == RMobileCall::KETel3rdPartyCallParamsV1) { LOGVOICE1("<<CSimVoiceCall::AnswerIncomingCallISV request from Etel 3rd Party client."); } } TInt ret=iLine->SetAutoAnswerCallObject(this); if(ret!=KErrNone) { ReqCompleted(aTsyReqHandle,ret); return KErrNone; } iAnswerIncomingCall.iNotifyPending=ETrue; iAnswerIncomingCall.iNotifyHandle=aTsyReqHandle; if(iState==RMobileCall::EStatusRinging) ret = ActionEvent(ECallEventAnswerIncoming,KErrNone); else if(iLine->iState==RMobileCall::EStatusRinging) { TRAPD(leaveValue, ret=ChangeStateL(RMobileCall::EStatusRinging,EFalse,EFalse)); if (leaveValue != KErrNone) { return leaveValue; } if (ret == KErrNone) { ret = ActionEvent(ECallEventAnswerIncoming,KErrNone); } } LOGVOICE3("<<CSimVoiceCall::AnswerIncomingCallISV 0x%08x, state %d exit",this,iState); return ret; }TInt CSimVoiceCall::AnswerIncomingCallISVCancel(const TTsyReqHandle /*aTsyReqHandle*/)/*** Cancels an EtelISV originated AnswerIncomingCall Request** @param aTsyReqHandle* @return KErrNone if successfully cancelled*/ { LOGVOICE1(">>CSimVoiceCall::AnswerIncomingCallISVCancel"); if(iAnswerIncomingCall.iNotifyPending) { iAnswerIncomingCall.iNotifyPending=EFalse; iLine->ResetAutoAnswerCallObject(this); ReqCompleted(iAnswerIncomingCall.iNotifyHandle,KErrCancel); } LOGVOICE1("<<CSimVoiceCall::AnswerIncomingCallISVCancel"); return KErrNone; }TInt CSimVoiceCall::Connect(const TTsyReqHandle aTsyReqHandle,const TDesC8* /*aCallParams*/) { ReqCompleted(aTsyReqHandle,KErrNotSupported); return KErrNone; }TInt CSimVoiceCall::ConnectCancel(const TTsyReqHandle aTsyReqHandle) { ReqCompleted(aTsyReqHandle,KErrNotSupported); return KErrNone; }TInt CSimVoiceCall::HangUp(const TTsyReqHandle aTsyReqHandle)/*** Process a client's HangUp request.** @param aTsyReqHandle* @return KErrNone*/ { LOGVOICE1(">>CSimVoiceCall::HangUp"); iHangUpRequestHandle=aTsyReqHandle; TInt ret=ActionEvent(ECallEventHangUp,KErrNone); if(ret!=KErrNone) ReqCompleted(aTsyReqHandle,ret); LOGVOICE1("<<CSimVoiceCall::HangUp"); return KErrNone; }TInt CSimVoiceCall::HangUpCancel(const TTsyReqHandle /*aTsyReqHandle*/)/*** Cancels a HangUp Request** @param aTsyReqHandle* @return KErrNone if successfully cancelled*/ { LOGVOICE1(">>CSimVoiceCall::HangUpCancel"); switch(iState) { case RMobileCall::EStatusIdle: SimPanic(EIllegalCancelRequest); // A DialCancel should never reach the TSY in this state. break; case RMobileCall::EStatusDisconnecting: iTimer->DoCancel(); // Can ignore for cancel TInt err; err = KErrNone; TRAP(err, (void)ChangeStateL(RMobileCall::EStatusConnected,EFalse,EFalse)); if (err != KErrNone) { ReqCompleted(iHangUpRequestHandle, err); } else { ReqCompleted(iHangUpRequestHandle, KErrCancel); } break; default: break; } LOGVOICE1("<<CSimVoiceCall::HangUpCancel"); return KErrNone; }TInt CSimVoiceCall::RelinquishOwnership() { return KErrNotSupported; }TInt CSimVoiceCall::GetBearerServiceInfo(const TTsyReqHandle aTsyReqHandle,RCall::TBearerService* /*aBearerService*/)/*** Retrieves the bearer service info* Not supported for voice calls*/ { ReqCompleted(aTsyReqHandle,KErrNotSupported); return KErrNone; }TInt CSimVoiceCall::GetCallParams(const TTsyReqHandle aTsyReqHandle, TDes8* /*aParams*/)/*** Retrives the call parameters* Not supported for voice calls*/ { ReqCompleted(aTsyReqHandle,KErrNotSupported); return KErrNone; }TInt CSimVoiceCall::LoanDataPort(const TTsyReqHandle,RCall::TCommPort*)/*** Loans the comm port.* This is a data call specific request so not supported here.*/ { return KErrNotSupported; }/*** Cancels the LoanDataPort request.* This is a data call specific request so not supported here.*/TInt CSimVoiceCall::LoanDataPortCancel(const TTsyReqHandle) { return KErrNotSupported; }TInt CSimVoiceCall::RecoverDataPort(const TTsyReqHandle)/*** Recovers the comm port.* This is a data call specific request so not supported here.*/ { return KErrNotSupported; }TInt CSimVoiceCall::Hold(const TTsyReqHandle aReqHandle)/** * Put the call on hold. * @param aReqHandle The request handle associated with this call. * @return TInt Standard error value. */ { if(iState!=RMobileCall::EStatusConnected) { ReqCompleted(aReqHandle,KErrEtelCallNotActive); return KErrNone; } iHoldResumeRequestHandle=aReqHandle; TInt ret=ActionEvent(ECallEventHold,KErrNone); return ret; }TInt CSimVoiceCall::HoldCancel(const TTsyReqHandle)/** * Cancel a Hold request. Since hold is completed synchronously, this function is empty. */ { return KErrNone; }/** * Cancel a NotifyConnectConfirmation request. It is possible to cancel * a pending notification if the client did not issue a Dial request. * @param aReqHandle The request handle associated with this call. */TInt CSimVoiceCall::NotifyConnectConfirmationCancel(const TTsyReqHandle aReqHandle) { if (iNotifyConnectConfirmReqHandle==aReqHandle) { iNotifyConnectConfirmReqHandle = NULL; } ReqCompleted(aReqHandle,KErrCancel); return KErrNone; }/** * Resume a pending MO Connection. * @param aReqHandle The request handle associated with this call. * @param aConnectContinue Boolean to indicate whether to continue/terminate * the call connection. * @return TInt Standard error value. */TInt CSimVoiceCall::ResumeConnect(const TTsyReqHandle aReqHandle, const TBool * aConnectContinue) { TInt ret=KErrNone; if(iWaitForConnectConfirm) { // synchronous operation for either case if (*aConnectContinue) { // okay to continue, initiate dialing, this will // change the state ret=ActionEvent(ECallEventConnectContinue,KErrNone); } else { // terminate the call... // there must be a dial request previously issue, // but we never send the dial request down to call-stack, // and we did not invoke the dial timer, so it will // never expire, so we complete the dial request here ReqCompleted(iDialRequestHandle,KErrNone); } // complete the resume request ReqCompleted(aReqHandle,ret); } else { // client did not issue dial request previously, this request // is received in the wrong state, reject this request ReqCompleted(aReqHandle,KErrAccessDenied); } return ret; }/** * Cancel a ResumeConnect request. Since resume is completed synchronously, this function is empty. */TInt CSimVoiceCall::ResumeConnectCancel(const TTsyReqHandle) { return KErrNone; }TInt CSimVoiceCall::Resume(const TTsyReqHandle aReqHandle)/** * Put the call on resume. * @param aReqHandle The request handle associated with this call. * @return TInt Standard error value. */ { if(iState!=RMobileCall::EStatusHold) { ReqCompleted(aReqHandle,KErrAccessDenied); return KErrNone; } iHoldResumeRequestHandle=aReqHandle; TInt ret=ActionEvent(ECallEventResume,KErrNone); return ret; }TInt CSimVoiceCall::ResumeCancel(const TTsyReqHandle)/** * Cancel a Resume request. Since resume is completed synchronously, this function is empty. */ { return KErrNone; }TInt CSimVoiceCall::Swap(const TTsyReqHandle aReqHandle)/** * If the call is active, put it on hold. If its on hold, resume it. * @param aReqHandle The request handle associated with this call. * @return TInt Standard error value. */ { TCallEvent event; if(iState==RMobileCall::EStatusConnected) { event=ECallEventHold; } else if(iState==RMobileCall::EStatusHold) { event=ECallEventResume; } else { ReqCompleted(aReqHandle,KErrEtelCallNotActive); return KErrNone; } iHoldResumeRequestHandle=aReqHandle; TInt ret=ActionEvent(event,ECallEventSwap); return ret; }TInt CSimVoiceCall::SwapCancel(const TTsyReqHandle)/** * Cancel a Swap request. Since swap is completed synchronously, this function is empty. */ { return KErrNone; }TInt CSimVoiceCall::ActionEvent(TCallEvent aEvent,TInt aOtherArgument)/*** Entry point when an event has occured that may advance the state machine.* The aEvent parameter describes the event.** This function contains the main state machine for the voice call. The outer layer* switches on the event type. Where appropriate, there are inner layer switches* or conditional statements to handle the different responses that may be required to* the same event occurring in different states.** @param aEvent The Call event to handle* @return value represents the error state caused by the attempted state machine jump.*/ { TInt ret=KErrNone; __ASSERT_ALWAYS(iState!=RMobileCall::EStatusUnknown,SimPanic(ECallStatusUnknownIllegal)); __ASSERT_ALWAYS(aEvent!=ECallEventNtRasConnected,SimPanic(ECallEventIllegal)); LOGVOICE3(">>CSimVoiceCall::ActionEvent 0x%08x %d",this,iState); switch(aEvent) { case ECallEventDial: LOGVOICE1(">>CSimVoiceCall::ActionEvent = [ECallEventDial]"); if(iState==RMobileCall::EStatusIdle) { TRAP(ret, ret=ChangeStateL(RMobileCall::EStatusDialling,EFalse,EFalse)); if(ret==KErrNone) iTimer->Start(iDiallingPause,this); } else return KErrEtelCallAlreadyActive; break; case ECallEventHangUp: { LOGVOICE1(">>CSimVoiceCall::ActionEvent = [ECallEventHangUp]"); switch(iState) { case RMobileCall::EStatusDialling: case RMobileCall::EStatusRinging: case RMobileCall::EStatusAnswering: case RMobileCall::EStatusConnecting: case RMobileCall::EStatusConnected: case RMobileCall::EStatusHold: TRAP(ret, ret=ChangeStateL(RMobileCall::EStatusDisconnecting,EFalse,EFalse)); if(ret==KErrNone) iTimer->Start(iDisconnectingPause,this); if(iSimDtmf) { iSimDtmf->CallClosureCallback(); iSimDtmf=NULL; } break; default: return KErrEtelCallNotActive; } } break; case ECallEventIncomingCall: LOGVOICE1(">>CSimVoiceCall::ActionEvent = [ECallEventIncomingCall]"); if(iState==RMobileCall::EStatusIdle) { if(iAnswerIncomingCall.iNotifyPending) { TRAP(ret, ret=ProcessAnswerIncomingCallL()); } else { TRAP(ret, ret=ChangeStateL(RMobileCall::EStatusRinging,EFalse,EFalse)); if(ret!=KErrNone) return ret; } } else return KErrEtelCallAlreadyActive; break; case ECallEventAnswerIncoming: LOGVOICE1(">>CSimVoiceCall::ActionEvent = [ECallEventAnswerIncoming]"); if(iState==RMobileCall::EStatusRinging) { TRAP(ret, ret=ProcessAnswerIncomingCallL()); if(ret!=KErrNone) { return ret; } } else SimPanic(EIllegalStateInconsistancy); // This is checked before calling ActionEvent break; case ECallEventRemoteHangup: LOGVOICE1(">>CSimVoiceCall::ActionEvent = [ECallEventRemoteHangup]"); if(iState==RMobileCall::EStatusConnected) { TRAP(ret, ret=ProcessRemoteHangupL()); if(ret!=KErrNone) { return ret; } } else SimPanic(EIllegalStateInconsistancy); // This is checked before calling ActionEvent break; case ECallEventTimeOut: { LOGVOICE1(">>CSimVoiceCall::ActionEvent = [ECallEventTimeOut]"); switch(iState) { case RMobileCall::EStatusDialling: LOGVOICE1(">>CSimVoiceCall::State = [EStatusDialling]"); TRAP(ret, ret=ChangeStateL(RMobileCall::EStatusConnecting,EFalse,EFalse)); if(ret==KErrNone) iTimer->Start(iConnectingPause,this); return ret; case RMobileCall::EStatusConnecting: LOGVOICE1(">>CSimVoiceCall::State = [EStatusConnecting]"); TRAP(ret, ret=ChangeStateL(RMobileCall::EStatusConnected,EFalse,EFalse)); UpdateRemotePartyInfoDirection(RMobileCall::EStatusConnecting); ReqCompleted(iDialRequestHandle,ret); return ret; case RMobileCall::EStatusDisconnecting: LOGVOICE1(">>CSimVoiceCall::State = [EStatusDisconnecting]"); TRAP(ret, ret=ChangeStateL(RMobileCall::EStatusIdle,EFalse,EFalse)); ReqCompleted(iHangUpRequestHandle,ret); return ret; case RMobileCall::EStatusAnswering: LOGVOICE1(">>CSimVoiceCall::State = [EStatusAnswering]"); TRAP(ret, ret=ChangeStateL(RMobileCall::EStatusConnected,EFalse,EFalse)); UpdateRemotePartyInfoDirection(RMobileCall::EStatusAnswering); ReqCompleted(iAnswerIncomingCall.iNotifyHandle,ret); return ret; default: break; } } break; case ECallEventHold: LOGVOICE1(">>CSimVoiceCall::ActionEvent = [ECallEventHold]"); __ASSERT_ALWAYS(iState==RMobileCall::EStatusConnected,SimPanic(EIllegalStateInconsistancy)); TRAP(ret, ret=ChangeStateL(RMobileCall::EStatusHold,aOtherArgument == ECallEventSwap,EFalse)); if (ret == KErrNone) ReqCompleted(iHoldResumeRequestHandle,ret); break; case ECallEventResume: LOGVOICE1(">>CSimVoiceCall::ActionEvent = [ECallEventResume]"); __ASSERT_ALWAYS(iState==RMobileCall::EStatusHold,SimPanic(EIllegalStateInconsistancy)); TRAP(ret, ret=ChangeStateL(RMobileCall::EStatusConnected,aOtherArgument == ECallEventSwap,EFalse)); if (ret == KErrNone) ReqCompleted(iHoldResumeRequestHandle,ret); break; case ECallEventConnectContinue: SimPanic(EIllegalVoiceCallEvent); // All other events not legal for voice call. break; default: SimPanic(EIllegalVoiceCallEvent); // All other events not legal for voice call. break; } return ret; }void CSimVoiceCall::TimerCallBack(TInt /*aId*/)/*** Timer callback function. When the timer goes off, it will call back into this* function for further processing.*/ { LOGVOICE1(">>CSimVoiceCall::TimerCallBack"); TInt ret=ActionEvent(ECallEventTimeOut,KErrNone); __ASSERT_ALWAYS(ret==KErrNone,SimPanic(ETimeOutEventActionFailed)); LOGVOICE1("<<CSimVoiceCall::TimerCallBack"); }TInt CSimVoiceCall::ProcessAnswerIncomingCallL()/*** Answers an Incoming Call.* First the call state must be changed to "answering", then the flag indicating* that an answer incoming call request is no longer pending. Finally, a new* call object must be assigned to receive the details of the next incoming call.*/ { LOGVOICE3(">>CSimVoiceCall::ProcessAnswerIncomingCall %d",iState,this); TInt ret=ChangeStateL(RMobileCall::EStatusAnswering,EFalse,EFalse); if(ret!=KErrNone) return ret; iTimer->Start(iAnswerIncomingPause,this); iAnswerIncomingCall.iNotifyPending=EFalse; iLine->ResetAutoAnswerCallObject(this); LOGVOICE1("<<CSimVoiceCall::ProcessAnswerIncomingCall"); return ret; }TInt CSimVoiceCall::ProcessRemoteHangupL()/*** Hangs up a call remotely.* First the call state must be changed to "disconnecting", then the flag indicating* that a remote hangup request is no longer pending. Finally, a new* call object must be assigned to receive the next remote hangup request.*/ { LOGVOICE3(">>CSimVoiceCall::ProcessRemoteHangupL %d",iState,this); TInt ret=ChangeStateL(RMobileCall::EStatusDisconnecting,EFalse,EFalse); if(ret!=KErrNone) return ret; iTimer->Start(iRemoteHangupPause,this); iLine->ResetRemoteHangupCallObject(this); LOGVOICE1("<<CSimVoiceCall::ProcessRemoteHangupL"); return ret; }void CSimVoiceCall::SetDtmfSession(CSimDtmf* aSimDtmf)/** * Set the DTMF session pointer. */ { __ASSERT_ALWAYS(iState==RMobileCall::EStatusConnected,SimPanic(EIllegalDtmfReq)); iSimDtmf=aSimDtmf; }CSimDtmf* CSimVoiceCall::GetDtmfSession()/** * Retrieve the DTMF session pointer. */ { return iSimDtmf; }TUint CSimVoiceCall::Caps()/** * Return the current capabilities of this call. * @return TUint Current call capabilities. */ { TUint caps=RCall::KCapsVoice; if(iState!=RMobileCall::EStatusIdle) { if(iState==RMobileCall::EStatusConnected) { caps |= RCall::KCapsHangUp; // If there is only a single call and its state is connected then the hold capability // should be set. // If there is more than one call then only the swap capability should be set as hold // and resume apply only to single calls. TInt i=0; TBool singleCall = ETrue; TInt count= iLine->iCalls->Count(); while(singleCall && i<count) { if(iLine->iCalls->At(i) != this && (iLine->iCalls->At(i)->iState == RMobileCall::EStatusConnected || iLine->iCalls->At(i)->iState == RMobileCall::EStatusHold)) singleCall = EFalse; i++; } if (singleCall) caps |= RMobileCall::KCapsHold; // Swap capability is applicable to single and multiple call // scenarios caps |= RMobileCall::KCapsSwap; } else if(iState==RMobileCall::EStatusHold) { caps |= RCall::KCapsHangUp; TBool otherConnected = EFalse; TInt count= iLine->iCalls->Count(); TInt i=0; while (!otherConnected && i<count) { if(iLine->iCalls->At(i) != this && (iLine->iCalls->At(i)->iState == RMobileCall::EStatusConnected || iLine->iCalls->At(i)->iState == RMobileCall::EStatusHold)) otherConnected = ETrue; i++; } if(otherConnected) { caps |= RMobileCall::KCapsSwap; } else { caps |= RMobileCall::KCapsResume; caps |= RMobileCall::KCapsSwap; } } else if (iState==RMobileCall::EStatusRinging) { if((iLine->IsAnswerCallObjectSpare())) caps |= RCall::KCapsAnswer; } } else { if(iLine->iState==RMobileCall::EStatusIdle || iLine->iState==RMobileCall::EStatusHold) { caps |= RCall::KCapsDial; if((iLine->IsAnswerCallObjectSpare())) caps |= RCall::KCapsAnswer; } else if (iLine->iState==RMobileCall::EStatusRinging) { if((iLine->IsAnswerCallObjectSpare())) caps |= RCall::KCapsAnswer; } } return caps; }void CSimVoiceCall::UpdateRemotePartyInfoDirection(RMobileCall::TMobileCallStatus aPreviousStatus)/**Update the direction of the call for the remote party info member*/ { if(iNotifyRemotePartyInfoTimer && iNotifyRemotePartyInfoTimer->iRemotePartyInfoV1.iRemoteIdStatus != RMobileCall::ERemoteIdentityUnknown) { if(aPreviousStatus == RMobileCall::EStatusAnswering) iNotifyRemotePartyInfoTimer->iRemotePartyInfoV1.iDirection = RMobileCall::EMobileTerminated; else iNotifyRemotePartyInfoTimer->iRemotePartyInfoV1.iDirection = RMobileCall::EMobileOriginated; } }