<!-- title: IMS会话修改机制拆解 -->
<!-- domain: ims -->

# IMS 中呼叫会话修改 Re-INVITE 机制全链拆解（基于 TS 24.229 Rel-19）

## 一、机制定位：为什么 IMS 需要 Re-INVITE

在 IMS/VoNR 体系中，一次成功的 `INVITE` 会在主被叫 UE 之间建立一条 SIP 对话（Dialog）。这条对话由三元组 `(Call-ID, From-tag, To-tag)` 唯一标识，并伴随一套已协商好的媒体参数（SDP offer/answer 结果）。然而通话一旦建立，业务远未结束：用户按"保持键"挂起对端、从纯语音升级到音视频通话、网络侧因会话定时器到期需要刷新、或者无线侧因编解码不匹配需要重协商——所有这些"在不拆掉现有对话的前提下、修改正在进行的会话参数"的操作，都依赖同一个核心信令：**Re-INVITE**。

Re-INVITE 并非一个新的方法（Method），它就是普通的 `INVITE`，只不过它被发送在**一个已经存在的 Dialog 之内**。3GPP 在 **TS 24.229《IP multimedia call control protocol based on SIP and SDP; Stage 3》** 中专门用 **Section 6.1.4 "Session modification"** 一整节来规范它的行为，下设三个子句：

- **6.1.4.1 General** —— 会话修改的总体原则
- **6.1.4.2 Generating session modification request** —— UE 作为发起方如何构造请求
- **6.1.4.3 Receiving session modification request** —— UE 作为接收方如何处理

Re-INVITE 的本质可以用一句话概括：**复用既有 Dialog 的路由集合与对话标识，递增 `CSeq`，携带一份新的 SDP offer，触发一次完整的 offer/answer 重协商**。它是 IMS 补充业务（Call Hold、Call Resume、Call Upgrade/Downgrade）、Session Timer 保活、动态 QoS 重协商统一承载的信令底座。理解它，就理解了 IMS 通话"建立之后"的全部动态行为。

## 二、核心概念：Dialog 复用与 Offer/Answer 重协商

Re-INVITE 之所以"轻量"，关键在于它**复用了初次 INVITE 谈成的全部对话上下文**。具体表现为四个不变与一个必变：

1. **Call-ID 不变**：同一次对话，标识符不变。
2. **From/To-tag 不变**：对话双方的身份标签沿用。
3. **Route 集合不变**：仍按 `Route` 头里记录的 P-CSCF/S-CSCF 链路转发，无需重新做 DNS 解析与服务路由发现。
4. **P-Asserted-Identity / P-Charging-Vector 不变**：尤其 **ICID（IMS Charging Identifier）** 沿用原对话，这意味着会话修改在计费上属于"同一计费会话的参数变更"，而非新建计费事件。
5. **CSeq 必须递增**：这是 SIP 协议的硬性要求（RFC 3261 Section 12.2.2）。`CSeq` 的序号部分必须严格单调递增，方法名保持 `INVITE`。任何对端收到 `CSeq` 不大于已处理序号的 re-INVITE，都会回 `500 Server Internal Error` 或直接丢弃。

SDP offer/answer 模型（RFC 3264）在 Re-INVITE 中有一个极易被忽视的规则：**新的 offer 必须完整描述整个会话，而不是只描述变化的部分**。也就是说，即便你只想新增一条视频流，offer 里仍要包含原有的音频 `m=` 行。这支持无状态代理（stateless proxy）转发和错误恢复。此外，offer 的提供方可以是任意一侧——既可由主叫侧（原 UAC）发起，也可由被叫侧（原 UAS）通过发送一个**不带 SDP 的 re-INVITE** 来反向请求对端给出新 offer。

## 三、完整信令时序图（主叫发起呼叫保持场景）

下面以**主叫 UE-A 将被叫 UE-B 置于保持（Call Hold）** 为例，画出 Re-INVITE 穿越整个 IMS 核心网的完整信令链。该流程严格遵循 TS 24.229 第 5.7 节（主叫侧）与第 6.2/6.3 节（P-CSCF/S-CSCF）的处理规则：

