You need to enable JavaScript to run this app.
导航
双向流式TTS - iOS SDK 接口文档
最近更新时间:2025.11.07 18:06:01首次发布时间:2025.07.16 20:25:06
复制全文
我的收藏
有用
有用
无用
无用

1. 集成指南

1.1 SDK 简介

双向流式TTS语音对话 SDK 是基于豆包端到端实时语音大模型,提供低延迟、双向流式TTS音频生成能力,可用于构建文本到语音的工具。

1.2 SDK版本

Android: com.bytedance.speechengine:speechengine_tob:0.0.12
iOS: pod 'SpeechEngineToB', '0.0.12'
该版本需要自行添加TTNet 依赖,否则Android 会崩溃,iOS 会编译报错。示例如下:
Android:

implementation 'com.bytedance.boringssl.so:boringssl-so:1.3.6'
implementation('org.chromium.net:cronet:4.2.210.3-tob') {
    exclude group: 'com.bytedance.common', module: 'wschannel'
}
implementation 'com.bytedance.frameworks.baselib:ttnet:4.2.210.3-tob'

iOS:

pod 'TTNetworkManager', '4.2.210.20'

1.3 Maven仓库

maven {
    url "https://artifact.bytedance.com/repository/Volcengine/"
}

1.4 组件依赖

source 'https://github.com/CocoaPods/Specs.git'
source 'https://github.com/volcengine/volcengine-specs.git'

# TTNet
pod 'TTNetworkManager', '{LATEST_VERSION}'

# Speech
pod 'SpeechEngineToB', '{LATEST_VERSION}'

1.5 兼容性

类别

兼容范围

系统

最低支持 iOS 12.0

架构

armv7,arm64,x86_64

网络

支持移动数据与 WiFi 两种网络环境

2.调用流程

2.1 初始化环境依赖

创建语音对话 SDK 引擎实例前调用,完成网络环境等相关依赖配置。APP 生命周期内仅需执行一次。

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    return [SpeechEngine prepareEnvironment];
}

2.2 创建引擎实例

语音对话 SDK 通过如下方式获取相关实例。

//创建实例
self.engine = [[SpeechEngine alloc] init];
//添加引擎代理,需要实现回调方法
[self.engine createEngineWithDelegate:self];

2.3 参数配置

其中 APPID 、TOKEN 获取方式参考 控制台使用FAQ-Q1 ,RESOURCE ID 设置为 volc.service_type.10029,URI设置为/api/v3/tts/bidirection

//【必需配置】Engine Name
[self.curEngine setStringParam:SE_BITTS_ENGINE forKey:SE_PARAMS_KEY_ENGINE_NAME_STRING];
//【可选配置】本地日志文件路径,SDK会在该路径文件夹下生成名为 speech_sdk.log 的日志文件,开发时设置,线上关闭。
[self.engine setStringParam:@"已存在的文件夹路径,或者空字符串" forKey:SE_PARAMS_KEY_DEBUG_PATH_STRING];
//【可选配置】日志级别,开发时设置为 TRACE(最低级别),线上设置 WARN;
[self.engine setStringParam:SE_LOG_LEVEL_TRACE forKey:SE_PARAMS_KEY_LOG_LEVEL_STRING];
//【可选配置】自定义请求Header
[self.curEngine setStringParam:headerStr forKey:SE_PARAMS_KEY_REQUEST_HEADERS_STRING];
//【可选配置】是否使用 SDK 内置播放器播放合成出的音频,默认为 true
[self.curEngine setBoolParam:[self.settings getBool:SETTING_TTS_ENABLE_PLAYER]
                          forKey:SE_PARAMS_KEY_TTS_ENABLE_PLAYER_BOOL];
