當開發者第一次閱讀 PJSIP 原始碼時,通常會產生一個疑問:為什麼一個看似簡單的 SIP INVITE 請求,要經過這麼多檔案、模組、回呼和狀態機?為什麼 PJSIP 同時提供 pjsip、pjsip-simple、pjsip-ua、PJSUA 和 PJSUA2,而不是只暴露一個簡單 API?
答案來自 PJSIP 的分層抽象與封裝思想。PJSIP 不是鬆散函式庫,而是一套從底層傳輸、記憶體管理、事件處理逐步抽象到帳戶、通話、對話、媒體會話和應用端點的通訊協定堆疊。
貝克通信在 SIP、VoIP、調度通信、閘道整合、工業電話、緊急對講和融合通信平台等場景中,都可以參考這種分層思想。

把 PJSIP 理解為分層物流系統
理解 PJSIP 的一种有效方式,是把它看成物流系统。坐席只想点击按钮开始通话,就像用户只想下单;但背后有道路、车辆、规则、运单、分拣中心、配送人员和服务流程。
PJSIP 也是这样。每一层隐藏一部分复杂性,并向上一层提供更实用的接口。一个 SIP INVITE 会经过多个组件,因为每一层都有清晰职责,这样系统才能稳定、可扩展、可维护。
| PJSIP 层级 | 物流类比 | 工程角色 |
|---|---|---|
| PJLIB | 道路和车辆 | 提供内存、线程、Socket、定时器和跨平台基础设施。 |
| PJSIP Core | 交通规则和运单 | 按照 RFC 3261 解析、路由、发送和接收 SIP 消息。 |
| PJSIP-UA | 分拣中心和配送人员 | 把原始 SIP 消息转换为对话、会话和用户代理行为。 |
| PJSUA / PJSUA2 | 电商前台 | 提供账户、呼叫、媒体、注册和应用逻辑的高层 API。 |
PJLIB 與 PJLIB-UTIL:基礎設施層
PJLIB 和 PJLIB-UTIL 位于 PJSIP 最底层,负责 C 网络编程中的基础问题,包括内存管理、跨平台兼容、Socket、定时器、事件轮询、线程、日志和工具函数。
RFC 3261 定义 SIP 协议行为,但不定义程序如何管理内存、并发或操作系统差异。PJSIP 通过 PJLIB 解决这些工程问题,使上层可以专注于 SIP 信令和媒体流程。
記憶體池抽象:pj_pool_t
SIP 解析会产生大量短生命周期字符串、头域、URI、参数和临时结构。如果频繁使用 malloc/free,在嵌入式设备、网关和长期运行系统中容易产生内存碎片。
pj_pool_t 不只是分配器,也是生命周期管理器。事务、对话或消息处理上下文中的相关内存可以从同一个池中分配,并在生命周期结束时一次性释放。
I/O 佇列抽象:pj_ioqueue
SIP 系统需要处理 UDP、TCP、TLS 等传输方式。不同系统使用不同事件模型,例如 Linux 的 epoll、Windows 的 IOCP 和 macOS/BSD 的 kqueue。
PJSIP 通过 pj_ioqueue 封装这种差异。开发者调用 pj_ioqueue_poll() 即可,让同一套应用可以运行在服务器、嵌入式设备、软电话、工业终端和网关上。
PJLIB 解决的是“可靠运行”的问题,为 PJSIP 提供内存、并发、定时器、Socket 和跨平台事件处理基础。
PJSIP Core:訊令管道層
PJSIP Core 是 SIP 信令的核心,但它不直接定义“坐席登录”“客户来电”或“调度组”等业务含义。它构建的是基于 SIP 规则的标准化消息管道。
这一层负责消息解析、消息生成、传输选择、endpoint 管理、模块分发、事务处理和路由逻辑。SIP 在这里从 Socket 上的文本变成工程化框架。
Endpoint 與模組架構
pjsip_endpoint 可以理解为信令世界的中心控制者。所有 SIP 消息都经过 endpoint,再根据优先级分发给 pjsip_module,例如事务模块、事件模块、用户代理模块和应用模块。
网络包到达后会被解析为 pjsip_rx_data。入站流程可能经过消息解析、传输处理、事务匹配、用户代理处理和应用回调;出站流程则反向完成创建、路由和发送。
SIP 處理的洋蔥模型
PJSIP 的模块系统像洋葱模型。每一层都可以检查、修改或处理 SIP 消息,而不需要改变整个核心。这适合加入认证、日志、路由策略、安全检查、头域改写、录音触发或网关互通。
例如,SIP 调度平台可以拦截 INVITE,检查主叫身份,应用路由规则,记录信令日志,再把呼叫送到坐席组、SIP 电话、工业电话或应急呼叫站。
交易抽象:pjsip_tsx
在 SIP 中,请求及其响应构成事务。RFC 3261 定义了 Timer A、Timer B、Timer D 等定时器和重传行为,手工实现非常容易出错。
pjsip_tsx 将请求-响应交互封装成状态机。开发者只需监听 on_tsx_state 等回调,而不用自己编写重传和超时逻辑。

