[pjsip] 中 define 的妙用

本文解析了预处理宏PJ_LOG的具体用法及其实现原理,详细介绍了如何通过宏定义实现不同级别的日志输出,并展示了实际代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

define 语法

define func funcA
上面的就是简单的替换 func 替换funcA的使用

看下pjsip的用法


// 案例: PJ_LOG(2, (__FILE__, "current value is %d", value));



#define PJ_LOG(level,arg)   do { \
                    if (level <= pj_log_get_level()) { \
                    pj_log_wrapper_##level(arg); \
                    } \
                } while (0)

//上面就是func 替换 funcA 的形式 但是,
//此时 ## 连接符 2 替换level , arg 代表 (__FILE__, "current value is %d", value)
// 所以最后形式 pj_log_wrapper_2(arg)  ,  此时arg 在编译之前不会替换
// ps: \ 还有 ## 是不同使用场景的连接符


#if PJ_LOG_MAX_LEVEL >= 2
    #define pj_log_wrapper_2(arg)   pj_log_2 arg //这里虽然有空格,不符合define 语法,注意下面分析
    /*
    替换结果
    pj_log_wrapper_2(arg)  pj_log_2 (__FILE__, "current value is %d", value)   函数

    不能纠结空格 
    pj_log_2 arg 相当于函数 pj_log_2 (__FILE__, "current value is %d", value)
    有像函数形式一样也有空格

    */


    PJ_DECL(void) pj_log_2(const char *src, const char *format, ...);
    /*
    所以 这里 src 指向 _FILE_ 字符串内容  format 就指向 "current value is %d", value  内容
    */



作者:贱贱的杨
从此你们的路上不会孤单,还有贱贱的我

### 封装 PJSIP 库以实现 VoIP 功能的分析 在开发 VoIP 应用程序时,PJSIP 提供了丰富的功能和灵活性。为了简化使用流程并隐藏底层复杂性,通常需要对 PJSIP 进行封装。这种封装可以通过将 PJSUA2(PJSIP 的高级 API)绑定到后台服务中,从而让开发者专注于高层次的功能实现[^1]。 #### 1. **PJSIP 核心组件概述** PJSIP 是一个包含了 SIP、SDP、RTP、RTCP、STUN 和 ICE 等协议的开源库。其核心是 SIP endpoint,它负责管理所有 SIP 对象,并且作为整个协议栈的核心模块,承担以下职责: - 管理内存池的分配与释放。 - 接收来自传输层的消息,并将其分发给上层模块(如 SIP transaction module、SIP dialog module 或 application module)。 - 允许开发者通过自定义模块截获和处理 SIP 消息[^4]。 #### 2. **封装 PJSIP 的关键步骤** ##### (1) **创建 SIP Endpoint** SIP endpoint 是应用程序的核心,通常每个进程只能创建一个。它是所有 SIP 对象的拥有者,并负责事件的调度和处理。初始化 SIP endpoint 时,需要配置内存池、线程以及事件循环机制。例如: ```cpp // 初始化 SIP endpoint pj_status_t status = pjsua_create(); if (status != PJ_SUCCESS) { // 错误处理 } ``` ##### (2) **封装 SIP 模块与对象** PJSIP 中的模块(module)是一种扩展库的方法,开发者可以定义优先级高于默认模块的自定义模块,用于拦截和处理 SIP 消息。此外,PJSIP 使用内存池进行动态内存管理,因此需要确保对象的生命周期和资源管理合理[^4]。 ##### (3) **多线程与互斥锁** 由于 PJSIP 是一个多线程库,必须正确处理并发访问问题。PJSIP 提供了互斥锁(mutex)的封装,例如 `pj_mutex_create` 和 `pj_mutex_lock`,用于保护共享资源。可以进一步封装这些锁操作,以简化代码逻辑: ```cpp class Sip_Lock { pj_mutex_t *m_mutex; public: Sip_Lock(pj_mutex_t *mutex) { this->m_mutex = mutex; pj_mutex_lock(m_mutex); } ~Sip_Lock() { pj_mutex_unlock(m_mutex); this->m_mutex = NULL; } }; #define SIP_GUARD(MUTEX, OBJ) Sip_Lock OBJ(MUTEX); ``` ##### (4) **绑定 PJSUA2 到 Android 后台服务** 对于 Android 平台,可以将 PJSUA2 绑定到后台服务中,从而实现长时间运行的 VoIP 功能。这样可以避免直接暴露 SIP 协议细节,同时提供简洁的接口供应用层调用。具体实现包括: - 创建 `Service` 类,用于启动和管理 PJSUA2 实例。 - 定义 JNI 接口,用于在 Java 层与 C/C++ 层之间通信。 - 在 Native 层实现 SIP 呼叫、注册、消息处理等功能。 #### 3. **示例:封装 SIP 调用功能** 下面是一个简单的封装示例,展示如何通过 PJSUA2 发起呼叫: ```cpp // 初始化 PJSUA2 pjsua_config cfg; pjsua_logging_config log_cfg; pjsua_init(&cfg, &log_cfg); // 添加账户 pjsua_account_config acc_cfg; acc_cfg.id = pj_str("sip:user@example.com"); acc_cfg.reg_uri = pj_str("sip:example.com"); acc_cfg.cred_count = 1; acc_cfg.cred_info[0].realm = pj_str("example.com"); acc_cfg.cred_info[0].username = pj_str("user"); acc_cfg.cred_info[0].data_type = PJSIP_CRED_DATA_PLAIN_PASSWD; acc_cfg.cred_info[0].passwd = pj_str("password"); pjsua_account_id acc_id; pjsua_account_add(&acc_cfg, PJ_TRUE, &acc_id); // 发起呼叫 pjsua_call_id call_id; pj_str_t uri = pj_str("sip:callee@example.com"); pjsua_call_make_call(acc_id, &uri, 0, NULL, NULL, &call_id); ``` #### 4. **文档与中文支持** 为了更好地理解和使用 PJSIP,开发者可以参考《PJSIP 开发指南中文版》项目,该项目提供了详细的中文文档,帮助开发者快速掌握 PJSIP 的集成与使用方法[^3]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值