You need to enable JavaScript to run this app.
导航
接入流程
最近更新时间:2022.09.26 17:46:17首次发布时间:2022.09.26 17:46:17
初始化

环境依赖

创建声音复刻 SDK 引擎实例前调用,完成网络环境等相关依赖配置。本方法每个App进程生命周期内仅需调用一次。

[SpeechEngine prepareEnvironment];

创建引擎实例

声音复刻 SDK 如下方式获取相关实例。

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

通用参数配置

对于声音复刻 SDK 所有流程,需配置如下通用参数:

引擎类型

// 声音复刻引擎
[self.engine setStringParam:SE_VOICECLONE_ENGINE forKey:SE_PARAMS_KEY_ENGINE_NAME_STRING];

日志

为便于开发者集成调试,有如下建议:

  • 日志级别,开发时设置为 TRACE线上设置WARN

  • 调试路径,声音复刻 SDK 会在该路径下生成名为 speech_sdk.log 的日志文件,开发时设置,线上关闭

// 日志级别
[self.engine setStringParam:SE_LOG_LEVEL_TRACE forKey:SE_PARAMS_KEY_LOG_LEVEL_STRING];
// 调试路径
[self.engine setStringParam:@"{DEBUG PATH}" forKey:SE_PARAMS_KEY_DEBUG_PATH_STRING];

用户子ID

  • UID,用户子ID,每个UID至多复刻一个音色类型。

如果需要一个用户持有多个音色,需要业务方自行组织用户子ID格式,例如通过“用户ID + 序号/时间戳”来生成用户子ID,从而确保音色的唯一性。

[self.engine setStringParam:@"{YOUR UID}" forKey:SE_PARAMS_KEY_UID_STRING];

鉴权

需要申请 AppidToken,配置时 Token 需要添加固定前缀 Bearer;

[self.engine setStringParam:@"{APPID}" forKey:SE_PARAMS_KEY_APP_ID_STRING];
[self.engine setStringParam:@"Bearer;{TOKEN}" forKey:SE_PARAMS_KEY_APP_TOKEN_STRING];

网络配置

发起声音复刻请求,需要配置请求地址 参数。

[self.engine setStringParam:@"https://openspeech.bytedance.com" forKey:SE_PARAMS_KEY_VOICECLONE_ADDRESS_STRING];
[self.engine setStringParam:@"wss://openspeech.bytedance.com" forKey:SE_PARAMS_KEY_VOICECLONE_STREAM_ADDRESS_STRING];

SDK 还支持调整建连、接收超时,单位:毫秒。

// 如无特殊需要,建议使用默认值
[self.engine setIntParam:12000 forKey:SE_PARAMS_KEY_VOICECLONE_CONN_TIMEOUT_INT];
[self.engine setIntParam:8000 forKey:SE_PARAMS_KEY_VOICECLONE_RECV_TIMEOUT_INT];

音频来源

语音识别 SDK 支持以录音机、原始音频流或音频文件作为输入,配置值分别为:

  • RECORDER_TYPE_RECORDER,系统内置录音机,SDK控制录音流程;
[self.engine setStringParam:SE_RECORDER_TYPE_RECORDER
                            forKey:SE_PARAMS_KEY_RECORDER_TYPE_STRING];
  • RECORDER_TYPE_FILE,原始音频文件,需要设置音频文件路径;
[self.engine setStringParam:SE_RECORDER_TYPE_FILE
                            forKey:SE_PARAMS_KEY_RECORDER_TYPE_STRING];
[self.engine setStringParam:@"../data/voiceclone_rec_file.pcm"
                            forKey:SE_PARAMS_KEY_RECORDER_FILE_STRING];
  • RECORDER_TYPE_STREAM,原始音频流,需要在执行过程中 输入音频数据,并在所有音频数据均输入完成后,发送 音频输入完成 指令;
[self.engine setStringParam:SE_RECORDER_TYPE_STREAM
                            forKey:SE_PARAMS_KEY_RECORDER_TYPE_STRING];