PJSIP-UA:從訊息到會話
RFC 3261 描述的是消息、请求、响应、头域、标签、事务和路由。但真实坐席关心的是接听、保持、转接和结束通话。
PJSIP-UA 把原始 SIP 消息转换为对话和 invite session 等用户代理概念,这是 PJSIP 从协议文本进入通信对象模型的关键一步。
對話抽象:pjsip_dlg
原生 SIP 通过 Call-ID、From tag 和 To tag 识别对话。手工管理这些字段既原始又有风险。
pjsip_dlg 自动维护 CSeq、路由集、对话匹配、响应处理和相关状态,让原本偏无状态的文本协议转变为有状态对象模型。
Invite 會話抽象:pjsip_inv_session
完整 SIP 通话可能包含 INVITE、100 Trying、180 Ringing、183 Session Progress、200 OK、ACK、PRACK、UPDATE、re-INVITE 和 BYE。
pjsip_inv_session 将多个事务连接成一个有意义的通话生命周期,并引入 SDP 协商,使 SIP 与 PJMEDIA 协作处理 RTP、编解码器、音频设备和媒体端口。
pjsip-simple:呈現、訊息和事件型服務
在呼叫中心和融合通信系统中,语音只是其中一部分。用户还需要呈现状态、即时消息、订阅、通知和事件服务,pjsip-simple 提供了这些 SIP SIMPLE 构件。
在贝克通信平台中,类似机制可用于显示终端可用性、调度状态、设备在线状态、报警通知和操作员状态。
PJSUA 與 PJSUA2:高層應用框架
多数应用开发者不需要直接操作 PJSIP Core 或 PJLIB。PJSUA 与 PJSUA2 把底层能力封装成实用接口。
PJSUA:高层 C API
PJSUA 将账户、呼叫、注册、媒体端口、音频设备和会议桥封装为便捷句柄。调用 pjsua_call_make_call() 时,框架会自动创建 INVITE 事务、对话、SDP、媒体连接和呼叫状态。
PJSUA2:物件導向的 C++ API
PJSUA2 将底层 C 结构包装成类。Endpoint 表示协议栈实例,Account 表示 SIP 账户,Call 表示包含信令回调和媒体操作的通信会话。

