前一段时间简单了解了 pjsip,后来研究别的就耽搁下来,仔细翻官网发现这个协议栈包含的库很多,提供的功能也有侧重,看的眼花缭乱,不知道从那里下手,官网文档列表感受一下:
好在官方还是介绍了它们之间的关系
各层级模块提供的功能描述如下
模块名称 | 功能描述 |
---|---|
PJLIB | 使用C语言编写的基础库,它是所有其它库运行的基础。 |
PJLIB-UTIL | 提供辅助工具库,如文本处理,XML;STUN;加密算法;DNS等。 |
PJMEDIA | 多媒体栈,提供音视频处理功能。 |
PJMEDIA-CODEC | 包含多种媒体编解码器实现。 |
PJSIP-CORE | 核心库,提供诸如 Endpoint,Transaction,Dialog 对象。 |
PJSIP-SIMPLE | 基于 Dialog,提供基础的事件功能,实现了状态与呼叫转移功能。 |
PJSIP-UA | 基于 Dialog,提供更高级别的 INVITE 会话抽象,实现了客户端注册与呼叫转移功能。 |
PJSUA-LIB | C语言实现,面向过程,封装了以上所有的功能,易用性提高。 |
补充一个在介绍文档出现之后的 PJSUA2,图中没有画。
模块名称 | 功能描述 |
---|---|
PJSUA2 | C语言实现,对 PJSUA-LIB 进一步封装,面向对象,更加的易用。 |
应该从哪里开始?
作者推荐刚接触 PJSIP 协议栈的开发者从以下两个方案中选择进行开发
- 使用 PJSUA-LIB / PJSUA2,比 PJSIP 更高层级的接口,包含了封装良好的通用 SIP 功能。
- 使用 PJSIP + PJMEDIA 可以更加的灵活,当然,也意味着更陡峭的学习曲线。
补充:
-
基于 PJSUA-LIB / PJSUA2 进行开发,会方便很多,比如它提供了多客户端注册,高层级的会话,好友列表,在线状态与即时消息,更易用的媒体操作,同时它也有保留了一定的应用自定义的能力。而基于 PJSIP 协议栈和媒体栈开发,有必要阅读一遍图1中文档列表最后一个文档 “PJSIP Developer's Guide (PDF)”,它是了解 PJSIP 协议栈设计概念的终极指南;在代码的
pjsip-apps/src/samples
目录,有一些例子可供参考;PJSUA-LIB 的源代码也有助于了解如何使用 PJSIP / PJMEDIA 开发高层级接口。 -
本小节中 PJSIP 是指 PJSIP-CORE,PJSIP-SIMPLE,PJSIP-UA 这些较底层的库。
再次提醒
较底层的接口(如:PJSIP,PJMEDIA,PJNATH)使用困难,如果你不是因为以下这些原因,最好不要直接使用它们。
- 你在开发中,只想使用PJSIP协议栈中的一个库,如PJNATH(用于NAT穿透的ICE, STUN和TURN的开源库 )。
- 特别需要节省空间的场景(如用几千字节代替几兆字节)。
- 你不是要开发一个 SIP UA 应用。
PJSUA2 简介
PJSUA2 是目前官方推荐的方式,在更高级别抽象的 PJSUA2 出现之前,PJSUA-LIB 被大多数的 PJSIP 用户使用。
它基于 PJSUA-LIB 模块,使用 C++ 开发的,面向对象。它的 API 和 PJSUA-LIB 不同,但是更加易用,且拥有更好的文档。
借助 SWIG 提供的绑定功能,Java、Python、C# 也可以使用 PJSUA2 的 API,不过脚本语言使用 PJSUA2 不能访问 PJSUA-LIB 或可能会使用到的C库。
还是推荐使用原生的 C++ 来基于 PJSUA2 进行开发,简单来说就是问题更少,接口更加统一,用到底层接口的时候没有限制,同时我觉得网上的参考资料会相对多些。
使用 PJSUA2 注意事项
- API 使用 Exception 方式返回错误,而不是 return。
- PJSUA2 使用了 C++ 标准库(STL)。
- 在现代设备上,因抽象而带来的额外性能损失应该可以忽略不记。
PJSUA2 主要类
示例代码
int main()
{
Endpoint ep;
ep.libCreate();
// Init endpoint
EpConfig ep_cfg;
ep_cfg.uaConfig.userAgent = "sip-server";
ep.libInit( ep_cfg );
// create transport.
TransportConfig tcfg;
tcfg.port = 5060;
try {
ep.transportCreate(PJSIP_TRANSPORT_UDP, tcfg);
} catch (Error &err) {
std::cout << err.info() << std::endl;
return 1;
}
// launch endpoint
ep.libStart();
std::cout << " *** PJSUA2 STARTED *** " << std::endl;
Version version = ep.libVersion();
std::cout << "version: " + version.full << std::endl;
// init account info
AccountConfig acfg;
acfg.idUri = "sip:34020000002000000001@192.168.3.189:5060";
// create account
ServerAccount * acc = new ServerAccount;
acc->create(acfg);
pj_thread_sleep(2000);
return 0;
}
1)ENDPOINT 类
ENDPOINT 是单例模式,一个应用有且只有一个实例,在最开始时创建,所有API都是基于它的,换句话说即销毁实例后不能再调用任何API,EpConfig 类用于 endpoint 类的自定义配置,可以设置 UAConfig,MediaConfig,LogConfig
之后需要创建传输(Transports)配置,至少创建一个用于接收发送 SIP 信令。
启动实例,这时它会进行一些初始化,如 STUN 连接,初始化视音频设备等。
2)Accounts 类
Accounts 用于用户的身份确认,一个用户有一个URI。
一个应用中至少应该存在一个 Accounts 实例,因为任何访问请求都需要携带 account 上下文,如果没有用户认证要求,应用可以创建一个 userless 账户。
使用 Accounts 应该创建一个它的子类 MyAccount,用于接收 onRegState、onIncomingCall 等事件。
同时使用 AccountConfig 类来初始化 Account 的配置。
3)Media 类
Media 可以产生媒体或操作媒体,AudioMedia 是重要的子类。 它可以捕获设备音频,回放设备音频,从远端用户获取发送音频,播放本地 WAV 文件,记录音频到本地 WAV 文件等。
4)Calls 类 用于发起请求的类 使用 Calls 也像 Account 一样,应该初始化一个子类,如MyCall,用于回调接收回调事件。
5)Buddy 类 在 Buddy 中,可以设置子类来接收好友的 Presence(在线状态) 变更等。
参考