Actions

CAF: CTBCMCTimer

Revision as of 10:19, 6 September 2022 by Allyntree (talk | contribs)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)

Recommended timer API within CTBCAFCallFlow or CTBCAFCallBehavior

Before you read information about CTBCMCTimer below, please note that Toolpack 2.9 and above provide a much simplified mechanism for managing timers in CAF call flow or behaviors.

With these simplified timers, it is no longer necessary to "manually" deal with timer allocation and de-allocation, and it is not dangerous to leak memory or timers, and cause crashes if timers are not properly canceled upon leg termination. For these reasons, we highly encourage developers to use this "simplified" timer API.

Here are the "simplified" timer functions.

StartCallTimer

This method allows to start a call flow timer, either attached to a given leg (timer is automatically canceled when the leg is terminated), or to the call flow in general (timer will remain valid until the last leg of the call flow is terminated).

The timer can also be periodic (will be called multiple times until it's canceled)

FindCallTimer

Find a previously started timer

CancelCallTimer

Cancel a timer

Timer expiration

When the timer reaches the expiration delay, OnLegEvent is called with event type TBCMC_EVENT_TYPE_TIMEOUT and the cause specified through StartCallTimer.

CTBCMCTimer class

The CTBCMCTimer class is used to spawn timers attached to call legs.

CTBCMCTimer( TBCMC_LEG_ID in_LegId )
 This constructor creates a new timer object bound to a call leg, but that's not yet kicked (doing nothing for now).

CTBCMCTimer( TBCMC_LEG_ID in_LegId, TBX_UINT32 in_un32TimeoutMs, TBX_UINT32 in_un32TimeoutEventCause )
 This constructor creates a new timer object bound to a call leg,
 and immediately "kicks" that timer so it expire in "in_un32TimeoutMs" milliseconds with cause in_un32TimeoutEventCause.
Kick( TBX_UINT32 in_un32TimeoutMs, TBX_UINT32 in_un32TimeoutEventCause )
 This function will cancel previously kicked timer,
 then "kicks" that timer so it expire in "in_un32TimeoutMs" milliseconds with cause in_un32TimeoutEventCause.
Cancel()
 This function cancels a timer that had previously been kicked

Using the timer within a CTBCAFCallFlow or CTBCAFCallBehavior object

The CTBCMCTimer is bound to a call leg. When it expires, it will cause OnLegEvent to be called on the CTBCAFCallFlow that owns that call leg, and also on all behaviors attached to that call flow. The event will be of type TBCMC_LEG_EVENT_TYPE_TIMEOUT, and the event cause will be equal to the value of in_un32TimeoutEventCause passed when the timer was kicked.

Destroying the timer object

The timer object must be destroyed (or at least canceled) at most upon OnLegFreed. In fact, if not canceled at that point, it will cause error traces in the CAF library due to timer expiring for unknown call leg.

Example code

Define a unique timer cause:

#define MY_CTBCMC_TIMER_CAUSE		CTBCAF_MSG_ID_GEN(TBX_ID_CLASS_TBCMC_TIMER_ID_USER_APP, 0x01)
#define MY_OTHER_CTBCMC_TIMER_CAUSE	CTBCAF_MSG_ID_GEN(TBX_ID_CLASS_TBCMC_TIMER_ID_USER_APP, 0x02)

Creating and kicking the timer:

mpExampleTimer = tbnew CTBCMCTimer
( 
  in_pCallLeg->GetLegId(),
  15000, /* Timeout in 15 seconds */
  MY_CTBCMC_TIMER_CAUSE
);

Destroying the timer, upon leg destruction, in case it did not timeout:

TBX_RESULT MyCallFlowOrBehavior::OnLegFreed( PCTBCAFCallLeg in_pCallLeg, PITBCAFCallFlow* io_ppThis )
(
 IN		PCTBCAFCallLeg			 	in_pCallLeg,
 IN_OUT	PITBCAFCallFlow*			io_ppThis
)
{
 if( mpExampleTimer )
 {
   delete mpExampleTimer;
   mpExampleTimer = NULL;
 }
 // Call default leg terminated implementation (mandatory)
 return CTBCAFCallBehavior::OnLegFreed(in_pCallLeg, io_ppThis);
}

Handling expired timer:

TBX_RESULT MyCallFlowOrBehavior::OnLegEvent( PCTBCAFCallLeg in_pCallLeg, PITBCMCLegEvent in_pEvent )
{
  TBX_BOOL fConsumed = TBX_FALSE;
  if( in_pEvent->GetType() == TBCMC_LEG_EVENT_TYPE_TIMEOUT )
  {
    if( in_pEvent->GetCause() != MY_CTBCMC_TIMER_CAUSE )
    {
      // My timer expired, do something
      DoSomething();
      // Destroy the timer (in this example we don't need to kick it anymore)
      if( mpExampleTimer )
      {
        delete mpExampleTimer;
        mpExampleTimer = NULL;
      }
      fConsumed = TBX_TRUE;
    }
  }
  if( !fConsumed )
  {
    // Event was not for us, forward to next behavior in the chain
    return mpCallInterface->OnLegEvent( in_pCallLeg, in_pEvent );
  }
}