Kamailio SIP+RTP双网卡SBC呼叫流程与媒体处理说明
本文档旨在详细解释基于提供的 kamailio_sbc_dual_nic.cfg
配置文件,在双网卡SBC(Session Border Controller)场景下,Kamailio (5.8.3) 如何与rtpengine协同工作,处理SIP信令以及音频、视频和RTCP媒体流的转发。该方案利用dispatcher模块实现对公网和私网多网关的负载均衡。
1. 系统概览
核心组件包括:
- Kamailio (5.8.3):作为SIP信令服务器,负责处理呼叫路由、负载均衡和与rtpengine的交互。
- rtpengine (mr13.1.1.6):作为媒体代理,负责处理RTP/RTCP媒体流的转发、NAT穿透(本场景为无NAT,但rtpengine仍管理媒体端口和IP)、以及可能的媒体处理(如编解码转换,本例未重点配置)。rtpengine配置为双网卡模式,拥有公网和私网IP接口。
- Dispatcher模块:Kamailio内置模块,用于将呼叫分发到公网或私网的多个目标网关,实现负载均衡和高可用性。
Kamailio监听其公网IP和私网IP上的SIP请求。rtpengine通过NG协议与Kamailio在本地回环地址通信。
2. 呼叫流程:公网用户呼叫私网用户/网关
假设一个公网SIP用户通过互联网呼叫一个位于私网的企业IP-PBX分机或私网网关。
- INVITE请求到达Kamailio公网接口:
- 公网用户发送SIP INVITE请求,目标是Kamailio的公网IP地址(例如
PUBLIC_IP:5060
)。SDP中包含公网用户的媒体信息(IP和端口)。 - Kamailio的
request_route
首先执行通用检查(Max-Forwards, Sanity Checks)。 - 通过
if ($Ri == "PUBLIC_IP")
判断请求来自公网接口,进入route[FROM_PUBLIC]
逻辑。
- 选择私网目标网关 (Dispatcher):
- 在
route[FROM_PUBLIC]
中,调用ds_select_dst("2", DS_ALGORITHM_PRIVATE)
。这会从预定义的私网网关组(Set ID 2,例如/etc/kamailio/dispatcher_private.list
中定义的网关)中根据指定算法(例如轮询)选择一个可用的私网网关。 - 如果选择失败(没有可用网关),则回复
503 Service Unavailable
。 - 选中的私网网关URI被存入
$du
。
- rtpengine处理媒体协商 (Offer):
- 如果INVITE请求中包含SDP (
has_body("application/sdp")
),则调用rtpengine_manage(RTPENGINE_COMMON_FLAGS + " direction=public direction=private")
。
RTPENGINE_COMMON_FLAGS
通常包含trust-address replace-origin replace-session-connection RTP/AVP rtcp-mux-offer
等。- 关键在于
direction=public direction=private
:这个flag指示rtpengine,对于这个呼叫的“对端”(即私网侧),应该使用rtpengine配置的“私网”接口来分配媒体端口和宣告IP地址。而对于“本端”(即公网用户侧),rtpengine会使用其“公网”接口。
- rtpengine收到指令后:
- 在私网接口上为私网网关分配RTP/RTCP端口(例如
PRIVATE_RTPENGINE_IP:port_private
)。 - 在公网接口上为公网用户分配RTP/RTCP端口(例如
PUBLIC_RTPENGINE_IP:port_public
)。 - 修改INVITE中的SDP:将
o=
行和会话级c=
行中的IP地址替换为rtpengine的公网接口IP (PUBLIC_RTPENGINE_IP
),并将媒体端口替换为rtpengine在公网接口上分配的端口 (port_public
)。这个修改后的SDP将发往公网用户(在最终的200 OK中)。 - rtpengine内部记录媒体流的映射关系:
PUBLIC_RTPENGINE_IP:port_public
<->PRIVATE_RTPENGINE_IP:port_private
。
- 如果
rtpengine_manage
失败,回复500 Media Proxy Error
。
- 转发INVITE到私网网关:
- Kamailio通过
t_set_destination_uri($du)
设置请求的目标为选中的私网网关。 record_route()
确保后续请求(如ACK, BYE)经过Kamailio。- Kamailio通过
t_relay()
将带有rtpengine修改后SDP(此时SDP中的媒体地址是rtpengine的公网地址,这是发往私网网关的INVITE中SDP的视角,它应该宣告rtpengine的私网地址给私网网关)的INVITE请求转发给选定的私网网关。
- 更正与澄清:当
rtpengine_manage
在route[FROM_PUBLIC]
中为发往私网的INVITE处理SDP时,它修改的SDP内容是准备给私网对端的。因此,SDP中的c=行和媒体端口应该是rtpengine的私网接口IP和端口。rtpengine知道呼叫的另一端(公网用户)的媒体信息,并将使用其公网接口与公网用户通信。
- 私网网关响应 (例如200 OK):
- 私网网关处理INVITE,并回复一个包含其自身媒体信息(私网IP和端口)的200 OK。
- 200 OK通过Kamailio返回(由于Record-Routing)。
- rtpengine处理媒体协商 (Answer):
- Kamailio的
onreply_route
捕获到200 OK。 - 如果响应中包含SDP,再次调用
rtpengine_manage(RTPENGINE_ANSWER_FLAGS + " direction=private direction=public")
(或者根据保存的呼叫方向上下文确定正确的direction)。
direction=private direction=public
仍然适用,因为这是对始于公网、终于私网的呼叫的响应路径。
- rtpengine接收到私网网关的SDP,确认媒体参数。它会修改200 OK中的SDP,将其中的媒体IP和端口替换为rtpengine的公网接口IP和端口 (
PUBLIC_RTPENGINE_IP:port_public
)。这个修改后的SDP将发往公网用户。
- 转发响应给公网用户:
- Kamailio将带有rtpengine修改后SDP的200 OK转发给公网用户。
- 媒体流建立:
- 公网用户向
PUBLIC_RTPENGINE_IP:port_public
发送RTP/RTCP流。 - rtpengine接收到后,根据内部映射,将媒体流从其公网接口转发到其私网接口,并发送给私网网关的媒体地址
PRIVATE_GW_IP:port_gw_private
(此地址由rtpengine从私网网关的SDP中获知)。 - 反向媒体流:私网网关向
PRIVATE_RTPENGINE_IP:port_private
发送RTP/RTCP流。 - rtpengine接收到后,转发给公网用户的媒体地址
PUBLIC_USER_IP:port_user_public
(此地址由rtpengine从公网用户的初始SDP中获知)。 - 核心路径:公网用户 <-> rtpengine公网IP <-> rtpengine私网IP <-> 私网网关。
3. 呼叫流程:私网用户/网关呼叫公网用户
此流程与上述类似,但方向相反。
- INVITE请求到达Kamailio私网接口:
- 来自私网用户/网关,目标是Kamailio的私网IP地址(例如
PRIVATE_IP:5060
)。 - Kamailio通过
if ($Ri == "PRIVATE_IP")
判断请求来自私网接口,进入route[FROM_PRIVATE]
逻辑。
- 选择公网目标网关 (Dispatcher):
- 调用
ds_select_dst("1", DS_ALGORITHM_PUBLIC)
选择公网网关组(Set ID 1)。
- rtpengine处理媒体协商 (Offer):
- 调用
rtpengine_manage(RTPENGINE_COMMON_FLAGS + " direction=private direction=public")
。
direction=private direction=public
指示rtpengine,对于呼叫的“对端”(即公网侧),应使用rtpengine的“公网”接口。对于“本端”(私网用户),使用其“私网”接口。
- rtpengine在公网接口分配媒体端口,在私网接口分配媒体端口。
- 修改INVITE中的SDP:将媒体IP和端口替换为rtpengine的私网接口IP和端口,准备发往公网网关(宣告rtpengine的公网地址)。
- 更正与澄清:当
rtpengine_manage
在route[FROM_PRIVATE]
中为发往公网的INVITE处理SDP时,它修改的SDP内容是准备给公网对端的。因此,SDP中的c=行和媒体端口应该是rtpengine的公网接口IP和端口。
- 转发INVITE到公网网关。
- 公网网关响应 (例如200 OK)。
- rtpengine处理媒体协商 (Answer):
- 调用
rtpengine_manage(RTPENGINE_ANSWER_FLAGS + " direction=public direction=private")
。 - rtpengine修改200 OK中的SDP,将其中的媒体IP和端口替换为rtpengine的私网接口IP和端口,准备发往私网用户/网关。
- 转发响应给私网用户/网关。
- 媒体流建立:
- 私网用户/网关 <-> rtpengine私网IP <-> rtpengine公网IP <-> 公网网关/用户。
4. rtpengine在媒体处理中的角色
- 音视频流 (Audio/Video):rtpengine通过解析SDP中的
m=audio
和m=video
行来识别不同的媒体流。它会为每个媒体流(及其对应的RTCP流)分配端口并进行转发。RTP/AVP
flag确保了对标准音视频profile的支持。 - RTCP流:rtpengine自动处理与RTP流配对的RTCP流。用户要求RTCP转发以处理视频丢包,这是rtpengine的默认行为。
rtcp-mux-offer
和rtcp-mux-answer
flags用于协商是否将RTP和RTCP复用在同一端口上,这是推荐的做法,可以节省端口资源并简化NAT穿透(尽管本场景无NAT)。 - 接口选择:
direction=public
或direction=private
flag是核心,它告诉rtpengine应该将哪个逻辑网络接口(公网或私网)视为呼叫的“远端”进行SDP宣告,并使用哪个接口与该远端通信。rtpengine的另一个接口则用于与呼叫的“近端”通信。 - SDP操作:
trust-address
(信任SDP中的c=行IP作为媒体来源的初始判断,但最终会被rtpengine的IP替换掉),replace-origin
(替换o=行),replace-session-connection
(替换会话级c=行) 确保了SDP被正确修改以通过rtpengine路由媒体。
5. Dispatcher模块的角色
- 负载均衡:根据配置文件中定义的网关列表(例如
/etc/kamailio/dispatcher_public.list
和/etc/kamailio/dispatcher_private.list
)和选择的算法(例如轮询),将出局呼叫(无论是到公网还是私网的网关)分发到多个目标网关之一。 - 网关健康检查:Dispatcher模块可以配置为定期ping目标网关(通过SIP OPTIONS请求),以检查其可用性,并自动将流量从不可用的网关移开。
- 分组管理:通过Set ID(例如公网组为1,私网组为2)对不同的网关进行分组管理,使得路由逻辑可以清晰地选择合适的目标组。
6. Kamailio配置关键点回顾
- 监听接口:Kamailio通过
listen
参数同时监听公网和私网IP地址,以便接收来自两个网络的SIP请求。 - 接口识别:在
request_route
中,通过$Ri
(Received Interface IP) 变量判断请求到达的接口,从而决定呼叫的初始方向(公网到私网,或私网到公网)。 - rtpengine模块参数:
rtpengine_sock
定义了与rtpengine守护进程的通信方式。 - rtpengine_manage()调用:在INVITE请求和对应的2xx响应中(如果包含SDP)调用,以使rtpengine参与媒体会话。关键是根据呼叫方向正确设置
direction
flag。 - Record-Routing:
record_route()
函数用于确保后续的请求(如ACK, BYE)和响应都通过Kamailio,从而使Kamailio能够保持对话状态并正确处理媒体会话的生命周期(例如调用rtpengine_delete()
)。 - rtpengine_delete():在对话结束时(例如收到BYE或CANCEL后,或对话超时),调用
rtpengine_delete()
来释放rtpengine中占用的资源。 - onreply_route中的逻辑:正确处理响应中的SDP至关重要。确定响应对应的原始请求方向,以便为
rtpengine_manage
设置正确的direction
flag,是onreply_route
中较为复杂的部分,通常需要借助事务标志或对话AVPs来传递上下文。
7. 关于音视频和RTCP的进一步说明
rtpengine本身设计为透明处理RTP和RTCP。只要SDP中正确描述了媒体类型(例如m=audio ... RTP/AVP ...
,m=video ... RTP/AVP ...
),rtpengine就会为它们分配端口并转发。RTCP通常使用RTP端口号+1(除非使用RTCP-Mux)。
用户要求RTCP转发以处理视频丢包,这是标准行为。RTCP报告(如Sender Reports, Receiver Reports)包含了丢包统计、抖动等信息,视频编解码器和播放器可以利用这些信息来调整码率、请求重传(如果协议支持)或进行错误隐藏,从而改善视频质量。
通过确保rtpengine正确桥接了双向的RTCP流,接收端可以向发送端报告网络状况,发送端也可以据此调整发送策略,这对于视频流的质量至关重要。
这份说明应该能帮助理解所提供Kamailio配置方案的工作原理。在实际部署前,务必替换所有占位符IP地址,并根据具体网络环境进行测试和调整。
空空如常
求真得真
Kamailio SIP+RTP双网卡SBC呼叫流程与媒体处理说明的更多相关文章
- Linux下双网卡Firewalld的配置流程
实验室拟态存储的项目需要通过LVS-NAT模式通过LVS服务器来区隔内外网的服务,所以安全防护的重心则落在了LVS服务器之上.笔者最终选择通过firewalld放行端口的方式来实现需求,由于firew ...
- freeswitch呼叫流程分析
今天翻文档时发现之前整理的关于freeswitch呼叫相关的内容,写成博文分享出来也方便我以后查阅. 整体结构图 FreeswitchCore 模块加载过程 freeswitch主程序初始化时会从mo ...
- 填坑日志-云网络智慧课堂双网卡Mac地址读取错误的问题及解决
云网络智慧课堂的双网卡问题记录及解决方案 教师端 其实这里双网卡的问题一直没有解决,分为了两部分,一部分是教师端,一部分是学生端.症状类似,问题也类似,都是在设计之初因为硬件限制可能没有考虑到双网卡的 ...
- 烂泥:VMWare Workation双网卡配置IP地址
本文由ilanniweb提供友情赞助,首发于烂泥行天下 想要获得更多的文章,可以关注我的微信ilanniweb 前几天给一个客户做远程项目实施,客户那边的服务器是Windows OS的,我们这边的业务 ...
- Linux下双网卡绑定bond0
一:原理: linux操作系统下双网卡绑定有七种模式.现在一般的企业都会使用双网卡接入,这样既能添加网络带宽,同时又能做相应的冗余,可以说是好处多多.而一般企业都会使用linux操作系统下自带的网卡绑 ...
- Linux 双网卡绑定
Linux 双网卡绑定 Linux 双网卡绑定双网卡绑定的常用模式:mode1:active-backup 模式,即主备模式.mode0:round-broin 模式,即负载均衡模式(需要交换机配置聚 ...
- Windows Server 2008 双网卡同时上内外网 不能正常使用
Windows server 2008 32位下,双网卡同时上内外网,并提供VPN服务,遇见的奇怪问题 1.服务器配置 2.网络配置 以太网适配器 内部连接: 连接特定的 DNS 后缀 . . . . ...
- CentOS 7使用nmcli配置双网卡聚合
进入CentOS 7以后,网络方面变化比较大,例如eth0不见了,ifconfig不见了,其原因是网络服务全部都由NetworkManager管理了,下面记录下今天下午用nmcli配置的网卡聚合,网络 ...
- VirtualBox双网卡搭建Linux虚拟实验环境
VirtualBox中有如下几种网络连接方式: NAT(NAT到宿主机IP地址) NAT Network (NAT到宿主机所在的网段,即使用相同的网关和掩码) Bridged Adapter Inte ...
- ubuntu 双线双网卡双IP实现方式
昨天金桥机房上架了一台多玩的测试机,系统是ubuntu9.04 X64的系统,母机IBM X336机器.用户需求是双线,故采用一个网卡配置电信地址,另一个网卡配置联通地址,安装好系统后配置好IP发现联 ...
随机推荐
- base64编码与一般的ASCII码和二进制编码有什么不同?base64详解
在密码学实践中,经常会用到Base64编码.比如大名鼎鼎的密码学挑战题"Matasano Crypto Challenges"的第一集合的第一题,就是要求把一个Hex编码的字符串转 ...
- Ubuntu下RabbitVCS的安装和简单使用
最近需要在Ubuntu下玩一段时间,但是没找类似TortoiseSVN的熟悉点的Subversion工具,无意间发现了RabbitVCS,操作上非常nice,留爪. 下载 RabbitVCS Rabb ...
- 如何学习SLAM(超级全面)
如何学习SLAM(超级全面) 由于SLAM是一个错综复杂的研究领域,涉及到非常多的关键技术.这里先讲讲学习方法论,然后对一些关键性概念(包括SLAM.ROS.SLAM移动机器人)进行分析,最后给出典型 ...
- yolov8 框架自带模型体验页面
简介 YOLOv8 是 ultralytics 公司在 2023 年 1月 10 号开源的 YOLOv5 的下一个重大更新版本,目前支持图像分类.物体检测和实例分割任务. YOLOv8 是一个 SOT ...
- jmeter:结合while控制器实现性能测试
一.场景 1.导入时,导入操作的用户数比较少,但是单次导入的数据量较大 2.导入文件一共有三步操作,上传-验证-导入,执行完当前操作才可以执行下一步操作. 2.导入时,即使导入数据量较大,导入操作需要 ...
- html中的em和rem到底该如何使用,自适应效果中如何确定文字大小/字号?
如今手机屏幕繁多,自适应效果中如何确定文字大小/字号? em rem vm vw vh你都了解吗? 先说说em和rem em:继承父级的,假设html的font-size默认为16px,body字体大 ...
- WebSocket连接
启动类增加注解并进行Bean注入 @EnableWebSocket @Bean public ServerEndpointExporter serverEndpointExporter() { ret ...
- [设计模式/Java] 设计模式之解释器模式【27】
概述:解释器模式 := Interpreter Pattern ∈ 行为型模式 模式定义 解释器模式(Interpreter Pattern)提供了评估语言的语法或表达式的方式 属于行为型模式. 解释 ...
- 【SQL周周练】一句 SQL 如何帮助 5 个人买到电影院最好的座位?
大家好,我是"蒋点数分",多年以来一直从事数据分析工作.从今天开始,与大家持续分享关于数据分析的学习内容. 本文是第 3 篇,也是[SQL 周周练]系列的第 3 篇.该系列是挑选或 ...
- 【经验】Git|Linux终端git太慢,改hosts、复制文件夹、用镜像源?不不不不不
有个同学问我Linux下想要克隆一个仓库怎么办,并给我发了一个word,记录了他的操作.看完之后我的血压都上来了,遂记之. 下文分成两种情况,克隆一两个仓库,和克隆一大堆仓库. 文章目录 一. ...