使用说明

  • Android

更新时间不可用

了解云市场在不同平台上的集成讯飞转写及翻译插件方式,包括接入流程、关键配置和平台差异。

技术原理

本文介绍如何在你的项目中集成和使用讯飞语音实时转写及翻译(多语种)插件(以下简称“讯飞转写及翻译插件”)。讯飞转写及翻译插件的工作流程如下:

  1. 设置源语种和目标语种。
  2. 声网 SDK 通过麦克风来流式录音。
  3. 音频传递给讯飞转写及翻译插件。
  4. 插件把音频上传给语音转写服务,并下载语音转写结果。
  5. 解析语音转写结果,得到语音转写文本。
  6. 把语音转写文本上传给文本翻译服务,并下载文本翻译结果。
  7. 解析文本翻译结果,得到文本翻译文本。

前提条件

Android 开发环境需满足以下要求:

  • Android Studio 4.1 以上版本。
  • 运行 Android 4.1 或以上版本的真机(非模拟器)。

示例项目

讯飞转写及翻译插件提供了示例项目,你可以前往克隆或下载并进行体验。

平台语言示例代码
AndroidJava点击下载
iOSObjective-C点击下载
WindowsC++点击下载
表格内容超出当前宽度,可横向滚动查看更多列。

运行步骤

参考以下步骤快速跑通示例项目:

  1. 在 Android Studio 中打开示例项目。

  2. 将项目与 Gradle 文件同步。

  3. 打开 AgoraWithHyAndroid/app/src/main/java/agoramarketplace/hy/demo/MainActivity.java 文件,将 #YOUR APP ID# 替换为你的声网 App ID。获取 App ID 请参考开通云市场服务。

    Java
    private static final String appId = "#YOUR APP ID#";
  4. 打开 AgoraWithHyAndroid/app/src/main/java/agoramarketplace/hy/demo/HyUtil.java 文件,填入以下参数:

    Java
    /** 在声网控制台购买插件后、由讯飞提供的 APPID */
    public static final String APP_ID = "";
    /** 在声网控制台购买插件后、由讯飞提供的 APIKey */
    public static final String API_KEY = "";
    /** 在声网控制台购买插件后、由讯飞提供的 APISecret */
    public static final String API_SECRET = "";
  5. 连接一台 Android 真机(非模拟器),运行项目。

预期效果

运行成功后,示例项目会安装到你的设备上。

  1. 启动 App,你可以在界面上看到中译英下拉控件,start、flush、stop 按钮,以及 tip、ist_text、its_text 文本视图。
  2. 可以单击中译英下拉控件选择参数。
  3. 单击 start 按钮启动倾听。
  4. 对着麦克风说话,语音转写文本会显示在 ist_text 文本视图中,文本翻译文本会显示在 its_text 文本视图中。
  5. 单击 flush 按钮结束音频获取结果,或单击 stop 按钮停止倾听。
  6. tip 文本视图会显示 onEnd。

集成和调用流程

1. 集成 SDK 和插件

开始前,你需要在项目中分别集成声网音频 SDK 和讯飞转写及翻译插件。

1.1 集成声网音频 SDK

讯飞转写及翻译插件需要与声网音频 SDK v4.x 搭配使用。参考以下文档集成音频 SDK v4.x 并实现基础的语音通话:

1.2 购买和激活插件

你需要进入声网控制台 > 云市场页面,按照提示购买讯飞转写及翻译插件。购买成功后,你会收到由讯飞提供的 APPID、APIKey 和 APISecret,后续启动倾听时需要用到。

1.3 集成插件

参考以下步骤集成插件:

  1. 进入声网控制台 > 云市场页面下载**讯飞语音实时转写及翻译(多语种)**的 Android 插件包。

  2. 解压文件夹,将所有 .aar 文件保存到项目文件夹的 /app/libs 路径。

  3. 打开 app/build.gradle 文件,在 dependencies 中添加如下行:

    Java
    implementation fileTree(dir: "libs", include: ["*.jar", "*.aar"])
  4. 打开编写逻辑的 Java 文件,添加如下行,导入插件信息类:

    Java
    import io.agora.hy.extension.ExtensionManager;

