前言
随着产品线的不断发展,公司的产品越来越多,为了提升产品的竞争力,在使用 SIP 协议实现通话,本着普及 SIP 知识点出发,编写此文。
概述
1. SIP 简述
SIP(Session Initiation Protocol),中文翻译为 会话初始协议,它是一种应用层协议,用于在IP网络中建立、修改和终止多媒体会话。这些会话包括但不限于语音通话、视频通话、即时消息传递和在线游戏等。SIP协议由IETF(Internet Engineering Task Force)制定,主要用于实时通信服务。
SIP 采用了基于文本的格式,消息使用类似HTTP的请求-响应模式进行传输。它使用URL(Uniform Resource Locator)来标识会话参与者,可以包含用户的电话号码、IP地址或其他标识符。SIP还支持用户身份验证和安全性,通过使用TLS(Transport Layer Security)和S/MIME(Secure/Multipurpose Internet Mail Extensions)等协议提供通信的保密性和完整性。
2. SIP 请求
SIP 还是一个对等的协议,类似于 P2P ,不像传统电话那样必须有一个中心的交换机,它可以在不需要服务器的情况下进行通信,只要通信双方都彼此知道对方地址(或者,只有发起 SIP 通话方知道 SIP 接收方地址)。
例如:A 的 IP 地址是 172.16.27.10,端口是 6000,B 的 IP 地址是 172.16.27.11,端口是 6000。当 A 呼叫 B 时,他只需要直接呼叫 B 的 SIP 地址:sip:A@172.16.27.11:6000,反过来 B 呼叫 A 时,只需要呼叫 A 的 SIP 地址:sip:B@172.16.27.10:6000。
下面是 A 呼叫 B 的完整流程:
A B
| |
| INVITE | -----------------> 发起 INVITE 请求
|--------------------> |
| 100 Trying | -----------------> 请求正在处理中
|<-------------------- |
| 180 Ringing | -----------------> 被呼叫方设备开始响铃
|<-------------------- |
| 200 OK | -----------------> 表示会话已建立
|<-------------------- |
| ACK | -----------------> 确认会话建立
|--------------------> |
| |
|<---RTP------------> |
|<---RTP------------> | -----------------> 通过 RTP 传输音频数据
|<---RTP------------> |
| ... |
| |
| BYE | -----------------> 双方都可以发送 BYE 以终止会话
|<-------------------> |
| 200 OK | -----------------> 确认会话终止
|--------------------> |
| |
2.1. INVITE 请求结构
上文中,我们举了 A 呼叫 B 的例子,A 与 B 发起通话时,会发起 INVITE 请求,在这个请求里携带了 INVITE 的请求结构,完整的请求结构包含了请求行、消息头、消息体三个部分,以下是 INVITE 请求示例:
INVITE sip:172.16.27.11:6000 SIP/2.0
Via: SIP/2.0/UDP 172.16.27.10:6000;branch=z9hG4bK776asdhds
Max-Forwards: 70
From: sip:172.16.27.10:6000;tag=1928301774
To: sip:172.16.27.11
Call-ID: a84b4c76e66710@pc33.example.com
CSeq: 314159 INVITE
Allow:INVITE, ACK, OPTIONS, CANCEL, BYE, REFER, INFO, NOTIFY, MESSAGE, SUBSCRIBE
Contact: sip:alice@pc33.example.com
Content-Type: application/sdp
Content-Length: 142
v=0
o=alice 2890844526 2890844526 IN IP4 pc33.example.com
s=Session SDP
c=IN IP4 172.16.27.10
t=0 0
m=audio 49170 RTP/AVP 0
a=rtpmap:0 PCMU/8000
2.1.1. 请求头
INVITE sip:172.16.27.11:6000 SIP/2.0
INVITE:请求方法,表示发起一个会话。
sip: 172.16.27.11:6000:请求URI,表示被呼叫方的SIP地址。
SIP/2.0:SIP 协议版本。
2.1.2. 消息头
Via: SIP/2.0/UDP 172.16.27.10:6000;branch=z9hG4bK776asdhds
Via:指明请求经过的路径和发送者的消息。
branch:标识请求(唯一)。
Max-Forwards: 70
Max-Forwards: 限制请求经过的最大跳数,防止循环。
From: sip:172.16.27.10:6000;tag=1928301774
To: sip:172.16.27.11
Form:呼叫方的 SIP 地址。
tag:区分不同的会话。
To:被呼叫方的 SIP 地址。
Call-ID: a84b4c76e66710@pc33.example.com
CSeq: 314159 INVITE
Allow:INVITE, ACK, OPTIONS, CANCEL, BYE, REFER, INFO, NOTIFY, MESSAGE, SUBSCRIBE
Contact: sip:alice@pc33.example.com
Content-Type: application/sdp
Content-Length: 142
Call-ID:会话的唯一标识符。
CSeq:序列号和请求方法,用于排序和匹配请求和响应。
Allow:发送方支持的SIP请求方法。
Contact:提供可以联系到主叫方的地址。
Content-Type:描述消息体的媒体类型。
Content-Length:消息体的长度,以字节为单位。
2.1.3. 消息体
SIP 请求的消息体,是由 SDP(Session Description Protocol,会话描述协议)组成的,通常位于 SIP 请求中空行后面的文本。SDP 是一种格式,用于描述多媒体通信会话的信息,以便参与者可以了解会话的细节。
v=0
o=alice 2890844526 2890844526 IN IP4 172.16.27.10
s=Session SDP
t=0 0
c=IN IP4 172.16.27.10
m=audio 49170 RTP/AVP 0
a=sendrecv
v=:SDP版本。
o=:会话创建者和会话的 ID。
s=:会话名称。
t=:会话的起始和结束时间。
c=:会话的连接信息。
m=:媒体描述。
a=:会话属性,表示接收模式。SIP 的接收属性有四种,分别是 sendrecv、recvonly、sendonly、inactive。具体的用途如下:
- sendrecv:是默认参数,表明终端既能发送也能接收媒体流。
- recvonly:表示该终端仅接收媒体,不发送任何媒体流。
- sendonly:表示该终端仅发送媒体,但不期望接收任何媒体流。
- inactive:表示该媒体流既不发送也不接收媒体。
3. 基于 SIP 协议的客户端方案
3.1. Linphone
目前最流行的 SIP 开源客户端,现如今做 SIP 的基本上都用他家的客户端做测试,或者直接集成 Linphone SDK 到自己的 App 上。
Linphone 支持 iOS、Android、Mac、Windows、Linux,既有 GUI 端,也有 Console 端,这也是很多人选择它的原因吧。
Linphone 的开源协议是 GNU GPLv3 ,你可以免费用源代码,但是改了它的代码你也要开源,当然它还有付费的服务。
Linphone 的核心是Liblinphone,底层是 C 语言写的,上层应用基于不同平台封装了不同的接口,比如桌面端有 C++封装接口,iOS 端是 Swift 封装接口,Android 是 Java 封装接口等。
Liblinphone 的核心组件有三个:
-
- Mediastreamer2:处理音视频,为了解决回音消除的问题,在 2013 年就整合了 WebRTC 的 AEC 算法。
- oRTP:RTP 库。
- belle-sip:早期使用的是 oSIP,后来 Linphone 自己重写了协议栈,取名 belle-sip。
官网链接:Linphone
3.2. PJSIP
PJSIP 是一个用 C 语言编写的免费开源多媒体通信库,可实现基于标准的协议,例如 SIP、SDP、RTP、STUN、TURN 和 ICE。它将信令协议 (SIP) 与丰富的多媒体框架和 NAT 遍历功能结合到高级 API 中,该 API 可移植且适用于从台式机、嵌入式系统到移动手机的几乎所有类型的系统。
PJSIP 既紧凑又功能丰富。它支持音频、视频、状态和即时消息,并具有丰富的文档。PJSIP 非常便携。在移动设备上,它抽象了系统相关的功能,并且在许多情况下能够利用设备原生的多媒体功能。
PJSIP 由一个自2005 年以来专门为该项目工作的小团队开发,有来自世界各地的数百名开发人员参与,并且自 2007 年以来在 SIP 互操作性事件(SIPit)上定期测试。
官网链接:PJSIP
4. SIP 与其它会话协议的比对
| / | SIP | H.323 | WebRTC |
|---|---|---|---|
| 协议制定者 | IETF | ITU-T | W3C、IETF |
| 目的 | 多媒体对话 | 多媒体对话 | 在Web浏览器和移动应用中提供简单、高效的实时通信能力,无需依赖任何插件或客户端安装 |
| 信令控制方式 | 请求 - 响应 | H.225 | 依赖于外部信令系统(如SIP、WebSocket、XMPP等) |
| 复杂度 | 简单 | 复杂 | 复杂 |
| 编码方式 | 文本 | 二进制 | 文本 |
| 媒体能力描述 | SDP | H.245 | SDP |
| 多媒体能力 | 支持 | 支持 | 支持 |
| 个人移动性 | 支持 | 部分支持 | 支持 |
| 支持终端 | 支持硬件 IP 电话、软件客户端 | 支持各种终端设备 | Chrome、Edge、Firefox、移动浏览器、原生App |
| 协议扩展性 | 优秀 | 一般 | 良好 |
| 协议兼容性 | 良好 | 优秀 | 良好 |
5. SIP 实现单向通话思路
5.1. 限制或阻止 RTP 双向流的输出
在上文中,我们提到了 SIP 的请求。在 SIP 完成连接后,通话双方会使用 RTP(Real-time Transport Protocol)协议来实时传输音频和视频等媒体数据。如果需要实现 A 呼叫 B,B 只能接收到 A 的 RTP 流,而 A 无法接收到 B 的 RTP 流的单向通话,在传输 RTP 流的时候可以通过关闭麦克风等手段限制其中一方的 RTP 流,以实现单向通话。
5.2. 修改 SIP 的 SDP 报文
SIP 的 SDP 报文,描述了 SIP 会话的详细信息,如媒体类型、格式、传输地址等。当使用 SIP 来建立通信会话时,SDP 报文通常作为 SIP 消息的一个组成部分被携带,以帮助通信双方协商媒体参数。在 SDP 报文中,使用了 a= 来表示 SIP 的会话属性,这个 a= 的会话属性默认为 sendrecv,将其改为 sendonly 即可实现单向发送音频。