OpenHarmony海思WS63星闪平台:Opus 音频编解码库介绍与海思 WS63 平台移植

文章目录

    • 前言
    • [1. Opus 是什么?](#1. Opus 是什么?)
      • [1.1 定位与标准](#1.1 定位与标准)
      • [1.2 主要能力(摘自公开说明与 `opus/include/opus.h` 文档)](#1.2 主要能力(摘自公开说明与 opus/include/opus.h 文档))
      • [1.3 库对外 API 轮廓](#1.3 库对外 API 轮廓)
      • [1.4 与本仓库 `opus/` 目录的关系](#1.4 与本仓库 opus/ 目录的关系)
    • [2. 本工程中的 Opus 与音频业务](#2. 本工程中的 Opus 与音频业务)
      • [2.1 目录结构(与移植相关部分)](#2.1 目录结构(与移植相关部分))
      • [2.2 应用侧示例:CI1302 Opus 解码](#2.2 应用侧示例:CI1302 Opus 解码)
    • [3. WS63 平台特点与移植目标](#3. WS63 平台特点与移植目标)
    • [4. 编译与集成方式](#4. 编译与集成方式)
      • [4.1 方式 A:海思 SDK / `build_component`(推荐,与本仓库 CMakeLists 一致)](#4.1 方式 A:海思 SDK / build_component(推荐,与本仓库 CMakeLists 一致))
      • [4.2 方式 B:独立 CMake 子工程 / 交叉编译](#4.2 方式 B:独立 CMake 子工程 / 交叉编译)
      • [4.3 方式 C:GN(`BUILD.gn`)静态库](#4.3 方式 C:GN(BUILD.gn)静态库)
    • [5. 头文件与链接检查清单](#5. 头文件与链接检查清单)
    • [6. 内存与实时性建议](#6. 内存与实时性建议)
    • [7. 功能验证建议](#7. 功能验证建议)
    • [8. 常见问题](#8. 常见问题)
    • [9. 参考链接](#9. 参考链接)
    • 总结

前言

Opus 是互联网语音与音频场景中最常用的开放编解码器之一,适合 VoIP、对讲、语音播报、流媒体等。海思 WS63 一类 IoT SoC 常跑 LiteOS / OpenHarmony 衍生内核 ,RAM 与 CPU 有限,需要在「功能完整」与「体积/内存」之间做裁剪。本仓库已在项目根目录提供 opus/ 源码树,且其中的 opus/CMakeLists.txt 已按 海思 SDK 组件(build_component 风格编写,便于与 WS63 工程链对接。

本文说明 Opus 是什么、能做什么 ,并结合本仓库布局给出在 WS63 工程编译集成、链接与使用 的实操要点(含与本项目 ci1302 Opus 解码 示例的衔接)。


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_initopus_decodeopus_decoder_destroy(或仅 init 配合静态缓冲,见下文)。
  • 编码opus_encoder_createopus_encodeopus_encoder_destroy
  • 头文件入口:opus.h (内部包含 opus_types.hopus_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 目录结构(与移植相关部分)

text 复制代码
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文件:

bash 复制代码
#===============================================================================
# @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_LINK
    true
)

set(MAIN_COMPONENT
    false
)

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 等组件相同模式):

  1. opus/ 置于 SDK 约定的 open_source/opus 或工程内等价路径。
  2. 确保 opus/CMakeLists.txt 被组件扫描到,configure_file 能在 CMAKE_CURRENT_BINARY_DIR 生成 config.h
  3. PRIVATE_DEFINES (本仓库已设)通常包括:
    • HAVE_CONFIG_HOPUS_BUILD
    • VAR_ARRAYS(C99 变长数组,需工具链支持)
    • OPUS_DISABLE_INTRINSICS
    • DISABLE_DEBUG_FLOATENABLE_HARDENING
    • HAVE_LRINTHAVE_LRINTF (与 float_cast.h 行为一致,避免多余 warning)
  4. PUBLIC_HEADER 指向 opus/include ,业务模块 include 目录 增加该路径(或拷贝生成的 config.h 可见路径)。
  5. 最终 静态库WHOLE_LINK 等由 build_component() 处理,应用链接时 -lopus 或等价组件依赖 即可。

4.2 方式 B:独立 CMake 子工程 / 交叉编译

若需在 PC 上先验证 ARM 静态库:

bash 复制代码
cd opus
mkdir build && cd build
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_POINTOPUS_FLOAT_APPROX 等,需以 当前树内 CMakeLists.txtcmake/OpusConfig.cmake 为准。本仓库根目录 opus/CMakeLists.txt不采用 通用 add_library,直接 cmake .. 可能需改用 官方 release 包自行写 add_library 包装 *_sources.mk

4.3 方式 C:GN(BUILD.gn)静态库

当前 xiaohongBUILD.gn 若尚未列出 opus 源文件,可新增 static_library("opus")

  • sources :需与 silk_sources.mkcelt_sources.mkopus_sources.mk 及 float 列表一致,或写脚本从 .mk 生成 GN 列表(维护成本较高)。
  • defines :与 opus/CMakeLists.txtPRIVATE_DEFINES 对齐,并保证 config.h 在 include 路径中(可预生成后 include_dirs += ["//path/to/opus/build_gen"])。
  • include_dirsopusopus/celtopus/silkopus/silk/float 、生成 config.h 的目录

5. 头文件与链接检查清单

步骤 说明
头文件 添加 opus/include ;若编译报 config.h missing ,检查是否执行了 configure_file 或手动放置生成结果。
符号 确认最终 elf/map 中含 opus_decodeopus_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. 功能验证建议

  1. 单元级 :在板端调用 opus_decoder_initopus_decode ,输入 已知 Opus 测试帧 (可由 PC opus_demo 生成),检查 返回值是否为样本数、PCM 是否合理
  2. 业务级 :打开 CI1302_TTS_DECODE_OPUS_TO_PCM ,走 CI1302 TTS 管线 ,听音并观察 CPU 占用与欠载
  3. 异常 :若返回 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 、GN deps
弱符号桩一直打印 未链真实 libopus 移除桩或调整链接顺序,确保强符号覆盖
解码杂音/失败 采样率/声道与流不一致 opus_decoder_initFs、channels 与编码端一致
RAM 暴涨 多路 create 或堆分配过多 单实例 + opus_decoder_ctl 限制 + 静态缓冲

9. 参考链接


总结

Opus 是 RFC 标准化的低延迟音频编解码库,适合 WS63 上的语音对讲、播报与网络音频。本仓库 opus/ 已含 完整源码面向海思 LiteOS build_componentCMakeLists.txt ,移植核心是:生成 config.h、编译全量 mk 所列源文件、导出 include、与业务(如 ci1302_opus_decode.c)正确链接 。在 RAM 紧张 场景下,优先采用 opus_decoder_init + 静态工作区 ,并控制 仅链接一份 Opus 、避免与 SDK 重复集成。按第 7 节在板端做 解码与听音验证 后,再投入量产参数(帧长、码率、任务优先级)。

相关推荐
the sun342 小时前
从Ubuntu迁移到QEMU驱动开发
linux·驱动开发·ubuntu
特立独行的猫a3 小时前
OpenHarmony海思WS63星闪平台:EasyLogger 移植到海思 WS63 平台完整指南
驱动开发·openharmony·ws63·hi3863·easylogger
国医中兴4 小时前
ClickHouse监控与运维策略:从告警到故障处理
flutter·harmonyos·鸿蒙·openharmony
国医中兴4 小时前
云原生存储的实践与挑战:从容器到 Kubernetes
flutter·harmonyos·鸿蒙·openharmony
国医中兴4 小时前
ClickHouse 生态系统的深度解析:从核心到周边
flutter·harmonyos·鸿蒙·openharmony
国医中兴5 小时前
ClickHouse 在高并发写入场景下的性能优化实践
flutter·harmonyos·鸿蒙·openharmony
研究点啥好呢5 小时前
3月26日Github热榜推荐 | AI代理工具链专栏
人工智能·驱动开发·python·ai
路溪非溪15 小时前
Linux下蓝牙框架的数据流
linux·arm开发·驱动开发
钛态16 小时前
Flutter for OpenHarmony:mockito 单元测试的替身演员,轻松模拟复杂依赖(测试驱动开发必备) 深度解析与鸿蒙适配指南
服务器·驱动开发·安全·flutter·华为·单元测试·harmonyos