1.4 升级插件

声网云市场推荐你在更新插件版本前使用数据库工具(如 SQLite)实现插件版本管理,从而确保插件版本与对应的资源包版本一致。因为当插件版本和资源包版本未对齐时,会出现 App 闪退、崩溃等现象。

以下是用 SQLite 来进行插件版本管理的示例:

  1. 使用 SQLite 数据库自行维护插件包和资源包的版本信息。
  2. 每次项目初始化时,自动检测当前项目使用的资源包版本:
    • 如果无记录文件或记录的资源包版本为旧,则更新资源。成功更新后,回写最新资源包版本信息到 SQLite。
    • 如果记录的资源包版本与当前匹配,则正常实现业务。

如果你的项目已经集成过声网云市场提供的第三方插件,并需要更新插件,可以参考以下步骤来保证更新后的可用性。

以下升级流程以相芯美颜特效插件为例:

  1. 参考集成插件章节下载所需平台最新版本的插件包和资源包。

  2. 删除项目内旧版本的插件包及其资源包后,再将新版插件和资源包放入对应位置。或者直接在对应目录下用新版插件和资源包替换旧版。

  3. 删除设备上用老版本插件和资源包编译的 App,重新编译你的项目并运行。

注意

编译 App 时,系统会优先使用连接设备上存在的资源包。请务必在删除旧版本应用程序后再进行编译和运行,否则可能会出现插件版本与资源包不匹配的情况,从而导致各种意外问题。

2. 初始化

集成插件后,你需要先初始化插件,步骤如下:

  1. RtcEngineConfig 实例调用 addExtension,将插件添加到 SDK 中。

    Java
    config.addExtension(ExtensionManager.EXTENSION_NAME);
  2. RtcEngineConfig 实例设置 mExtensionObserver 监听器。

    Java
    private final IMediaExtensionObserver mMediaExtensionObserver = new IMediaExtensionObserver() {
        @Override
        public void onEvent(String provider, String extension, String key, String value) {
            Log.i(TAG, "onEvent | provider: " + provider + ", extension: " + extension
                    + ", key: " + key + ", value: " + value);
            if (!ExtensionManager.EXTENSION_VENDOR_NAME.equals(provider)
                    || !ExtensionManager.EXTENSION_AUDIO_FILTER_NAME.equals(extension)) {
                return;
            }
    
            mHyUtil.onEvent(key, value);
        }
    }
    Java
    config.mExtensionObserver = mMediaExtensionObserver;
  3. 在加入频道前,调用 enableExtension 开启插件。

    Java
    mRtcEngine.enableExtension(ExtensionManager.EXTENSION_VENDOR_NAME, ExtensionManager.EXTENSION_AUDIO_FILTER_NAME, true);
  4. 插件设置 logcat 日志等级。

    Java
    mRtcEngine.setExtensionProviderProperty(ExtensionManager.EXTENSION_VENDOR_NAME, "log_lvl", "" + 8);

3. 启动倾听

空闲时可调用,调用后会进入会话。会话最长 5 小时。

