CAF: Working With Call Legs

From TBwiki
Revision as of 15:52, 6 November 2009 by Mathieu St-Jean (Talk | contribs)
Jump to: navigation, search

Contents

Call Leg Definition

The main mechanism through which the customer application controls the Toolpack system is via the management of call legs. The application creates a call leg (or more than one for conferencing and bridging) at the beginning of a call, then controls it through a simple, protocol-agnostic API. When a call is terminated, the call leg can be destroyed.

A call leg is represented by an instance of the CTBCMCLeg class. It represents a full-duplex media resource and/or its associated signaling entity. Typical examples of call legs with signaling would be an SS7 ISUP call with its associated CIC (mapped to a TDM interface such as a T1 timeslot) or a SIP call with its associated VOIP codec resource (attached to an IP/UDP endpoint). A media-only call leg would represent a standalone TDM endpoint (such as a T1 timeslot) or a VOIP endpoint (VOIP codec resource attached to an IP/UDP endpoint). The section titled Leg Creation will show how different types of call legs can be created.

The CTBCMCLeg class allows a programmer to easily act upon the call leg to influence the signaling portion (e.g. accept, answer, terminate, etc) and to use the media portion as well (e.g play prompts, record voice, play or collect digits and tones).

Other member functions are available to retrieve (and change in some cases) the call leg attributes including the media profile (e.g. parameters to the media resource) or signaling information (e.g. protocol type, called and calling party numbers, etc). Joining/unjoining (connection/disconnection) of call legs is also a typical action handled by this class for ’gateway-type’ applications. It is important to note that this class is protocol-agnostic and can handle any type of supported call legs (e.g. SIP/VOIP, ISDN, SS7, Media only, etc).


Caveats
  • Do not confuse a call leg with a call. A call leg represents one full-duplex link to a party while a call represents the agglomeration of multiple (two or more) call legs. For example, a bridge is a form of call that uses two call legs.
  • Do not confuse the base class CTBCMCLeg with the class CTBCAFCallLeg. The later is an implementation class specialized to be used by the ITBCAFCallFlow interface when dealing with multiple legs. It is designed to represent a leg within a call. It cannot be instanciated as a standalone object without modifications to make it independent from the ITBCAFCallFlow interface.
  • If the overall goal is to bridge two or more call legs together, then the programmer would be advised to use the CTBCAFBridge class for leg creation instead of creating call legs manually. This class already deals with the issues of handling multiple legs simultaneously.

Command Flow for Leg Actions in CAF

All actions requested on a leg are executed asynchronously. For each action DoSomething() on a leg, a corresponding OnDoSomethingResponse() event will be received on the leg once Toolpack starts processing the command. If the OnXXXResponse() function does not handle the response (the default implementation is empty) and the result of the action was a failure, the default error handling function OnLegError() will be called. Most of the actions executed on a leg can take variable time to complete. In these case, an extra event will be received on the leg once the action is complete (OnXXXResponse() is always called when Toolpack starts executing the action).


For example, to play a digit sequence, one would call PlayDigit(). It would then almost immediately receive the OnPlayDigitResponse() event indicating that Toolpack has received the command. At the same time this event is called, Toolpack will start playing the digits on the leg. Once the digits play is completed, the user will receive an OnDigitPlayingDone() event.


Leg Creation

Creating a leg is always done through the definition of a call leg attribute. The values entered in the call leg attribute will define the type of call leg created and its parameters. The following sections describe several scenarios in which you build a call leg. Instruction will be given on how to fill the leg attributes and how to use them to create the call leg.


Preparing Leg Attributes

Normal Call Leg Attributes

For calls including both the signaling and the media path, there is very few parameters that one must enter. The required parameters are:

Toolpack will automatically select an available channel in the specified NAP to make the call leg. Only NAPs of type SS7, ISDN or SIP can be specified for call leg attribute (see NAP Types).

The following code snippet shows how to build the attributes.

 PTRCTBCMC_CALL_LEG_ATTRIBUTE ptrOutgoingLegAttribute;

 ptrOutgoingLegAttribute = tbnew CTBCMC_CALL_LEG_ATTRIBUTE();

 ptrOutgoingLegAttribute->GetCalledNumber()            = "123-4567";
 ptrOutgoingLegAttribute->GetCallingNumber()           = "987-6543";
 ptrOutgoingLegAttribute->GetNetworkAccessPoint()      = "NAP_SS7_MONTREAL";

Media-only Leg Attributes

