OpenHarmony海思WS63星闪平台:Opus 音频编解码库介绍与海思 WS63 平台移植
文章目录
- 前言
- 1. Opus 是什么?
- 1.1 定位与标准
- 1.2 主要能力(摘自公开说明与 `opus/include/opus.h` 文档)
- 1.3 库对外 API 轮廓
- 1.4 与本仓库 `opus/` 目录的关系
- 2. 本工程中的 Opus 与音频业务
- 2.1 目录结构(与移植相关部分)
- 2.2 应用侧示例:CI1302 Opus 解码
- 3. WS63 平台特点与移植目标
- 4. 编译与集成方式
- 4.1 方式 A:海思 SDK / `build_component`(推荐,与本仓库 CMakeLists 一致)
- 4.2 方式 B:独立 CMake 子工程 / 交叉编译
- 4.3 方式 C:GN(`BUILD.gn`)静态库
- 5. 头文件与链接检查清单
- 6. 内存与实时性建议
- 7. 功能验证建议
- 8. 常见问题
- 9. 参考链接
- 总结
前言
Opus是互联网语音与音频场景中最常用的开放编解码器之一,适合 VoIP、对讲、语音播报、流媒体等。海思 WS63一类 IoT SoC 常跑LiteOS / OpenHarmony 衍生内核,RAM 与 CPU 有限,需要在「功能完整」与「体积/内存」之间做裁剪。本仓库已在项目根目录提供opus/源码树,且其中的opus/CMakeLists.txt已按海思 SDK 组件(build_component)风格编写,便于与 WS63 工程链对接。
本文说明 Opus是什么、能做什么,并结合本仓库布局给出在WS63 工程中编译集成、链接与使用的实操要点(含与本项目ci1302Opus 解码示例的衔接)。
1. Opus 是什么?
Opus 是一款完全开放、免版税且功能强大的音频编解码器。它在互联网上的交互式语音和音乐传输方面无可匹敌,同时也适用于存储和流媒体应用。它由互联网工程任务组 (IETF) 制定为RFC 6716标准 ,该标准融合了 Skype 的 SILK 编解码器和 Xiph.Org 的 CELT 编解码器的技术。
1.1 定位与标准
- IETF RFC 6716定义了 Opus 比特流格式与解码过程。
- 实现融合了Skype SILK(语音)与Xiph CELT(通用音频)两条技术路线,由IETF Codec 工作组标准化。
- github地址:https://github.com/xiph/opus
- 官方资料与下载:https://opus-codec.org/
1.2 主要能力(摘自公开说明与opus/include/opus.h文档)
| 维度 | 典型范围 |
|---|---|
| 采样率 | 8 kHz~48 kHz |
| 帧长 | 2.5 ms~60 ms(多种离散长度) |
| 声道 | 单声道、立体声,以及多流 API 下的多声道场景 |
| 码率 | 约 6 kb/s~510 kb/s(与模式/帧长有关) |
| 特性 | 语音与音乐、CBR/VBR、丢包隐藏(PLC)等 |
1.3 库对外 API 轮廓
嵌入式最常用的是解码(播放 TTS、网络语音)或编码(上行录音):
- 解码:
opus_decoder_create/opus_decoder_init、opus_decode、opus_decoder_destroy(或仅init配合静态缓冲,见下文)。 - 编码:
opus_encoder_create、opus_encode、opus_encoder_destroy。 - 头文件入口:
opus.h(内部包含opus_types.h、opus_defines.h)。
比特流若走RTP,需遵守RFC 7587;若存文件,通常用Ogg 封装(RFC 7845),需额外opusfile/libogg等,与本仓库「裸 Opus 帧」解码场景不同。
1.4 与本仓库opus/目录的关系
- 根目录
opus/为Xiph 官方 Opus 参考实现的完整源码树(含celt/、silk/、dnn/等)。 - 上游版本号由
opus/cmake/OpusPackageVersion.cmake等解析;本仓库opus/CMakeLists.txt在无法读取版本时回退为 1.5.2,与常见 HiSilicon 集成版本一致。 - 与上游唯一显著差异:根目录
opus/CMakeLists.txt不是通用add_library(opus …),而是为海思build_component()准备的组件描述(源列表来自*_sources.mk,生成config.h)。在非海思构建系统中需自行等价实现(见第 4 节)。
2. 本工程中的 Opus 与音频业务
2.1 目录结构(与移植相关部分)
opus/ ├── CMakeLists.txt # 海思 LiteOS 组件式构建(本仓库已提供) ├── cmake/ │ ├── config.h.cmake.in # 生成 config.h 的模板 │ └── … ├── include/ # 对外头文件:opus.h 等 ├── celt/、silk/、src/ # 编解码核心实现 ├── *_sources.mk # 参与编译的源文件列表(由 CMakeLists 读取) └── …2.2 应用侧示例:CI1302 Opus 解码
在src/audio/ci1302/中,当宏CI1302_TTS_DECODE_OPUS_TO_PCM打开时,会编译ci1302_opus_decode.c,通过opus.h调用解码接口,将 Opus 帧解为 PCM。该实现刻意使用opus_decoder_get_size+opus_decoder_init+ 静态缓冲,避免在堆很小的 LiteOS上频繁opus_decoder_create导致OPUS_ALLOC_FAIL。
未链接真实 libopus 时,可用ci1302_opus_decoder_weak_stub.c提供弱符号占位,便于分阶段联调。
结论:WS63 上「移植 Opus」在工程层面的落点是:把opus/编成静态库并链到最终镜像,保证#include "opus.h"与链接符号解析成功。
3. WS63 平台特点与移植目标
- WS63为海思面向连接类 IoT 的芯片平台,软件栈常见LiteOS-M + CMSIS-RTOS2 + 厂商驱动,构建可能是GN(OpenHarmony 系)或CMake +
build_component。 - 无 MMU 或资源紧张时,建议:
- 使用与本仓库
opus/CMakeLists.txt一致的OPUS_DISABLE_INTRINSICS等选项,避免依赖难以在 MCU 上统一验证的 SIMD/内联汇编路径; - 解码器状态尽量静态分配或可控堆,避免与 WiFi 等任务抢堆导致
LOS_TaskCreate失败(与ci1302_opus_decode.c注释一致)。
- 使用与本仓库
4. 编译与集成方式
CMakeLists文件:
#===============================================================================# @brief cmake file — Opus 静态库(LiteOS / HiSilicon SDK build_component 集成)# @details 风格对齐 open_source/lvgl/CMakeLists.txt;源文件列表与上游 silk/celt/opus 的 .mk 保持一致。# 与 ESP-IDF 工程(如 xiaozhi-esp32/main/CMakeLists.txt 中 esp_audio_codec 链 libopus)# 为两套集成方式,本文件仅用于 sdkv106 中 LiteOS 组件构建。# Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved.#===============================================================================set(COMPONENT_NAME"opus")set(CMAKE_OPUS_SOURCE_DIR${CMAKE_CURRENT_SOURCE_DIR})list(APPEND CMAKE_MODULE_PATH"${CMAKE_OPUS_SOURCE_DIR}/cmake")include(OpusFunctions)include(OpusPackageVersion)get_package_version(PACKAGE_VERSION PROJECT_VERSION)if(NOT PACKAGE_VERSION OR PACKAGE_VERSION STREQUAL"0")set(PACKAGE_VERSION"1.5.2")endif()configure_file(${CMAKE_OPUS_SOURCE_DIR}/cmake/config.h.cmake.in${CMAKE_CURRENT_BINARY_DIR}/config.h @ONLY)get_opus_sources(SILK_SOURCES${CMAKE_OPUS_SOURCE_DIR}/silk_sources.mk silk_sources_rel)get_opus_sources(SILK_SOURCES_FLOAT${CMAKE_OPUS_SOURCE_DIR}/silk_sources.mk silk_sources_float_rel)get_opus_sources(CELT_SOURCES${CMAKE_OPUS_SOURCE_DIR}/celt_sources.mk celt_sources_rel)get_opus_sources(OPUS_SOURCES${CMAKE_OPUS_SOURCE_DIR}/opus_sources.mk opus_sources_rel)get_opus_sources(OPUS_SOURCES_FLOAT${CMAKE_OPUS_SOURCE_DIR}/opus_sources.mk opus_sources_float_rel)set(SOURCES"")foreach(src${silk_sources_rel}${silk_sources_float_rel}${celt_sources_rel}${opus_sources_rel}${opus_sources_float_rel})list(APPEND SOURCES"${CMAKE_OPUS_SOURCE_DIR}/${src}")endforeach()set(PUBLIC_HEADER${CMAKE_OPUS_SOURCE_DIR}/include)set(PRIVATE_HEADER${CMAKE_OPUS_SOURCE_DIR}${CMAKE_OPUS_SOURCE_DIR}/celt${CMAKE_OPUS_SOURCE_DIR}/silk${CMAKE_OPUS_SOURCE_DIR}/silk/float${CMAKE_CURRENT_BINARY_DIR})set(COMPONENT_PUBLIC_CCFLAGS)set(COMPONENT_CCFLAGS -Wno-jump-misses-init -Wno-error=unused-parameter -Wno-error=sign-compare)# 与上游 CMake 默认接近:C99 变长数组、关闭 SIMD/内联汇编路径(适合 Cortex-M 等无 x86/NEON 运行时检测环境)# HAVE_LRINT / HAVE_LRINTF:避免 celt/float_cast.h 走 #else 里的 #warning(与 cmake/OpusConfig.cmake 中 check_symbol_exists 一致)set(PRIVATE_DEFINES HAVE_CONFIG_H OPUS_BUILD VAR_ARRAYS OPUS_DISABLE_INTRINSICS DISABLE_DEBUG_FLOAT ENABLE_HARDENING HAVE_LRINT HAVE_LRINTF)set(WHOLE_LINKtrue)set(MAIN_COMPONENTfalse)set(LIB_OUT_PATH${BIN_DIR}/${CHIP}/libs/${TARGET_COMMAND})build_component()4.1 方式 A:海思 SDK /build_component(推荐,与本仓库 CMakeLists 一致)
若父工程已支持海思build_component()(与open_source中 LVGL、opus 等组件相同模式):
- 将
opus/置于 SDK 约定的open_source/opus或工程内等价路径。 - 确保
opus/CMakeLists.txt被组件扫描到,configure_file能在CMAKE_CURRENT_BINARY_DIR生成config.h。 PRIVATE_DEFINES(本仓库已设)通常包括:HAVE_CONFIG_H、OPUS_BUILDVAR_ARRAYS(C99 变长数组,需工具链支持)OPUS_DISABLE_INTRINSICSDISABLE_DEBUG_FLOAT、ENABLE_HARDENINGHAVE_LRINT、HAVE_LRINTF(与float_cast.h行为一致,避免多余 warning)
PUBLIC_HEADER指向opus/include,业务模块include 目录增加该路径(或拷贝生成的config.h可见路径)。- 最终静态库与
WHOLE_LINK等由build_component()处理,应用链接时-lopus或等价组件依赖即可。
4.2 方式 B:独立 CMake 子工程 / 交叉编译
若需在 PC 上先验证 ARM 静态库:
cdopusmkdirbuild&&cdbuild cmake..-DCMAKE_TOOLCHAIN_FILE=/path/to/arm-none-eabi.cmake\-DCMAKE_BUILD_TYPE=Release\-DBUILD_SHARED_LIBS=OFF\-DOPUS_BUILD_PROGRAMS=OFF\-DOPUS_BUILD_TESTING=OFF cmake--build.说明:上游官方opus/CMakeLists.txt(若与本文档「海思定制版」不同)选项名可能为OPUS_FIXED_POINT、OPUS_FLOAT_APPROX等,需以当前树内CMakeLists.txt与cmake/OpusConfig.cmake为准。本仓库根目录opus/CMakeLists.txt已不采用通用add_library,直接cmake ..可能需改用官方 release 包或自行写add_library包装*_sources.mk。
4.3 方式 C:GN(BUILD.gn)静态库
当前xiaohong的BUILD.gn若尚未列出opus源文件,可新增static_library("opus"):
sources:需与silk_sources.mk、celt_sources.mk、opus_sources.mk及 float 列表一致,或写脚本从.mk生成 GN 列表(维护成本较高)。defines:与opus/CMakeLists.txt中PRIVATE_DEFINES对齐,并保证config.h在 include 路径中(可预生成后include_dirs += ["//path/to/opus/build_gen"])。include_dirs:opus、opus/celt、opus/silk、opus/silk/float、生成config.h的目录。
5. 头文件与链接检查清单
| 步骤 | 说明 |
|---|---|
| 头文件 | 添加opus/include;若编译报config.hmissing,检查是否执行了configure_file或手动放置生成结果。 |
| 符号 | 确认最终 elf/map 中含opus_decode、opus_decoder_init等,而非仅弱符号桩。 |
| 重复定义 | 同时链SDK 自带 opus与本仓库opus会冲突,应二选一。 |
| 浮点 | WS63 工具链若使用硬浮点 ABI,需全工程一致;Opus 本树含float 路径源(见*_float_rel),与DISABLE_DEBUG_FLOAT等宏共同决定行为。 |
6. 内存与实时性建议
- 解码器状态:
opus_decoder_get_size(channels)给出单实例所需字节数;单声道常见约十几 KB 量级(随版本与宏略变),ci1302_opus_decode.c使用20 KiB 静态区并opus_decoder_init,避免堆碎片。 - 栈:
opus_decode内部有一定栈深度,解码任务栈不宜过小(建议≥ 2~4 KB起步,以实测为准)。 - CPU:48 kHz、20 ms 帧在无 NEON 的 Cortex-M上仍可能占用可观 MIPS,需在目标板上profiling。
- DNN / LPCNet:新版 Opus 含深度学习扩展(如 DRED),嵌入式若不需要,应通过源列表 / CMake 选项关闭相关编译单元以减体积(具体以当前
opus_sources.mk与构建脚本为准)。
7. 功能验证建议
- 单元级:在板端调用
opus_decoder_init→opus_decode,输入已知 Opus 测试帧(可由 PCopus_demo生成),检查返回值是否为样本数、PCM 是否合理。 - 业务级:打开
CI1302_TTS_DECODE_OPUS_TO_PCM,走CI1302 TTS 管线,听音并观察CPU 占用与欠载。 - 异常:若返回
OPUS_ALLOC_FAIL (-7),优先检查堆与静态缓冲策略,与ci1302_opus_decode.c设计对齐。
8. 常见问题
| 现象 | 可能原因 | 处理方向 |
|---|---|---|
找不到config.h | 未运行configure_file或未加入 include 路径 | 按opus/CMakeLists.txt生成并包含CMAKE_CURRENT_BINARY_DIR |
| 链接 undefined reference | 未链 opus 静态库或源列表不全 | 检查WHOLE_LINK、GNdeps |
| 弱符号桩一直打印 | 未链真实 libopus | 移除桩或调整链接顺序,确保强符号覆盖 |
| 解码杂音/失败 | 采样率/声道与流不一致 | opus_decoder_init的Fs、channels与编码端一致 |
| RAM 暴涨 | 多路create或堆分配过多 | 单实例 +opus_decoder_ctl限制+ 静态缓冲 |
9. 参考链接
- Opus 官网:https://opus-codec.org/
- RFC 6716:https://www.rfc-editor.org/rfc/rfc6716
- RTP 封装 RFC 7587:https://www.rfc-editor.org/rfc/rfc7587
- Ogg Opus RFC 7845:https://www.rfc-editor.org/rfc/rfc7845
- 上游仓库(GitLab):https://gitlab.xiph.org/xiph/opus
- 本仓库
opus/cmake/README.md:通用 CMake 构建说明(与海思组件 CMake 并存时以根目录opus/CMakeLists.txt为准)
总结
Opus是 RFC 标准化的低延迟音频编解码库,适合 WS63 上的语音对讲、播报与网络音频。本仓库opus/已含完整源码及面向海思 LiteOSbuild_component的CMakeLists.txt,移植核心是:生成config.h、编译全量mk所列源文件、导出include、与业务(如ci1302_opus_decode.c)正确链接。在RAM 紧张场景下,优先采用opus_decoder_init+ 静态工作区,并控制仅链接一份 Opus、避免与 SDK 重复集成。按第 7 节在板端做解码与听音验证后,再投入量产参数(帧长、码率、任务优先级)。
