> For the complete documentation index, see [llms.txt](https://prosbcdocs.telcobridges.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://prosbcdocs.telcobridges.com/telecom-references/other-pages/caf-leg-creation-samples.md).

# CAF: Leg Creation Samples

### Creating a Standalone Outgoing Call Leg

```
PTRCTBCMC_CALL_LEG_ATTRIBUTE ptrOutgoingLegAttribute;
ptrOutgoingLegAttribute = tbnew CTBCMC_CALL_LEG_ATTRIBUTE();

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

PCTBCMCLeg pCallLeg = tbnew CTBCMCLeg( ++mun32LegId, ptrOutgoingLegAttribute, this, 0, &mLegMutex );
pCallLeg->CreateCall();
```

### Bridging an Incoming Call Leg (using CTBCAFBridge )

```
TBX_VOID CTBS2GWSimpleCall::OnCallLegPresent
(
IN	TBCMC_LEG_ID						in_LegId,
IN	CTBCMC_CALL_LEG_ATTRIBUTE_COMMON &	in_CallLegAttribute,
IN	CTBCMC_PROTOCOL_ATTRIBUTE &			in_ProtocolAttribute
)
{
TBX_RESULT								Result;
PITBCAFCallFlow			 				pBridge;
PTRCTBCMC_CALL_LEG_ATTRIBUTE			ptrIncomingLegAttribute;
PTRCTBCMC_PROTOCOL_ATTRIBUTE			ptrIncomingLegProtocolAttributes;
PTRCTBCMC_PROTOCOL_ATTRIBUTE			ptrAcceptCallProtAttribute;
PTRCTBCMC_CALL_LEG_ATTRIBUTE			ptrOutgoingLegAttribute;
PTRCTBCMC_PROTOCOL_ATTRIBUTE			ptrOutgoingLegProtocolAttributes;

/*---------------------------------------------------------------------------------------------------------------------------
|  Code section
```

* \--------------------------------------------------------------------------------------------------------------------------\*/ CAFCODE( CTBS2GWSimpleCall::OnCallLegPresent ) { // Create smart pointers to incoming call leg attributes so behaviors can keep reference to it if needed ptrIncomingLegAttribute = tbnew CTBCMC\_CALL\_LEG\_ATTRIBUTE( \*(in\_CallLegAttribute.GetCallLegAttribute()) ); ptrIncomingLegProtocolAttributes = tbnew CTBCMC\_PROTOCOL\_ATTRIBUTE( in\_ProtocolAttribute, TBX\_TRUE );

  // Build default protocol attributes object so behaviors can modify // attributes used to Accept the incoming call leg ptrAcceptCallProtAttribute = tbnew CTBCMC\_PROTOCOL\_ATTRIBUTE();

  // Build default protocol attributes object so behaviors can modify // attributes used to create the outgoing call leg ptrOutgoingLegProtocolAttributes = tbnew CTBCMC\_PROTOCOL\_ATTRIBUTE();

  // Create an empty outgoing call leg attribute object ptrOutgoingLegAttribute = tbnew CTBCMC\_CALL\_LEG\_ATTRIBUTE();

  // Fill some information in the outgoing call leg attributes from the incoming leg attributes // \*\*\* Warning: Don't use operator=. We dont wan't to copy EVERYTHING, but only information // common to both incoming and outgoing legs, such as calling/called number. // Function CopyLegAttributeFrom() takes care of copying relevant information. ptrOutgoingLegAttribute->CopyLegAttributeFrom( \*(ptrIncomingLegAttribute.Get()) );

  // Create the call (i.e. which contains 2 call legs) pBridge = tbnew CTBCAFBridge( 0, this ); TBCAF\_EXIT\_ON\_NULL( pBridge, TBX\_RESULT\_FAIL, "Failed to allocate call." );

  /\* Prepare the chain of behaviors \*/ PITBCAFCallFlow pPreviousBehavior = pBridge;

  /\* Add the example behavior to the chain of behaviors \*/ pPreviousBehavior = tbnew CTBS2GWCallBehaviorExample( pPreviousBehavior );

  // Add legs information Result = pBridge->AddIncoming( in\_LegId, ptrIncomingLegAttribute, ptrIncomingLegProtocolAttributes, ptrAcceptCallProtAttribute ); TBCAF\_EXIT\_ON\_ERROR(Result, "AddIncoming Failed." );

  // Provide an uninitialized PTRCTBCMC\_PROTOCOL\_ATTRIBUTE Result = pBridge->AddOutgoing( ptrOutgoingLegAttribute, ptrOutgoingLegProtocolAttributes ); TBCAF\_EXIT\_ON\_ERROR(Result, "AddOutgoing Failed." );

  Result = pBridge->InitCall( \&pBridge ); if( pBridge == NULL ) { /\* Note: If this return value is NULL, this means the InitCall function has initialized no call leg's state machine (failed to) and destroyed itself immediately (it normally destroys itself later when the state machine of all call legs has terminated). The above line of code shall thus be the last of the function to avoid accessing any member of "this" here. \*/ TBX\_EXIT\_CLEANUP( Result ); } TBCAF\_EXIT\_ON\_ERROR(Result, "InitCall Failed." );

  TBX\_EXIT\_SUCCESS( TBX\_RESULT\_OK ); }

  /\*--------------------------------------------------------------------------------------------------------------------------- | Exception handling section
* \--------------------------------------------------------------------------------------------------------------------------\*/ CAF\_EXCEPTION\_HANDLING

  /\*--------------------------------------------------------------------------------------------------------------------------- | Error handling section
* \--------------------------------------------------------------------------------------------------------------------------\*/ CAF\_ERROR\_HANDLING( CAF\_VERBOSE ) { if( pBridge == NULL ) { // Try to refuse the call leg CTBCMCLeg::RefuseLeg( in\_LegId, in\_CallLegAttribute ); } }

  /\*--------------------------------------------------------------------------------------------------------------------------- | Cleanup section
* \--------------------------------------------------------------------------------------------------------------------------\*/ CAF\_CLEANUP { }

  RETURN\_VOID; }

InitCall() will create each leg added from AddIncoming() and AddOutgoing() and incoming and outgoing call leg will be joined when we receive the notification OnCallLegAnswered() indicating that the outgoing call has been answered by the remote peer.

### Pitfall

It is mandatory that the call leg and protocol attribute objects passed to AddIncoming() and AddOutgoing() remain valid until function InitCall() returns.

### Creating a Media-only Leg

#### If you are using a nap of type NAP\_MEDIA\_TDM:

```
PTRCTBCMC_MEDIA_ONLY_LEG_ATTRIBUTE ptrLegAttribute;
PTBCMC_MEDIA_DESCRIPTION           pMediaDesc;

ptrLegAttribute = tbnew CTBCMC_MEDIA_ONLY_LEG_ATTRIBUTE();
pMediaDesc	  = &ptrLegAttribute->GetProfile().GetMediaDescription();

ptrLegAttribute->GetNetworkAccessPoint()      = "NAP_MEDIA_TDM";
pMediaDesc->Type                              = TBCMC_MEDIA_TYPE_AUDIO;
pMediaDesc->Transport                         = TBCMC_MEDIA_TRANSPORT_TDM;
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)
);

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

#### If you are using a nap of type NAP\_MEDIA\_VOIP:

```
TBX_RESULT                         Result;
TBX_SDP_INFO                       SdpInfo;
PTRCTBCMC_MEDIA_ONLY_LEG_ATTRIBUTE ptrLegAttribute;
PTBCMC_MEDIA_DESCRIPTION           pMediaDesc;

ptrLegAttribute = tbnew CTBCMC_MEDIA_ONLY_LEG_ATTRIBUTE();
pMediaDesc	   = &ptrLegAttribute->GetProfile().GetMediaDescription();

ptrLegAttribute->GetNetworkAccessPoint()      = "NAP_MEDIA_VOIP";
pMediaDesc->Type                              = TBCMC_MEDIA_TYPE_AUDIO;
pMediaDesc->Transport                         = TBCMC_MEDIA_TRANSPORT_IP;
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);

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

Note that you have two possibilities to build a TBX\_SDP\_INFO structure. The first one is like in the example (BuildSdpInfo()) where you can build manually your TBX\_SDP\_INFO structure and the second one is when you have an sdp info in text format. There is a function that will parse the text and build a TBX\_SDP\_INFO structure from it.

```
TBXMediaLibSdpParse
(
IN    PTBX_CHAR                        in_pszSdp,
OUT   PTBX_SDP_INFO                    out_pSdpInfo,
IN    TBX_MEDIA_SDP_PARSE_OPTIONS      in_Options
);
```

To see how to build a TBX\_SDP\_INFO structure, refer to [Filling an SDP Structure](https://github.com/telcobridges-main/tmedia-wiki/tree/main/reference/sip-voip/caf-filling-sdp-structures/README.md).


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://prosbcdocs.telcobridges.com/telecom-references/other-pages/caf-leg-creation-samples.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