For media-only legs, no signaling information is needed but the user can specify which media channel to use and which media profile to use. The only required parameters are the Network Access Point and the leg type. Only NAPs of type MEDIA TDM or MEDIA VOIP can be specified for media-only leg attribute (see NAP Types).

 PTBCMC_MEDIA_DESCRIPTION           pMediaDesc;
 PTRCTBCMC_MEDIA_ONLY_LEG_ATTRIBUTE ptrLegAttribute;

 ptrLegAttribute = tbnew CTBCMC_MEDIA_ONLY_LEG_ATTRIBUTE();
 pMediaDesc      = ptrLegAttribute->GetProfile().GetMediaDescription();
 
 ptrLegAttribute->GetNetworkAccessPoint()      = "NAP_MEDIA_1"; 
 pMediaDesc->Type                              = TBCMC_MEDIA_TYPE_AUDIO;
 pMediaDesc->Transport                         = TBCMC_MEDIA_TRANSPORT_TDM or TBCMC_MEDIA_TRANSPORT_IP;

When only the NAP and type are specified, Toolpack will automatically select an available channel in the specified NAP to allocate the media path. For MEDIA TDM NAPs, a trunk/timeslot from the specified NAP will be chosen by Toolpack. For MEDIA VOIP NAPs, an IP interface and port from the specified NAP will be chosen.

If the user wants to specify which media channel to use, it can do so by adding extra information in the leg attribute. For TDM legs, a trunk name and a timeslot number can be specified.

 PTBCMC_MEDIA_DESCRIPTION pMediaDesc;

 pMediaDesc->Settings.TdmAudio.Type            = TBCMC_MEDIA_SETTINGS_TYPE_TDM_AUDIO;
 pMediaDesc->Settings.TdmAudio.un8Timeslot     = 5;
 Strncpy
 (
     pMediaDesc->Settings.TdmAudio.szTrunkName,
     "TRUNK_TORONTO_1",
     sizeof(pMediaDesc->Settings.TdmAudio.szTrunkName)
 );

For VOIP legs, the user can control the media by providing local SDP and peer SDP. Setting the local SDP defines the codec and IP/port used to for the received media stream. Most of the time, the IP address and port should be left empty to let Toolpack choose an available port. Setting the peer SDP defines the codec and IP/port used for the transmitted media stream. Note that Toolpack only allows for the same codec to be used in RX and TX. If both local SDP and peer SDP are specified, codecs that are not in both SDP will be filtered out.

For details on how to fill the TBX_SDP_INFO structure needed for SetLocalSDP and SetPeerSDP, see Filling an SDP Structures.

 TBX_RESULT               Result;
 TBX_SDP_INFO             SdpInfo;
 PTBCMC_MEDIA_DESCRIPTION pMediaDesc;

 pMediaDesc = ptrLegAttribute->GetProfile().GetMediaDescription();
 pMediaDesc->Settings.PacketAudio.Type         = TBCMC_MEDIA_SETTINGS_TYPE_PACKET_AUDIO;

 // Set Local SDP
 Result = BuildSdpInfo("", 0, SdpInfo);                 // No IP specified, Toolpack will choose one
 TBCAF_EXIT_ON_ERROR( Result, "BuildSdpInfo failed." );
 ptrLegAttribute->GetProfile().SetLocalSDP(SdpInfo);

 // Set Peer SDP
 Result = BuildSdpInfo("10.0.0.15", 5000, SdpInfo);     // Using peer IP address and port
 TBCAF_EXIT_ON_ERROR( Result, "BuildSdpInfo failed." );
 ptrLegAttribute->GetProfile().SetPeerSDP(SdpInfo);

Creating the Leg

Once the leg attributes have been filled, creating the leg in Toolpack is only a matter of creating a CTBCMCLeg object and calling CreateCall() on it. No action is taken when an instance of a CTBCMCLeg is created. Call resources are only allocated in the Toolpack system when CreateCall() is called on the object.

 pCallLeg = new CTBCMCLeg( mun32LegId++, ptrLegAttribute, this, 0, &mLegMutex );
 pCallLeg->CreateCall();

For legs with signaling, the CreateCall() will trigger the sending of the call setup message (SIP Invite, SS7 IAM, etc.). In that case, the media resources are not allocated immediately. They will be allocated only when the signaling part of the call setup is complete. If the application requests a media action (PlayFile, StartDigitCollection, etc.) on the leg, this will immediately trigger the allocation of the media resources even if the call is not yet answered (used for early media for example).

Call flow for creation of leg with signaling


For media-only legs, the media ressources will always be allocated as soon as CreateCall() is called.

Call flow for media-only leg creation


