AMR(Adaptive Multi-Rate,自适应多速率音频压缩) 是由 3GPP 组织制定并应用于蜂窝移动通信网络(GSM、UMTS 等)的语音编码标准。
AMR 使用码激励线性预测(CELP, Code-Excited Linear Prediction),面向语音通话编码。它以 20 ms 为一帧,支持多个码率模式;蜂窝系统可以根据信道条件调整所用模式。下面整理 AMR-NB、AMR-WB、接口帧和存储文件的区别。
1. AMR-NB 与 AMR-WB 规格对比
┌──────────────────────────────────────────────┐
│ AMR 语音编码体系 │
└──────────────────────┬───────────────────────┘
┌───────────────┴───────────────┐
▼ ▼
┌───────────────────────────────┐ ┌───────────────────────────────┐
│ AMR-NB (窄带语音编码) │ │ AMR-WB (宽带语音 / G.722.2) │
│ * 采样率: 8,000 Hz │ │ * 采样率: 16,000 Hz │
│ * 频宽: 300 ~ 3,400 Hz (电话) │ │ * 频宽: 50 ~ 7,000 Hz (宽带) │
│ * 8 种动态码率 (4.75~12.2kbps)│ │ * 9 种动态码率 (6.60~23.85kbps)│
└───────────────────────────────┘ └───────────────────────────────┘
1.1 动态自适应机制(Adaptive Rate Control)
在无线蜂窝信道中,总信道带宽相对固定。AMR 根据基站与终端测得的信干比(C/I):
- 信道优良时:选用较高码率(如 NB 12.2 kbps),语音清晰度更高;
- 信道恶化(边缘或强干扰)时:自动降低语音码率(如 NB 4.75 kbps),将节省的比特资源分配给前向信道纠错编码(FEC / Channel Coding),保证弱信号下的通话连续性。
2. 传输接口帧格式:AMR IF1 vs AMR IF2
在协议栈传输(如 RTP 流、基带无线链路)中,AMR 帧分为两种标准化接口格式:
2.1 AMR IF1(Interface Format 1 —— 具备无线抗错分级)
IF1 是移动通信空口传输的标准格式。为了应对无线误码,IF1 将每帧 20ms 的数据按照对听觉的重要程度划分为三类:
+─────────────────────+─────────────────────+─────────────────────+─────────────────────+
| Header (Frame Type) | Class A 数据位 | Class B 数据位 | Class C 数据位 |
| (4b Mode + 1b FQI) | (核心基频/LPC参数) | (辅音频谱参数) | (量化低位/细节) |
+─────────────────────+─────────────────────+─────────────────────+─────────────────────+
- Class A(敏感位):包含 LPC 线性预测系数与基音周期。若此部分 CRC 校验失败,整帧通常判定为损坏(Bad Frame),解码器将执行静音或丢包补偿(PLC);
- Class B / Class C:受损时对语音可懂度影响较小,物理层通常对 Class A 施加最强的纠错保护。
2.2 AMR IF2(Interface Format 2 —— 紧凑格式)
IF2 省略了部分信道控制字段(去除 Mode Indication / Request),将 Frame Type 与语音载荷以紧凑字节排列,适合存储与内部数据交换。
3. 存储文件格式 (.amr) 与文件头标识
当 AMR 录音保存为本地文件时,其文件结构如下:
+──────────────────────────────────+──────────────────────────────+
| 文件起始标识 (Magic Number) | 连续的 20ms 语音帧序列 |
| (单声道 6 字节 / 宽带 9 字节) | [Frame 0][Frame 1]...[FrameN]|
+──────────────────────────────────+──────────────────────────────+
3.1 文件头 Magic 字节
// AMR-NB 单声道文件头 (6 字节 ASCII: "#!AMR\n")
const uint8_t AMR_NB_MAGIC[] = { 0x23, 0x21, 0x41, 0x4D, 0x52, 0x0A };
// AMR-WB 宽带文件头 (9 字节 ASCII: "#!AMR-WB\n")
const uint8_t AMR_WB_MAGIC[] = { 0x23, 0x21, 0x41, 0x4D, 0x52, 0x2D, 0x57, 0x42, 0x0A };
3.2 帧读取与步长计算
AMR 文件没有全局索引表,播放器需逐帧解析帧头:
uint8_t frame_header = fgetc(fp);
// 帧头高 1 位保留为 0,第 3~6 位为 Frame Type (模式)
uint8_t mode = (frame_header >> 3) & 0x0F;
// 根据 AMR-NB 模式查表获取当前 20ms 帧的物理字节数
static const int block_size[] = { 13, 14, 16, 18, 20, 21, 27, 32, 6, 0, 0, 0, 0, 0, 0, 1 };
int frame_size = block_size[mode]; // 例如 12.2kbps (mode 7) 对应 32 字节
4. 总结
解析 .amr 文件时,先用文件头区分 NB 和 WB,再按各自的 Frame Type 表读取帧长。接口帧、RTP 载荷与文件帧的布局不能混用;切出完整帧以后,还需要对应的语音解码器才能得到 PCM。