Exosip lib库提供了call的4类接口:
把 eXosip_call_build_initial_invite 拆成 「参数校验 → 基础请求构造 → Dialog 外请求构建 → INVITE 字段补充 → 协议合规检查」
检查 To 头域是否包含合法的 SIP URI(格式如 sip:[email protected]
)。
From 头域需符合 eXosip 初始化配置的生成规则(如 from_tag
)。
依据 RFC 3261 第 8.1.1 节(SIP 消息格式)和第 12.1 节(Dialog 标识规则)。
设置 SIP 版本为默认值 SIP/2.0
。
初始化 From 头域,包含由 eXosip 生成的 from_tag
。
生成全局唯一的 Call-ID,确保 Dialog 标识唯一性。
参考 RFC 3261 第 8.1.1.7 节(Call-ID 规则)和第 12.1.1 节(From/To Tag 规则)。
调用 generating_request_out_of_dialog
构建初始 INVITE 请求。
无需关联已有 Dialog 的 CSeq 或 Route 头域。
Dialog 外请求的 Call-ID 为全新生成,CSeq 从 1
开始递增。
Dialog 内请求需复用 Call-ID 和 From/To Tag,且 CSeq 必须大于当前 Dialog 记录值(RFC 3261 第 12.2.1.1 节)。
通过 _eXosip_dialog_add_contact
填充 Contact 头域(如 sip:[email protected]:5060
)。
使用 osip_message_set_subject
设置可选呼叫主题(如会议名称)。
通过 osip_message_set_expires
设置会话超时时间(默认 3600
秒)。
协议依据:RFC 3261 第 8.1.1.8 节(Contact)和第 20.19 节(Expires)。
校验 CSeq 是否为初始值(如 1
)且方法为 INVITE
。
Route 头域可选,未指定时依赖 eXosip 默认路由配置。
若包含 SDP,需确保 Content-Type
为 application/sdp
且符合 RFC 4566 格式。### 表格:Dialog 内外请求的核心差异
场景 | Dialog 外(初始 INVITE) | Dialog 内(Re-INVITE 等) |
---|---|---|
Call-ID | 全新生成(全局唯一) | 复用 Dialog 的 Call-ID |
From/To Tag | To Tag 由对端生成(本端无 To Tag) | 复用 Dialog 的 From/To Tag |
CSeq | 初始值(如 1),方法为 INVITE | 必须 > Dialog 中记录的 CSeq,方法匹配 |
Route | 依赖 eXosip 初始化配置 | 复用 Dialog 的 Route Set |
说明:
结合 SIP 协议逻辑与代码分层,将流程拆解为 「呼叫初始化 → 事务构建 → 消息准备 → 事件驱动」 四个核心阶段,清晰呈现线程交互与状态流转:
分配唯一 call_id
并创建呼叫结构体,包含 c_out_tr
字段用于关联事务。此时暂不绑定 Dialog,需等待对端应答后建立会话容器。
SIP 呼叫生命周期覆盖从发起至终止的全过程,call_id
作为会话的唯一标识符贯穿始终。
调用 _eXosip_transaction_init
初始化 ICT(Invite Client Transaction),事务类型指定为处理 INVITE 请求。将事务指针绑定至 Call 结构体的 c_out_tr
字段,后续状态机由事务驱动。
ICT 实现遵循 RFC 3261 第 17.1 节状态机规范,自动处理重传与超时逻辑。事务进入 COMPLETE 状态时,标志呼叫建立完成。
通过 osip_new_outgoing_sipmessage
创建基础 SIP 消息框架,填充以下关键字段:
SIP/2.0
From
、Call-ID
To
头域Contact
头域指定响应接收地址Expires
字段设置会话有效期INVITE 消息格式严格遵循 RFC 3261 第 8.1 节请求结构规范,特殊头域如 Supported
可扩展业务能力。
调用 osip_transaction_add_event
将 TX_MSG_SENT
事件加入事务队列,标志待发送的 INVITE 请求。呼叫实例同时被注册至全局 call
链表,由框架统一管理活跃会话。
处理线程通过独立事件循环监控事务队列,实际网络发送操作由该线程异步执行,发起线程仅负责事件提交。
osip_transaction_add_event
通过 eXosip_update
触发处理线程唤醒,典型实现包含以下方式:
select/poll
的 I/O 线程该机制确保事件处理延迟低于系统调度周期,通常控制在毫秒级响应。
关键函数 / 操作 | SIP协议映射 | 线程交互逻辑 |
---|---|---|
创建新 Call | eXosip_call_init | RFC 3261 第13节(呼叫建立流程) |
初始化 ICT事务 | _eXosip_transaction_init | RFC 3261 第17.1节(ICT状态机) |
构建 INVITE消息 | osip_new_outgoing_sipmessage | RFC 3261 第8.1节(请求消息结构) |
事件入队 | osip_transaction_add_event | RFC 3261 第17节(事务事件驱动) |
唤醒处理线程 | eXosip_update | -(实现层调度逻辑) |
Dialog 需等待对端返回非 100 应答(如 180、200)后,由 eXosip 自动创建。在 Call 初始化阶段不会直接建立 Dialog,而是在收到对端应答后调用 _eXosip_dialog_init
完成 Dialog 的初始化。
代码示例:
// 收到对端 200 OK 后触发 Dialog 创建
if (msg->status_code == 200) {
_eXosip_dialog_init(excontext, call_id, dialog_id);
}
Call 状态与事务状态紧密关联:
调试建议:
eXosip_call_get_state
监控 Call 状态变化。osip_transaction_dump
输出)分析超时或失败原因。异步发送机制分为两个线程协作:
eXosip_call_send_initial_invite
):仅负责消息准备和事件入队,不直接发送消息。eXosip_execute
):实际执行消息发送并处理响应。问题排查方法:
osip_transaction_dump
打印事务状态,确认事务是否正常创建。代码示例(异步发送流程):
// 发起线程:准备 INVITE 并加入队列
eXosip_call_send_initial_invite(call_id, invite_packet);
// 处理线程:执行实际发送
while (1) {
eXosip_execute();
usleep(10000); // 避免 CPU 占用过高
}
「创建 Call → 初始化 ICT 事务 → 构建 INVITE 消息 → 事件入队 → 唤醒处理线程发送」
核心设计是 “事件驱动的异步发送”,通过事务状态机解耦发起线程与网络 I/O,同时遵循 SIP 协议分层管理 Call、Dialog、Transaction 的生命周期。理解这一流程后,可快速定位呼叫建立阶段的典型问题(如事务超时、Dialog 未创建、消息未发送等)。