最初版本的simplecall是如何把2个callleg连起来的

因为是实例程序, 能简化的地方都简化了 , 比如 被叫号码和走哪个NAP 就是直接一一对应的 ,先定义这样一个结构 :

typedef struct _TBS2GWSIMPLECALL_ROUTE
{
    TBX_CHAR                        szCalledNumber[TBCMC_STRING_LEN];
    TBX_CHAR                        szNap[TBCMC_STRING_LEN];

} TBS2GWSIMPLECALL_ROUTE, *PTBS2GWSIMPLECALL_ROUTE;


然后在 private 变量里 定义 :

private : 

 TBS2GWSIMPLECALL_ROUTE    maRoutes[TBS2GW_SIMPLE_CALL_MAX_ROUTES];


在构造函数中 :

        strcpy( maRoutes[0].szCalledNumber    , "87654321" );
        strcpy( maRoutes[0].szNap            , "NAP_SS7"    );

        strcpy( maRoutes[1].szCalledNumber    , "12345678" );
        strcpy( maRoutes[1].szNap            , "SIP1"    );

        strcpy( maRoutes[2].szCalledNumber    , "5550002"    );
        strcpy( maRoutes[2].szNap            , "sip_proxy_1");

至此为止 , 被叫号码和NAP得到一一对应。

--------------------------------------------------------------------------------------------------------------------------------

因为 CSimpleCall继承自 CTBCMCLibUser

typedef class CTBS2GWSimpleCall *PCTBS2GWSimpleCall;
class CTBS2GWSimpleCall
 : public CTBCMCLibUser
 , public ITBCAFServiceAlmMgmtClient            /* ALM (application launch management) client (being launched, shutdown, monitored by Toolpack OAM application) */
 , public ITBCAFServiceCmMgmtClient                /* CM (Configuration management) client (being notified when Toolpack configuration is reloaded) */
 , public ITBCMCFreeListener<CTBCMCLeg>            /* CTBCMCLeg free listener (we are responsible to free memory for terminated call legs) */
 , public ITBCMCFreeListener<ITBCAFCallFlow>    /* CTBCMCLeg free listener (we are responsible to free memory for terminated call flows) */


所以能接收到callleg  MSG , 比如 calllegPresent

重点分析 onCallLegPresent 代码