// ...
// 启动某复刻流程
// ...

// 流式输入音频数据
while (data_size > 0) {
    SEEngineErrorCode ret = [self.engine feedAudio:data length:data_size];
    if (ret != SENoError) {
        NSLog(@"Fail to feed data to engine: %d", ret);
    }
}
// 音频输入完成
SEEngineErrorCode ret = [self.engine sendDirective:SEDirectiveFinishTalking];
if (ret != SENoError) {
    NSLog(@"Fail to finish talking: %d", ret);
}

写录音文件

对于复刻流程中可能出现的录音操作,是否将录到的音频以wav格式写录音文件。

// 是否开启写录音文件
[self.engine setBoolParam:TRUE forKey:SE_PARAMS_KEY_VOICECLONE_ENABLE_DUMP_BOOL];
// 写录音文件路径
[self.engine setStringParam:@"{REC FILE PATH}" forKey:SE_PARAMS_KEY_VOICECLONE_REC_PATH_STRING];

初始化引擎实例

参数配置完成后,调用 初始化接口,完成引擎实例的初始化。

SEEngineErrorCode ret = [self.engine initEngine];
if (ret != SENoError) {
    NSLog(@"Init Engine failed: %d", ret);
}
执行复刻流程

1 获取声音复刻任务信息

1.1 额外参数配置

  • 用户性别: 设置用户性别从而提升复刻效果,false为男,true为女.
// 设置用户性别
[self.engine setBoolParam:FALSE forKey:SE_PARAMS_KEY_VOICECLONE_GENDER_BOOL];

1.2 执行指令

  • 获取声音复刻任务信息
SEEngineErrorCode ret = [self.engine sendDirective:SEDirectiveVoiceCloneGetTask];
if (ret != SpeechEngineDefines.ERR_NO_ERROR) {
    NSLog(@"Fail to get task: %d", ret);
}

1.3 处理回调结果

- (void)onMessageWithType:(SEMessageType)type andData:(NSData *)data {
    NSString *dataStr = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
    switch (type) {
        case SEVoiceCloneGetTaskResult: 
            NSLog(@"Get task: %@.", dataStr);
            break;
    }
}

其中data为任务信息JSON字符串,JSON格式如下:

[
        {
            "task_id":10,                 // int32, 音色复刻任务ID,任务类型标识
            "progress":1,                 // int32, 当前用户已完成进度
            "total_text":20,              // int32, 任务文本数
            "texts":["文本","文本","文本"]  // array(string), 任务文本数组,每项为所需朗读的文本字符串
        },
        {
            "task_id":11,
            "progress":1,
            "total_text":20,
            "texts":["文本","文本","文本"]
        }
]

2 录音环境检测

2.1 额外参数配置

  • 复刻任务ID 设置执行的复刻任务ID。
// 设置当前执行的任务ID
[self.engine setIntParam:10 forKey:SE_PARAMS_KEY_VOICECLONE_TASKID_INT];

2.2 执行指令

  • 录音环境检测
SEEngineErrorCode ret = [self.engine sendDirective:SEDirectiveVoiceCloneCheckEnv];
if (ret != SpeechEngineDefines.ERR_NO_ERROR) {
    NSLog(@"Fail to check env: %d", ret);
}

2.3 处理回调结果

- (void)onMessageWithType:(SEMessageType)type andData:(NSData *)data {
    NSString *dataStr = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
    switch (type) {
        case SEVoiceCloneCheckEnvResult: 
            NSLog(@"Check env: %@.", dataStr);
            break;
    }
}

其中data为检测结果JSON字符串,JSON格式如下:

{
    "status":0,    // int32, 环境检测状态
    "noise":1,     // double(float64), 噪音分贝
}

其中status:(等于0 -- 通过;小于0 -- 未通过;大于0 -- 检测中)

  • 2:检测中,当前时间区间噪音较大

  • 1:检测中,当前时间区间信噪比检测正常

  • 0:检测通过

  • -1:检测失败,未知错误

  • -2:检测未通过,噪音较大

