当你阅读到此篇文章想必对TTS有一定了解。如果不清楚可以查阅TTS文档。
1.封装C#文件
using System;
using UnityEngine;
#if UNITY_ANDROID
/// <summary>
/// 基于AndroidTextToSpeech封装
/// https://developer.android.google.cn/reference/kotlin/android/speech/tts/TextToSpeech?hl=en
/// </summary>
public class AndroidTextToSpeech
{
/// <summary>
/// 发生错误
/// </summary>
public const int ERROR = -1;
/// <summary>
/// 表示由无效请求导致的故障。
/// </summary>
public const int ERROR_INVALID_REQUEST = -8;
/// <summary>
/// 表示由网络连接问题导致的故障。
/// </summary>
public const int ERROR_NETWORK = -6;
/// <summary>
/// 表示网络超时导致的故障。
/// </summary>
public const int ERROR_NETWORK_TIMEOUT = -7;
/// <summary>
/// 表示由于未完成语音数据下载而导致的故障。
/// </summary>
public const int ERROR_NOT_INSTALLED_YET = -9;
/// <summary>
/// 表示与输出(音频设备或文件)相关的故障。
/// </summary>
public const int ERROR_OUTPUT = -5;
/// <summary>
/// 表示TTS服务故障。
/// </summary>
public const int ERROR_SERVICE = -4;
/// <summary>
/// 表示TTS引擎无法合成给定输入。
/// </summary>
public const int ERROR_SYNTHESIS = -3;
/// <summary>
/// 表示语言可按语言环境使用,但不能按国家和变体使用。
/// </summary>
public const int LANG_AVAILABLE = 0;
/// <summary>
/// 表示语言适用于语言环境指定的语言和国家,但不适用于变体。
/// </summary>
public const int LANG_COUNTRY_AVAILABLE = 1;
/// <summary>
/// 表示语言完全按照区域设置的指定可用。
/// </summary>
public const int LANG_COUNTRY_VAR_AVAILABLE = 2;
/// <summary>
/// 语言数据丢失
/// </summary>
public const int LANG_MISSING_DATA = -1;
/// <summary>
/// 语言不支持
/// </summary>
public const int LANG_NOT_SUPPORTED = -2;
/// <summary>
/// 队列模式,其中新条目添加到播放队列的末尾。
/// </summary>
public const int QUEUE_ADD = 1;
/// <summary>
/// 队列模式,其中删除播放队列中的所有条目(要播放的媒体和要合成的文本),并用新条目替换。
/// </summary>
public const int QUEUE_FLUSH = 0;
/// <summary>
/// 客户端请求停止
/// </summary>
public const int STOPPED = -2;
/// <summary>
/// 成功
/// </summary>
public const int SUCCESS = 0;
/// <summary>
/// Init回调
/// </summary>
private Action<int> onInit;
/// <summary>
///
/// </summary>
/// <param name="activity">activity</param>
/// <param name="engine">tts引擎</param>
public AndroidTextToSpeech(AndroidJavaObject activity, string engine = null)
{
Init(activity, null, engine);
}
/// <summary>
///
/// </summary>
/// <param name="activity">activity</param>
/// <param name="initCall">初始化回调</param>
/// <param name="engine">tts引擎</param>
public AndroidTextToSpeech(AndroidJavaObject activity,Action<int> initCall = null, string engine = null)
{
Init(activity, initCall, engine);
}
/// <summary>
///
/// </summary>
/// <param name="initCall">初始化回调</param>
/// <param name="engine">tts引擎</param>
public AndroidTextToSpeech(Action<int> initCall,string engine = null)
{
Init(null, initCall, engine);
}
/// <summary>
///
/// </summary>
/// <param name="engine">tts引擎</param>
public AndroidTextToSpeech(string engine=null)
{
Init(null, null, engine);
}
/// <summary>
/// 设置音调
/// </summary>
/// <param name="pitch">设置音调,值越大声音越尖(女生),值越小则变成男声,1.0是常规</param>
/// <returns>返回结果SUCCESS或者ERROR</returns>
public int SetPitch(float pitch)
{
return textToSpeechObject.Call<int>("setPitch", pitch);
}
/// <summary>
/// 设置语速
/// </summary>
/// <param name="pitch">语速</param>
/// <returns>返回结果SUCCESS或者ERROR</returns>
public int SetSpeechRate(float speechRate)
{
return textToSpeechObject.Call<int>("setSpeechRate", speechRate);
}
/// <summary>
/// 正在讲话?
/// </summary>
/// <returns>True:正在讲话</returns>
public bool IsSpeaking()
{
return textToSpeechObject.Call<bool>("isSpeaking");
}
/// <summary>
/// 设置语言
/// </summary>
/// <param name="locale">java.util.Locale 对象</param>
/// <returns>返回结果SUCCESS或者ERROR</returns>
public int SetLanguage(AndroidJavaObject locale)
{
return textToSpeechObject.Call<int>("setLanguage", locale);
}
/// <summary>
/// 设置语言
/// </summary>
/// <param name="localeString">
/// java.util.Locale 中应定义的常量名
/// CHINA;US;等
/// https://developer.android.google.cn/reference/kotlin/java/util/Locale.html?hl=en
/// </param>
/// <returns></returns>
public int SetLanguage(string localeString)
{
return SetLanguage(localeClass.GetStatic<AndroidJavaObject>(localeString));
}
/// <summary>
/// 返回一个语音实例,描述当前用于发送到TextToSpeech引擎的合成请求的语音。
/// </summary>
/// <returns></returns>
public AndroidJavaObject GetVoice()
{
return localeClass.GetStatic<AndroidJavaObject>("getVoice");
}
/// <summary>
/// 讲话
/// </summary>
/// <param name="text">文字</param>
/// <param name="queueMode">模式</param>
/// <param name="utteranceId">唯一标识</param>
/// <returns>返回结果SUCCESS或者ERROR</returns>
public int Speak(string text,int queueMode, string utteranceId=null)
{
return Speak(text, queueMode,null, utteranceId);
}
/// <summary>
/// 讲话
/// </summary>
/// <param name="text">文字</param>
/// <param name="queueMode">模式</param>
/// <param name="param">参数,是android.os.Bundle对象</param>
/// <param name="utteranceId">唯一标识</param>
/// <returns></returns>
public int Speak(string text, int queueMode, AndroidJavaObject param,string utteranceId)
{
return textToSpeechObject.Call<int>("speak", text, queueMode, param, utteranceId);
}
/// <summary>
/// 停止
/// </summary>
/// <returns>返回结果SUCCESS或者ERROR</returns>
public int Stop()
{
return textToSpeechObject.Call<int>("stop");
}
/// <summary>
/// 终止
/// </summary>
public void Shutdown()
{
textToSpeechObject.Call<int>("shutdown");
}
/// <summary>
/// 初始化
/// </summary>
/// <param name="activity"></param>
/// <param name="initCall"></param>
/// <param name="engine"></param>
private void Init(AndroidJavaObject activity,Action<int> initCall,string engine)
{
onInit = initCall;
if (activity == null)
{
activity = new AndroidJavaClass("com.unity3d.player.UnityPlayer").GetStatic<AndroidJavaObject>("currentActivity");
}
if (!string.IsNullOrEmpty(engine))
{
textToSpeechObject = new AndroidJavaObject("android.speech.tts.TextToSpeech", activity, new OnInitListener(this), engine);
}
else
{
textToSpeechObject = new AndroidJavaObject("android.speech.tts.TextToSpeech", activity, new OnInitListener(this));
}
localeClass = new AndroidJavaClass("java.util.Locale");
}
/// <summary>
/// textToSpeech对象
/// </summary>
private AndroidJavaObject textToSpeechObject;
/// <summary>
/// locale类映射
/// </summary>
private AndroidJavaClass localeClass;
/// <summary>
/// 用于处理TextToSpeech中OnInitListener监听回调代理
/// </summary>
private class OnInitListener : AndroidJavaProxy
{
private AndroidTextToSpeech androidTextToSpeech;
public OnInitListener(AndroidTextToSpeech androidTextToSpeech) : base("android.speech.tts.TextToSpeech$OnInitListener")
{
this.androidTextToSpeech = androidTextToSpeech;
}
/// <summary>
/// 初始化结果处理
/// </summary>
/// <param name="state"></param>
void onInit(int state)
{
androidTextToSpeech.OnInit(state);
}
}
private void OnInit(int state)
{
onInit?.Invoke(state);
}
}
#endif
2.使用
如果是Android 11+需要在AndroidManifest.xml中的manifest节点下填入queries信息如下(这里要与application节点同级):
<queries>
<intent>
<action android:name="android.intent.action.TTS_SERVICE" />
</intent>
</queries>
测试
using UnityEngine;
using UnityEngine.UI;
public class TTSTest : MonoBehaviour
{
public Text Tip;
public InputField InputField;
AndroidTextToSpeech AndroidTextToSpeech;
void Start()
{
AndroidTextToSpeech = new AndroidTextToSpeech((state)=> {
if (state == AndroidTextToSpeech.SUCCESS)
{
Tip.text += "启动成功\n";
int res = AndroidTextToSpeech.SetLanguage("CHINA");
if (res == AndroidTextToSpeech.LANG_MISSING_DATA)
{
Tip.text += "语言数据丢失\n";
}
else if (res == AndroidTextToSpeech.LANG_NOT_SUPPORTED)
{
Tip.text += "语言不支持\n";
}
}
});
AndroidTextToSpeech.SetPitch(1);
AndroidTextToSpeech.SetSpeechRate(0.5f);
}
public void Speak()
{
if (!string.IsNullOrEmpty(InputField.text) && !AndroidTextToSpeech.IsSpeaking())
{
AndroidTextToSpeech.Speak(InputField.text, AndroidTextToSpeech.QUEUE_FLUSH);
}
}
private void OnDestroy()
{
AndroidTextToSpeech.Stop();
AndroidTextToSpeech.Shutdown();
}
}