//【可选配置】是否令 SDK 通过回调返回播放器播放的pcm音频数据,默认不返回。
// 开启后,SDK 会流式返回音频,收到 SEPlayerStartPlayAudio SEPlayerFinishPlayAudio表示开始播放当前句对应音频
//收到SEPlayerAudioData表示流式的pcm音频数据
[self.curEngine setBoolParam:[self.settings getBool:SETTING_ENABLE_PLAYER_AUDIO_CALL_BACK] ? SETtsDataCallbackModeAll : SETtsDataCallbackModeNone forKey:SE_PARAMS_KEY_ENABLE_PLAYER_AUDIO_CALLBACK_BOOL];
//【可选配置】是否将合成出的音频保存到设备上,为 true 时需要正确配置 PARAMS_KEY_TTS_AUDIO_PATH_STRING 才会生效
[self.curEngine setBoolParam:[self.settings getBool:SETTING_TTS_ENABLE_DUMP]
//【可选配置】TTS播放文件保存路径,如不为空字符串,则SDK会将播放器音频保存到该路径下,文件格式为 .wav
[self.curEngine setStringParam:self.debugPath forKey:SE_PARAMS_KEY_TTS_AUDIO_PATH_STRING];
    
//【必需配置】在线合成鉴权相关:Appid
[self.curEngine setStringParam:self.ttsAppId forKey:SE_PARAMS_KEY_APP_ID_STRING];
//【必需配置】语音合成服务域名
[self.curEngine setStringParam:ttsAddress forKey:SE_PARAMS_KEY_TTS_ADDRESS_STRING];
//【必需配置】语音合成服务Uri
[self.curEngine setStringParam:ttsUri forKey:SE_PARAMS_KEY_TTS_URI_STRING];
//【必需配置】语音合成服务资源id
[self.curEngine setStringParam:resourceId forKey: SE_PARAMS_KEY_RESOURCE_ID_STRING];
//【可选配置】TTS连接超时时间
[self.curEngine setIntParam:10000 forKey:SE_PARAMS_KEY_TTS_CONN_TIMEOUT_INT];
//【必需配置】StarSession时的payload,指定音频生成相关参数,不包含待合成的文本
[self.curEngine setStringParam:startPayload forKey:SE_PARAMS_KEY_START_ENGINE_PAYLOAD_STRING];

2.4 初始化引擎实例

初始化引擎对象并设置回调监听。

// 初始化引擎实例
SEEngineErrorCode ret = [self.engine initEngine];
if (ret != SENoError) {
    NSLog(@"初始化失败,返回值: %d", ret);
    return;
}

2.5 发送指令

语音对话 SDK 通过发送指令接口 sendDirective 触发各种操作,需要注意不建议在 SDK 的回调线程中调用该接口。

2.5.1 启动引擎

启动引擎的传参为StartSession命令的参数,详细参数可以见双向流式TTS的Event事件

// 注意这里先调用同步停止,避免SDK内部异步线程带来的问题
[self.engine sendDirective:SEDirectiveSyncStopEngine];
// 启动BiTTS引擎
SEEngineErrorCode ret = [self.engine sendDirective:SEDirectiveStartEngine data: startSessionPayload];
if (ret != SENoError) {
    NSLog(@"Send directive say hello failed: %d", ret);
    return;
}

startSessionPayload参数示例如下,包含了音色、音频生成参数。

"{\"user\":{\"uid\":\"YOURUID\"},\"req_params\":{\"speaker\":\"zh_female_roumeinvyou_emo_v2_mars_bigtts\",\"audio_params\":{\"emotion\":\"excited\",\"loudness_rate\":50}}}"

说明

注意:启动BiTTS引擎只完成了建连操作,没有发起StartSession,在开始合成前需要先调用[self.curEngine sendDirective:SEDirectiveEventStartSession data:@""];

2.5.2 开始合成服务-StartSession

双向流式TTS支持在一个链接中多次调用StartSession和FinishSession。每调用一次表示开始合成服务和结束合成服务。
调用StartSession时data字段有如下2种设置方式

  • 传空字符串:表示使用SEDirectiveStartEngine时传入的 startSessionPayload参数来合成;
  • 新传入json格式的sessionpayload参数:更新合成参数,按新参数来合成文本;
SEEngineErrorCode ret = [self.curEngine sendDirective:SEDirectiveEventStartSession data:@""];
//或者传入更新后的新参数
//SEEngineErrorCode ret = [self.curEngine sendDirective:SEDirectiveEventStartSession data:startSessionPayload];
if (ret != SENoError) {
    NSLog(@"Send directive say Start Session failed: %d", ret);
    return;
}

2.5.3 结束合成服务-FinishSession

如果没有文本了,或者需要强制结束时可以调用FinishSession让服务端基于已收到的文本完成音频合成并返回。

说明

注意:如果传输文本最后不包含标点符号,那么服务端会等待后续文本到来才会触发合成。超时4秒没有收到后续文本也会触发合成。如果期望服务端立马开始合成则需要调用FinishSession。

SEEngineErrorCode ret = [self.curEngine sendDirective:SEDirectiveEventFinishSession data:""];
if (ret != SENoError) {
    NSLog(@"Send directive Finish Session failed: %d", ret);
    return;
}

2.5.4 发送合成文本

文本内容需要拼装车json格式的字符串传入。如果有其他参数可以透传给服务端。

NSString* taskRequestJson = [NSString stringWithFormat: @"{\"req_params\":{\"text\":\"%@\"}}", text];
SEEngineErrorCode ret = [self.curEngine sendDirective:SEDirectiveEventTaskRequest data:taskRequestJson];
if (ret != SENoError) {
    NSLog(@"Send directive Task Request failed: %d", ret);
    return;
}

说明

可以调用多次SEDirectiveEventTaskRequest向服务端发送待合成的文本内容。服务端会切句逐个返回。如果需要立即返回音频内容,可以在发送SEDirectiveEventTaskRequest前后调用StartSession和FinishSession确保音频马上返回。

2.5.5 取消合成服务-CancleSession

如果要取消当前合成服务,期望服务端不再返回音频。则调用CancleSession

SEEngineErrorCode ret = [self.curEngine sendDirective:SEDirectiveEventCancleSession data:""];
if (ret != SENoError) {
    NSLog(@"Send directive Finish Session failed: %d", ret);
    return;
}

2.5.6 暂停播放

可以在播放音频时发送指令SEDirectivePausePlayer*,​*暂停tts音频播放。

SEEngineErrorCode ret = [self.curEngine sendDirective:SEDirectivePausePlayer];
NSLog(@"Pause playback status: %d", ret);

2.5.7 恢复播放

可以在播放音频时发送指令SEDirectiveResumePlayer*,​*恢复tts音频播放

SEEngineErrorCode ret = [self.curEngine sendDirective:SEDirectiveResumePlayer];
NSLog(@"Resume playback status: %d", ret);

2.5.8 停止引擎

// 会等待回调函数执行完成,不可在回调线程中执行。
[self.engine sendDirective:SEDirectiveSyncStopEngine];

2.6 回调接收返回数据

启动引擎后,SDK会不断回调消息。回调的消息内容,请参考双向流式TTS的Event事件说明。

- (void)onMessageWithType:(SEMessageType)type andData:(NSData *)data {
    NSLog(@"Message Type: %d.", type);
    NSString *strData = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
    switch (type) {
        case SEEngineStart:
            // Callback: 引擎启动成功回调
            NSLog(@"Callback: 引擎启动成功: %@", strData);
            break;
        case SEEngineStop:
            // Callback: 引擎关闭回调,启动引擎成功后,此消息必定发生且为最后一个回调消息
            NSLog(@"Callback: 引擎关闭: %@", strData);
            break;
        case SEEngineError:
            // Callback: 错误信息回调
            NSLog(@"Callback: 错误信息: %d, data: %@", type, strData);
            break;
        case SEEventConnectionStarted:
            NSLog(@"Callback: SEEventConnectionStarted");
            break;
        case SEEventConnectionFailed:
            NSLog(@"Callback: SEEventConnectionFailed");
            break;
        case SEEventConnectionFinished:
            NSLog(@"Callback: SEEventConnectionFinished");
            break;
        case SEEventSessionStarted:
            NSLog(@"Callback: SEEventSessionStarted");
            break;
        case SEEventSessionCanceled:
            NSLog(@"Callback: SEEventSessionCanceled");
            break;
        case SEEventSessionFinished:
            NSLog(@"Callback: SEEventSessionFinished");
            break;
        case SEEventSessionFailed:
            NSLog(@"Callback: SEEventSessionFailed");
            break;
        case SEEventTTSSentenceStart:
            NSLog(@"Callback: 合成开始 SentenceStart: %@", data);
            break;
        case SEEventTTSSentenceEnd:
            NSLog(@"Callback: 合成结束 SentenceEnd: %@", data);
        case SEEventTTSResponse:
            NSLog(@"Callback: 收到合成音频 TTSResponse: %@", data);
        case SEEventTTSEnded:
            NSLog(@"Callback: TTSEnd: %@", data);
        case SEPlayerAudioData:
            NSLog(@"Callback: 播放的pcm音频: %@", data);
            break;
        case SEPlayerStartPlayAudio:
            NSLog(@"Callback: 开始播放当前句的TTS音频");
            break;
        case SEPlayerFinishPlayAudio:
            NSLog(@"Callback: 结束播放当前句的TTS音频");
            break;        
        default:
            break;
    }
}

2.7 销毁引擎实例

当不再需要语音对话后,建议对引擎实例进行销毁,释放内存资源。

// 内部会执行SYNC_STOP,不可在回调线程中执行。
[self.engine destroyEngine];
self.engine = nil;

3. 示例工程
SpeechDemoIOS.zip
未知大小

3.1 运行方法

  1. 首先修改 Podfile 文件中的SDK依赖版本,添加TTNet 依赖,并执行 pod install --repo-update
  1. XCode 打开 SpeechDemo.xcodeproj ,要运行语音对话功能,至少需修改SensitiveDefines.m 代码中下述内容:

其中 APPID 、TOKEN 获取方式参考 控制台使用FAQ-Q1

RESOURCE ID 设置为 volc.service_type.10029

const NSString* SDEF_BITTS_DEFAULT_RESOURCE_ID = @"volc.service_type.10029";
const NSString* SDEF_BITTS_DEFAULT_URI = @"/api/v3/tts/bidirection";
  1. 修改所有代码配置后,配置SpeechDemo为开发者自己的签名,然后点击XCode 三角号执行demo 构建运行即可。
  1. 选择 语音合成 ->双向流式合成 进入双向流式TTS 测试页,对应的页面代码文件为 SpeechDemo/BiTTSViewController.m

Image

  1. 点击 Init Engine -> Start Engine->Synchesis 即可体验双向流式TTS功能。

一段完整的TTS合成日志如下所示

Callback: SEEventSessionStarted
Callback: 合成开始 SentenceStart: {length = 87, bytes = 0x7b227068 6f6e656d 6573223a 5b5d2c22 ... 72647322 3a5b5d7d }
Callback: 收到合成音频 TTSResponse: {length = 4, bytes = 0x4f676753}
Callback: TTSEnd: {length = 4, bytes = 0x4f676753}
Callback: 开始播放TTS音频
Callback: 收到合成音频 TTSResponse: {length = 4, bytes = 0x4f676753}
Callback: TTSEnd: {length = 4, bytes = 0x4f676753}
Callback: 收到合成音频 TTSResponse: {length = 4, bytes = 0x4f676753}
Callback: TTSEnd: {length = 4, bytes = 0x4f676753}
Callback: 收到合成音频 TTSResponse: {length = 4, bytes = 0x4f676753}
Callback: TTSEnd: {length = 4, bytes = 0x4f676753}
Callback: 收到合成音频 TTSResponse: {length = 4, bytes = 0x4f676753}
Callback: TTSEnd: {length = 4, bytes = 0x4f676753}
Callback: 收到合成音频 TTSResponse: {length = 4, bytes = 0x4f676753}
Callback: TTSEnd: {length = 4, bytes = 0x4f676753}
Callback: 收到合成音频 TTSResponse: {length = 4, bytes = 0x4f676753}
Callback: TTSEnd: {length = 4, bytes = 0x4f676753}
Callback: 收到合成音频 TTSResponse: {length = 4, bytes = 0x4f676753}
Callback: TTSEnd: {length = 4, bytes = 0x4f676753}
Callback: 收到合成音频 TTSResponse: {length = 4, bytes = 0x4f676753}
Callback: TTSEnd: {length = 4, bytes = 0x4f676753}
Callback: 收到合成音频 TTSResponse: {length = 4, bytes = 0x4f676753}
Callback: TTSEnd: {length = 4, bytes = 0x4f676753}
Callback: 收到合成音频 TTSResponse: {length = 4, bytes = 0x4f676753}
Callback: TTSEnd: {length = 4, bytes = 0x4f676753}
Callback: 合成结束 SentenceEnd: {length = 87, bytes = 0x7b227068 6f6e656d 6573223a 5b5d2c22 ... 72647322 3a5b5d7d }
Callback: 收到合成音频 TTSResponse: {length = 87, bytes = 0x7b227068 6f6e656d 6573223a 5b5d2c22 ... 72647322 3a5b5d7d }
Callback: TTSEnd: {length = 87, bytes = 0x7b227068 6f6e656d 6573223a 5b5d2c22 ... 72647322 3a5b5d7d }
Callback: SEEventSessionFinished
Callback: 结束播放TTS音频