Once a call is fully active (call answered and media allocated), event OnProfileChanged() will be sent on the leg. In the cases where the user had not specified the IP/port to use, once this event is received, the media profile has been updated with the values chosen by Toolpack and the updated values can be retrieved using the functions GetLocalSDP() and GetPeerSDP() of the profile. Note that the OnProfileChanged() event is also sent after the media profile has been modified with the ChangeProfile() function (see Modifying Media Profile) and when a connected peer has requested it (through a SIP re-INVITE for example).


See Leg creation example for sample code of leg creation in different scenarios.

Caveats

  • The call leg attribute is an object containing the call leg information (called/calling numbers, media profile, etc) that needs to be allocated by the caller and used when creating the leg object. It will be freed automatically when the leg is destroyed (it uses a shared-pointer so it is in fact destroyed when there are no more reference to it).


Interaction with Legs

Playing and Collecting Digits

You can add tones you want to play by using AddToneString() available in CTBCMC_EVENT_ATTRIBUTE class. You can then play digits defined by calling PlayDigit() on a leg. Toolpack will receive the request and play the digits. Once digits are played, the leg will receive OnDigitPlayingDone() event.

You can also configure a leg to collect digits played. To start the digit collection, you have to call StartDigitCollection() on the leg. Note that you will have to specify which digits you want to collect before starting the digit collection by calling AddToneString() on a CTBCMC_EVENT_ATTRIBUTE object. To stop the digit collection, you have to call StopDigitCollection(). A leg will receive OnDigitCollected() event on each digit received that was specified with the previously call to AddToneString().

Playing and Collecting Tones

You can play an event on a leg by calling PlayEvent() on it. Toolpack will receive the request and play the event. Once the event is played, the leg will receive OnEventPlayingDone() event. Note that you can cancel an event to be played by calling CancelEvent() on the leg after a PlayEvent() has been called.

You can also configure a leg to collect events played. To start the event collection, you have to call StartEventCollection() on the leg. Note that you will have to specify which events you want to collect before starting the event collection. To stop the event collection, you have to call StopEventCollection(). A leg will receive OnEventCollected() event on each event received that was specified when the call to StartEventCollection() was made.

Playing and Recording Audio Files

You can play an audio stream on a leg by calling PlayStream() on it. Toolpack will receive the request and play the stream. Once it is played, the leg will receive OnStreamPlayingDone() event.

You can also configure a leg to record an audio stream by calling RecordStream(). Once the stream is recorded, the leg will receive OnStreamRecordingDone() event.

You can pause an active playing or recording stream by calling PauseStream() and you can resume it by calling ResumeStream(). If you want to stop an active playing or recording stream, you have to call StopStream() on the leg.

Modifying Media Profile

It is always possible to modify the media profile of a leg after it was created. This can be used for example to change to a more compressed codec if bandwidth resources become sparse or to switch to T.38 Fax after a fax tone was detected.

The media profile is stored in the leg attributes and can be modified like this :

 TBX_SDP_INFO                        SdpInfo;
 PCTBCMC_MEDIA_ONLY_LEG_ATTRIBUTE    pMediaLegAttribute;
 
 pMediaLegAttribute = pCallLeg->GetAttributes().GetMediaOnlyLegAttribute();
 pMediaLegAttribute->GetProfile().GetLocalSDP(SdpInfo);
 Strncpy
 (
     SdpInfo.aConnections[0].szIp,
     "",
     sizeof( SdpInfo.aConnections[0].szIp )
 );
 SdpInfo.Capabilities.aCapGroups[0].aSimultaneousCap[0].un16UdpPort = 0;
 pMediaLegAttribute->GetProfile().SetLocalSDP(SdpInfo);
 
 pCallLeg->ChangeProfile();

Once the attributes have been modified, ChangeProfile() must be called to activate the new profile. In the case of media-only legs, activating a modified profile will immediately reallocate the media resources. In the case of a SIP call leg, activating the new profile will trigger a new negotiation with the peer (INVITE-RESPONSE) after which the media resources will be allocated using the newly negotiated codecs.

Once the profile change has completed (or failed), event OnProfileChanged() will be received on the leg.

For SIP call leg, if the peer entity sends us re-INVITE with a new SDP during a call, the media resource will be automatically updated and event OnProfileChanged() will be received on the leg.

Controlling the Signaling

When a call leg receives the OnCallLegPresent() event, it indicates an incoming call. To confirm that the call contains sufficient valid information to process the call on the system, you have to call AcceptCall() on the leg. If a call leg receives the OnCallAccepted() event, it means that an outgoing call has been accepted by the remote peer. This event usually means that the calling number has been accepted and that the call is currently being processed.

