因为是实例程序, 能简化的地方都简化了 , 比如 被叫号码和走哪个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 IN CTBCMC_PROTOCOL_ATTRIBUTE & in_ProtocolAttribute // In legProtocolAttribute ) { 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; //多出的这个是做什么的 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 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\n" ); // 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) pBridge = tbnew CTBCAFBridge( un32AccountId, 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 */ // 将 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 \ref CTBCAFBridge. // Add the incoming leg by calling \ref AddIncoming. // Add the outgoing leg by calling \ref AddOutgoing. // Initialize the call by calling \ref 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."); 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 ) }
时间: 2024-10-12 08:27:06