TBX_VOID CTBS2GWSimpleCall::OnCallLegPresent
(
  IN    TBCMC_LEG_ID                        in_LegId,       //进来的legID
  IN    CTBCMC_CALL_LEG_ATTRIBUTE_COMMON &    in_CallLegAttribute,     // In legAttribute IncomingCallLeg的attribute
  IN    CTBCMC_PROTOCOL_ATTRIBUTE &            in_ProtocolAttribute    // In legProtocolAttribute  IncomingCallLeg的 protocol attribute
)
{
TBCAF_MUTEX_GET_SCOPE_BEGIN( &mMutex )
    TBX_RESULT                                Result;
    PITBCAFCallFlow                             pBridge;    // 预示将使用 CBridge 这个 callFlow
PTRCTBCMC_CALL_LEG_ATTRIBUTE ptrIncomingLegAttribute; PTRCTBCMC_PROTOCOL_ATTRIBUTE ptrIncomingLegProtocolAttributes;

    PTRCTBCMC_CALL_LEG_ATTRIBUTE            ptrOutgoingLegAttribute;
    PTRCTBCMC_PROTOCOL_ATTRIBUTE            ptrOutgoingLegProtocolAttributes;
PTRCTBCMC_PROTOCOL_ATTRIBUTE ptrAcceptCallProtAttribute; //多出的这个是做什么的

  //***** ptrAcceptCallProtAttribute 的用途

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

*****//

TBX_UINT32 un32AccountIndex; TBX_UINT32 un32AccountId; TBX_UINT32 un32RouteIndex; CTBCMC_PLAY_ATTRIBUTE PlayAttr;
/*--------------------------------------------------------------------------------------------------------------------------- | Code section *--------------------------------------------------------------------------------------------------------------------------*/ CAFCODE( CTBS2GWSimpleCall::OnCallLegPresent ) { pBridge = NULL; LogTrace( TBCAF_TRACE_LEVEL_1, "CTBS2GWSimpleCall::OnCallLegPresent: Leg 0x%08x", in_LegId ); LogTrace(TBCAF_TRACE_LEVEL_3, FYELLOW"simplecall oncalllegpresent"); if( !IsReady() ) { TBCAF_EXIT_ON_ERROR(TBX_RESULT_INVALID_STATE, "CMC library is not ready." ); } /* Sanity checks */ TBCAF_EXIT_ON_FALSE ( in_CallLegAttribute.GetLegType() == TBCMC_LEG_TYPE_CALL, TBX_RESULT_NOT_SUPPORTED, "This class only supports legs of type TBCMC_LEG_TYPE_CALL" ); TBCAF_EXIT_ON_NULL( in_CallLegAttribute.GetCallLegAttribute(), TBX_RESULT_NOT_SUPPORTED, "Can't get pointer to call leg attributes" ); // 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(); // Get the account for the call un32AccountId = 0; for( un32AccountIndex=0; un32AccountIndex < TBS2GW_SIMPLE_CALL_MAX_ACCOUNTS; un32AccountIndex++ ) { // If we found the account CTBCAFString 可以直接和 TCHAR 比较吗 if( ptrIncomingLegAttribute->GetCalledNumber() == maAccount[un32AccountIndex].szCalledNumber ) { un32AccountId = maAccount[un32AccountIndex].un32AccountId; break; } } if( un32AccountId == 0 ) { TBCAF_EXIT_ON_ERROR(TBX_RESULT_NOT_FOUND, "Account not found." ); } // 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.
     // CopyLegAttributeFrom 是在 tbCMC.cpp文件里实现, 但是 ptrOutgoingLegAttribute 为什么能调用这个函数???
ptrOutgoingLegAttribute->CopyLegAttributeFrom( *(ptrIncomingLegAttribute.Get()) ); // Change the NAP of the outgoing call leg attribute from the routing information // -> First find the route for the call for( un32RouteIndex=0; un32RouteIndex < TBS2GW_SIMPLE_CALL_MAX_ROUTES; un32RouteIndex++ ) { // If we found the route if( ptrIncomingLegAttribute->GetCalledNumber() == maRoutes[un32RouteIndex].szCalledNumber ) { // Set the NAP ptrOutgoingLegAttribute->GetNetworkAccessPoint() = maRoutes[un32RouteIndex].szNap; break; } } if( un32RouteIndex == TBS2GW_SIMPLE_CALL_MAX_ROUTES ) { TBCAF_EXIT_ON_ERROR(TBX_RESULT_NOT_FOUND, "Route not found." ); } // Validate the availability of the chosen NAP (by consulting NAP Stats for that outgoing NAP) if( !TestNapAvailable( ptrOutgoingLegAttribute->GetNetworkAccessPoint() ) ) { TBCAF_EXIT_ON_ERROR(TBX_RESULT_NOT_READY, ptrOutgoingLegAttribute->GetNetworkAccessPoint().c_str()); //TBCAF_EXIT_ON_ERROR(TBX_RESULT_NOT_READY, "Outgoing NAP is not actually available." ); } //PlayAttr.AddPlayFilePath( "file://prompts/demo/music0.wav" ); //PlayAttr.GetPtr()->un32RepeatCount = 10000; //PlayAttr.GetPtr()->fNotifyStartOfNewFile = TBX_TRUE; //if( ptrIncomingLegAttribute ) //{ // LogTrace( TBCAF_TRACE_LEVEL_3, "debugAlain:PlayStream " ); // ptrIncomingLegAttribute->PlayStream( PlayAttr ); //} LogTrace(TBCAF_TRACE_LEVEL_2, FYELLOW"ready to bridge");
     //凡是继承自 CTBCAFCallFlow 的 都可以视作一个behavior, 下面几行代码的意思是 :
     //bridge是第一个behavior , CTBS2GWCallBehaviorExample 是第二个
// Create the call (i.e. which contains 2 call legs)    pCallFlow = tbnew CTBCAFBridge(this );

// 因为 SIMPLEcALL继承自 public ITBCMCFreeListener<ITBCAFCallFlow>


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 */
     // 将 bridge 和 behavior 分开是想减少功能的耦合, gateway的只管gateway , behavior 只管 behavior
LogTrace(TBCAF_TRACE_LEVEL_2, FYELLOW"will attach a behavior"); pPreviousBehavior = tbnew CTBS2GWCallBehaviorExample( pPreviousBehavior ); #ifdef SET_SS7_IE { // Add a behavior to the call pPreviousBehavior = tbnew CTBS2GWCallBehaviorSS7IE ( pPreviousBehavior, 0x0d, // Test category ptrOutgoingLegAttribute->GetPtr()->szCallingNumber, ptrOutgoingLegAttribute->GetPtr()->szCalledNumber, 0x01, // Subscriber number 0x00, 0x00 ); } #endif
     //以下代码真正将 incoingLeg 和 outgoingLeg连在一起

//To create a new call one must:
// Create the call with the account id by calling ef CTBCAFBridge.
// Add the incoming leg by calling ef AddIncoming.
// Add the outgoing leg by calling ef AddOutgoing.
// Initialize the call by calling ef InitCall.

// Add legs information Result = pBridge->AddIncoming( in_LegId, ptrIncomingLegAttribute, ptrIncomingLegProtocolAttributes, ptrAcceptCallProtAttribute ); TBCAF_EXIT_ON_ERROR(Result, "AddIncoming Failed." ); LogTrace(TBCAF_TRACE_LEVEL_2, FYELLOW"AddIncoming success."); // Provide an uninitialized PTRCTBCMC_PROTOCOL_ATTRIBUTE Result = pBridge->AddOutgoing( ptrOutgoingLegAttribute, ptrOutgoingLegProtocolAttributes ); TBCAF_EXIT_ON_ERROR(Result, "AddOutgoing Failed." ); LogTrace(TBCAF_TRACE_LEVEL_2, FYELLOW"AddOutgoing success.");

     //以上几句需要特别注意的是: bridge并未重载 AddIncoming,AddOutgoing 函数, 所以实际调用的还是 CTBCAFCallFlow
      的这两个函数 , 这也意味着  AddIncoming,AddOutgoing 两个函数并不起到 join的作用, join的发生是在 Bnum接起电话
      之后 , 也就是说 , bridge类真正有价值的部分在 OnCallLegAlertingOnCallLegAnswered , join 发生在后者 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." ); LogTrace(TBCAF_TRACE_LEVEL_2, FYELLOW"bridge initcall success."); // Allocate new call pointer from our pool of calls { PTRITBCAFCallFlow * pptrCallInPool; pptrCallInPool = mPoolOfCalls.Alloc( TBCAF_DEBUG_INFO, pBridge->GetLinkId() ); TBCAF_EXIT_ON_NULL( pptrCallInPool, TBX_RESULT_FAIL, "Failed to keep call bridge in pool of calls!" ); /* Assign our allocated call to our pool of calls */ *pptrCallInPool = pBridge; } 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; TBCAF_MUTEX_GET_SCOPE_END( &mMutex ) }
原文地址:https://www.cnblogs.com/lthxk-yl/p/4073462.html