Java
public void start(ParamWrap paramWrap) {
    mParser.clear();

    String val = null;
    try {
        JSONObject rootJo = new JSONObject();
        // 公共对象。必选。
        JSONObject commonJo = new JSONObject();
        {
            // 应用标识。必选。对应在声网控制台购买插件后、由讯飞提供的 APPID。
            commonJo.put("app_id", APP_ID);
            // API 密钥。必选。对应在声网控制台购买插件后、由讯飞提供的 APIKey。
            commonJo.put("api_key", API_KEY);
            // API 秘密。必选。对应在声网控制台购买插件后、由讯飞提供的 APISecret。
            commonJo.put("api_secret", API_SECRET);
        }
        rootJo.put("common", commonJo);
        // 语音转写对象。必选。
        JSONObject istJo = new JSONObject();
        {
            // URI。必选。
            istJo.put("uri", "wss://ist-api.xfyun.cn/v2/ist");
            // 请求对象。必选。
            JSONObject reqJo = new JSONObject();
            {
                // 业务对象。必选。
                JSONObject businessJo = new JSONObject();
                {
                    // 语种。必选。
                    businessJo.put("language", paramWrap.mIstLanguage);
                    // 口音。必选。
                    businessJo.put("accent", paramWrap.mIstAccent);
                    // 领域。必选。
                    businessJo.put("domain", paramWrap.mIstDomain);
                    // 语言类型
                    // 值类型:int
                    // 值范围:
                    // 1:中英文模式,中文英文均可识别;
                    // 3:英文模式,只识别出英文
                    // 值默认:1
                    businessJo.put("language_type", paramWrap.mIstLanguageType);
                    // 动态修正
                    businessJo.put("dwa", paramWrap.mIstDwa);
                }
                reqJo.put("business", businessJo);
            }
            istJo.put("req", reqJo);
        }
        rootJo.put("ist", istJo);
        // 文本翻译对象。
        JSONObject itsJo = new JSONObject();
        {
            // URI。必选。
            itsJo.put("uri", "https://itrans.xfyun.cn/v2/its");
            // 请求对象。必选。
            JSONObject reqJo = new JSONObject();
            {
                // 业务对象。必选。
                JSONObject businessJo = new JSONObject();
                {
                    // 源语种。必选。
                    businessJo.put("from", paramWrap.mItsFrom);
                    // 目标语种。必选。
                    businessJo.put("to", paramWrap.mItsTo);
                }
                reqJo.put("business", businessJo);
            }
            itsJo.put("req", reqJo);
        }
        rootJo.put("its", itsJo);
        val = rootJo.toString();
    } catch (JSONException e) {
        mListener.onLogE(TAG + ".start | json fail", e);
        return;
    }
    int errCode = mRtcEngine.setExtensionProperty(ExtensionManager.EXTENSION_VENDOR_NAME,
            ExtensionManager.EXTENSION_AUDIO_FILTER_NAME, "start_listening", val);
    mListener.onLogI(TAG + ".start | mRtcEngine.setExtensionProperty errCode: " + errCode);
}

4. 结束音频获取结果

会话时可调用,调用后会先处理完音频和结果,再进入空闲,回调 "end"。

Java
public void flush() {
    // 值不能为空,否则收不到。
    int errCode = mRtcEngine.setExtensionProperty(ExtensionManager.EXTENSION_VENDOR_NAME, ExtensionManager.EXTENSION_AUDIO_FILTER_NAME, "flush_listening", "{}");
    mListener.onLogI(TAG + ".flush | mRtcEngine.setExtensionProperty errCode: " + errCode);
}

讯飞转写及翻译插件会通过 onEvent 回调返回语音转写和文本翻译结果。识别结果的含义详见 onEvent 回调的 key。

5. 停止倾听

会话时可调用,调用后会先丢弃音频和结果,再进入空闲,回调 "end"。

Java
public void stop() {
    int errCode = mRtcEngine.setExtensionProperty(ExtensionManager.EXTENSION_VENDOR_NAME, ExtensionManager.EXTENSION_AUDIO_FILTER_NAME, "stop_listening", "{}");
    mListener.onLogI(TAG + ".stop | mRtcEngine.setExtensionProperty errCode: " + errCode);
}

参考信息

API 参考

常见问题

1. 在 MacBook 上运行 Android 示例项目为什么会编译失败?

由于示例项目中 Android NDK 的路径默认为 Windows 设备上的路径,因此在 MacBook 上会编译失败并提示 Location specified by ndk.dir did not contain a valid NDK。参考以下步骤解决:

  1. 在 Android Studio 的顶部菜单栏中依次点击 File > Project Structure... > SDK Location,将 Android NDK location 的路径替换为你的本地路径,并且复制该路径。

  2. 打开 local.properties 文件,将 ndk.dir 的路径替换为你刚才复制的路径,并且保存修改。

  3. 连接 Android 设备,再次运行。

2. 为什么在编译 App 时会出现 models: no match 的报错?

该错误通常是由于资源包匹配问题引起的。很可能是因为在编译新插件时,没有删除旧版本的 App。建议你删除旧版 App 后重新编译运行。