版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/weixin_40391500/article/details/88897920
上一遍写了语音唤醒和语音合成,这篇写下语音合成
/**
* 语音识别
* Created by fujiayi on 2017/6/13.
* EventManager内的方法如send 都可以在主线程中进行,SDK中做过处理
*/
public class RecognizerUtils {
private final String TAG = this.getClass().getSimpleName();
private static RecognizerUtils utils = null;
/**
* SDK 内部核心 EventManager 类
*/
private EventManager asr;
// SDK 内部核心 事件回调类, 用于开发者写自己的识别回调逻辑
private EventListener eventListener;
// 是否加载离线资源
private boolean isOfflineEngineLoaded = false;
// 未release前,只能new一个
private volatile boolean isInited = false;
/**
* 0: 方案1, backTrackInMs > 0,唤醒词说完后,直接接句子,中间没有停顿。
* 开启回溯,连同唤醒词一起整句识别。推荐4个字 1500ms
* backTrackInMs 最大 15000,即15s
*
* >0 : 方案2:backTrackInMs = 0,唤醒词说完后,中间有停顿。
* 不开启回溯。唤醒词识别回调后,正常开启识别。
* <p>
*
*/
private static int backTrackInMs = 0;
private static Handler handler = null;
public static final int RECOGNIZER_ERROR = 1012;
public static RecognizerUtils getIntance(){
if (utils == null){
synchronized (RecognizerUtils.class){
if (utils == null){
utils = new RecognizerUtils();
}
}
}
return utils;
}
public void init(Handler mHandler){
handler = mHandler;
if (isInited) {
LogUtils.log(TAG,"还未调用release(),请勿新建一个新类");
return;
}
isInited = true;
// SDK集成步骤 初始化asr的EventManager示例,多次得到的类,只能选一个使用
asr = EventManagerFactory.create(MyApplication.context, "asr");
// SDK集成步骤 设置回调event, 识别引擎会回调这个类告知重要状态和识别结果
asr.registerListener(new EventListener() {
@Override
public void onEvent(String name, String params, byte[] data, int offset, int length) {
eventListener = this;
if (name.equals(SpeechConstant.CALLBACK_EVENT_ASR_LOADED)) {
LogUtils.log("RecognizerUtils", "离线命令词资源加载成功");
} else if (name.equals(SpeechConstant.CALLBACK_EVENT_ASR_UNLOADED)) {
LogUtils.log("RecognizerUtils", "离线命令词资源释放成功");
} else if (name.equals(SpeechConstant.CALLBACK_EVENT_ASR_READY)) {
// 引擎准备就绪,可以开始说话
LogUtils.log("RecognizerUtils", "引擎准备就绪,可以开始说话");
} else if (name.equals(SpeechConstant.CALLBACK_EVENT_ASR_BEGIN)) {
// 检测到用户的已经开始说话
LogUtils.log("RecognizerUtils", "检测到用户的已经开始说话");
} else if (name.equals(SpeechConstant.CALLBACK_EVENT_ASR_END)) {
// 检测到用户的已经停止说话
LogUtils.log("RecognizerUtils", "检测到用户的已经停止说话");
} else if (name.equals(SpeechConstant.CALLBACK_EVENT_ASR_PARTIAL)) {
RecogResult recogResult = RecogResult.parseJson(params);
// 临时识别结果, 长语音模式需要从此消息中取出结果
LogUtils.log("RecognizerUtils", "临时识别结果, 长语音模式需要从此消息中取出结果");
String[] results = recogResult.getResultsRecognition();
if (recogResult.isFinalResult()) {
LogUtils.log("RecognizerUtils", "isFinalResult 可能返回多个结果,请取第一个结果" + Arrays.toString(results));
Resolution.getIntance().resolution(handler, Arrays.toString(results));
} else if (recogResult.isPartialResult()) {
LogUtils.log("RecognizerUtils", "onAsrBegin 后 随着用户的说话,返回的临时结果" + Arrays.toString(results));
} else if (recogResult.isNluResult()) {
LogUtils.log("RecognizerUtils", "isNluResult 可能返回多个结果,请取第一个结果" + new String(data, offset, length));
}
} else if (name.equals(SpeechConstant.CALLBACK_EVENT_ASR_FINISH)) {
// 识别结束, 最终识别结果或可能的错误
LogUtils.log("RecognizerUtils", name + "- CALLBACK_EVENT_ASR_FINISH识别结束, 最终识别结果或可能的错误");
RecogResult recogResult = RecogResult.parseJson(params);
if (recogResult.hasError()) {
// int errorCode = recogResult.getError();
// int subErrorCode = recogResult.getSubError();
if (handler != null){
handler.sendEmptyMessage(RECOGNIZER_ERROR);
}
LogUtils.log("RecognizerUtils", "识别结束, 最终识别结果错误" + recogResult.getDesc());
} else {
LogUtils.log("RecognizerUtils", "识别结束, 最终识别结果" + params);
}
} else if (name.equals(SpeechConstant.CALLBACK_EVENT_ASR_LONG_SPEECH)) { // 长语音
LogUtils.log("RecognizerUtils", "长语音");
} else if (name.equals(SpeechConstant.CALLBACK_EVENT_ASR_EXIT)) {
LogUtils.log("RecognizerUtils", "退出");
} else if (name.equals(SpeechConstant.CALLBACK_EVENT_ASR_VOLUME)) {
// Logger.info(TAG, "asr volume event:" + params);
LogUtils.log("RecognizerUtils", params);
} else if (name.equals(SpeechConstant.CALLBACK_EVENT_ASR_AUDIO)) {
// LogUtils.log("RecognizerUtils", "长语音");
}
}
});
loadOfflineEngine(fetchOfflineParams());
}
/**
* 离线命令词,在线不需要调用
*
* @param params 离线命令词加载参数,见文档“ASR_KWS_LOAD_ENGINE 输入事件参数”
*/
private void loadOfflineEngine(Map<String, Object> params) {
String json = new JSONObject(params).toString();
// SDK集成步骤(可选)加载离线命令词(离线时使用)
asr.send(SpeechConstant.ASR_KWS_LOAD_ENGINE, json, null, 0, 0);
isOfflineEngineLoaded = true;
// 没有ASR_KWS_LOAD_ENGINE这个回调表试失败,如缺少第一次联网时下载的正式授权文件。
}
private Map<String, Object> fetchOfflineParams() {
Map<String, Object> map = new HashMap<String, Object>();
map.put(SpeechConstant.DECODER, 2);
map.put(SpeechConstant.ASR_OFFLINE_ENGINE_GRAMMER_FILE_PATH, "assets:///baidu_speech_grammar.bsg");
// map.putAll(fetchSlotDataParam());
return map;
}
private Map<String, Object> fetchSlotDataParam() {
Map<String, Object> map = new HashMap<String, Object>();
try {
JSONObject json = new JSONObject();
json.put("name", new JSONArray().put("妈妈").put("老伍"))
.put("appname", new JSONArray().put("手百").put("度秘"));
map.put(SpeechConstant.SLOT_DATA, json);
} catch (JSONException e) {
e.printStackTrace();
}
return map;
}
/**
* 开始
*/
public void start() {
// 此处 开始正常识别流程
Map<String, Object> params = new LinkedHashMap<String, Object>();
if (isOfflineEngineLoaded){
params.put(SpeechConstant.DECODER, 2);
}
params.put(SpeechConstant.ACCEPT_AUDIO_VOLUME, false);
params.put(SpeechConstant.VAD, SpeechConstant.VAD_DNN);
// 如识别短句,不需要需要逗号,使用1536搜索模型。其它PID参数请看文档
params.put(SpeechConstant.PID, 1536);
if (backTrackInMs > 0) {
// 方案1 唤醒词说完后,直接接句子,中间没有停顿。开启回溯,连同唤醒词一起整句识别。
// System.currentTimeMillis() - backTrackInMs , 表示识别从backTrackInMs毫秒前开始
params.put(SpeechConstant.AUDIO_MILLS, System.currentTimeMillis() - backTrackInMs);
}
cancel();
// SDK集成步骤 拼接识别参数
String json = new JSONObject(params).toString();
asr.send(SpeechConstant.ASR_START, json, null, 0, 0);
}
/**
* 提前结束录音等待识别结果。
*/
public void stop() {
// SDK 集成步骤(可选)停止录音
if (!isInited) {
// throw new RuntimeException("release() was called");
}
if (asr == null) {
return;
}
asr.send(SpeechConstant.ASR_STOP, "{}", null, 0, 0);
}
/**
* 取消本次识别,取消后将立即停止不会返回识别结果。
* cancel 与stop的区别是 cancel在stop的基础上,完全停止整个识别流程,
*/
public void cancel() {
if (!isInited) {
// throw new RuntimeException("release() was called");
}
if (asr == null) {
return;
}
// SDK集成步骤 (可选) 取消本次识别
asr.send(SpeechConstant.ASR_CANCEL, "{}", null, 0, 0);
}
public void release() {
isInited = false;
cancel();
if (asr == null) {
return;
}
if (isOfflineEngineLoaded) {
// SDK集成步骤 如果之前有调用过 加载离线命令词,这里要对应释放
asr.send(SpeechConstant.ASR_KWS_UNLOAD_ENGINE, null, null, 0, 0);
isOfflineEngineLoaded = false;
}
// SDK 集成步骤(可选),卸载listener
asr.unregisterListener(eventListener);
asr = null;
isInited = false;
utils = null;
}
}
/**
* 解析语音识别
*/
public class Resolution {
private final String TAG = this.getClass().getSimpleName();
private static Resolution utils = null;
public static Resolution getIntance() {
if (utils == null) {
synchronized (Resolution.class) {
if (utils == null) {
utils = new Resolution();
}
}
}
return utils;
}
/**
* 解析 通过handler返回状态
* @param handler
* @param work 识别结果
*/
public void resolution(Handler handler, String work) {
try {
if (PhoneUtils.CALL_PHONE
&& (work.equals("[确定]") || work.equals("[是的]"))
&& !StringUtils.isEmpty(PhoneUtils.PHONE)){
PhoneUtils.getInstance().callPhone(PhoneUtils.PHONE);
}else if (work.indexOf("打开") != -1) {
InstallAppUtils.getIntanste().openApp(work);
} else if (work.indexOf("打电话") != -1) {
PhoneUtils.getInstance().call(work);
}else {
TTSUtils.getInstance().speak(MyApplication.context.getString(R.string.wakeup_no_hear), true);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
/**
* 安装的APP实例
* Created by pc20170521 on 2017-10-28.
*/
public class InstallAppInfo {
private boolean check = false;
private String pakecge;
private Drawable icon;
private String name;
private ComponentName component;
public InstallAppInfo(){
}
public InstallAppInfo(Drawable d, String s, ComponentName cn){
icon = d;
name = s;
component = cn;
}
public Drawable getIcon() {
return icon;
}
public void setIcon(Drawable icon) {
this.icon = icon;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public ComponentName getComponent() {
return component;
}
public void setComponent(ComponentName component) {
this.component = component;
}
public boolean isCheck() {
return check;
}
public void setCheck(boolean check) {
this.check = check;
}
public String getPakecge() {
return component.getPackageName();
}
public void setPakecge(String pakecge) {
this.pakecge = pakecge;
}
}
/**
* 获取安装的APP
* Created by pc20170521 on 2017-10-28.
*/
public class InstallAppUtils {
private final String TAG = this.getClass().getSimpleName();
private ArrayList<InstallAppInfo> appList = null;
private static InstallAppUtils utils = null;
public static InstallAppUtils getIntanste(){
if (utils == null){
synchronized (InstallAppUtils.class){
if(utils == null){
utils = new InstallAppUtils();
}
}
}
return utils;
}
/***
* 获取安装的APP
* @return
*/
public ArrayList<InstallAppInfo> getInstallApp(){
appList = new ArrayList<>();
PackageManager pkgMgt = MyApplication.context.getPackageManager();
Intent it = new Intent(Intent.ACTION_MAIN);
it.addCategory(Intent.CATEGORY_LAUNCHER);
List<ResolveInfo> ra = pkgMgt.queryIntentActivities(it,0);
for(int i=0;i<ra.size();i++){
ActivityInfo ai = ra.get(i).activityInfo;
String label = ai.loadLabel(pkgMgt).toString();
ComponentName c = new ComponentName(ai.applicationInfo.packageName,ai.name);
InstallAppInfo item = new InstallAppInfo(ai.loadIcon(pkgMgt),label,c);
appList.add(item);
}
return appList;
}
public ArrayList<InstallAppInfo> getAppList() {
if (appList == null){
appList = getInstallApp();
}
return appList;
}
/***
* 语音打开某个APP
*/
public void openApp(String name){
name = name.substring(2);
LogUtils.log(TAG, name);
boolean isHasApp = false;
for (int i = 0; i < getAppList().size(); i++) {
if (name.contains(appList.get(i).getName())){
TTSUtils.getInstance().speak(MyApplication.context.getString(R.string.wakeup_open_wx)
+ appList.get(i).getName());
try {
Intent intent;
PackageManager packageManager = MyApplication.context.getPackageManager();
intent = packageManager.getLaunchIntentForPackage(appList.get(i).getPakecge());
MyApplication.context.startActivity(intent);
isHasApp = true;
break;
} catch (Exception e) {
TTSUtils.getInstance().speak(MyApplication.context.getString(R.string.wakeup_no_wx)
+ appList.get(i).getName());
e.printStackTrace();
}
}
}
if (!isHasApp){
TTSUtils.getInstance().speak(MyApplication.context.getString(R.string.wakeup_no_hear));
}
}
}
/**
* 获取电话本/打电话工具类
*/
public class PhoneUtils {
private final String TAG = this.getClass().getSimpleName();
private static PhoneUtils utils = null;
public static boolean CALL_PHONE = false;//语音拨电话请求
public static String PHONE = "";//电话号码
private List<PhoneInfo> list;
public static PhoneUtils getInstance(){
if (utils == null){
synchronized (PhoneUtils.class){
if (utils == null){
utils = new PhoneUtils();
}
}
}
return utils;
}
/**
* 获取电话本
* @return
*/
public List<PhoneInfo> getPhoneList() {
list = new ArrayList<>();
Cursor cursor = MyApplication.context.getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
new String[] { "display_name", "sort_key", "contact_id",
"data1" }, null, null, null);
// moveToNext方法返回的是一个boolean类型的数据
while (cursor.moveToNext()) {
//读取通讯录的姓名
String name = cursor.getString(cursor
.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));
//读取通讯录的号码
String number = cursor.getString(cursor
.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
int Id = cursor.getInt(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.CONTACT_ID));
String Sortkey = getSortkey(cursor.getString(1));
PhoneInfo phoneInfo = new PhoneInfo(name, number,Sortkey,Id);
list.add(phoneInfo);
// LogUtils.log("电话联系人", name);
}
cursor.close();
return list;
}
private static String getSortkey(String sortKeyString) {
String key =sortKeyString.substring(0,1).toUpperCase();
if (key.matches("[A-Z]")){
return key;
}else
return "#";
}
/**
* 语音识别并拨打电话
*/
public void call(String name){
try {
name = name.substring(3);
LogUtils.log(TAG, name);
if (name.contains("10086")) {
PHONE = "10086";
name = "10086";
callTips(name);
} else {
boolean isPhone = false;
List<PhoneInfo> list = PhoneUtils.getInstance().getPhoneList();
for (int i = 0; i < list.size(); i++) {
if (name.contains(list.get(i).getName())
|| name.contains(list.get(i).getNumber())) {
PHONE = list.get(i).getNumber();
name = list.get(i).getName();
isPhone = true;
break;
}
}
if (isPhone) {
callTips(name);
} else {
TTSUtils.getInstance().speak(MyApplication.context.getString(R.string.wakeup_no_phone));
}
}
} catch (Exception e) {
TTSUtils.getInstance().speak(MyApplication.context.getString(R.string.wakeup_no_phone));
e.printStackTrace();
}
}
/**
* 拨打电话
*/
private void callTips(String name) {
CALL_PHONE = true;
String tips = MyApplication.context.getString(R.string.wakeup_find_phone) + name
+ MyApplication.context.getString(R.string.wakeup_find_phone1);
TTSUtils.getInstance().speak(tips, true);
ProgressDialog dialog = new ProgressDialog(MyApplication.context);
dialog.setTitle(tips);
dialog.setOnDismissListener(new DialogInterface.OnDismissListener() {
@Override
public void onDismiss(DialogInterface dialog) {
dialog.dismiss();
}
});
}
/**
* 拨打电话
* @param phone
*/
public void callPhone(String phone) {
Uri uri = Uri.parse("tel:" + phone);
Intent intent = new Intent(Intent.ACTION_CALL, uri);
if (ActivityCompat.checkSelfPermission(MyApplication.context, Manifest.permission.CALL_PHONE) != PackageManager.PERMISSION_GRANTED) {
ToastUtils.show(MyApplication.context, MyApplication.context.getString(R.string.phone_permision));
PermissionsUtils.getInstance().showSystemPermissionsSettingDialog(MyApplication.activity);
return;
}
MyApplication.activity.startActivityForResult(intent, 1);
PHONE = "";
CALL_PHONE = false;
}
}
/**
* Created by fujiayi on 2017/6/24.
*/
public class RecogResult {
private static final int ERROR_NONE = 0;
private String origalJson;
private String[] resultsRecognition;
private String origalResult;
private String sn; // 日志id, 请求有问题请提问带上sn
private String desc;
private String resultType;
private int error = -1;
private int subError = -1;
public static RecogResult parseJson(String jsonStr) {
RecogResult result = new RecogResult();
result.setOrigalJson(jsonStr);
try {
JSONObject json = new JSONObject(jsonStr);
int error = json.optInt("error");
int subError = json.optInt("sub_error");
result.setError(error);
result.setDesc(json.optString("desc"));
result.setResultType(json.optString("result_type"));
result.setSubError(subError);
if (error == ERROR_NONE) {
result.setOrigalResult(json.getString("origin_result"));
JSONArray arr = json.optJSONArray("results_recognition");
if (arr != null) {
int size = arr.length();
String[] recogs = new String[size];
for (int i = 0; i < size; i++) {
recogs[i] = arr.getString(i);
}
result.setResultsRecognition(recogs);
}
}
} catch (JSONException e) {
e.printStackTrace();
}
return result;
}
public boolean hasError() {
return error != ERROR_NONE;
}
public boolean isFinalResult() {
return "final_result".equals(resultType);
}
public boolean isPartialResult() {
return "partial_result".equals(resultType);
}
public boolean isNluResult() {
return "nlu_result".equals(resultType);
}
public String getOrigalJson() {
return origalJson;
}
public void setOrigalJson(String origalJson) {
this.origalJson = origalJson;
}
public String[] getResultsRecognition() {
return resultsRecognition;
}
public void setResultsRecognition(String[] resultsRecognition) {
this.resultsRecognition = resultsRecognition;
}
public String getSn() {
return sn;
}
public void setSn(String sn) {
this.sn = sn;
}
public int getError() {
return error;
}
public void setError(int error) {
this.error = error;
}
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
public String getOrigalResult() {
return origalResult;
}
public void setOrigalResult(String origalResult) {
this.origalResult = origalResult;
}
public String getResultType() {
return resultType;
}
public void setResultType(String resultType) {
this.resultType = resultType;
}
public int getSubError() {
return subError;
}
public void setSubError(int subError) {
this.subError = subError;
}
}