集成百度离在线语音唤醒/语音合成sdk

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/weixin_40391500/article/details/88814281

在libs和jniLibs加入对应jar包和so库

/**
 * 唤醒
 */
public class WakeUpUtils {

    private final String TAG = this.getClass().getSimpleName();
    private static WakeUpUtils utils = null;
    private EventManager eventManager;
    private EventListener listener;
    private boolean isInited = false;
    private static Handler handler;
    private final int WAKEUP = 1010;
    // 是否加载离线资源
    private boolean isOfflineEngineLoaded = false;

    public WakeUpUtils(){
        init();
    }

    public static WakeUpUtils getIntance(Handler mHandler){
        handler = mHandler;
        if (utils == null){
            synchronized (WakeUpUtils.class){
                if (utils == null){
                    utils = new WakeUpUtils();
                }
            }
        }
        return utils;
    }

    private void init(){
        if (isInited){
            LogUtils.log(TAG,"还未调用release(),请勿新建一个新类");
            return;
        }
        isInited = true;
        //创建唤醒事件管理器
        eventManager = EventManagerFactory.create(MyApplication.context,"wp");
        //注册唤醒事件监听器
        eventManager.registerListener(new EventListener() {
            @Override
            public void onEvent(String name, String params1, byte[] bytes, int i, int i1) {
                try{
                    listener = this;
                    if ("wp.data".equals(name)){
                        LogUtils.log("唤醒", params1);
                        TTSUtils.getInstance().speak(MyApplication.context.getString(R.string.wakeup_yes), true);
//                        handler.sendEmptyMessage(WAKEUP);
//                        RecognizerUtils.getIntance(handler).start();
                    }else if ("wp.exit".equals(name)){
                        LogUtils.log("唤醒退出", params1);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
        loadOfflineEngine(fetchOfflineParams());
    }

    /**
     * 离线命令词,在线不需要调用
     *
     * @param params 离线命令词加载参数,见文档“ASR_KWS_LOAD_ENGINE 输入事件参数”
     */
    private void loadOfflineEngine(Map<String, Object> params) {
        String json = new JSONObject(params).toString();
        // SDK集成步骤(可选)加载离线命令词(离线时使用)
        eventManager.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() {
        if (eventManager != null){
            HashMap params = new HashMap();
            params.put("kws-file","assets:///WakeUp.bin");
            eventManager.send("wp.start",new JSONObject(params).toString(), null,0,0);
        }
    }

    public void stop() {
        if (eventManager != null){
            eventManager.send(SpeechConstant.WAKEUP_STOP, null, null, 0, 0);
        }
    }

    public void release() {
        isInited = false;
        stop();
        if (eventManager != null){
            if (isOfflineEngineLoaded) {
                // SDK集成步骤 如果之前有调用过 加载离线命令词,这里要对应释放
                eventManager.send(SpeechConstant.ASR_KWS_UNLOAD_ENGINE, null, null, 0, 0);
                isOfflineEngineLoaded = false;
            }
            eventManager.unregisterListener(listener);
            eventManager = null;
            utils = null;
        }
    }

}

// 合成
public class TTSUtils {
    private static TTSUtils utils = null;
    private SpeechSynthesizer mSpeechSynthesizer;
    private boolean isWakeUp = false;

    public TTSUtils(){
        new Thread(new Runnable() {
            @Override
            public void run() {
                init();
            }
        }).start();
    }
    public static TTSUtils getInstance(){
        if (utils == null){
            synchronized (TTSUtils.class){
                if (utils == null){
                    utils = new TTSUtils();
                }
            }
        }
        return utils;
    }

    /**
     * speak 实际上是调用 synthesize后,获取音频流,然后播放。
     * 获取音频流的方式见SaveFileActivity及FileSaveListener
     * 需要合成的文本text的长度不能超过1024个GBK字节。
     */
    public void speak(String text) {
        // 需要合成的文本text的长度不能超过1024个GBK字节。
        if (mSpeechSynthesizer != null){
            mSpeechSynthesizer.speak(text);
        }
    }

    /**
     * speak 实际上是调用 synthesize后,获取音频流,然后播放。
     * 获取音频流的方式见SaveFileActivity及FileSaveListener
     * 需要合成的文本text的长度不能超过1024个GBK字节。
     */
    public void speak(String text, boolean isWakeUp) {
        this.isWakeUp = isWakeUp;
        // 需要合成的文本text的长度不能超过1024个GBK字节。
        if (mSpeechSynthesizer != null){
            mSpeechSynthesizer.speak(text);
        }
    }

    public void pause() {
        // 需要合成的文本text的长度不能超过1024个GBK字节。
        if (mSpeechSynthesizer != null){
            mSpeechSynthesizer.pause();
        }
    }

    public void resume() {
        // 需要合成的文本text的长度不能超过1024个GBK字节。
        if (mSpeechSynthesizer != null){
            mSpeechSynthesizer.resume();
        }
    }

    public void stop() {
        // 需要合成的文本text的长度不能超过1024个GBK字节。
        if (mSpeechSynthesizer != null){
            mSpeechSynthesizer.stop();
        }
    }

    public void release() {
        // 需要合成的文本text的长度不能超过1024个GBK字节。
        if (mSpeechSynthesizer != null){
            mSpeechSynthesizer.release();
        }
    }


    private void init(){
        mSpeechSynthesizer = SpeechSynthesizer.getInstance();
        mSpeechSynthesizer.setContext(MyApplication.context.getApplicationContext());
        mSpeechSynthesizer.setSpeechSynthesizerListener(new SpeechSynthesizerListener() {
            @Override
            public void onSynthesizeStart(String s) {
//                LogUtils.log("TTSUtils", "onSynthesizeStart" + "--" + s);
            }

            @Override
            public void onSynthesizeDataArrived(String s, byte[] bytes, int i) {
//                LogUtils.log("TTSUtils", "onSynthesizeDataArrived" + "--" + s);
            }

            @Override
            public void onSynthesizeFinish(String s) {
//                LogUtils.log("TTSUtils", "onSynthesizeFinish" + "--" + s);
            }

            @Override
            public void onSpeechStart(String s) {
//                LogUtils.log("TTSUtils", "onSpeechStart" + "--" + s);
            }

            @Override
            public void onSpeechProgressChanged(String s, int i) {
//                LogUtils.log("TTSUtils", "onSpeechProgressChanged" + "--" + s);
            }

            @Override
            public void onSpeechFinish(String s) {
//                LogUtils.log("TTSUtils", "onSpeechFinish" + "--" + s);
                if (isWakeUp){
                    isWakeUp = false;
                    RecognizerUtils.getIntance().start();
                }
            }

            @Override
            public void onError(String s, SpeechError speechError) {
//                LogUtils.log("TTSUtils", "onError" + "--" + s + "--" +speechError.description);
            }
        });
        /*这里只是为了让Demo运行使用的APPID,请替换成自己的id。*/
        mSpeechSynthesizer.setAppId("15692915");
        /*这里只是为了让Demo正常运行使用APIKey,请替换成自己的APIKey*/
        mSpeechSynthesizer.setApiKey("R2XiXKorcR75HyIejnBROSMm",
                "Co85H7ZXROB0DEM4WfLgAlEojUd5GXFi");

        // 授权检测接口(只是通过AuthInfo进行检验授权是否成功。选择纯在线可以不必调用auth方法。
        AuthInfo authInfo = mSpeechSynthesizer.auth(TtsMode.MIX);
        if (!authInfo.isSuccess()) {
            // 离线授权需要网站上的应用填写包名。本demo的包名是com.baidu.tts.sample,定义在build.gradle中
            String errorMsg = authInfo.getTtsError().getDetailMessage();
            LogUtils.log("TTSUtils","鉴权失败 =" + errorMsg);
        } else {
            LogUtils.log("TTSUtils","验证通过,离线正式授权文件存在。");
        }

        getParams();
        // 初始化tts
        int result = mSpeechSynthesizer.initTts(TtsMode.MIX);
        if (result != 0) {
            LogUtils.log("TTSUtils","【error】initTts 初始化失败 + errorCode:" + result);
            return;
        }
        // 此时可以调用 speak和synthesize方法
        LogUtils.log("TTSUtils", "合成引擎初始化成功");
    }

    /**
     * 合成的参数,可以初始化时填写,也可以在合成前设置。
     *
     * @return
     */
    protected Map<String, String> getParams() {
        Map<String, String> params = new HashMap<>();
        // 离线资源文件,从assets目录中复制到临时目录,需要在initTTs方法前完成
        setOfflineVoiceType(VOICE_FEMALE);
        // 文本模型文件路径 (离线引擎使用), 注意TEXT_FILENAME必须存在并且可读
        mSpeechSynthesizer.setParam(SpeechSynthesizer.PARAM_TTS_TEXT_MODEL_FILE, textFilename);
        // 声学模型文件路径 (离线引擎使用), 注意TEXT_FILENAME必须存在并且可读
        mSpeechSynthesizer.setParam(SpeechSynthesizer.PARAM_TTS_SPEECH_MODEL_FILE, modelFilename);
        // 以下参数均为选填
        // 设置在线发声音人: 0 普通女声(默认) 1 普通男声 2 特别男声 3 情感男声<度逍遥> 4 情感儿童声<度丫丫>
        params.put(SpeechSynthesizer.PARAM_SPEAKER, "0");
        // 设置合成的音量,0-9 ,默认 5
        params.put(SpeechSynthesizer.PARAM_VOLUME, "9");
        // 设置合成的语速,0-9 ,默认 5
        params.put(SpeechSynthesizer.PARAM_SPEED, "5");
        // 设置合成的语调,0-9 ,默认 5
        params.put(SpeechSynthesizer.PARAM_PITCH, "5");

        params.put(SpeechSynthesizer.PARAM_MIX_MODE, SpeechSynthesizer.MIX_MODE_HIGH_SPEED_SYNTHESIZE);
        // 该参数设置为TtsMode.MIX生效。即纯在线模式不生效。
        // MIX_MODE_DEFAULT 默认 ,wifi状态下使用在线,非wifi离线。在线状态下,请求超时6s自动转离线
        // MIX_MODE_HIGH_SPEED_SYNTHESIZE_WIFI wifi状态下使用在线,非wifi离线。在线状态下, 请求超时1.2s自动转离线
        // MIX_MODE_HIGH_SPEED_NETWORK , 3G 4G wifi状态下使用在线,其它状态离线。在线状态下,请求超时1.2s自动转离线
        // MIX_MODE_HIGH_SPEED_SYNTHESIZE, 2G 3G 4G wifi状态下使用在线,其它状态离线。在线状态下,请求超时1.2s自动转离线

        // 声学模型文件路径 (离线引擎使用), 请确认下面两个文件存在
        params.put(SpeechSynthesizer.PARAM_TTS_TEXT_MODEL_FILE, textFilename);
        params.put(SpeechSynthesizer.PARAM_TTS_SPEECH_MODEL_FILE, modelFilename);
        return params;
    }

    private static HashMap<String, Boolean> mapInitied = new HashMap<String, Boolean>();
    private final String VOICE_FEMALE = "F";//离线女声
    private final String VOICE_MALE = "M";//离线男声
    private final String VOICE_DUYY = "Y";//离线度逍遥
    private final String VOICE_DUXY = "X";//离线度丫丫
    private String textFilename = "";
    private String modelFilename = "";
    private void setOfflineVoiceType(String voiceType) {
        String text = "bd_etts_text.dat";
        String model;
        if (VOICE_MALE.equals(voiceType)) {
            model = "bd_etts_common_speech_m15_mand_eng_high_am-mix_v3.0.0_20170505.dat";
        } else if (VOICE_FEMALE.equals(voiceType)) {
            model = "bd_etts_common_speech_f7_mand_eng_high_am-mix_v3.0.0_20170512.dat";
        } else if (VOICE_DUXY.equals(voiceType)) {
            model = "bd_etts_common_speech_yyjw_mand_eng_high_am-mix_v3.0.0_20170512.dat";
        } else if (VOICE_DUYY.equals(voiceType)) {
            model = "bd_etts_common_speech_as_mand_eng_high_am_v3.0.0_20170516.dat";
        } else {
            throw new RuntimeException("voice type is not in list");
        }
        textFilename = copyAssetsFile(text);
        modelFilename = copyAssetsFile(model);
    }

    private String copyAssetsFile(String sourceFilename) {
        String destFilename = FileUtil.createTmpDir(MyApplication.context) + "/" + sourceFilename;
        try {
            File file = new File(destFilename);
            if (file.exists()){
                return destFilename;
            }
            boolean recover = false;
            Boolean existed = mapInitied.get(sourceFilename); // 启动时完全覆盖一次
            if (existed == null || !existed) {
                recover = true;
            }
            FileUtil.copyFromAssets(MyApplication.context.getApplicationContext().getAssets(),
                    sourceFilename, destFilename, recover);
            return destFilename;
        }catch (Exception e){
            e.printStackTrace();
        }
        return destFilename;
    }

猜你喜欢

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