1. 概述
TTS 能力的应用场景多为语音播报,将文本信息转换为语音数据后,需要在音频设备上播放出来。TTS 播放器就是针对这一场景而设计开发的一款通用产品。本开发指南面向iOS平台。
1.1 特性
TTS 播放器有以下特性
- 支持创建多个实例同时进行合成播报
- 支持暂停/继续/调整播放进度等控制
- 支持播放进度通知。仅本地 TTS 能力
- 支持合成进度通知。仅本地 TTS 能力
- 播放过程中可以通知正在播放的音节(拼音),及当前断句。仅本地 TTS 能力
- 支持简化播放。当业务场景非常简单时(仅使用一个播放器实例),可使用简化接口省略 TTS 能力初始化等调用。
- 平台相关功能可扩展。
2. 设计
TTS 播放器由三个模块组成
- 语音合成。使用异步逻辑实现
- 音频播放器。
- TTS 播放器主模块。
其中语音合成和音频播放器功能明确,进行了较高程度的抽象封装,可在其他场景中独立使用。
2.1 语音合成
语音合成是 TTS 播放器的根本,在这里我们设计了一个通用的异步语音合成类 HCITtsSynthesizer
,如下图:
HCITtsSynthesizer
提供简单的 start
(启动合成) 和 synth
(合成) 两个操作。合成的进度、生成语音数据均通过 HCISynthesizerDelegate
接口进行通知。
涉及 TTS 能力配置,语音格式等相关的内容,请参考灵云 SDK 开发手册和灵云 SDK 开发指南
使用
HCITtsSynthesizer
的前提是已成功初始化灵云 SDK 和灵云 TTS 能力
2.2 音频播放器
音频播放器用于播放指定格式的音频数据,类图如下:
HCITtsAudioPlayer 主要封装了平台无关的音频播放逻辑。主要提供四个操作:
- play 开始播放
- stop 停止播放
- seek: 进度跳转
- pausePlayer 暂停播放
- resumePlayer 继续播放
2.3 TTS 播放器
TTS 播放器正是基于 HCITtsSynthesizer 和 HCITtsAudioPlayer 得以实现,类图如下:
HCITtsPlayerManager
为 TTS 播放器的核心功能实现,基于HCITtsSynthesizer。
3. 使用
3.1 简易调用示例
当仅使用一个 TTS 播放器实例且无其他 TTS 能力调用时,可以参考以下示例
// 初始化灵云 SDK
NSMutableString *config = [NSMutableString stringWithFormat:@"developerKey=%@,appKey=%@,cloudUrl=%@",developerKey,appKey,cloudUrl];
hci_init(config.UTF8String);
//初始化播放器单例,需要遵循HCITtsPlayerManagerDelegate协议
HCITtsPlayerManager *manager = [HCITtsPlayerManager sharedInstance];
manager.delegate = self;
//设置capkey以v9为例
manager.capkey = @"tts.local.synth.v9";
manager.resPrefix = @"jTTSV9_";
//开启会话 并播放
[manager startSession:@"需要播放的文本"];
[manager play:@""];
});
// ****** 以下调用不一定在同一线程上,但是时序上要保证正确 ********
[manager play]("要播放的文本");
// ... 其他逻辑
[manager resume];
// ... 其他逻辑
[manager seek:1000]; // 调整进度至 1000,调整完成后,自动 resume
// ... 其他逻辑
[manager stop];
// ... 其他逻辑
[manager destroy];
3.2播放器事件回调
/**
播放器状态改变
*/
- (void)onPlayerEventStateChange:(HCI_PLAYER_STATE)state{
switch (state) {
case HCI_PLAYER_STATE_NOT_INIT:
{
NSLog(@"HCI_PLAYER_STATE_NOT_INIT:播放器未初始化");
}
break;
case HCI_PLAYER_STATE_INIT:
{
NSLog(@"HCI_PLAYER_STATE_INIT:播放器已初始化");
}
break;
case HCI_PLAYER_STATE_SYNTHESIZING:
{
NSLog(@"HCI_PLAYER_STATE_SYNTHESIZING:播放器正在内部合成音频");
}
break;
case HCI_PLAYER_STATE_SYNTHESIZE_COMPLETE:
{
NSLog(@"HCI_PLAYER_STATE_SYNTHESIZE_COMPLETE:播放器合成音频完成");
}
break;
case HCI_PLAYER_STATE_START_PLAY:
{
NSLog(@"HCI_PLAYER_STATE_START_PLAY:播放器开始播放音频");
}
break;
case HCI_PLAYER_STATE_PAUSE_PLAY:
{
NSLog(@"HCI_PLAYER_STATE_PAUSE_PLAY:播放器暂停播放音频");
}
break;
case HCI_PLAYER_STATE_RESUME_PLAY:
{
NSLog(@"HCI_PLAYER_STATE_RESUME_PLAY:播放器恢复播放音频");
}
break;
case HCI_PLAYER_STATE_CANCEL_PLAY:
{
NSLog(@"HCI_PLAYER_STATE_CANCEL_PLAY:播放器取消播放音频");
}
break;
case HCI_PLAYER_STATE_COMPLETE:
{
NSLog(@"HCI_PLAYER_STATE_COMPLETE:播放器已完成合成和播放任务");
}
break;
case HCI_PLAYER_STATE_IDLE:
{
NSLog(@"HCI_PLAYER_STATE_IDLE:播放器处于空闲状态");
}
break;
default:
break;
}
}
/**
播放器出错
*/
- (void)onPlayerEventPlayerError:(SinoVoiceError *)error{
NSLog(@"播放器出错,错误码:%d,错误信息:%@",error.errorCode,error.errorDesc);
}
/**
时间进度变化
@param current 当前播放时间
@param total 合成音频的总时长
*/
- (void)onPlayerEventTimeChange:(int)current andTotal:(int)total{
}
/**
播放进度变化
@param sentence 当前正在播放的文本内容
@param syllables 如支持音节输出则对外输出音节信息
*/
- (void)onPlayerEventProgressChange:(NSString *)sentence andSyllablesList:(NSArray *)syllables{
NSLog(@"当前正在播放的文本为:%@",sentence);
for (HCITtsSynthSyllable *syllable in syllables) {
NSLog(@"音节对应的文本:%@,音节对应的拼音:%@",syllable.text,syllable.pronouciationText);
}
}