VoNR(Voice over New Radio)作为5G SA架构下的原生语音方案,其语音承载在IMS(IP Multimedia Subsystem)之上,通过5G NR空口和5G Core传递。表面上看,VoNR不过是一通SIP电话,但与普通互联网VoIP相比,VoNR面临一个核心矛盾:应用层的SIP会话协商与网络层的QoS资源(专用QoS Flow)建立是两条并行、且时序不可预知的链路。
设想一个没有预条件机制的场景:主叫UE发出INVITE,被叫UE立刻振铃并摘机,200 OK(INVITE)返回,主叫开始说话——但此时主叫侧的专用GBR承载(5QI=1)可能尚未建立完成。结果就是:主叫听不到被叫的声音,被叫也收不到主叫的声音,通话"接通却单通"。
预条件(Precondition)机制正是为解决这一矛盾而生,其核心设计意图可归纳为三点:
这套机制定义在RFC 3312(Integration of Resource Management and SIP),并由3GPP TS 24.229(IP Multimedia Call Control Protocol based on SIP and SDP)针对移动场景做了严格的程序性约束。在TS 24.229 V18.8.0中,主叫侧过程定义于5.1.2.3节(Originating mobile procedures),初始INVITE的处理规则定义于5.1.4.1节,被叫侧过程定义于5.1.2.4节。
预条件机制的全部信息都编码在SDP(Session Description Protocol)的属性行中。RFC 3312定义了三类核心属性,它们共同构成了一套"资源预留状态机"。
| 属性 | 语法 | 语义 | 典型取值 |
|---|---|---|---|
| 当前状态 | a=curr:qos <direction> <status> |
本端"此刻"观测到的QoS状态 | direction: local/remote/e2e;status: none/sendrecv/send/recv |
| 期望状态 | a=des:qos <strength> <direction> <status> |
本端"要求"达到的QoS门限 | strength: mandatory/optional;其余同上 |
| 确认请求 | a=conf:qos <direction> <status> |
请求对端在本端资源就绪后回送确认 | direction: local/remote;status: sendrecv等 |
这里有两个极易混淆的概念必须厘清:
a=curr:qos local sendrecv,这里的"local"指的是UE-A自己的资源;当该SDP到达UE-B时,UE-B眼中的"local"变成了它自己。RFC 3312原文明确:"the tags 'local' and 'remote' represent the point of view of the entity composing the SDP"。也就是说,每经过一次Offer/Answer交换,local/remote的视角都要在两端之间对换理解。这是抓包排错时最容易看错的地方。a=des:qos中的strength字段决定了资源预留未满足时的行为:
VoNR的标准部署中,主被叫双方均采用mandatory local sendrecv+mandatory remote sendrecv的双向强制预条件,这是呼叫建立时序可控的根本保证。
预条件属性遵循RFC 3264的Offer/Answer规则:Offer方提出一组curr/des/conf组合,Answer方必须给出对应的curr/des回应,并可以新增或修改自己的des要求。一个合法的Offer/Answer交换,其des条件不能在会话中途被无端撤销(除非通过后续UPDATE显式协商)。
flowchart TD
subgraph OFFER["SDP Offer (UE-A → UE-B)"]
A1["a=curr:qos local none<br/>a=curr:qos remote none"]
A2["a=des:qos mandatory local sendrecv<br/>a=des:qos mandatory remote sendrecv"]
A3["a=conf:qos remote sendrecv"]
end
subgraph ANSWER["SDP Answer (UE-B → UE-A)"]
B1["a=curr:qos local sendrecv<br/>a=curr:qos remote none"]
B2["a=des:qos mandatory local sendrecv<br/>a=des:qos mandatory remote sendrecv"]
end
OFFER -->|RFC3264 Answer| ANSWER
style OFFER fill:#eef,stroke:#336
style ANSWER fill:#efe,stroke:#363
上图揭示了一次完整的初始Offer/Answer:主叫UE-A在INVITE中声明自己当前local none(资源未建)、remote none(不知对端状态),并要求双向都达到mandatory sendrecv;被叫UE-B在183中回应当前自己local sendrecv(本端资源已就绪)、remote none(确认主叫侧尚未就绪)。注意UE-B回答里"remote"指的就是UE-A——这正是前文强调的视角对换。
下图给出了一个标准的VoNR主叫(MO)会话建立全链路,融合了IMS域的SIP信令与5G Core的专用QoS Flow(5QI=1)建立过程。这是VoNR区别于纯IMS VoIP的关键所在。
sequenceDiagram
participant UA as UE-A (主叫)
participant PCSCFA as P-CSCF-A
participant SCSCFA as S-CSCF-A
participant SCSCFB as S-CSCF-B
participant PCSCFB as P-CSCF-B
participant UB as UE-B (被叫)
participant PCF as PCF/SMF (5GC)
Note over UA,UB: 阶段一:初始Offer,声明QoS未就绪
UA->>PCSCFA: INVITE (SDP Offer1)<br/>Require: precondition,100rel<br/>curr local none / curr remote none<br/>des mandatory local/remote sendrecv
PCSCFA->>PCF: AAR (Rx/N5) 请求专载
PCF-->>PCSCFA: AAA (GBR 5QI=1 决策)
PCSCFA->>SCSCFA: INVITE (转发Offer1)
SCSCFA->>SCSCFB: INVITE
SCSCFB->>PCSCFB: INVITE
PCSCFB->>UB: INVITE
Note over UB: 被叫建本地专载
UB->>PCF: 触发PDU会话修改建立5QI=1
PCF-->>UB: 专用QoS Flow就绪
Note over UA,UB: 阶段二:可靠临时响应,回送Answer1
UB->>PCSCFB: 183 Session Progress (SDP Answer1)<br/>Require:100rel<br/>curr local sendrecv / curr remote none
PCSCFB->>SCSCFB: 183
SCSCFB->>SCSCFA: 183
SCSCFA->>PCSCFA: 183
PCSCFA->>UA: 183 (触发主叫侧专载建立)
Note over UA: 主叫建本地专载
UA->>PCF: PDU会话修改建立5QI=1
PCF-->>UA: 专用QoS Flow就绪
Note over UA,UB: 阶段三:PRACK确认183并更新主叫资源状态
UA->>UB: PRACK (SDP Offer2)<br/>curr local sendrecv / curr remote sendrecv
UB->>UA: 200 OK (PRACK)(SDP Answer2)<br/>双向 curr sendrecv 全满足
Note over UA,UB: 阶段四:预条件满足,振铃与摘机
UB->>UA: 180 Ringing
Note right of UB: 被叫振铃(此时预条件已满足)
UB->>UA: 200 OK (INVITE)
Note right of UB: 被叫摘机
UA->>UB: ACK
Note over UA,UB: 双向RTP/EVS媒体流开始
这条时序链的精妙之处在于四个阶段的严格分工,下文逐一拆解每个关键消息的IE(Information Element)。
主叫UE-A发出的初始INVITE是整个流程的基石。其SIP头与SDP体包含如下关键IE:
| 位置 | IE/参数 | 典型取值 | 作用 |
|---|---|---|---|
| SIP头 | Require | precondition, 100rel | 强制要求对端支持预条件与可靠临时响应(RFC 4028) |
| SIP头 | P-Preferred-Identity | sip:[email protected] | 主叫偏好身份 |
| SDP | m=audio | 50000 RTP/AVP 96 97 | 媒体行,端口与PayloadType列表 |
| SDP | a=rtpmap | 96 EVS/16000, 97 AMR-WB/16000 | 编解码能力列表(EVS为VoNR优选) |
| SDP | a=curr:qos | local none / remote none | 声明两端资源当前均未建立 |
| SDP | a=des:qos | mandatory local sendrecv / mandatory remote sendrecv | 要求双向均强制满足 |
| SDP | a=conf:qos | remote sendrecv | 请求对端在自己资源就绪后确认 |
这里有两个设计要点:第一,Require: 100rel是预条件生效的前提——因为183 Session Progress这种携带SDP Answer的临时响应必须可靠传输,否则主叫无法保证收到被叫的资源状态更新。第二,初始Offer中curr全部为none,是诚实声明;若主叫谎报local sendrecv,将破坏后续门控逻辑,这是协议合规性的红线。
INVITE到达P-CSCF后,触发5G Core侧的专用承载建立,这是VoNR区别于普通VoIP的物理层保障:
这一串交互对应了"主叫local资源从none变为sendrecv"的物理过程。P-CSCF在此扮演了IMS与5GC之间的策略桥梁角色,这是5G IMS架构中P-CSCF比VoLTE时代更重要的原因之一。
被叫UE-B在本地专载建立完成后,回送183并携带SDP Answer1。关键IE:
| IE | 取值 | 语义 |
|---|---|---|
| Require | 100rel | 强制可靠传输,要求主叫回PRACK |
| a=curr:qos | local sendrecv | 被叫本端资源已就绪(视角:被叫) |
| a=curr:qos | remote none | 被叫认为主叫侧资源未就绪 |
| a=des:qos | mandatory local/remote sendrecv | 维持双向强制要求 |
注意:UE-B此刻回送的是临时响应(1xx类),按SIP默认规则临时响应是不可靠的,会丢包。正因为携带了关键的SDP Answer,所以必须配合100rel机制让主叫用PRACK显式确认收到。这一步的可靠性保障,是预条件流程正确性的工程基础。
主叫在收到183并完成本地专载建立后,发出PRACK,其SDP Offer2更新主叫的资源状态:
a=curr:qos local sendrecv ; 主叫本端已就绪
a=curr:qos remote sendrecv ; 主叫确认被叫也已就绪(从183得知)
a=des:qos mandatory local sendrecv
a=des:qos mandatory remote sendrecv
被叫以200 OK(PRACK)回应,其SDP Answer2同样声明双向curr sendrecv。到这一刻,双向的mandatory预条件全部满足——这正是后续振铃与摘机的"放行信号"。PRACK/200(PRACK)这一对消息完成了Offer2/Answer2的二次协商,是预条件状态收敛的关键握手。
由于mandatory预条件已在PRACK阶段满足,被叫振铃(180)、摘机(200 OK)、主叫确认(ACK)即可顺利推进。整个媒体面(RTP/EVS)在ACK之后正式双向打通。反过来说,若任一方资源迟迟未就绪,180/200就永远不会发出,呼叫会在定时器超时后被BYE挂断。
预条件机制本质上是一台在两端各自运行的资源预留状态机。下图以主叫UE-A的视角刻画状态迁移:
stateDiagram-v2
[*] --> QosNone: 发出INVITE<br/>curr local none
QosNone --> QosHalf: 收到183<br/>已知被叫local sendrecv<br/>但自身专载未建
QosHalf --> QosReady: 本地专载(5QI=1)建立<br/>PRACK更新 curr local sendrecv
QosReady --> AllMet: 收到200(PRACK)<br/>确认被叫也确认双向就绪
AllMet --> Ringing: 预条件全满足<br/>允许180/200放行
QosReady --> Failed: 定时器超时<br/>资源仍none→BYE挂断
Ringing --> [*]: 通话建立
Failed --> [*]: 呼叫释放
被叫UE-B运行一台镜像状态机,区别仅在于它要先等自己的本地专载建好才发183,再等PRACK确认主叫就绪后才振铃。两台状态机通过Offer/Answer交换相互驱动,最终在"AllMet"状态同步收敛,这正是预条件机制"门控振铃"的形式化体现。
理解一个机制的最佳方式往往是对比。下表将预条件方案与无预条件(早期VoIP式)方案并置:
| 维度 | 有Precondition(VoNR/VoLTE标准) | 无Precondition(普通VoIP/软交换) |
|---|---|---|
| 振铃门控 | 强制,双向QoS满足才振铃 | 无门控,被叫随时振铃 |
| 单通风险 | 极低,资源先于通话就绪 | 高,常出现接通无声 |
| 信令开销 | 大,多出183/PRACK/UPDATE若干交互 | 小,INVITE/200/ACK三步走 |
| 呼叫建立时延 | 较长(受专载建立影响) | 短,但不保证质量 |
| 可靠临时响应 | 必须(100rel) | 可选 |
| 适用场景 | 移动网保证带宽语音 | 互联网尽力而为通话 |
| 故障定位 | SDP的curr/des可逐跳追踪 | 难,需端到端抓包 |
这张表也回答了一个常见疑问:"为什么VoNR通话接通比微信语音慢?"——因为VoNR为每一通电话都付出了建立专用GBR承载+多次SDP协商的代价,换来的是运营商级的通话质量保证。
在IMS信令面抓包中,可按以下特征快速定位VoNR预条件流程:
sip 或 sip.Method == "INVITE";a=des:qos与a=curr:qos,以及Require头中的precondition、100rel;PDU Session Resource Setup,在PFCP面观察5QI=1的GBR Flow建立;| 症状 | 可能根因 | 排查方向 |
|---|---|---|
| 被叫不振铃 | 主叫侧5QI=1专载建立失败,curr remote一直为none |
查P-CSCF AAR/PCF策略/SMF PDU会话修改/NGAP拒绝原因 |
| 接通后单通 | 双向预条件未真正满足就强行放行(某端违规) | 比对PRACK/200(PRACK)的curr是否真为sendrecv |
| 183不返回 | 被叫本地专载超时或编解码无交集 | 查被叫UE专载日志/INVITE与183编解码列表 |
| 呼叫几十秒后BYE | 预条件定时器超时(典型约30s级) | 查资源预留哪一端卡住,定位gNB/UPF |
| SDP协商失败 | Offer/Answer的des条件被中途撤销 | 检查UPDATE是否合规修改了des |
| ## 八、常见问题 |
Q: Precondition机制和100rel(可靠临时响应)是什么关系?为什么总是一起出现?
A: 预条件依赖在临时响应(如183 Session Progress)中携带SDP Answer来同步资源状态。但SIP默认临时响应不可靠、会丢包。100rel(RFC 4028)机制让主叫用PRACK显式确认收到临时响应,从而保证这些携带关键SDP的临时响应可靠送达。因此Require: precondition, 100rel总是成对出现——预条件提供状态语义,100rel提供传输可靠性,二者缺一不可。
Q: local和remote到底指谁?为什么抓包里看着是反的?
A: local/remote是"SDP撰写者"的视角。UE-A写的local是UE-A自己的资源,但这份SDP到达UE-B后,UE-B要把它理解成"远端(对UE-B而言是remote)"。所以当UE-A声明curr remote none,UE-B看到的是"我自己(UE-B)的资源状态为none"——这正是UE-B尚未建专载时主叫的合理推测。理解了视角对换,抓包就不会看反。
Q: 为什么VoNR不用早期媒体(Early Media)直接放回铃音,而要走这么复杂的预条件? A: 早期媒体(RFC 3960/P-Early-Media)解决的是"通话前播放彩铃/通知音"的问题,与预条件解决的是不同维度的问题——前者是媒体内容,后者是资源就绪门控。VoNR可以同时使用两者:用预条件保证QoS就绪,用早期媒体在振铃阶段播放彩铃。二者并不冲突,预条件是基础保障,早期媒体是体验增强。
Q: 如果网络不支持预条件,VoNR还能打电话吗? A: 严格按TS 24.229程序,VoNR终端应支持预条件框架;运营商可在网络侧配置是否强制。若关闭预条件(非标准部署),呼叫会更快接通但丧失单通防护,质量无法保证。工程上不建议关闭。当VoNR不可用时(如NR覆盖不足或终端/网络不支持),网络会触发EPS Fallback回落到VoLTE,此时切换到4G承载继续IMS语音——这是另一个独立的信令话题。
Q: PRACK里带的Offer2和后续可能的UPDATE带的Offer有什么区别? A: PRACK携带的Offer2主要用于"确认183并更新资源状态",是预条件状态收敛的一次性握手;而UPDATE是会话建立过程中或建立后主动修改会话参数(如改编解码、QoS状态再次变化)的独立方法。二者都遵循Offer/Answer模型,但触发时机不同:PRACK绑定在确认临时响应上,UPDATE是独立的会话更新请求。两者都需满足RFC 3312的状态一致性约束。
本文由「51学通信」技术团队出品。51学通信由通信行业18年老兵爱卫生(微信ID: gprshome201101)维护,聚焦5G/6G核心网、3GPP标准解读、通信前沿技术深度分析。 出版作品有《5G核心网原理与实践》《IMS原理与实践》等4本通信专业书籍。知识星球「51学通信」提供深度技术答疑和行业洞察。
[!tip] 51学通信知识星球 星主:爱卫生(微信:gprshome201101)——公众号「51学通信」创办者,19 年通信行业运维与讲师经验,著有《GPRS网络信令实例详解》《EPC原理与实践》《5G核心网原理与实践》三本纸质书(各大电商平台有售)。 星球定位:深耕 5G 核心网、IMS、NFV/AI、云原生等 ICT 领域,主打运维岗位与信令分析。 当前规模:5200 篇主题 / 990 个回答,198 元/年。 加入福利:加入星球后请加爱卫生微信,拉您进知识星球年度陪伴与答疑群——不限量回复您的各种问题,另有群内分享。 AI 加持:51学通信知识星球已作为 skill 接入 WorkBuddy,使用 deepseek-4-flash 在海量星球帖子中精准找贴、找视频、找 FAQ 和案例,做总结、找文档和 PPT 等场景全覆盖。
