telephonyserverplugins/simtsy/src/CSimDtmf.cpp
changeset 0 3553901f7fa8
child 19 630d2f34d719
equal deleted inserted replaced
-1:000000000000 0:3553901f7fa8
       
     1 // Copyright (c) 2001-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 // Implements the functionality required to provide DMTF transmission services.
       
    15 // 
       
    16 //
       
    17 
       
    18 /**
       
    19  @file
       
    20 */
       
    21 
       
    22 #include <testconfigfileparser.h>
       
    23 #include "CSimDtmf.h"
       
    24 #include "CSimPhone.h"
       
    25 #include "CSimVoiceCall.h"
       
    26 #include "Simlog.h"
       
    27 
       
    28 const TInt KPauseDuration=2;		//< The duration of a "pause" DTMF character.
       
    29 const TInt KDtmfToneDuration=3;		//< The duration of a standard DTMF character (tone or "pause").
       
    30 
       
    31 CSimDtmf* CSimDtmf::NewL(CSimPhone* aPhone)
       
    32 /**
       
    33  * Standard two-phase constructor.
       
    34  * @param aPhone		The parent phone object.
       
    35  * @return CSimDtmf		The new signal strength class.
       
    36  */
       
    37 	{
       
    38 	CSimDtmf* self=new(ELeave) CSimDtmf(aPhone);
       
    39 	CleanupStack::PushL(self);
       
    40 	self->ConstructL();
       
    41 	CleanupStack::Pop();
       
    42 	return self;
       
    43 	}
       
    44 
       
    45 CSimDtmf::CSimDtmf(CSimPhone* aPhone)
       
    46 		: iPhone(aPhone)
       
    47 /**
       
    48  * Trivial first phase construction.
       
    49  * @param aPhone	The parent phone object.
       
    50  */
       
    51 	{
       
    52 	}
       
    53 
       
    54 void CSimDtmf::ConstructL()
       
    55 /**
       
    56  * Second phase construction.  Create instances of the necessary heap-based
       
    57  * objects and read in the DTMF information from the configuration file.
       
    58  *
       
    59  * Entries in the configuration file will take the following format:
       
    60  * "XXX= <Yyy>, <Zzz>"
       
    61  * A number of these entries may be included to create a signal strength profile
       
    62  * for the duration of the test.
       
    63  */
       
    64 	{
       
    65 	iTimer=CSimTimer::NewL(iPhone);
       
    66 	}
       
    67 
       
    68 CSimDtmf::~CSimDtmf()
       
    69 /**
       
    70  * Standard destructor.  Destroy the heap-based object owned by this object.
       
    71  */
       
    72 	{
       
    73 	delete iDtmfData;
       
    74 	delete iTimer;
       
    75 	}
       
    76 
       
    77 TInt CSimDtmf::GetDtmfCaps(TTsyReqHandle aReqHandle,TDes8* aPckg1)
       
    78 /**
       
    79  * Retrieve DMTF capability information.  This function completes the
       
    80  * client's request synchronously.
       
    81  *
       
    82  * @param aReqHandle	The request handle associated with this request.
       
    83  * @param aPckg1		The first parameter package.  This will be populated with the
       
    84  *						capability data to be returned.
       
    85  * @return TInt			Standard error value.
       
    86  */
       
    87 	{
       
    88 	TPckg<TUint32>* dtmfCapsPckg=(TPckg<TUint32>*)aPckg1;
       
    89 	TUint32& dtmfCaps=(*dtmfCapsPckg)();
       
    90 
       
    91 	dtmfCaps= RMobilePhone::KCapsSendDTMFString |
       
    92 			  RMobilePhone::KCapsSendDTMFSingleTone;
       
    93 	iPhone->ReqCompleted(aReqHandle,KErrNone);
       
    94 	return KErrNone;
       
    95 	}
       
    96 
       
    97 TInt CSimDtmf::NotifyDtmfCapsChange(TTsyReqHandle /*aReqHandle*/,TDes8* /*aPckg1*/)
       
    98 /**
       
    99  * Register a client's interest in being notified when the DMTF Caps change.
       
   100  * Since the capabilities remain static, this request is not completed.
       
   101  *
       
   102  * @param aReqHandle	The handle associated with this request.
       
   103  * @param aPckg1		The first parameter package.  This is populated with the changed
       
   104  *						capability information.
       
   105  * @return TInt			Standard error value.
       
   106  */
       
   107 	{
       
   108 	return KErrNone;
       
   109 	}
       
   110 
       
   111 void CSimDtmf::NotifyDtmfCapsChangeCancel(TTsyReqHandle aReqHandle)
       
   112 /**
       
   113  * Cancel a previous request to be notified of a change in DTMF capabilities.
       
   114  */
       
   115 	{
       
   116 	iPhone->ReqCompleted(aReqHandle,KErrCancel);
       
   117 	}
       
   118 
       
   119 TInt CSimDtmf::SendDTMFTones(TTsyReqHandle aReqHandle,TDes* aPckg1)
       
   120 /**
       
   121  * Send a series of DMTF tones.
       
   122  *
       
   123  * @param aReqHandle	The request handle associated with this request.
       
   124  * @param aPckg1		The first parameter package.  This will be populated with the
       
   125  *						DTMF tone data to be sent.
       
   126  * @return TInt			Standard error value.
       
   127  */
       
   128 	{
       
   129 	TInt ret=SetDtmfCall();
       
   130 	if(ret!=KErrNone)
       
   131 		{
       
   132 		iPhone->ReqCompleted(aReqHandle,KErrEtelCallNotActive);
       
   133 		return KErrNone;
       
   134 		}
       
   135 
       
   136 	if(aPckg1->Length()==0)
       
   137 		{
       
   138 		iPhone->ReqCompleted(aReqHandle,KErrNone);
       
   139 		return KErrNone;
       
   140 		}
       
   141 
       
   142 	iDtmfData=HBufC::New(aPckg1->Length());
       
   143 	if(iDtmfData==NULL)
       
   144 		{
       
   145 		iPhone->ReqCompleted(aReqHandle,KErrNoMemory);
       
   146 		return KErrNone;
       
   147 		}
       
   148 	iDtmfData->Des().Copy(*aPckg1);
       
   149 
       
   150 	iDtmfString=ETrue;
       
   151 	iDtmfStringIndex=0;
       
   152 	iDtmfStringReqPending=aReqHandle;
       
   153 	ret=ActionEvent(EEventStartDtmfString,(*iDtmfData)[iDtmfStringIndex]);
       
   154 	if(ret!=KErrNone)
       
   155 		{
       
   156 		CompleteDtmfStringTx(ret);
       
   157 		}
       
   158 	return KErrNone;
       
   159 	}
       
   160 
       
   161 TInt CSimDtmf::StartDTMFTone(TTsyReqHandle aReqHandle,TDes8* aPckg1)
       
   162 /**
       
   163  * Send a single DMTF tone.
       
   164  *
       
   165  * @param aReqHandle	The request handle associated with this request.
       
   166  * @param aPckg1		The first parameter package.  This will be populated with the
       
   167  *						DTMF tone to be sent.
       
   168  * @return TInt			Standard error value.
       
   169  */
       
   170 	{
       
   171 	TInt ret=SetDtmfCall();
       
   172 	if(ret!=KErrNone)
       
   173 		{
       
   174 		iPhone->ReqCompleted(aReqHandle,KErrEtelCallNotActive);
       
   175 		return KErrNone;
       
   176 		}
       
   177 
       
   178 	TPckg<TChar>* tonePckg=(TPckg<TChar>*)aPckg1;
       
   179 	TChar& tone=(*tonePckg)();
       
   180 
       
   181 	ret=ActionEvent(EEventStartDtmfTone,tone);
       
   182 	iPhone->ReqCompleted(aReqHandle,ret);
       
   183 	return KErrNone;
       
   184 	}
       
   185 
       
   186 TInt CSimDtmf::StopDTMFTone(TTsyReqHandle aReqHandle)
       
   187 /**
       
   188  * Stop transmission of a single DMTF tone.
       
   189  *
       
   190  * @param aReqHandle	The request handle associated with this request.
       
   191  * @return TInt			Standard error value.
       
   192  */
       
   193 	{
       
   194 	__ASSERT_ALWAYS(CheckForActiveVoiceCall(),SimPanic(EIllegalDtmfReq));
       
   195 	TInt ret=ActionEvent(EEventStopDtmfTone);
       
   196 	iPhone->ReqCompleted(aReqHandle,ret);
       
   197 	return KErrNone;
       
   198 	}
       
   199 
       
   200 TInt CSimDtmf::NotifyStopInDTMFString(TTsyReqHandle aReqHandle)
       
   201 /**
       
   202  * Register a client's interest in being notified of when a stop tone is reached.
       
   203  * @param aReqHandle	The request handle associated with this request.
       
   204  * @return TInt			Standard error value.
       
   205  */
       
   206 	{
       
   207 	__ASSERT_ALWAYS(!iNotifyStopChar,SimPanic(EIllegalDtmfEvent));
       
   208 	iNotifyStopChar=ETrue;
       
   209 	iNotifyStopReqHandle=aReqHandle;
       
   210 	return KErrNone;
       
   211 	}
       
   212 
       
   213 void CSimDtmf::NotifyStopInDTMFStringCancel()
       
   214 /**
       
   215  * Cancel a client's interest in being notified of when a stop tone is reach.
       
   216  */
       
   217 	{
       
   218 	if(iNotifyStopChar)
       
   219 		{
       
   220 		iNotifyStopChar=EFalse;
       
   221 		iPhone->ReqCompleted(iNotifyStopReqHandle,KErrCancel);
       
   222 		}
       
   223 	}
       
   224 
       
   225 TInt CSimDtmf::ContinueDtmfStringSending(TTsyReqHandle aReqHandle,TDes8* aPckg1)
       
   226 /**
       
   227  * Continue transmitting a DTMF String after a wait character has been hit.
       
   228  * @param aPckg1		The first request package, which contains an indication of
       
   229  *						whether the request should be continued.
       
   230  * @param aReqHandle	The request handle associated with this request.
       
   231  * @return TInt			Standard error value.
       
   232  */
       
   233 	{
       
   234 	if(!CheckForActiveVoiceCall())
       
   235 		{
       
   236 		iPhone->ReqCompleted(aReqHandle,KErrNotReady);
       
   237 		return KErrNone;
       
   238 		}
       
   239 
       
   240 	TPckg<TBool>* contPckg=(TPckg<TBool>*)aPckg1;
       
   241 	TBool& cont=(*contPckg)();
       
   242 
       
   243 	if(cont)
       
   244 		{
       
   245 		TInt ret=ActionEvent(EEventContinueDtmf);
       
   246 		iPhone->ReqCompleted(aReqHandle,ret);
       
   247 		}
       
   248 	else
       
   249 		{
       
   250 		TInt ret=ActionEvent(EEventTerminateDtmf);
       
   251 		iPhone->ReqCompleted(aReqHandle,ret);
       
   252 		}
       
   253 	return KErrNone;
       
   254 	}
       
   255 
       
   256 TInt CSimDtmf::ActionEvent(TEvent aEvent)
       
   257 /**
       
   258  * Shell function for events that don't pass a DTMF tone character.
       
   259  * @param aEvent	The event to be actioned.
       
   260  * @return TInt		Standard error return.
       
   261  */
       
   262 	{
       
   263 	const TChar KNullChar(0);
       
   264 	return ActionEvent(aEvent,KNullChar);
       
   265 	}
       
   266 
       
   267 TInt CSimDtmf::ActionEvent(TEvent aEvent,const TChar& aTone)
       
   268 /**
       
   269  * Action a DTMF event.
       
   270  * @param aEvent	The event to be actioned.
       
   271  * @param aTone		Optionally, a tone associated with the event.
       
   272  * @return TInt		Standard error return.
       
   273  */
       
   274 	{
       
   275 	TInt ret = KErrNone;
       
   276 	switch(aEvent)
       
   277 		{
       
   278 	case EEventStartDtmfString:
       
   279 		if(iState==ETxTone)
       
   280 			return KErrInUse;
       
   281 		ret = ProcessTone(aTone,ETrue);
       
   282 		return ret;
       
   283 
       
   284 	case EEventStartDtmfTone:
       
   285 		if(iState==ETxTone)
       
   286 			return KErrInUse;
       
   287 		ret = ProcessTone(aTone,EFalse);
       
   288 		return ret;
       
   289 
       
   290 	case EEventTimer:
       
   291 		__ASSERT_ALWAYS(iState==ETxTone,SimPanic(EIllegalDtmfEvent));
       
   292 		__ASSERT_ALWAYS(iDtmfString,SimPanic(EIllegalDtmfEvent));
       
   293 		LOGMISC1("Completed sending DTMF Tone");
       
   294 		iDtmfStringIndex++;
       
   295 		if(iDtmfStringIndex<iDtmfData->Length())
       
   296 			ret = ProcessTone((*iDtmfData)[iDtmfStringIndex],ETrue);
       
   297 		else
       
   298 			{
       
   299 			iState=EIdle;
       
   300 			CompleteDtmfStringTx(KErrNone);
       
   301 			}
       
   302 		return ret;
       
   303 
       
   304 	case EEventStopDtmfTone:
       
   305 		if(iDtmfString)
       
   306 			return KErrInUse;
       
   307 		if(iState!=ETxTone)			// If there's been no StartDtmfTone, then return an error.
       
   308 			return KErrUnknown;
       
   309 		LOGMISC1("Stopping DTMF Tone");
       
   310 		iState=EIdle;
       
   311 		return KErrNone;
       
   312 
       
   313 	case EEventContinueDtmf:
       
   314 		if(iState!=EStopped)
       
   315 			return KErrUnknown;
       
   316 		__ASSERT_ALWAYS(iDtmfString,SimPanic(EIllegalDtmfEvent));
       
   317 		LOGMISC1("Continuing Transmitting a DTMF string after a wait");
       
   318 		iDtmfStringIndex++;
       
   319 		if(iDtmfStringIndex<iDtmfData->Length())
       
   320 			ret = ProcessTone((*iDtmfData)[iDtmfStringIndex],ETrue);
       
   321 		else
       
   322 			{
       
   323 			iState=EIdle;
       
   324 			CompleteDtmfStringTx(KErrNone);
       
   325 			}
       
   326 		return ret;
       
   327 
       
   328 	case EEventTerminateDtmf:
       
   329 		if(iState==EStopped)
       
   330 			{
       
   331 			__ASSERT_ALWAYS(iDtmfString,SimPanic(EIllegalDtmfEvent));
       
   332 			iState=EIdle;
       
   333 			CompleteDtmfStringTx(KErrAccessDenied);
       
   334 			return KErrNone;
       
   335 			}
       
   336 		else
       
   337 			return KErrUnknown;
       
   338 	case EEventCallClosure:
       
   339 		if(iDtmfString)
       
   340 			{
       
   341 			iTimer->Cancel();
       
   342 			CompleteDtmfStringTx(KErrEtelNoCarrier);
       
   343 			}
       
   344 		iState=EIdle;
       
   345 		return KErrNone;
       
   346 		}
       
   347 
       
   348 	SimPanic(EIllegalDtmfEvent);
       
   349 	return KErrNone;		// Dummy to stop compiler error.
       
   350 	}
       
   351 
       
   352 /**
       
   353 Process a tone, i.e. check the tone's validity and, if necessary, start the timer.
       
   354 
       
   355 @param aTone The DTMF character to be processed.
       
   356 @param aStartTimer  A flag indicating whether the timer should be started.
       
   357                     The timer is not required for the single DTMF tone transmissions.
       
   358 @return TInt Standard error return.
       
   359 */
       
   360 TInt CSimDtmf::ProcessTone(const TChar& aTone, TBool aStartTimer)
       
   361 	{
       
   362 	const TChar wait('w');
       
   363 	const TChar pause('p');
       
   364 
       
   365 	if(aTone==wait)
       
   366 		{
       
   367 		LOGMISC1("Starting to perform a DTMF wait; character w");
       
   368 		iState=EStopped;
       
   369 		CheckNotification();
       
   370 		return KErrNone;
       
   371 		}
       
   372 	else if(aTone.IsDigit()||(aTone>='A')&&(aTone<='D'))
       
   373 		{
       
   374 		LOGMISC2("Starting to send DTMF Tone %c", TUint(aTone));
       
   375 		iState=ETxTone;
       
   376 		if(aStartTimer)
       
   377 			{
       
   378 			iTimer->Start(KDtmfToneDuration,this);
       
   379 			}
       
   380 		return KErrNone;
       
   381 		}
       
   382 	else if(aTone==pause)
       
   383 		{
       
   384 		if(!aStartTimer)
       
   385 			{
       
   386 			return KErrArgument;  // can't tx a single "pause" character
       
   387 			}
       
   388 		LOGMISC1("Starting to perform a DTMF pause; character p");
       
   389 		iState=ETxTone;
       
   390 		iTimer->Start(KPauseDuration,this);
       
   391 		return KErrNone;
       
   392 		}
       
   393 	return KErrArgument;			// Illegal DTMF character.
       
   394 	}
       
   395 
       
   396 void CSimDtmf::CompleteDtmfStringTx(TInt aStatus)
       
   397 /**
       
   398  * Complete a DTMF string transmission.
       
   399  * @param aStatus	Completion value.
       
   400  */
       
   401 	{
       
   402 	iDtmfString=EFalse;
       
   403 	delete iDtmfData;
       
   404 	iDtmfData=NULL;
       
   405 	iPhone->ReqCompleted(iDtmfStringReqPending,aStatus);
       
   406 	}
       
   407 
       
   408 void CSimDtmf::CheckNotification()
       
   409 /**
       
   410  * If pending, complete a DTMF "wait" command notification.
       
   411  */
       
   412 	{
       
   413 	if(iNotifyStopChar)
       
   414 		{
       
   415 		iNotifyStopChar=EFalse;
       
   416 		iPhone->ReqCompleted(iNotifyStopReqHandle,KErrNone);
       
   417 		}
       
   418 	}
       
   419 
       
   420 TInt CSimDtmf::SetDtmfCall()
       
   421 /**
       
   422  * Set a pointer to this class in the active voice call class, so that the call class
       
   423  * can callback if the call becomes inactive.
       
   424  * @return TInt		Standard error return.
       
   425  */
       
   426 	{
       
   427 	CSimVoiceCall* call;
       
   428 	TInt ret=iPhone->FindActiveVoiceCall(call);
       
   429 	if(ret!=KErrNone)
       
   430 		return ret;
       
   431 	call->SetDtmfSession(this);
       
   432 	return ret;
       
   433 	}
       
   434 
       
   435 TBool CSimDtmf::CheckForActiveVoiceCall()
       
   436 /**
       
   437  * Check the active call DTMF pointer is pointing to this class.
       
   438  * @return TBool	ETrue if the call's pointer is correctly set.  EFalse if not.
       
   439  */
       
   440 	{
       
   441 	CSimVoiceCall* call;
       
   442 	TInt ret=iPhone->FindActiveVoiceCall(call);
       
   443 	if(ret!=KErrNone)
       
   444 		return EFalse;
       
   445 	if(call->GetDtmfSession()==this)
       
   446 		return ETrue;
       
   447 	return EFalse;
       
   448 	}
       
   449 
       
   450 
       
   451 void CSimDtmf::TimerCallBack(TInt /*aId*/)
       
   452 /**
       
   453  * The timer callback function.  This function will be called when the timer
       
   454  * completes.  It indicates a DTMF tone completion.  So, the action event function
       
   455  * is called to advance the class' state.
       
   456  *
       
   457  * @param aId	This parameter is unused.  It is only required for CSimXxx classes
       
   458  *				that have more than one timer instance and need to identify which
       
   459  *				timer has expired.
       
   460  */
       
   461 	{
       
   462 	TInt ret=ActionEvent(EEventTimer);
       
   463 	__ASSERT_ALWAYS(ret==KErrNone,SimPanic(EIllegalDtmfEvent));
       
   464 	}
       
   465 
       
   466 void CSimDtmf::CallClosureCallback()
       
   467 	{
       
   468 	TInt ret=ActionEvent(EEventCallClosure);
       
   469 	__ASSERT_ALWAYS(ret==KErrNone,SimPanic(EIllegalDtmfEvent));
       
   470 	}
       
   471 
       
   472 const CTestConfigSection* CSimDtmf::CfgFile()
       
   473 /**
       
   474  * Returns a pointer to the current configuration file section.
       
   475  *
       
   476  * @return CTestConfigSection	A pointer to the current configuration file section.
       
   477  */
       
   478 	{
       
   479 	return iPhone->CfgFile();
       
   480 	}
       
   481 
       
   482 void CSimDtmf::SendDTMFTonesCancel()
       
   483 /**
       
   484 Cancels pending SendDTMFTone
       
   485 */
       
   486 	{
       
   487 	iState=EIdle;
       
   488 	if(iTimer->Running())
       
   489 		iTimer->Cancel();
       
   490 	CompleteDtmfStringTx(KErrCancel);
       
   491 	
       
   492 	}