After an incoming call has been accepted, a call leg can notify the remote peer that the incoming call has been put in the "ringing" state by calling AlertCall(). In the same way, a call leg will receive OnCallAlerting() event when an outgoing call has been put in the "ringing" state by the remote peer.

When an incoming call is answered, a call leg can notify the remote peer of the incoming call answered by calling AnswerCall(). In the same way, a call leg will receive OnCallAnswered() event when an outgoing call has been answered by the remote peer.

SendCallSuppInfo/OnCallSuppInfo

Leg Termination

Terminating a call leg is a 2 steps process:

  1. Call TerminateCall()
  2. Free leg object on OnCallTerminated()

When TerminateCall() is called, the Toolpack framework will start leg termination. This includes media resources freeing and, for leg with signaling, sending of the appropriate signaling message to terminate the call. Once the media resources have been deallocated and call termination signaling is done, Toolpack will call OnCallTerminated() on the leg. When this event is received on the leg, this leg no more exists in Toolpack and the object can thus be freed. At the end of the OnCallTerminated() handler, the default implementation of class CTBCMCLeg will call method Free() on the leg's ITBCMCFreeListener interface. The ITBCMCFreeListener to use can be specified either in the CTBCMCLeg constructor and by calling SetFreeListener() on the leg. The leg can be it's own FreeListener, in which it just 'delete' itself when its Free() method is called. An application specific FreeListener can be used for cases where other action needs to be taken before the leg is deleted. An example could be the case where the leg object was allocated from a pool and it should be returned to that pool instead of being deleted.

Call flow for leg termination initiated by user application


In some situation, it is possible that leg termination be initiated by Toolpack. This can happen for leg with signaling, when a call termination request is received on the signaling channel. It can also happen on any type of leg in the event of sudden media resource unavailability and other media resource or signaling error. In these cases, the OnCallTerminatingIndication() is sent to the leg. On reception of this event, the application should initiate call termination as shown below.

Call flow for leg termination initiated by Toolpack


In case of internal system error or major communication lost with the Toolpack engine, Toolpack would send the OnLegTerminated() event. This event indicates that the leg does not exist anymore on the Toolpack side and the user should free its object without trying any other interaction with Toolpack through it.

Leg Synchronization on Failover

When a Toolpack application is restarted or when a standby application is activated, it goes through a synchronization phase with the Toolpack framework. During this phase, Toolpack informs the application of all the already allocated call legs through the OnCallLegSync() event of the ITBCMCLibUser interface (this interface must be implemented by all user applications). One event will be received for each leg being synchronized. The course of action to take when receiving a leg synchronization event depends on the ability of the application to resynchronize its states with theses legs.

  • If the application can't resynchronize active legs or if it does not want to resychronize the leg for which it is receiving an OnCallLegSync() event, it must refuse the leg by calling the static function RefuseLeg().
  • If the application wants the resynchronize the leg or if it does not yet have enough information to decide, it must create a CTBCMCLeg object using the leg attributes received in the event.

Once all OnCallLegSync() have been sent, Toolpack will start synchronization of the links between legs through OnLinkSync(). This event indicates that two legs are connected together. It can be used by the application to rebuild its internal states. As for the legs, unwanted links can be refused by calling the static function RefuseLink().

When all links have been synchronized, Toolpack sends the OnCmcLibReady() event indicating that active resources synchronization is complete. At that moment, the application has all the information available on the Toolpack side to determine if the legs should be kept or release. Any leg that the application does not want to keep can be refused by calling RefuseLeg() on it. For all legs that have not been refused, an event OnSyncDone() will be sent on the leg. Once this event has been received on a leg, the leg is fully functional and the application can start calling any usual Toolpack function on it.

Call flow for leg synchronization


Loss of Communication with Toolpack Engine

If communication is lost with the Toolpack Engine, event OnCmcLibNotReady() will be sent to the application. It indicates that the Toolpack framework is no more accessible. The legs are still valid at that time but no action can be executed on them as long the CmcLib is not ready. If the connection with the Toolpack Engine is not back up in less than 10 seconds, the CmcLib will declare a major communication loss and will call OnLegTerminated() on all the legs. In that case, when communication is regained with the Toolpack Engine, the synchronization sequence will start again from the beginning.

Call flow for leg synchronization after a communication restart passed 10 seconds.


If the communication is regained before the 10 seconds timeout, event OnCmcLibReady() will be sent and the application can then continue working normally with its existing call legs. Note that you can also receive OnLegTerminated() on some legs before receiving the OnCmcLibReady() if those legs were in a transient state when disconnection occurred.

Call flow for leg synchronization after a communication restart within 10 seconds.
Personal tools