最初版本的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
  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

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

Entity Framework 6:专家版本

随着 Entity Framework 最新主版本 EF6 的推出,Microsoft 对象关系映射 (ORM) 工具达到了新的专业高度,与久负盛名的 .NET ORM 工具相比已不再是门外汉. EF 已经完全成熟,正在超越以前广泛使用的工具. Entity Framework 已经度过了青涩期,它最初只是供数据库开发者使用的工具,后来在 .NET 社区的敏捷开发者中间引起轰动. 它学会了如何摆脱应用程序开发模式,转向了普通旧 CLR 对象 (POCO) 模型,支持以测试和域为中心的软件开发,同

普元部署多个应用的方法(适用EOS6.5以上版本,且无需governor中添加应用)

在EOS下跑default项目之外的另外一个项目,比如defaultNew 步骤1 安装EOS6.5,安装路径如下:E:\program\eos: 启动EOS Eos默认的应用名称为Default 步骤2 把tomcat\webapps下的default工程进行拷贝,注意此default文件夹下内容必须是最初版本: 把default改为defaultNew,拷贝至tomcat\webapps下. 步骤3 在E:\program\eos\apps_config目录下,拷贝default文件夹,改名

VS 引用dll版本冲突问题

1.删除项目中的对应引用: 2.如果是有用到NetGet引用的删除项目中的packages里面的对应包文件: 3.如果是在NetGet中引用的注释项目中packages.config对应的插件名: 4.在Web.config里面可以控制对应的版本 此处以Newtonsoft.Json为例, <runtime> <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"> <dependentAssem

图的所有简单算法实现

包括邻接链表.有向无向图.带权图.增删顶点和边.查找.连通.DFS和BFS等.这只是一个最初版本,有些复杂的算法还没有实现. package structure; //图的邻接链表的节点 public class GraphListNode { private int vertex;//图的顶点 private int weight;//边的权重 private boolean visited;//是否访问过 //带权重图的节点 public GraphListNode(int vertex,i

全方位解读及介绍windows网络安全及常见攻击方式

本来我就是来逛逛论坛的,可是看到前面有位一样是干网络安全的同行,留下来过的痕迹,发了一篇相对不错的文章,我寻思咱既然来这一趟,也不能显得就比别人差啊.所以我也就写了这一片不算成熟小文章,望各位共勉之哈.1.网络安全的概念网络安全的定义:网络系统的硬件.软件和数据受到保护,不因偶然和恶意的原因而遭到破坏.更改和泄露,系统可以连续正常运行,网络服务不会终止. 1>.网络安全主要涉及3个方面: 硬件安全:即要保证网络设备的安全,如网络中的服务器.交换机.路由器等设备的安全. 软件和数据安全:即保证网络

苹果ipa软件包破解笔记

苹果的验证机制: Appstore上的应用都采用了DRM(digital rights management)数字版权加密保护技术,直接的表现是A帐号购买的app,除A外的帐号无法使用,其实就是有了数字签名验证,而app的破解过程,实质也是去除数字签名的过程.去除过程包括两部分,如下所示: ipa文件都是使用苹果公司的FairPlay DRM技术进行加密保护 appsync没有装是不能安装的,程序没有破解是不能运行的 条件一,设备越狱,获得root权限,去除掉设备上的签名检查,允许没有合法签名的

软件工程过程 第2章 软件开发的主要活动

1.需求工程.P13 需求是任何软件开发项目的基础. 好的需求是项目成功开发的必要条件. 需求分析工作可划分为两个阶段:需求开发和需求管理.需求开发就是传统意义上的需求分析. 2.需求开发(需求分析)的目标.P13 与客户和其他涉众在系统的工作内容方面达成并保持一致. 使系统开发人员能够更清楚地了解系统需求,定义系统边界: 为软件实施计划提供基础: 为估算开发系统所需成本和时间提供基础: 定义系统用户的需求和目标. 3.需求开发阶段包括需求获取.需求分析.规格化说明和需求验证4个活动:需求管理包

前端学PHP之正则表达式基础语法

前面的话 正则表达式是用于描述字符排列和匹配模式的一种语法规则.它主要用于字符串的模式分割.匹配.查找及替换操作.在PHP中,正则表达式一般是由正规字符和一些特殊字符(类似于通配符)联合构成的一个文本模式的程序性描述.正则表达式有三个作用:1.匹配,也常常用于从字符串中析取信息:2.用新文本代替匹配文本:3.将一个字符串拆分为一组更小的信息块.本文将详细介绍PHP中的正则表达式基础语法 [注意]关于javascript的正则表达式的详细信息移步至此 历史 在PHP中有两套正则表达式函数库,两者功

android 练习之路 (六)

项目的github地址:https://github.com/Qunter/SearchAndCall ------------------------------------------------------------------------ 今天做详情页以及列表的刷新,今天做完之后算暂时把最初版本的学校资讯给做完了 惯例,先上效果图 PS:那个??的图片是因为我们学校有个校领导叫X??X的名字,结果维护官网的同学可能是图简单就直接切了个图丢进去,命名又没命名好,我想了一两个小时都没想出来