鸿蒙操作系统使用 Core Speech Kit 实现文本转语音播报实战
一、背景说明
文本转语音(TTS)是无障碍朗读、新闻听书、语音导航类应用的基础能力。HarmonyOS 7 开发套件 26.0.1 Beta1(11 月 10 日面向开发者发布)的 Core Speech Kit 又新增了播报暂停/继续接口,语音播报的播放控制能力进一步补齐。本文基于 Core Speech Kit 的 textToSpeech 模块,完整实现"创建引擎 → 合成播报 → 监听回调 → 停止控制"全流程,代码可在 API 11 及以上(含 26.0.x)工程中运行。
二、技术原理
Core Speech Kit 将不超过 10000 字符的中英文文本(简体、繁体、数字、英文)合成为语音并按选定音色播报,核心概念有四个:
- 引擎(TextToSpeechEngine):由
textToSpeech.createEngine创建,参数指定语言(zh-CN)、音色(person)与在线/离线模式(online);引擎创建成功后全局复用,不必每次播报重建; - 播报参数(SpeakParams):包含 requestId 与 extraParams(语速 speed、音量 volume、音调 pitch、语言上下文、音频类型等),requestId 在同一实例内只能使用一次;
- 回调监听(SpeakListener):onStart / onComplete / onStop / onData(返回 PCM 音频流)/ onError 五个回调覆盖播报全生命周期,必须先 setListener 再 speak;
- 播放控制:stop 同步停止合成与播报;播报文本支持
[pN]标记插入毫秒级静音停顿,支持设置汉字发音、数字播报、单词读法策略。
数据流为:createEngine(一次性)→ setListener → speak(text, SpeakParams) → 引擎边合成边播报,onData 持续吐流、onComplete 收尾。
三、实现步骤
无需申请任何 ohos.permission 权限(引擎按 online 参数决定是否联网,首次使用可能需要设备下载音色资源)。工程要求 Stage 模型、API 4.1.0(11) 及以上。
新建 src/main/ets/tts/TtsPlayer.ets(完整代码,引擎管理 + 播报 + 回调封装):
import { textToSpeech } from '@kit.CoreSpeechKit';
import { BusinessError } from '@kit.BasicServicesKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
const TAG: string = 'TtsPlayer';
export class TtsPlayer {
private engine: textToSpeech.TextToSpeechEngine | null = null;
private reqSeq: number = 0;
// 创建引擎(全局只创建一次)
async init(): Promise<void> {
if (this.engine) { return; }
const initParamsInfo: textToSpeech.CreateEngineParams = {
language: 'zh-CN',
person: 0, // 0 为默认音色
online: 1 // 1 在线合成;0 离线
};
try {
this.engine = await textToSpeech.createEngine(initParamsInfo);
this.setListener();
hilog.info(TAG, 'engine created');
} catch (err) {
const e: BusinessError = err as BusinessError;
hilog.error(TAG, 'createEngine failed: %{public}d %{public}s', e.code, e.message);
throw e;
}
}
private setListener(): void {
const listener: textToSpeech.SpeakListener = {
onStart: (requestId: string, response: textToSpeech.StartResponse) => {
hilog.info(TAG, 'onStart %{public}s', requestId);
},
onComplete: (requestId: string, response: textToSpeech.CompleteResponse) => {
hilog.info(TAG, 'onComplete %{public}s', requestId);
},
onStop: (requestId: string, response: textToSpeech.StopResponse) => {
hilog.info(TAG, 'onStop %{public}s', requestId);
},
onData: (requestId: string, audio: ArrayBuffer, response: textToSpeech.SynthesisResponse) => {
// 需要保存音频文件或自绘波形时在这里消费 PCM 流
},
onError: (requestId: string, errorCode: number, errorMessage: string) => {
hilog.error(TAG, 'onError %{public}s %{public}d %{public}s', requestId, errorCode, errorMessage);
}
};
this.engine?.setListener(listener);
}
// 播报文本;文本支持 [p500] 形式的静音停顿标记
speak(text: string): void {
if (!this.engine) { throw new Error('engine not initialized'); }
if (text.length > 10000) {
throw new Error('text too long, max 10000 chars');
}
this.reqSeq += 1; // requestId 在同一实例内不可重复
const extraParam: Record<string, Object> = {
'queueMode': 0, // 0 排队播报
'speed': 1, // 语速 0.5~2
'volume': 2, // 音量 0~2
'pitch': 1, // 音调
'languageContext': 'zh-CN',
'audioType': 'pcm',
'soundChannel': 3,
'playType': 1
};
const speakParams: textToSpeech.SpeakParams = {
requestId: `tts-${this.reqSeq}`,
extraParams: extraParam
};
try {
this.engine.speak(text, speakParams);
} catch (err) {
const e: BusinessError = err as BusinessError;
hilog.error(TAG, 'speak failed: %{public}d %{public}s', e.code, e.message);
}
}
// 停止合成与播报
stop(): void {
try { this.engine?.stop(); } catch (err) { }
}
}
四、应用场景示例
在 Index.ets 中实现一个简易听书控制器:
import { TtsPlayer } from '../tts/TtsPlayer';
@Entry
@Component
struct Index {
private tts: TtsPlayer = new TtsPlayer();
@State text: string = '欢迎使用鸿蒙系统[p500]今天是不错的天气。';
build() {
Column({ space: 16 }) {
TextArea({ text: this.text }).height(120)
Row({ space: 12 }) {
Button('播报')
.onClick(async () => {
await this.tts.init();
this.tts.speak(this.text);
})
Button('停止')
.onClick(() => { this.tts.stop(); })
}
}
.width('100%').height('100%').justifyContent(FlexAlign.Center)
}
}
运行后点「播报」,设备即以默认音色朗读文本,并在"鸿蒙系统"后停顿 500ms。
五、技术要点
- requestId 一次性:同一引擎实例内 requestId 不可重复使用,重复会报错,示例中用自增序号保证唯一;
- 先 setListener 再 speak:不设置监听就播报,合成与播报回调都收不到,错误也只能靠异常感知;
- 文本长度上限 10000 字符(不含首尾空白),超限抛 1002300001,长文章需分段播报并按 onComplete 串联下一段;
- 引擎复用:createEngine 开销较大且已初始化时会直接返回实例,应用级单例持有即可,不要在每次播报时重建;
- 停顿与读法策略:
[p500]插入 500ms 静音;数字、多音字的读法可通过播报策略配置,中文数字场景(如念电话号码)务必显式设置,否则默认按数值读; - 异常包裹:speak 可能同步抛参数校验异常(401),try/catch 与 onError 回调两条路径都要处理。
六、扩展建议
若需要把合成结果保存为音频文件而非即时播放,可在 onData 回调中累积 PCM 流,写入沙箱文件:
onData: (requestId: string, audio: ArrayBuffer, response: textToSpeech.SynthesisResponse) => {
buffers.push(new Uint8Array(audio.slice(0)));
}
// onComplete 后将 buffers 合并写入 fileIo 生成的 .pcm/.wav 文件
26.0.1 Beta1 新增的暂停/继续播报接口可用于听书类应用的临时打断场景(如来电提示后恢复播报),升级到该版本后可直接调用对应接口实现秒级恢复,无需记录播放进度重新合成。
结语
本文用约 110 行 ArkTS 完成了文本转语音从引擎创建、回调监听、策略化播报到停止控制的完整闭环,核心是 createEngine → setListener → speak 三步链路加 requestId 与文本分段控制。TTS 接入成本低、无权限门槛,适合快速为阅读、导航、客服类应用增加语音输出能力。
更多推荐




所有评论(0)