```mermaid
sequenceDiagram
    autonumber
    participant UEa as 主叫 UE-A
    participant PCSCFa as P-CSCF-A
    participant SCSCFa as S-CSCF-A
    participant AS as TAS / AS
    participant SCSCFb as S-CSCF-B
    participant PCSCFb as P-CSCF-B
    participant UEb as 被叫 UE-B
    Note over UEa,UEb: 已建立 VoNR 会话,处于 Confirmed 状态
    UEa->>PCSCFa: INVITE(re-INVITE) CSeq+1, SDP offer(a=sendonly)
    Note right of PCSCFa: 6.2:SDP 授权校验<br/>Rx 更新 QoS(5QI=1 方向)
    PCSCFa->>SCSCFa: INVITE(re-INVITE)
    SCSCFa->>AS: INVITE(命中 iFC,触发 Hold 补充业务)
    AS-->>SCSCFa: INVITE(透传/放音指示)
    SCSCFa->>SCSCFb: INVITE
    SCSCFb->>PCSCFb: INVITE
    PCSCFb->>UEb: INVITE(re-INVITE) a=sendonly
    Note left of UEb: 6.1.4.3:接收 offer<br/>本地媒体方向置为 recvonly
    UEb-->>PCSCFb: 200 OK (SDP answer a=recvonly)
    PCSCFb-->>SCSCFb: 200 OK
    SCSCFb-->>SCSCFa: 200 OK
    SCSCFa-->>PCSCFa: 200 OK
    Note right of PCSCFa: 确认 Rx 资源<br/>charging 透传 ICID
    PCSCFa-->>UEa: 200 OK
    UEa-->>UEb: ACK(端到端,完成事务)
    Note over UEa,UEb: 对话存活,媒体变为单向(UEa 停发只收)
```

**关键设计意图**说明：

- **第 2、8 步**展示了 P-CSCF 的核心职责。P-CSCF 在 SIP 层是"信令代理"，但在策略层是"门禁"。它会解析 re-INVITE 中的新 SDP，判断媒体流方向、带宽、编解码是否变化，并通过 **Rx 参考点**与 PCF 交互；PCF 再经 Npcf/N7 接口驱动 SMF 调整 5GC 侧的 QoS Flow（5G）或专用承载。对于 Call Hold 这种"不改变 QoS 需求、只改变方向"的场景，Rx 交互通常很轻量；但若涉及新增媒体流（如加视频，5QI=2），则必须重新走完整的 QoS 授权。
- **第 5 步**经过 TAS/AS：Re-INVITE 会命中 S-CSCF 上该用户签约的 **iFC（initial Filter Criteria）**，被触发到 TAS。对于 Hold 这种**补充业务**，TS 24.173 规范了 TAS 可在保持期间插入保持音（MOH）。这也解释了为什么 Hold 不是纯 UE 行为，而是需要网络侧协同的"业务"。
- **会话定时器刷新**走的是完全相同的信令链路，只是 SDP offer 中媒体参数不变、仅刷新 `Session-Expires`。

## 四、SDP Offer 的 IE 结构与方向语义

Re-INVITE 携带的 SDP offer 是整个机制的"数据载荷"。以 Call Hold 为例，UE-A 发出的 offer 关键 IE 如下：

```
INVITE sip:user_b@ims.mnc.mcc.3gppnetwork.org SIP/2.0
Via: SIP/2.0/UDP [UEa_IP]:PORT;branch=z9hG4bK...new
Route: <sip:pcscf_a;lr>, <sip:scscf_a;lr>
Call-ID: a1b2c3d4@uea  (与原会话相同)
From: <sip:user_a...>;tag=7777  (与原会话相同)
To:   <sip:user_b...>;tag=8888  (与原会话相同)
CSeq: 3 INVITE                      (递增: 原 CSeq=2)
Session-Expires: 1800;refresher=uac (会话定时器)
Require: 100rel, precondition
Content-Type: application/sdp

v=0
o=- 2890844526 2890844527 IN IP4 UEa_IP   (version号必须递增)
c=IN IP4 UEa_IP
m=audio 49170 RTP/AVP 96 97             (媒体行不变)
a=curr:qos local sendrecv               (当前本地QoS已满足)
a=curr:qos remote sendrecv              (当前远端QoS已满足)
a=des:qos mandatory local sendrecv
a=des:qos mandatory remote sendrecv
a=sendonly                              (★保持:方向改为只发不收)
a=rtpmap:96 EVS/...
```

被叫侧的 answer 关键差异仅在 `a=recvonly`（被叫只能收不能发，配合主叫只发不收，于是双向媒体实际停摆），形成"伪单工"。下表归纳 IMS 中常用的媒体方向语义：

