HarmonyOS 百度 TTS 客户端集成技术分析报告

1. 项目背景和功能

众所周知,鸿蒙没有原生语音合成能力,第三方API还要收钱,而且唯一的第三方API不仅不能用,开发商还是个Nobody。如果你的应用想增加语音合成能力,又想用大厂产品,又不想付钱,怎么办?
在这里插入图片描述

该项目演示了如何在 HarmonyOS (ArkTS) 环境下集成百度语音合成(TTS)SDK (baidu-tts 模块)。它实现了在线合成、离线合成、混合模式合成,以及播放控制(暂停、恢复、停止)和实时进度回调显示等功能。

2. 软件架构

项目采用经典的 UI - 业务逻辑 - SDK 三层架构,基于 HarmonyOS 的 ArkTS 声明式开发范式。

  • UI层 (View): Index.ets 负责构建界面,提供操作按钮(如“合成”、“播放”、“暂停”)和富文本显示区域(用于高亮显示播放进度)。
  • 业务逻辑层 (ViewModel/Controller): 也是在 Index.ets 中实现,负责持有 SpeechSynthesizer 实例,配置鉴权参数,加载离线资源,并处理 SDK 的异步回调。
  • SDK层 (Model/Service): libs/com.baidu.tts_1.0.8.har (即 baidu-tts) 提供了核心语音合成能力。

3. 核心工作原理

3.1 核心类说明

类名 作用
SpeechSynthesizer 核心控制类。负责引擎初始化、参数设置、控制播放生命周期(speak, pause, stop)。
TtsEntity 合成实体。封装了一次合成任务的数据,包括文本内容、合成模式(Online/Offline)、任务ID。
SynthesizerResponse 回调响应。在回调函数中返回的状态对象,包含当前状态类型、音频进度、错误信息等。
TtsMode 模式枚举ONLINE (在线), OFFLINE (离线), MIX (混合)。

3.2 工作流程

集成流程主要分为四个阶段:

  1. 初始化 (Init): 创建 SpeechSynthesizer 实例,绑定回调上下文。
  2. 配置 (Config): 设置 AppID、AppKey、SecretKey 以及离线模型路径。
  3. 加载 (Load): 根据模式调用 loadOnlineTts()loadOfflineTts() 初始化引擎。
  4. 合成/播放 (Synthesize/Speak): 创建 TtsEntity 并调用接口开始工作。

4. 技术要点与实现细节

4.1 引入与初始化

SDK 通过 HAR 包形式引入。在 Index.ets 中,首先需要实例化 SpeechSynthesizer,并将当前组件 (this) 作为回调接收者传递进去。

// 导入核心类
import { SpeechSynthesizer, SynthesizerResponse, TtsEntity, TtsMode } from 'baidu-tts';

@Entry
@Component
struct Index {
  // 1. 创建实例,传入 this 以便于接收回调
  private speechSynthesizer: SpeechSynthesizer = new SpeechSynthesizer(this);
  
  aboutToAppear() {
     this.initialTts(); // 2. 组件加载时初始化
  }
}

4.2 参数配置 (鉴权与资源)

这是最关键的一步。代码区分了公共参数在线参数离线参数

  • AppCode/鉴权: 需要设置 PARAM_APP_ID, PARAM_API_KEY, PARAM_SECRET_KEY
  • 离线资源: 离线模式需要加载 .dat 模型文件(文本模型和声学模型)。
    • 在 HarmonyOS 项目中,通过 this.context.resourceDir 获取资源路径。
    • 模型文件通常放置在 src/main/resources/resfile 目录下。

核心配置代码:

private setOfflineParam(speechSynthesizer: SpeechSynthesizer): void {
    // 设置序列号 (SN)
    speechSynthesizer.setParam(SpeechSynthesizer.PARAM_AUTH_SERIAL_NUMBER, "你的序列号");
    
    // 配置离线模型路径 (JSON格式的键值对)
    let offlineModel: Record<string, string> = {};
    offlineModel[SpeechSynthesizer.TTS_TEXT_MODEL_FILE] = 
        this.context.resourceDir + "/" + "bd_etts_..._text.dat"; // 文本模型
    offlineModel[SpeechSynthesizer.TTS_SPEECH_MODEL_FILE] = 
        this.context.resourceDir + "/" + "bd_etts_..._speech.dat"; // 声学模型
        
    speechSynthesizer.setParam(SpeechSynthesizer.PARAM_OFFLINE_MODEL, JSON.stringify(offlineModel));
    
    // 异步加载离线引擎
    speechSynthesizer.loadOfflineTts().then((result) => { /* 处理结果 */ });
}

