# OpenCoreAMR

`opencore-amr` 是 AMR-NB / AMR-WB 语音编解码的 C 库（OpenCORE 项目，Martin
Storsjo 维护）。新外壳沿用 daoqi msext 时期的同一份二进制 + 公开头，**不打
xcframework 不重新编译**。理由见下文「ADR」一节。

## 用途

支撑 H5 的语音功能（`prepareaudio` 录音 → AMR 编码 → 七牛上传；
`mediaTypeAudio` 下载 → AMR 解码 → 播放）。AMR-NB 格式是跨端（iOS / Android /
旧版本客户端）契约硬约束，不可换成 AAC / Opus。详见
`docs/H5-Native-Contract.md` §3.1 ［4］［5］ + §3.2 ［9］。

## 来源

- 上游：https://sourceforge.net/projects/opencore-amr/
- 当前镜像：https://github.com/BelledonneCommunications/opencore-amr
- 二进制版本：daoqi 沿用，约 2014 年打包，对应上游 **0.1.3** 时间点（v0.1.x 目
  录命名取自此）。具体小版本无可考——`.a` 二进制无版本号字段，public 头
  (`interf_enc.h` / `interf_dec.h`) 自 0.1.0 以来 ABI 未变
- daoqi 项目路径：`daoqi/msext/Class/Common/VoiceConvert/{lib/, opencore-amrnb/}`

## 目录

```
v0.1.x/
├── libopencore-amrnb.a    （5 slice fat：i386 + x86_64 + armv7 + armv7s + arm64-device）
├── interf_dec.h           （AMR-NB 解码 C API）
└── interf_enc.h           （AMR-NB 编码 C API）
```

不 vendor `libopencore-amrwb.a`——daoqi `amrFileCodec.mm` 实际只用 NB（窄带，
8kHz 单声道），WB 路径源码注释掉了，新外壳同样只用 NB。

## fat header 对齐补丁

daoqi `.a` 在 2026-06-20 用 `lipo -segalign 8` 重新打包过，所有 5 个 slice 的
fat header `align = 2^3 (8)`。这是为了适配 Xcode 26+ 的新链接器
`ld_prime` 对 fat 库 architecture slice 对齐字段的硬性要求（≥ 2^3）；不修则
会要 `-ld_classic` 过渡选项（已确认是定时炸弹）。

详细背景与修复命令见 `youle_app_ios/CLAUDE.md` 「2026-06-20：opencore-amr 静
态库 fat header 重新对齐」一节。

**已知遗留链接器警告（无害）**：
- `No platform load command found in ... assuming: iOS`（每个 .o 一行，约 154
  行）— 2014 年 .o 不带 `LC_VERSION_MIN_IPHONEOS` / `LC_BUILD_VERSION` load
  command；新链接器假定为 iOS，行为正确
- `Reducing alignment of section __DATA,__common from 0x8000 to 0x4000`

要彻底消除这两类警告需要重编 opencore-amr 源码，违反「稳定 > 一切」原
则——**接受现状**。

## simulator-arm64 缺失

`.a` 是 2014 年打包，**没有 arm64-simulator slice**（这是 2020 年 Apple
Silicon 上市后才有的概念）。M1+ Mac 上 simulator 编译需要在 Build Settings 设
置：

```
EXCLUDED_ARCHS[sdk=iphonesimulator*] = arm64
```

让 simulator 退回 x86_64 切片（通过 Rosetta 跑）。**仅影响开发期 simulator**，
release device 是 arm64 完整可用。

## 为何不打 xcframework / 不重编源码？

ADR：选 vendor 现成 .a 而非现代化 xcframework / 源码重编。

- **依据**：`opencore-amr` 整个 iOS 生态都是"老 vendor 模式"——各家大厂（微
  信、QQ、网易云信、声网 IM 等）都内部 vendor `.a`，没人公开维护 SPM / 官方
  xcframework。社区无"现代主流"形态可参照
- **稳定性**：daoqi 这份 `.a` 已上线 N 年稳定运行；现代化"形态"（xcframework）
  本质上仍是 vendor 同一份二进制字节，形态收益边际，引入新打包/编译路径反而
  增加风险
- **跨编辑成本**：要完整 xcframework 必须从源码编出 arm64-simulator slice，跨
  编 iOS（autoconf）容易踩坑，1+ 小时调试 vs vendor 几分钟落地
- **CLAUDE.md 原则一致**：项目「稳定 > 一切」+「daoqi 是工作参照实现」精神
  要求避免"为现代化而现代化"。本目录的现代化收益体现在**组织规范 + 文档完
  备**（与 WechatSDK Vendor 并列、README 来源/版本/修复历史齐全），而不是打包
  形态

未来若 Xcode 大版本彻底干掉对 fat `.a` 的支持（被动升级），再走 xcframework
化或源码重编路线，按 CLAUDE.md「Xcode 26.5+ 兼容性 Build Settings」一节的
patch 形式记录即可。

## 替换 / 升级流程（未来用）

1. 从 SourceForge / GitHub mirror 拉新版本源码（如 0.1.6）
2. 用 `xcrun -sdk iphoneos clang` + `-arch arm64` 跨编 device slice
3. 用 `xcrun -sdk iphonesimulator clang` + `-arch arm64`/`-arch x86_64` 跨编
   simulator slice
4. `lipo -create -segalign 8` 合并为新 fat `.a`
5. 替换 `v0.1.x/` 下文件，更新本 README、提交

## 链接配置

- Build Phases → Link Binary With Libraries：加 `libopencore-amrnb.a`
- Build Settings → Header Search Paths：追加
  `$(PROJECT_DIR)/Vendor/OpenCoreAMR/v0.1.x`
- Build Settings → Library Search Paths：追加
  `$(PROJECT_DIR)/Vendor/OpenCoreAMR/v0.1.x`
- Build Settings → Excluded Architectures（iphonesimulator）：`arm64`

wrapper 源码（`amrFileCodec.{h,mm}` + `AMRCodec.swift`）放在
`ylgamehall/Source/Audio/AMRFileCodec/` 与 `ylgamehall/Source/Audio/`，
由项目同步组（PBXFileSystemSynchronizedRootGroup）自动加入编译，无需在
pbxproj 中显式声明。