3 录音上传

3.1 额外参数配置

  • 复刻任务ID 设置执行的复刻任务ID。

  • 文本序号: 当前朗读的文本在整个任务中的序号,0为第一句。

  • 文本内容: 当前朗读的任务文本内容。

// 设置当前执行的复刻任务ID
[self.engine setIntParam:10 forKey:SE_PARAMS_KEY_VOICECLONE_TASKID_INT];
// 设置任务文本序号
[self.engine setIntParam:0 forKey:SE_PARAMS_KEY_VOICECLONE_TEXT_SEQ_INT];
// 设置任务文本内容
[self.engine setStringParam:@"文本" forKey:SE_PARAMS_KEY_VOICECLONE_TEXT_STRING];

3.2 执行指令

  • 开始录音并上传
SEEngineErrorCode ret = [self.engine sendDirective:SEDirectiveVoiceCloneRecordVoice];
if (ret != SpeechEngineDefines.ERR_NO_ERROR) {
    NSLog(@"Fail to record voice: %d", ret);
}
  • 结束录音
// 音频输入完成,等待最终处理结果
[self.engine sendDirective:SEDirectiveFinishTalking];

3.3 处理回调结果

- (void)onMessageWithType:(SEMessageType)type andData:(NSData *)data {
    NSString *dataStr = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
    switch (type) {
        case SEVoiceCloneRecordVoiceResult: 
            NSLog(@"Record voice: %@.", dataStr);
            break;
    }
}

其中data为检测结果JSON字符串,JSON格式如下:

{
    "status":0,         // int32, 录音检测结果
    "wrong_index": [    // array(int32), 检测未通过的word索引,假设有文本 "一二三四五六"  而wrong_index:[2] 的意思是 "三"字没有通过检测
        2, 3
    ]
}

其中status: (等于0 -- 通过;小于0 -- 未通过;大于0 -- 检测中)

  • 0: 检测通过

  • -1: 检测失败,未知错误

  • -2: 噪音太大

  • -3: 声音太小

  • -4: 声音太大

  • -5: 信噪比过低

  • -6: 识别结果中有错字

  • -7: 识别结果中有多读

  • -8: 识别结果中有漏读

  • -9: 录音进度冲突,如重复录制当前位置之前的文本

注:多读、漏读时wrong_index为空,且问题优先级:多读 > 漏读 > 错字,即有多读时会忽略漏读错字等问题。

4 提交训练任务

4.1 额外参数配置

  • 复刻任务ID 设置执行的复刻任务ID。
// 设置当前执行的任务ID
[self.engine setIntParam:10 forKey:SE_PARAMS_KEY_VOICECLONE_TASKID_INT];

4.2 执行指令

  • 提交训练任务
SEEngineErrorCode ret = [self.engine sendDirective:SEDirectiveVoiceCloneSubmitTask];
if (ret != SpeechEngineDefines.ERR_NO_ERROR) {
    NSLog(@"Fail to submit: %d", ret);
}

4.3 处理回调结果

- (void)onMessageWithType:(SEMessageType)type andData:(NSData *)data {
    NSString *dataStr = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
    switch (type) {
        case SEVoiceCloneSubmitTaskResult: 
            NSLog(@"Submit task: %@.", dataStr);
            break;
    }
}

其中data 为JSON字符串, JSON格式如下:

{
    "voice_type":"abc",     // string, 音色名,用于训练完成后语音合成时做传入参数
}

5 查询用户训练任务状态

5.1 额外参数配置

  • 查询用户子ID 设置需要查询的用户子ID,可以使用英文分号";"连接,从而一次查询多个uid状态。其中若存在空字符串则会被忽略(请不要插入空格等额外字符,空格等会被认为是用户子ID的一部分)。示例: "uid1;uid2;uid3"
// 设置需要查询的用户子ID
[self.engine setStringParam:@"uid1;uid2;uid3" forKey:SE_PARAMS_KEY_VOICECLONE_QUERY_UIDS_STRING];