PJSIP 如何支援呼叫中心和調度系統開發
呼叫中心平台必须处理注册、呼入、呼出、振铃、接听、保持、转接、会议、录音、路由、媒体协商和状态监控。如果全部基于原始 SIP 消息开发,效率会很低。
PJSIP 的分层架构让工程师获得合适的控制层级。简单 SIP 端点可用 PJSUA2 快速开发;高级调度服务器可使用低层模块拦截消息、应用策略、连接网关并集成外部系统。
帳戶註冊與認證
每个坐席终端或 SIP 设备通常需要一个 SIP 账户。PJSUA2 可以封装注册、认证和状态更新,让开发者把账户作为应用对象管理,而不是手工构造 REGISTER 消息。
通話控制與座席工作流程
呼叫可表示为具有 calling、ringing、confirmed、disconnected、held 等状态的对象。坐席软件可基于回调显示状态、触发录音、启动转接或更新 CRM 数据。
媒體處理與 SDP 協商
SIP 信令本身不承载语音。语音通过 SDP 协商,再通过 RTP 或相关路径传输。PJSIP 与 PJMEDIA 协同处理编解码器、音频设备、媒体端口、会议桥和流管理。
閘道與工業終端整合
贝克通信方案可能包含 SIP 电话、工业电话、应急呼叫站、寻呼终端、RoIP 网关、广播系统和调度台。PJSIP 风格架构支持这种集成,因为信令、会话、媒体和应用逻辑可以清晰分离。
貝克通信技術方案視角
从贝克通信方案角度看,PJSIP 的分层哲学与真实通信平台高度相关。控制中心可能需要 SIP 中继、IP PBX、工业电话、应急对讲、无线网关、PA 广播、CCTV 联动和调度台集成。
可靠架构不应把所有逻辑混在一个应用层中,而应清晰分离:底层是传输和系统资源,核心是 SIP 信令,中间是对话和会话逻辑,顶部是业务工作流。
PJSIP 的强大之处在于把协议复杂性与业务开发分离,这正是现代呼叫中心、调度和工业通信系统需要的设计原则。
为什么 PJSIP 使用这么多层
PJSIP 的分层抽象是为了解决 RFC 3261 的复杂性与工程效率之间的矛盾。PJLIB 解决可靠运行,PJSIP Core 处理 SIP 消息,PJSIP-UA 管理对话、会话和 SDP,PJSUA and PJSUA2 支持快速应用开发。
因此 PJSIP 可以裁剪用于嵌入式设备和 IoT 终端,也可以扩展用于软电话、视频通话、会议系统、调度平台和呼叫中心应用。
面向開發者的實際工程價值
更好的可維護性
职责清晰后,内存问题属于基础设施层,重传问题属于事务层,呼叫状态问题属于对话或 invite session 层,业务流程问题属于应用层。
更好的可擴充性
模块化 SIP 处理允许增加认证、路由、日志、监控、录音触发和安全规则,而不必重写整个协议栈。
更好的產品重用
融合通信企业可在 SIP 电话、呼叫中心坐席、调度台、寻呼网关和工业应急终端之间复用同一套 SIP 基础能力。
Conclusion
PJSIP 初看复杂,是因为一个 INVITE 请求会穿过许多文件和层级。但这种复杂性是有意设计的,它把 SIP 从原始协议消息转换为结构化工程系统。
对于贝克通信类型的方案,这种分层设计是重要参考。无论建设 SIP 呼叫中心、工业通信平台、RoIP 网关、应急对讲系统还是调度台,最佳架构都应分离传输、信令、会话控制、媒体和业务逻辑。
FAQ
為什麼一個簡單的 SIP INVITE 會經過這麼多 PJSIP 檔案?
因为 PJSIP 将职责拆分到不同层级,一个 INVITE 可能涉及传输、解析、endpoint 分发、事务处理、对话匹配、invite session、SDP 和应用回调。
PJLIB 在 PJSIP 中的作用是什麼?
PJLIB 提供内存池、Socket、定时器、事件轮询、线程、日志和跨平台抽象,帮助 PJSIP 在不同系统和设备上可靠运行。
PJSIP Core 與 PJSIP-UA 有什麼區別?
PJSIP Core 关注消息处理、传输、模块和事务;PJSIP-UA 关注对话、invite session、呼叫生命周期和 SDP 会话控制。
PJSUA2 用來做什麼?
PJSUA2 是 C++ 面向对象 API,可用于开发软电话、呼叫中心客户端、调度应用和 SIP 通信工具。
這種架構如何幫助貝克通信方案?
它为 SIP 呼叫中心、调度平台、RoIP 网关、工业电话、应急对讲和融合通信系统提供清晰技术模型。