title: 在Unity中接入语音相关功能(二)
date: 2023-09-22
description: 通过跨进程通讯的方式,在Unity程序中添加语音交互指令,实现语音助手。
在Unity中接入语音相关功能(二)
在Unity中接入语音相关功能(一) 中通过跨进程通讯的方式实现了调用后台语音服务。
本篇介绍在Unity程序内如何通过调用 思必驰 SDK,快速地接入语音唤醒、语音识别和语音合成。
若是使用讯飞、百度语音等其它语音平台,同理。
快速入手
介绍如何在unity中创建一个“语音助手”,实现语音交互的任务。
获取API KEY
参考(思必驰)DUI开放平台创建产品,获取到以下内容。
- Product ID
- Product Key
- Product Secret
- APIKEY
开发环境配置
- 将aar拷贝至Unity的Assets/Plugins/Android/目录
-
speech-plugin-1.0.6.aar : 包含思必驰的DUI-lite-SDK-for-Android.jar和相关语音资源。
-
unitydev-1.0.6.aar :简化了Unity与Java的互相调用
- 导入当前版本的unitypackage
使用语音助手
简述
通过整合语音唤醒、语音识别、语音合成三个功能,按照下图流程实现了“VoiceAssistant”组件。
包含以下功能:
- 唤醒词唤醒
- 语音助手询问指令
- 倾听用户指令
- 超时反馈
使用
- 打开“Holo-XR -> Holo-Settings”,填写思必驰SDK相关信息
- 在层级菜单右键,创建"Holo -> VoiceAssistant"
- 绑定Unity事件
- 创建一个名为“AiSpeechScript”的脚本。
public class AiSpeechScript : MonoBehaviour
{
public VoiceAssistant voiceAssistant;
public Text text;
public void UpdateText()
{
//将语音内容显示在文本框中
textC.text = voiceAssistant.content;
}
}
- 创建个空游戏对象(下图中为“测试方法”)添加上述脚本,然后将该对象的对应属性与上一步创建的“VoiceAssistant”绑定。
通用引擎
ISpeechEngine
ISpeechEngine是针对诸如讯飞、思必驰等Android SDK的Engine对象中抽象出来的,便于后续扩展。
ISpeechEngine主要包含以下方法
- InitEngine
- StartEngine
- StopEngine
- DestroyEngine
public abstract class ISpeechEngine
{
/// <summary>
/// 引擎初始化
/// </summary>
/// <param name="callback">事件回调</param>
public abstract void InitEngine(UnitySpeechCallback callback);
/// <summary>
/// 启动引擎
/// </summary>
public virtual void StartEngine()
{
//...
}
/// <summary>
/// 停止引擎
/// </summary>
public void StopEngine()
{
//...
}
/// <summary>
/// 销毁引擎
/// </summary>
public void DestroyEngine()
{
//...
}
}
}
UnitySpeechCallback
值得注意的是,ISpeechEngine在初始化时涉及到UnitySpeechCallback对象。
而在此处,UnitySpeechCallback主要用于android java 与Unity中的c#进行通讯。
安卓给Unity通讯可以通过这个AndroidJavaProxy 的方式,使用这个代理相当于给Unity 的回调。另外,安卓与Unity通讯也可UnityPlayer.UnitySendMessage,但是发消息使用的反射的机制,可能会有发送失败、延迟等可能。
/// <summary>
/// Unity中语音回调
/// </summary>
public class UnitySpeechCallback : AndroidJavaProxy
{
public UnitySpeechCallback() : base("com.eqgis.speech.UnitySpeechCallback") { }
/// <summary>
/// 检测到说话时回调
/// </summary>
public virtual void OnBeginningOfSpeech() { }
/// <summary>
/// 说话结束时回调
/// </summary>
public virtual void OnEndOfSpeech() { }
/// <summary>
/// 语音识别就绪
/// </summary>
public virtual void OnReadyForSpeech() { }
/// <summary>
/// 音频音量发生改变时回调,在主UI线程
/// </summary>
/// <param name="var1"></param>
public virtual void OnRmsChanged(float var1) { }
/// <summary>
/// 出错回调
/// </summary>
/// <param name="error"></param>
public virtual void OnError(String error) { }
/// <summary>
/// 初始化成功
/// </summary>
public virtual void OnInitSuccess() { }
/// <summary>
/// ASR-识别出结果
/// </summary>
/// <param name="var1">识别结果</param>
public virtual void OnResults(String var1) { }
/// <summary>
/// ASR-超时响应
/// </summary>
public virtual void OnAsrTimeout() { }
/// <summary>
/// WakeUp-语音唤醒成功
/// </summary>
/// <param name="confidence">置信度</param>
/// <param name="wakeupWord">唤醒词</param>
public virtual void OnWakeup(double confidence, String wakeupWord) { }
/// <summary>
/// TTS-开始合成
/// </summary>
/// <param name="utteranceId"></param>
public virtual void OnSynthesizeStart(String utteranceId) { }
/// <summary>
/// TTS-合成结束
/// </summary>
/// <param name="utteranceId"></param>
public virtual void OnSynthesizeFinish(String utteranceId) { }
/// <summary>
/// TTS-开始播放
/// </summary>
/// <param name="utteranceId"></param>
public virtual void OnSpeechStart(String utteranceId) { }
/// <summary>
/// TTS-播放完成
/// </summary>
/// <param name="utteranceId"></param>
public virtual void OnSpeechFinish(String utteranceId) { }
}
在Andorid java代码中,与之相对应的是
package com.eqgis.speech;
/**
* Unity中语音接口回调
* <p>Unity中调用,unity中需要对应类继承AndroidJavaProxy</p>
* <pre>
* 注意:C#采用Pascal规则命名,注意方法命名规范。此处需要方法名保持一致。
* </pre>
**/
public interface UnitySpeechCallback {
/**
* 检测到说话时回调
*/
void OnBeginningOfSpeech();
/**
* 说话结束时回调
*/
void OnEndOfSpeech();
/**
* 语音识别就绪
*/
void OnReadyForSpeech();
/**
* 音频音量发生改变时回调,在主UI线程
*/
void OnRmsChanged(float rmsDB);
/**
* 出错回调
*/
void OnError(String error);
/**
* 初始化成功
*/
void OnInitSuccess();
/**
* ASR-识别出结果
*/
void OnResults(String result);
/**
* 语音识别超时
*/
void OnAsrTimeout();
/**
* WakeUp-语音唤醒成功
*/
void OnWakeup(double confidence, String wakeupWord );
/**
* TTS-开始合成
*/
void OnSynthesizeStart(String utteranceId);
/**
* TTS-合成结束
*/
void OnSynthesizeFinish(String utteranceId);
/**
* TTS-开始播放
*/
void OnSpeechStart(String utteranceId);
/**
* TTS-播放完成
*/
void OnSpeechFinish(String utteranceId);
}
单项组件
“单项组件”中的…Engine都是ISpeechEngine的子类。
“快速入手”中介绍了如何使用“语音助手”。下面将介绍“语音助手”中涉及的几个单项组件。
鉴权工具
功能:
用于思必驰SDK的鉴权,通过onSuccess和onError方法回调SDK鉴权结果。
使用:
如下图所示,挂载“SbcPlugin”脚本,在相应的Unity事件中绑定对应方法即可。
语音唤醒
基于通用引擎(ISpeechEngine),结合思必驰-本地语音唤醒(Android)实现
功能:
通过唤醒词(“小老弟”)唤醒,触发UnitySpeechCallback的OnWakeup方法。
使用:
如下图所示,挂载“SbcWakeupEngine”脚本
语音识别
基于通用引擎(ISpeechEngine),结合思必驰-实时短语音识别(Android) 和思必驰-本地语音识别实现
功能:
识别用户的语音内容,在UnitySpeechCallback的OnResults(String result)返回文本。
使用:
如下图所示,挂载“SbcAsrEngine”脚本。
注意:
- 若要使用在线语音识别(在线实时短语音识别),在Cloud处打钩。
- 在线语音识别可以修改ResourceType,默认为comm,可取 airobot, aihome, custom
- 当未勾选Cloud时,可在本地设置中修改语音资源路径(设备绝对路径)
语音合成
基于通用引擎(ISpeechEngine),结合思必驰-本地语音合成(Android)实现
功能:
提供将文字信息转化为声音信息的能力。
使用:
如下图所示,挂载“SbcTtsEngine”脚本。
在需要进行语音合成的地方,参考如下示例调用。
ttsEngine.textContent = "/*要进行语音合成的文本内容*/";
ttsEngine.StartEngine();