Android百度语音识别/语音助手

版权声明:本文为博主原创文章,未经博主允许不得转载。 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;
    }
}

猜你喜欢

转载自blog.csdn.net/weixin_40391500/article/details/88897920