| SDP 方向属性 | 主叫侧语义 | 被叫侧应答 | 典型业务场景 |
|---|---|---|---|
| `a=sendrecv` | 双向收发 | `a=sendrecv` | 正常通话/Resume |
| `a=sendonly` | 只发不收 | `a=recvonly` | **Call Hold**（RFC 6337 推荐） |
| `a=recvonly` | 只收不发 | `a=sendonly` | 监听/会议旁听 |
| `a=inactive` | 既不发也不收 | `a=inactive` | 全媒体挂起/双向保持 |
| `c=IN IP4 0.0.0.0` | 连接地址无效 | 任意 | **Legacy Hold**（RFC 2543，已弃用） |

> **设计要点**：RFC 6337 明确弃用了 `c=0.0.0.0` 这种"用非法地址表示保持"的老做法，推荐用 `a=sendonly`/`a=inactive`。但在现网抓包中，仍能见到某些老 SBC/终端混用 `c=0.0.0.0`。若主叫发 `c=0.0.0.0` 而被叫按现代规范回 `a=recvonly`，会导致 RTP 流向一个不存在的地址，表现为"保持后仍有单向杂音"。

## 五、Precondition（资源预留前提）的处理逻辑

TS 24.229 6.1.4.2 给出了一段非常关键、却又容易被误读的 precondition 处理规则，可以用下面的决策流精确还原：

```mermaid
flowchart TD
    S[re-INVITE 会话修改请求] --> Q1{是否使用\nprecondition 机制?}
    Q1 -- 否 --> O1[SDP 无 QoS 状态属性\n直接 offer/answer]
    Q1 -- 是 --> Q2{QoS 需求是否增加?\n新增媒体流/更高带宽编解码}
    Q2 -- 否<br/>如:呼叫保持 --> M1[local 与 remote 的 QoS\n均标记为 met 已满足]
    Q2 -- 是<br/>如:呼叫升级加视频 --> M2[按 6.1.2 初始流程\n本地 curr=none, des=mandatory]
    M1 --> OUT[发送 re-INVITE/UPDATE/PRACK]
    M2 --> PRE[触发 183 + PRACK + UPDATE\n等待 QoS 确认]
    PRE --> OUT
    O1 --> OUT
    OUT --> FAIL{网络资源修改/预留失败?}
    FAIL -- 是 --> CAN[发送 CANCEL 终止本次修改]
    FAIL -- 否 --> DONE[200 OK + ACK, 完成]
```

这段逻辑的精髓在于区分两类修改：

- **不抬升 QoS 的修改**（如 Call Hold、纯音频下的 Call Hold/Resume）：因为对空口和传输资源的需求没有增加（甚至减少），所以 offer 里把 `local` 和 `remote` 的当前 QoS 都直接标记为 `met`（已满足）。这意味着不需要再等待任何资源预留确认，对端收到后可以直接回 200 OK，**整个修改一步到位**，信令开销最小。
- **抬升 QoS 的修改**（如更换为更高带宽的 EVS 编解码、Call Upgrade 新增视频流）：必须回到 6.1.2（初始会话建立）的处理模式，即本地当前状态写 `none`、期望状态写 `mandatory`，从而触发标准的 `183 → PRACK → 资源确认 → UPDATE → 200` 完整交互链。这是因为新媒体流需要重新建立专用 QoS Flow/承载，必须等资源真正就绪后才能宣称"已满足"。

最后一道保险：**如果网络侧资源修改或预留失败，UE 必须（shall）发送 `CANCEL` 来终止本次会话修改**，回退到原会话参数，而不是把会话搞挂。这是 IMS 容错设计的体现。

## 六、Glare 冲突与 491 Request Pending 处理

Re-INVITE 引出了一个 SIP 特有的竞态问题——**Glare（眩光冲突）**。当主被叫两侧在几乎同一时刻各自发出一个 re-INVITE（或 re-INVITE 与 UPDATE），且对方尚未收到本端的请求时，双方就陷入了"各自有一个 pending 的 INVITE 事务、又各收到对端一个 INVITE"的僵局。SIP 不允许在同一个 Dialog 内同时存在两个 pending 的 INVITE 事务（会话状态机无法确定以谁的 offer 为准）。

