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

环境依赖

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

SpeechEngineGenerator.PrepareEnvironment(getApplicationContext(), getApplication());

创建引擎实例

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

SpeechEngine engine = SpeechEngineGenerator.getInstance();
engine.createEngine();

通用参数配置

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

引擎类型

// 声音复刻引擎
engine.setOptionString(SpeechEngineDefines.PARAMS_KEY_ENGINE_NAME_STRING,
                        SpeechEngineDefines.VOICECLONE_ENGINE);

日志

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

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

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

engine.setOptionString(SpeechEngineDefines.PARAMS_KEY_LOG_LEVEL_STRING,
                        SpeechEngineDefines.LOG_LEVEL_WARN);
engine.setOptionString(SpeechEngineDefines.PARAMS_KEY_DEBUG_PATH_STRING,
                        "{DEBUG PATH}");

用户子ID

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

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

engine.setOptionString(SpeechEngineDefines.PARAMS_KEY_UID_STRING, "{YOUR UID}");

鉴权

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

engine.setOptionString(SpeechEngineDefines.PARAMS_KEY_APP_ID_STRING,
                        "{YOUR APPID}");
engine.setOptionString(SpeechEngineDefines.PARAMS_KEY_APP_TOKEN_STRING,
                        "Bearer;{YOUR TOKEN}");

网络配置

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

engine.setOptionString(SpeechEngineDefines.PARAMS_KEY_VOICECLONE_ADDRESS_STRING,
                        "https://openspeech.bytedance.com");
engine.setOptionString(SpeechEngineDefines.PARAMS_KEY_VOICECLONE_STREAM_ADDRESS_STRING,
                        "wss://openspeech.bytedance.com");

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

// 如无特殊需要,建议使用默认值
engine.setOptionInt(SpeechEngineDefines.PARAMS_KEY_VOICECLONE_CONN_TIMEOUT_INT, 12000);
engine.setOptionInt(SpeechEngineDefines.PARAMS_KEY_VOICECLONE_RECV_TIMEOUT_INT, 8000);

音频来源

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

  • RECORDER_TYPE_RECORDER,系统内置录音机,SDK控制录音流程;
engine.setOptionString(SpeechEngineDefines.PARAMS_KEY_RECORDER_TYPE_STRING,
                        SpeechEngineDefines.RECORDER_TYPE_RECORDER);
  • RECORDER_TYPE_FILE,原始音频文件,需要设置音频文件路径;
engine.setOptionString(SpeechEngineDefines.PARAMS_KEY_RECORDER_TYPE_STRING,
                        SpeechEngineDefines.RECORDER_TYPE_FILE);
engine.setOptionString(SpeechEngineDefines.PARAMS_KEY_RECORDER_FILE_STRING,
                        "../data/voiceclone_rec_file.pcm");
  • RECORDER_TYPE_STREAM,原始音频流,需要在执行过程中 输入音频数据,并在所有音频数据均输入完成后,发送 音频输入完成 指令;
engine.setOptionString(SpeechEngineDefines.PARAMS_KEY_RECORDER_TYPE_STRING,
                        SpeechEngineDefines.RECORDER_TYPE_STREAM);

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

// 流式输入音频数据
while (nread > 0) {
    int ret = engine.feedAudio(buffer, nread);
    if (ret != SpeechEngineDefines.ERR_NO_ERROR) {
        Log.e(SpeechDefines.TAG, "Feed audio Failed: " + ret);
    }
}
// 音频输入完成
int ret = engine.sendDirective(SpeechEngineDefines.DIRECTIVE_FINISH_TALKING, "");
if (ret != SpeechEngineDefines.ERR_NO_ERROR) {
    Log.e(SpeechDefines.TAG, "Finish talking Failed: " + ret);
}

写录音文件

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

// 是否开启写录音文件
engine.setOptionBoolean(SpeechEngineDefines.PARAMS_KEY_VOICECLONE_ENABLE_DUMP_BOOL, true);
// 写录音文件路径
engine.setOptionString(SpeechEngineDefines.PARAMS_KEY_VOICECLONE_REC_PATH_STRING, "{REC FILE PATH}");

初始化引擎实例

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

int ret = engine.initEngine();
if (ret != SpeechEngineDefines.ERR_NO_ERROR) {
    String errMessage = "Init Engine Failed: " + ret;
    Log.e(SpeechDefines.TAG, errMessage);
}
engine.setListener(this);
执行复刻流程

1 获取声音复刻任务信息

1.1 额外参数配置

  • 用户性别: 设置用户性别从而提升复刻效果,false为男,true为女.
// 设置用户性别
engine.setOptionBoolean(SpeechEngineDefines.PARAMS_KEY_VOICECLONE_GENDER_BOOL, false);

1.2 执行指令

  • 获取声音复刻任务信息
int ret = engine.sendDirective(SpeechEngineDefines.DIRECTIVE_VOICECLONE_GET_TASK, "");
if (ret != SpeechEngineDefines.ERR_NO_ERROR) {
    Log.e(SpeechDefines.TAG, "Fail to get task: " + ret);
}

1.3 处理回调结果

