使用说明
本文介绍如何在你的项目中集成和使用讯飞语音实时转写及翻译(多语种)插件(以下简称“讯飞转写及翻译插件”)。
技术原理
讯飞转写及翻译插件的工作流程如下:
- 设置源语种和目标语种。
- 声网 SDK 通过麦克风来流式录音。
- 音频传递给讯飞转写及翻译插件。
- 插件把音频上传给语音转写服务,并下载语音转写结果。
- 解析语音转写结果,得到语音转写文本。
- 把语音转写文本上传给文本翻译服务,并下载文本翻译结果。
- 解析文本翻译结果,得到文本翻译文本。
前提条件
Android 开发环境需满足以下要求:
- Android Studio 4.1 以上版本。
- 运行 Android 4.1 或以上版本的真机(非模拟器)。
示例项目
讯飞转写及翻译插件提供了示例项目,你可以前往克隆或下载并进行体验。
平台 | 语言 | 示例代码 |
---|---|---|
Android | Java | 点击下载 |
iOS | Objective-C | 点击下载 |
Windows | C++ | 点击下载 |
运行步骤
参考以下步骤快速跑通示例项目:
-
在 Android Studio 中打开示例项目。
-
将项目与 Gradle 文件同步。
-
打开
AgoraWithHyAndroid/app/src/main/java/agoramarketplace/hy/demo/MainActivity.java
文件,将#YOUR APP ID#
替换为你的声网 App ID。获取 App ID 请参考开通服务。Javaprivate static final String appId = "#YOUR APP ID#";
-
打开
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 = ""; -
连接一台 Android 真机(非模拟器),运行项目。
预期效果
运行成功后,示例项目会安装到你的设备上。
- 启动 App,你可以在界面上看到中译英下拉控件,start、flush、stop 按钮,以及 tip、ist_text、its_text 文本视图。
- 可以单击中译英下拉控件选择参数。
- 单击 start 按钮启动倾听。
- 对着麦克风说话,语音转写文本会显示在 ist_text 文本视图中,文本翻译文本会显示在 its_text 文本视图中。
- 单击 flush 按钮结束音频获取结果,或单击 stop 按钮停止倾听。
- tip 文本视图会显示 onEnd。
集成和调用流程
1. 集成 SDK 和插件
开始前,你需要在项目中分别集成声网音频 SDK 和讯飞转写及翻译插件。
1.1 集成声网音频 SDK
讯飞转写及翻译插件需要与声网音频 SDK v4.x 搭配使用。参考以下文档集成音频 SDK v4.x 并实现基础的语音通话:
1.2 购买和激活插件
你需要进入声网控制台 > 云市场页面,按照提示购买讯飞转写及翻译插件。购买成功后,你会收到由讯飞提供的 APPID、APIKey 和 APISecret,后续启动倾听时需要用到。
1.3 集成插件
参考以下步骤集成插件:
-
进入声网控制台 > 云市场页面下载讯飞语音实时转写及翻译(多语种)的 Android 插件包。
-
解压文件夹,将所有
.aar
文件保存到项目文件夹的/app/libs
路径。 -
打开
app/build.gradle
文件,在dependencies
中添加如下行:Javaimplementation fileTree(dir: "libs", include: ["*.jar", "*.aar"])
-
打开编写逻辑的 java 文件,添加如下行,导入插件信息类:
Javaimport io.agora.hy.extension.ExtensionManager;
1.4 升级插件
声网云市场推荐你更新插件版本前使用数据库工具 (如 SQLite) 来实现插件版本管理,从而确保插件版本与对应的资源包版本一致。因为当插件版本和资源包版本未对齐时,会出现 App 闪退、崩溃等现象。
以下是用 SQLite 来进行插件版本管理的示例:
- 使用 SQLite 数据库自行维护插件包和资源包的版本信息。
- 每次项目初始化时,自动检测当前项目使用的资源包版本:
- 如果无记录文件或记录的资源包版本为旧,则更新资源。成功更新后,回写最新资源包版本信息到 SQLite。
- 如果记录的资源包版本与当前匹配,则正常实现业务。
如果你的项目已经集成过声网云市场提供的第三方插件,并需要更新插件,可以参考以下步骤来保证更新后的可用性。
以下升级流程以相芯美颜特效插件为例:
-
参考集成插件章节下载所需平台最新版本的插件包和资源包。
-
删除项目内旧版本的插件包及其资源包后,再将新版插件和资源包放入对应位置。或者直接在对应目录下用新版插件和资源包替换旧版。
-
删除设备上用老版本插件和资源包编译的 App,重新编译你的项目并运行。
编译 App 时,系统会优先使用连接设备上存在的资源包。请务必在删除旧版本应用程序后再进行编译和运行,否则可能会出现插件版本与资源包不匹配的情况,从而导致各种意外问题。
2. 初始化
集成插件后,你需要先初始化插件,步骤如下:
-
RtcEngineConfig
实例调用addExtension
,将插件添加到 SDK 中。Javaconfig.addExtension(ExtensionManager.EXTENSION_NAME);
-
RtcEngineConfig
实例设置mExtensionObserver
监听器。Javaprivate 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);
}
}Javaconfig.mExtensionObserver = mMediaExtensionObserver;
-
在加入频道前,调用
enableExtension
开启插件。JavamRtcEngine.enableExtension(ExtensionManager.EXTENSION_VENDOR_NAME, ExtensionManager.EXTENSION_AUDIO_FILTER_NAME, true);
-
插件设置 logcat 日志等级。
JavamRtcEngine.setExtensionProviderProperty(ExtensionManager.EXTENSION_VENDOR_NAME, "log_lvl", "" + 8);
3. 启动倾听
空闲时可调用,调用后会进入会话。会话最长 5 小时。
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"
。
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"
。
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
。参考以下步骤解决:
- 在 Android Studio 的顶部菜单栏中依次点击 File > Project Structure... > SDK Location,将 Android NDK location 的路径替换为你的本地路径,并且复制该路径。
- 打开
local.properties
文件,将ndk.dir
的路径替换为你刚才复制的路径,并且保存修改。 - 连接 Android 设备,再次运行。
2. 为什么在编译 App 时会出现 models: no match
的报错?
该错误通常是由于资源包匹配问题引起的。很可能是因为在编译新插件时,没有删除旧版本的 App。建议你删除旧版 App 后重新编译运行。