RFC 3261 Section 14.2 规定：当 UAS 收到一个 INVITE 请求，而该 Dialog 内已有一个 INVITE 客户端事务处于 Proceeding/Completed 状态时，UAS 必须（MUST）回 **`491 Request Pending`**。冲突化解靠的是**随机回退（Randomized Backoff）**：

```mermaid
flowchart TD
    A[UE-A 发送 re-INVITE-A] --> B{对端是否已有\npending INVITE 事务?}
    B -- 否 --> C[正常处理: 183/200]
    B -- 是 --> D[返回 491 Request Pending]
    D --> E[随机回退 2.1 ~ 4 秒]
    E --> F[重新发送 re-INVITE-A']
    C --> G[200 OK + ACK 会话更新]
    F --> C
```

随机区间 **2.1s–4s** 的设计非常巧妙：它避免了两侧退避相同时间后再次同时重发、再次冲突的死循环。由于双方退避时间不同，几乎必然会错开重发窗口。需要强调的是，在 3GPP IMS 中，S-CSCF/P-CSCF 作为有状态代理（stateful proxy），会忠实地把 491 透传回原发方，**不会**自己吞掉或改写——这也是为什么 Glare 问题在端到端抓包中清晰可见。

实务中 Glare 高发于两种场景：一是 Session Timer 到期时两侧同时刷新；二是补充业务（如 Call Hold）与网络侧主动发起的媒体重协商撞车。优秀的 IMS 终端实现会在收到 491 后严格按随机退避重试，而劣质实现可能直接放弃，表现为"保持操作偶发失败"。

## 七、会话状态机视角

从协议状态机的角度看，Re-INVITE 让会话在 `Confirmed`（已确认）与 `Modifying`（修改中）状态间往返。下图标出了所有合法转移，包括 precondition 子状态与失败回退路径：

```mermaid
stateDiagram-v2
    [*] --> Confirmed: 初次 INVITE 建立成功
    Confirmed --> Modifying: 发送/接收 re-INVITE(含 offer)
    Modifying --> Modifying_Early: 触发 precondition\n(183+PRACK+UPDATE)
    Modifying_Early --> Confirmed: 200 OK + ACK
    Modifying --> Confirmed: 200 OK + ACK\n(无需 precondition)
    Modifying --> Terminating: CANCEL\n(资源修改/预留失败)
    Terminating --> Confirmed: 回退原会话参数
    Confirmed --> Glare: 收到 491\n(对端有 pending 事务)
    Glare --> Modifying: 随机回退后重发 re-INVITE
    Confirmed --> [*]: BYE 释放
```

这张状态机是排错时定位问题的"地图"：当一次 Hold 失败，首先要回答的问题是——会话当前到底卡在 `Modifying` 还是 `Modifying_Early`？前者说明卡在 200 OK/ACK，多半是 P-CSCF 的 Rx 授权或端到端 ACK 丢失；后者说明卡在 precondition 的 QoS 确认，多半是无线侧 QoS Flow 没建立起来。

## 八、抓包识别与实战排错

**如何在一次 Wireshark 抓包中识别 Re-INVITE 链？** 关键判据有四：

1. **同 Call-ID、同 From/To-tag，但 `CSeq` 方法名为 `INVITE` 且序号比已建立会话大**——这就是 re-INVITE 的指纹。
2. **`Via` 头的 `branch` 参数以 `z9hG4bK` 开头且为新值**（RFC 3261 魔数，用于事务区分）。
3. 跟踪同一 Dialog 内紧随的 `200 OK` 与 `ACK`，三者构成一个完整事务。
4. 对比 re-INVITE 的 SDP offer 与原会话 answer 的 SDP，差异点（`a=sendonly`、新增 `m=video` 行、`Session-Expires` 刷新）即本次修改的语义。

| 常见故障现象 | 根因定位思路 | 涉及网元/接口 |
|---|---|---|
| Hold 后对端仍能听到背景音 | 主叫发 `a=sendonly` 但本地 RTP 仍在上行；或被叫未按 RFC 6337 应答 `a=recvonly` | UE 媒体栈 / SBC |
| Hold 操作偶发失败、报 491 | Glare 冲突，终端未做随机退避重试 | UE SIP 栈 |
| Call Upgrade 加视频失败 | precondition 未满足，`UPDATE` 未发出或 Rx 未授权 5QI=2 | P-CSCF↔PCF(Rx) / 无线 QoS Flow |
| 会话静默掉线（无 BYE） | Session Timer 失效，两侧都没刷新且未检测到失效 | UE / P-CSCF 会话定时 |
| re-INVITE 后无 ACK，会话悬挂 | 端到端 ACK 被 NAT/SBC 丢弃，事务超时 | P-CSCF / SBC |