@Override
public void onSpeechMessage(int type, byte[] bytes, int len) {
    String data = new String(bytes);
    switch (type) {
        case SpeechEngineDefines.MESSAGE_TYPE_VOICECLONE_GET_TASK_RESULT:
            Log.i(SpeechDefines.TAG, "Get task: " + data);
            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
engine.setOptionInt(SpeechEngineDefines.PARAMS_KEY_VOICECLONE_TASKID_INT, 10);

2.2 执行指令

  • 录音环境检测
int ret = engine.sendDirective(SpeechEngineDefines.DIRECTIVE_VOICECLONE_CHECK_ENV, "");
if (ret != SpeechEngineDefines.ERR_NO_ERROR) {
    Log.e(SpeechDefines.TAG, "Fail to check env: " + ret);
}

2.3 处理回调结果

@Override
public void onSpeechMessage(int type, byte[] bytes, int len) {
    String data = new String(bytes);
    switch (type) {
        case SpeechEngineDefines.MESSAGE_TYPE_VOICECLONE_CHECK_ENV_RESULT:
            Log.i(SpeechDefines.TAG, "Check env: " + data);
            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
engine.setOptionInt(SpeechEngineDefines.PARAMS_KEY_VOICECLONE_TASKID_INT, 10);
// 设置任务文本序号
engine.setOptionInt(SpeechEngineDefines.PARAMS_KEY_VOICECLONE_TEXT_SEQ_INT, 0);
// 设置任务文本内容
engine.setOptionString(SpeechEngineDefines.PARAMS_KEY_VOICECLONE_TEXT_STRING, "文本");

3.2 执行指令

  • 开始录音并上传
int ret = engine.sendDirective(SpeechEngineDefines.DIRECTIVE_VOICECLONE_RECORD_VOICE, "");
if (ret != SpeechEngineDefines.ERR_NO_ERROR) {
    Log.e(SpeechDefines.TAG, "Fail to record voice: " + ret);
}
  • 结束录音
// 音频输入完成,等待最终处理结果
engine.sendDirective(SpeechEngineDefines.DIRECTIVE_FINISH_TALKING, "");

3.3 处理回调结果

@Override
public void onSpeechMessage(int type, byte[] bytes, int len) {
    String data = new String(bytes);
    switch (type) {
        case SpeechEngineDefines.MESSAGE_TYPE_VOICECLONE_RECORD_VOICE_RESULT:
            Log.i(SpeechDefines.TAG, "Record voice: " + data);
            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
engine.setOptionInt(SpeechEngineDefines.PARAMS_KEY_VOICECLONE_TASKID_INT, 10);

4.2 执行指令

  • 提交训练任务
int ret = engine.sendDirective(SpeechEngineDefines.DIRECTIVE_VOICECLONE_SUBMIT_TASK, "");
if (ret != SpeechEngineDefines.ERR_NO_ERROR) {
    Log.e(SpeechDefines.TAG, "Fail to submit: " + ret);
}

4.3 处理回调结果

@Override
public void onSpeechMessage(int type, byte[] bytes, int len) {
    String data = new String(bytes);
    switch (type) {
        case SpeechEngineDefines.MESSAGE_TYPE_VOICECLONE_SUBMIT_TASK_RESULT:
            Log.i(SpeechDefines.TAG, "Submit: " + data);
            break;
    }
}

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

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

5 查询用户训练任务状态

5.1 额外参数配置

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

5.2 执行指令

  • 查询用户训练任务状态
int ret = engine.sendDirective(SpeechEngineDefines.DIRECTIVE_VOICECLONE_QUERY_STATUS, "");
if (ret != SpeechEngineDefines.ERR_NO_ERROR) {
    Log.e(SpeechDefines.TAG, "Fail to query status: " + ret);
}

5.3 处理回调结果

@Override
public void onSpeechMessage(int type, byte[] bytes, int len) {
    String data = new String(bytes);
    switch (type) {
        case SpeechEngineDefines.MESSAGE_TYPE_VOICECLONE_QUERY_STATUS_RESULT:
            Log.i(SpeechDefines.TAG, "Query status: " + data);
            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
engine.setOptionInt(SpeechEngineDefines.PARAMS_KEY_VOICECLONE_TASKID_INT, 10);

6.2 执行指令

  • 删除用户训练数据
int ret = engine.sendDirective(SpeechEngineDefines.DIRECTIVE_VOICECLONE_DELETE_DATA, "");
if (ret != SpeechEngineDefines.ERR_NO_ERROR) {
    Log.e(SpeechDefines.TAG, "Fail to delete data: " + ret);
}

6.3 处理回调结果

@Override
public void onSpeechMessage(int type, byte[] bytes, int len) {
    String data = new String(bytes);
    switch (type) {
        case SpeechEngineDefines.MESSAGE_TYPE_VOICECLONE_DELETE_DATA_RESULT:
            Log.i(SpeechDefines.TAG, "Delete data");
            break;
    }
}

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

停止引擎

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

异步停止

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

engine.sendDirective(SpeechEngineDefines.DIRECTIVE_STOP_ENGINE, "");

同步停止

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

engine.sendDirective(SpeechEngineDefines.DIRECTIVE_SYNC_STOP_ENGINE, "");
销毁引擎实例

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

engine.destroyEngine();