Osip源代码框架13--Call创建流程

文章目录

      • Call创建流程
      • eXosip_call_build_initial_invite的流程
        • 参数合法性校验(阶段 A)
        • 基础请求初始化(阶段 B)
        • Dialog 外请求构造(阶段 C)
        • INVITE 专属字段填充(阶段 D)
        • 协议合规性检查(阶段 E)
        • Dialog 内外请求的核心差异
      • eXosip_call_send_initial_invite 流程
        • 初始化呼叫流程
        • 创建客户端事务
        • 构建 SIP 请求
        • 事件驱动处理
        • 线程协同机制
        • SIP协议操作映射表
        • 开发 / 调试视角
          • Dialog 延迟建立机制
          • 事务驱动 Call 状态
          • 异步发送的实现
        • 总结

Call创建流程

Exosip lib库提供了call的4类接口:

  • 第一次建立一个call的initial invite创建及发送接口;
  • 在dialog中创建及发送的其它request;
  • 在dialog中创建及发送对从对端发送过来的request的response;
  • 在invite请求中回应对端response的ACK的创建和发送。

eXosip_call_build_initial_invite的流程

把 eXosip_call_build_initial_invite 拆成 「参数校验 → 基础请求构造 → Dialog 外请求构建 → INVITE 字段补充 → 协议合规检查」
Osip源代码框架13--Call创建流程_第1张图片

参数合法性校验(阶段 A)

检查 To 头域是否包含合法的 SIP URI(格式如 sip:[email protected])。
From 头域需符合 eXosip 初始化配置的生成规则(如 from_tag)。
依据 RFC 3261 第 8.1.1 节(SIP 消息格式)和第 12.1 节(Dialog 标识规则)。

基础请求初始化(阶段 B)

设置 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 规则)。

Dialog 外请求构造(阶段 C)

调用 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 节)。

INVITE 专属字段填充(阶段 D)

通过 _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)。

协议合规性检查(阶段 E)

校验 CSeq 是否为初始值(如 1)且方法为 INVITE
Route 头域可选,未指定时依赖 eXosip 默认路由配置。
若包含 SDP,需确保 Content-Typeapplication/sdp 且符合 RFC 4566 格式。### 表格:Dialog 内外请求的核心差异

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

说明

  • Dialog 外:适用于初始 INVITE 请求,需遵循 SIP 会话建立的初始规则,如生成新的 Call-ID 和 From Tag。
  • Dialog 内:适用于后续请求(如 Re-INVITE、UPDATE),需复用 Dialog 的已有字段并遵守 SIP 对话状态机规则。

eXosip_call_send_initial_invite 流程

结合 SIP 协议逻辑与代码分层,将流程拆解为 「呼叫初始化 → 事务构建 → 消息准备 → 事件驱动」 四个核心阶段,清晰呈现线程交互与状态流转:
Osip源代码框架13--Call创建流程_第2张图片

初始化呼叫流程

分配唯一 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 状态时,标志呼叫建立完成。

构建 SIP 请求

通过 osip_new_outgoing_sipmessage 创建基础 SIP 消息框架,填充以下关键字段:

  • 协议头:SIP/2.0
  • 会话标识:FromCall-ID
  • 目标地址:To 头域
  • 物理地址:Contact 头域指定响应接收地址
  • 超时控制:Expires 字段设置会话有效期

INVITE 消息格式严格遵循 RFC 3261 第 8.1 节请求结构规范,特殊头域如 Supported 可扩展业务能力。

事件驱动处理

调用 osip_transaction_add_eventTX_MSG_SENT 事件加入事务队列,标志待发送的 INVITE 请求。呼叫实例同时被注册至全局 call 链表,由框架统一管理活跃会话。

处理线程通过独立事件循环监控事务队列,实际网络发送操作由该线程异步执行,发起线程仅负责事件提交。
osip_transaction_add_event

线程协同机制

通过 eXosip_update 触发处理线程唤醒,典型实现包含以下方式:

  • 信号量通知阻塞在 select/poll 的 I/O 线程
  • 设置事件标志位强制线程检查新任务
  • 管道或套接字中断方式传递唤醒信号

该机制确保事件处理延迟低于系统调度周期,通常控制在毫秒级响应。

SIP协议操作映射表
关键函数 / 操作 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 延迟建立机制

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 状态

Call 状态与事务状态紧密关联:

  • 事务处于 CALLING 状态时,对应 Call 状态为 EXOSIP_CALL_INIT
  • 事务进入 COMPLETE 状态且收到 200 OK 时,Call 状态更新为 EXOSIP_CALL_ANSWERED

调试建议:

  • 使用 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 未创建、消息未发送等)。

你可能感兴趣的:(osip源代码框架分析,网络,linux,服务器,网络协议,c++)