4.2.1 百度智能云鉴权代码解析

在使用百度语音服务前,必须在百度智能云控制台创建应用并获取鉴权密钥。代码中主要通过 setParam 方法配置以下关键参数:

  1. 公共参数 (AppID):
    setPublicParam 方法中设置 PARAM_APP_ID。这是应用的唯一标识。

    speechSynthesizer.setParam(SpeechSynthesizer.PARAM_APP_ID, "你的AppID");
    
  2. 在线鉴权 (API Key & Secret Key):
    setOnlineParam 方法中设置。用于验证用户身份以使用在线合成服务。

    speechSynthesizer.setParam(SpeechSynthesizer.PARAM_API_KEY, "你的ApiKey");
    speechSynthesizer.setParam(SpeechSynthesizer.PARAM_SECRET_KEY, "你的SecretKey");
    
  3. 离线鉴权 (Serial Number):
    setOfflineParam 方法中设置 PARAM_AUTH_SERIAL_NUMBER。这是离线 SDK 授权序列号,通常与包名或特定设备绑定。

    speechSynthesizer.setParam(SpeechSynthesizer.PARAM_AUTH_SERIAL_NUMBER, "你的序列号");
    speechSynthesizer.setParam(SpeechSynthesizer.PARAM_LICENSE_URL, "https://upl.baidu.com/auth"); // 必须设置授权URL
    

注意:代码演示中使用了硬编码的 Key,实际开发中建议配合安全机制管理这些敏感信息。

4.3 合成与播放

SDK 提供了两个主要方法:

  • synthesize(): 仅合成音频数据,不自动播放。适用于需要保存音频或自定义播放的场景。
  • speak(): 合成并自动播放。适用于大多数直接播报场景。
// 触发播放
let ttsEntity = new TtsEntity(
    "需要播报的文本", // 文本
    TtsMode.OFFLINE,  // 模式:TtsMode.ONLINE 或 TtsMode.OFFLINE
    '123456'          // 唯一的请求ID
);

this.speechSynthesizer.speak(ttsEntity).then((err) => {
    if(err) { /* 处理启动错误 */ }
});

4.4 事件回调处理

Index 组件中定义了 onSynthesizeResponse 方法,SDK 会自动调用它来通知状态变化。这是实现 UI 进度更新(如高亮当前读到的文字)的关键。

onSynthesizeResponse(response: SynthesizerResponse): void {
    let type = response.getSynthesizeType();
    
    switch (type) {
      case SynthesizeType.SYNTHESIZE_START: // 合成开始
        break;
      case SynthesizeType.PLAY_PROGRESS:    // 播放进度回调
        let data = response.getSynthesizerData();
        if (data) {
           // 获取当前播放字符的索引
           let progress = data.getAudioProgress(); 
           // 更新 UI 高亮
           this.updateTextHighlight(progress);
        }
        break;
      case SynthesizeType.PLAY_FINISH:      // 播放结束
        break;
      case SynthesizeType.SYNTHESIZE_ERROR: // 发生错误
        // 读取错误码和描述
        break;
    }
}

5. 项目文件结构分析

该 Demo 关键文件如下:

  • entry/src/main/ets/pages/default/Index.ets:
    • 应用入口页面,包含所有逻辑。
    • 定义了 initialTts 方法加载参数。
    • 定义了 SDK 回调函数 onSynthesizeResponse
  • entry/src/main/resources/resfile/:
    • 存放离线所需的 .dat 文件 (如 bd_etts_common_text...dat)。
    • 代码中使用 this.context.resourceDir 指向此目录。
  • oh_modules/baidu-ttslibs/*.har:
    • 百度 TTS 的鸿蒙 SDK 库文件。

6. 开发注意事项

  1. 资源路径: 确保离线模型文件正确放置在 resources/resfile 中,鸿蒙系统打包时会将此目录下的文件保留在应用沙箱中供路径访问。
  2. 异步操作: SDK 的主要操作(load, speak, synthesize, stop)均返回 Promise,务必使用 .then()await 处理异步结果,避免阻塞 UI 线程。
  3. 鉴权参数: 在正式发布时,PARAM_APP_IDPARAM_API_KEYPARAM_SECRET_KEY 必须替换为在百度智能云控制台申请的真实值,否则会报鉴权错误。
  4. 生命周期管理: 建议在页面销毁时调用 speechSynthesizer.release() 释放资源,防止内存泄漏。

7. 真机运行结果(无线调试+多屏协同,太方便了!)

注意!这个程序不能在模拟器运行,因为模拟器只能用X86指令集,百度这个库用的是ARM指令集!
在这里插入图片描述

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