- **Hold 编码方式**：高通系终端偏好 `a=sendonly`（现代规范）；部分老款 SBC 和企业 PBX 仍用 `c=0.0.0.0`，混用时易出单向杂音。
- **会话定时器刷新载体**：有的厂商用 re-INVITE 刷新（兼容性好但开销大），有的用更轻的 `UPDATE`（RFC 3311）刷新。若对端不支持 UPDATE 刷新，会退化为 re-INVITE。
- **precondition 严格度**：爱立信/华为核心网对"未抬升 QoS 也声明 met"的宽松场景兼容良好；个别小厂 BAF 在新增流时校验过严，会把本可不等待的 Hold 也拖入完整 precondition 链，增加 200ms 以上时延。

## 九、常见问题

**Q1：Re-INVITE 和 UPDATE 都能改会话，区别是什么？**
A：二者都能携带 SDP 做 offer/answer 重协商，区别在于事务语义。Re-INVITE 用于 **Confirmed 状态（对话已建立后）** 的会话修改；`UPDATE`（RFC 3311）则主要用于 **Early Dialog（早期对话，即 200 OK 之前）** 的早期媒体参数更新（如更新 precondition 的 QoS 状态），也可在确认后用于轻量刷新。Re-INVITE 还能修改 Dialog 自身参数（如目标 URI），UPDATE 不能。会话定时器刷新两者皆可。

**Q2：为什么 Call Hold 不需要重新做 QoS 预留？**
A：因为按 TS 24.229 6.1.4.2，Hold 不抬升 QoS 需求（带宽、5QI 都不变，只是方向变更）。所以 offer 中 local/remote 当前 QoS 直接标记为 `met`，不触发 precondition 等待链，对端可直接回 200 OK，一步完成。

**Q3：被叫侧如何主动发起媒体重协商？**
A：被叫（原 UAS）若想改媒体，可发送一个**不含 SDP 的 re-INVITE**，主叫收到后必须回一个带 SDP offer 的 200 OK，被叫再以 ACK 携带 answer。这是反向 offer 的标准玩法。也可直接由被叫发带 offer 的 re-INVITE（若它此前是 answer 方，则可"角色切换"为 offer 方）。

**Q4：491 之外，Re-INVITE 还会遇到哪些冲突响应？**
A：主要是 `500 Server Internal Error`（带 Retry-After）和 `503 Service Unavailable`（过载）。但 491 是唯一专门针对"同一 Dialog 内 pending INVITE 冲突"的标准响应，且是唯一明确要求随机退避重试的。其他响应更多是通用服务端故障。

**Q5：Re-INVITE 期间的媒体怎么处理？**
A：在 offer/answer 交换完成前，双方应维持**旧媒体参数**继续收发，直到收到新的 200 OK + ACK 后才切换。若 offer 把某流置为 `a=inactive`，则在该 answer 确认后该流停摆。整个修改是"平滑切换"，不应中断正在进行的媒体。

## 参考来源

1. [3GPP TS 24.229 V19.x.x — IP multimedia call control protocol based on SIP and SDP; Stage 3](https://www.3gpp.org/dynareport/24229.htm) — Section 6.1.4 (Session modification), 6.2 (P-CSCF), 6.3 (S-CSCF)
2. [3glteinfo — VoNR Call Hold / Resume Procedure](https://www.3glteinfo.com/call-flows/5g/vonr-hold-resume/) — re-INVITE 与 SDP 方向变更流程图
3. [RFC 6337 — Session Initiation Protocol (SIP) Usage of the Offer/Answer Model（Call Hold 现代规范）](https://datatracker.ietf.org/doc/html/rfc6337)
4. [RFC 3261 Section 14 — SIP Dialog Modification & Glare/491 处理](https://datatracker.ietf.org/doc/html/rfc3261#section-14)
5. [RFC 4028 — Session Timers in SIP（Session-Expires/Min-SE）](https://datatracker.ietf.org/doc/html/rfc4028)

---

> 本文由「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 等场景全覆盖。

![51学通信知识星球海报-扫码加入](https://wiki.500nian.com/images/zhixingqiu_qrcode.png)