5.2 执行指令

  • 查询用户训练任务状态
SEEngineErrorCode ret = [self.engine sendDirective:SEDirectiveVoiceCloneQueryStatus];
if (ret != SpeechEngineDefines.ERR_NO_ERROR) {
    NSLog(@"Fail to query status: %d", ret);
}

5.3 处理回调结果

- (void)onMessageWithType:(SEMessageType)type andData:(NSData *)data {
    NSString *dataStr = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
    switch (type) {
        case SEVoiceCloneQueryStatusResult: 
            NSLog(@"Query status: %@.", dataStr);
            break;
    }
}

其中data为查询结果JSON字符串,JSON格式如下:

[
    {
        "status":0,                 // int32, 状态码
        "uid":"388808087185088",    // string, 用户子ID 
        "task_id":1,                // int32, 任务ID
        "appid":"test",
        "extra":{
            "voice_type": "xxx",    // string, 音色名,用于训练完成后语音合成时做传入参数
            "vc_styles":[
                {"name":"通用中文","value":"default"},
                {"name":"通用美式英文","value":"en"}
            ],  // 音色支持的风格名和风格值,其中风格值可以传入TTS引擎合成使用。
            "record_url":["",""] // 录音音频地址
        }
    },
    {
        "status":1,
        "uid":"388808087185088",
        "appid":"test",
        "task_id":1,
        "extra":{}
    },
    {
        "uid":"388808087185088",
        "appid":"test",
        "task_id":1,
        "status":2,
        "extra":{
            "queueing_count":10, // 前面排队中的人
            "queueing_cost":50, // 排队耗时,单位为分钟
        }
    },
    {
        "uid":"388808087185088",
        "appid":"test",
        "task_id":1,
        "status":3,
        "extra":{
            "training_cost":50, // 训练平均耗时,单位为分钟
        }
    },
    {
        "uid":"388808087185088",
        "appid":"test",
        "task_id":1,
        "status":4,
        "extra":{
            "loading_cost":2, // 加载平均耗时,单位为分钟
        }
    }
]

其中status: (等于0 -- 通过;小于0 -- 训练失败;大于0 -- 训练中)

  • -2: 任务不存在

  • -1: 训练失败

  • 0: 音色可用

  • 1: 录制中

  • 2: 排队中

  • 3: 训练中

  • 4: 音色加载中

6 删除用户训练数据

6.1 额外参数配置

  • 复刻任务ID 设置执行的复刻任务ID。
// 设置当前执行的任务ID
[self.engine setIntParam:10 forKey:SE_PARAMS_KEY_VOICECLONE_TASKID_INT];

6.2 执行指令

  • 删除用户训练数据
SEEngineErrorCode ret = [self.engine sendDirective:SEDirectiveVoiceCloneDeleteData];
if (ret != SpeechEngineDefines.ERR_NO_ERROR) {
    NSLog(@"Fail to delete data: %d", ret);
}

6.3 处理回调结果

- (void)onMessageWithType:(SEMessageType)type andData:(NSData *)data {
    switch (type) {
        case SEVoiceCloneDeleteDataResult: 
            NSLog(@"Delete data.");
            break;
    }
}

接收到该回调即为删除成功,其中data为空字符串。

停止引擎

一个引擎实例在一时间只能执行某一个流程,可以通过两种方式立刻停止正在执行的流程而不需要处理结果。

异步停止

需要在收到 SEEngineStop 消息后引擎才算真正停止。

[self.engine sendDirective:SEDirectiveStopEngine];

同步停止

执行后会在当前位置等待引擎结束,再执行下一行代码。请勿直接在回调线程中执行该方法,否则可能导致死锁等待。

[self.engine sendDirective:SEDirectiveSyncStopEngine];
销毁引擎实例

当不再需要声音复刻功能后,建议对引擎实例进行销毁,释放内存资源。

[self.engine destroyEngine];
self.engine = nil;