android apk内语音控制

最近的音频播放项目需要在应用程序中进行语音控制。

[En]

Recent audio playback projects require voice control within the application.

使用iFLYTEK,可能会把它整理成一条笔记:

[En]

Use iFLYTEK, probably sort it out as a note:

首先在lib目录下引入:XiriScene.jar和XiriFeedback.jar

android apk内语音控制

然后在bulid.gradle文件中加入:

implementation files('libs\\XiriScene.jar')
implementation files('libs\\XiriFeedback.jar')

接下来是代码:

1.XiriISceneListener.java
package com.mychtech.himalayajs.service;

import android.content.Intent;

public interface XiriISceneListener {
    String onQuery();

    void onExecute(Intent var1);
}
2.XiriManager.java
package com.mychtech.himalayajs.service;

import android.content.Context;
import android.content.Intent;
import android.util.Log;

import com.iflytek.xiri.Feedback;

import org.json.JSONException;
import org.json.JSONObject;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;

public class XiriManager implements XiriISceneListener {
    private static XiriManager mInstance = null;
    private XiriScene mScene;
    private Feedback mFeedback;
    private String mSceneJson;
    private Context mContext = null;
    private IXiriManager mIXiriManager = null;

    public static XiriManager getInstance() {
        synchronized (XiriManager.class) {
            if (mInstance == null) {
                mInstance = new XiriManager();
            }
        }
        return mInstance;
    }

    public void onCreate(Context context, IXiriManager iXiriManager) {
        mIXiriManager = iXiriManager;
        mContext = context;
        mScene = new XiriScene(context);
        mFeedback = new Feedback(context);
        mScene.init(this);
        Log.i("XiriManager", "XiriManager add XiriManager oncreate....");
    }

    public void onResume() {
        //初始化Scene,在界面显示的时候才可调用
        mScene.init(this);
        Log.i("XiriManager", "XiriManager add XiriManager onResume....");
    }
    public void onPause() {
        //释放Scene,在界面消失的时候调用
        mScene.release();
        Log.i("XiriManager", "XiriManager add XiriManager onPause....");
    }

    @Override
    public String onQuery() {
        return regiestScene();
    }

    @Override
    public void onExecute(Intent intent) {
        mFeedback.begin(intent);
        //判断是否有注册的场景
        Log.i("XiriManager", "XiriManager add _scene = " + intent.hasExtra("_scene"));
        if (intent.hasExtra("_scene") && intent.getStringExtra("_scene")
                .equals("com.mychtech.himalayajs.activity.AudioDetailActivity")) {
            if (intent.hasExtra("_command")) {    //需注意,此处是_command,不是场景注册时候的_commands,千万别搞错了!
                String commands = intent.getStringExtra("_command");
                Log.i("XiriManager", "XiriManager add commands:" + commands);
                JSONObject params = new JSONObject();
                if ("key1".equals(commands)) {
                    //key1--> 固定命令(打开,退出)
                    mFeedback.feedback("打开", Feedback.SILENCE);
                    if(mIXiriManager != null) {
                        mIXiriManager.setXiriToJs("打开", "", params.toString());
                    }
                } else if ("key2".equals(commands)) {
                    //key2--> 预定于语义$P(_PLAY)
                    String action = intent.getStringExtra("_action");
                    Log.i("XiriManager", "onExecute___key2__action: "+action);
                    if("SEEK".equals(action)) {
                        int position = intent.getIntExtra("position", -1);
                        try {
                            params.put("position", position);
                        } catch (JSONException e) {
                            e.printStackTrace();
                        }
                    } else if("FORWARD".equals(action) || "BACKWARD".equals(action)) {
                        int position = intent.getIntExtra("offset", -1);
                        try {
                            params.put("offset", position);
                        } catch (JSONException e) {
                            e.printStackTrace();
                        }
                    }
                    mFeedback.feedback(action, Feedback.SILENCE);
                    if(mIXiriManager != null) {
                        mIXiriManager.setXiriToJs("$P(_PLAY)", action, params.toString());
                    }
                } else if ("key3".equals(commands)) {
                    //ke3-->预定义槽 $P(_PAGE)
                    String  action = intent.getStringExtra("_action");
                    if ("PREV".equals(action))
                    {
                        mFeedback.feedback("上一页", Feedback.SILENCE);
                    }
                    else if ("NEXT".equals(action))
                    {
                        mFeedback.feedback("下一页", Feedback.SILENCE);
                    }
                    else if ("INDEX".equals(action))
                    {
                        String index = intent.getStringExtra("index");
                        mFeedback.feedback("第" + index + "页", Feedback.SILENCE);
                        try {
                            params.put("index", index);
                        } catch (JSONException e) {
                            e.printStackTrace();
                        }
                    }
                    if(mIXiriManager != null) {
                        mIXiriManager.setXiriToJs("$W(video)", action, params.toString());
                    }
                } else if ("key4".equals(commands)) {
                    //key3-->自定义槽$W(video)
                    String video = intent.getStringExtra("video");
                    mFeedback.feedback(video, Feedback.SILENCE);
                    if(mIXiriManager != null) {
                        mIXiriManager.setXiriToJs("$W(video)", "", params.toString());
                    }
                } else if("key5".equals(commands)) {
                    //$P(_EPISODE)
                    String action = intent.getStringExtra("_action");
                    if ("PREV".equals(action))
                    {
                        //mFeedback.feedback("上一集", Feedback.SILENCE);
                    }
                    else if ("NEXT".equals(action))
                    {
                        //mFeedback.feedback("下一集", Feedback.SILENCE);
                    }
                    else if ("INDEX".equals(action))
                    {
                        int index = intent.getIntExtra("index",0);
                        ///mFeedback.feedback("第" + index + "集", Feedback.SILENCE);
                        try {
                            params.put("index", index);
                        } catch (JSONException e) {
                            e.printStackTrace();
                        }

                    }
                    if(mIXiriManager != null) {
                        mIXiriManager.setXiriToJs("$P(_EPISODE)", action, params.toString());
                    }
                } else if("key6".equals(commands)) {
                    //$P(_SELECT)
                    try {
                        params.put("row", intent.getIntExtra("row", -1));
                        params.put("index", intent.getIntExtra("index", -1));
                    } catch (JSONException e) {
                        e.printStackTrace();
                    }
                    if(mIXiriManager != null) {
                        mIXiriManager.setXiriToJs("$P(_SELECT)", "", params.toString());
                    }
                } else if("key7".equals(commands)) {
                    //退出应用
                    if(mIXiriManager != null) {
                        mIXiriManager.setXiriToJs("退出", "", params.toString());
                    }
                }
            }
        }
    }

    /**
     * 读取注册了相关场景的方法
     * @param is
     * @return
     */
    public String getSceneText(InputStream is) {
        StringBuilder builder = new StringBuilder();
        if (is != null) {
            try {
                InputStreamReader isr = new InputStreamReader(is);
                BufferedReader br = new BufferedReader(isr);
                String line;
                while ((line = br.readLine()) != null) {
                    builder.append(line);
                }
                br.close();
                isr.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        return builder.toString();
    }

    /**
     * 场景命令词注册:
     * _scene: 场景标识,命名规则为前面是应用包名,后面是场景名。
     *
     * _commands:是命令描述,包含发回给应用的命令和说法,以键值对的形式存储。
     * 其中键是命令id,值为该功能的各种可能的说法,说法分为三种:
     * 1、 命令词短语(如:打开、退出);
     * 2、 预定义的语义,以“$P“开头(如:$P(_PLAY));
     * 3、 模糊槽,以“$W“开头后跟槽的名字(如:$W(video)其中的“video”对应的是_fuzzy_words 节点中的槽的名字);
     *
     * _fuzzy_words:该内容和“_commands”节点中的自定义槽对应。如果“commands”节点中没有自定义槽,那么“_fuzzy_words“节点则不存在。
     */
    public String regiestScene() {
        try {
            mSceneJson = getSceneText(mContext.getAssets().open("XiriSceneText.json"));
        } catch (IOException e) {
            e.printStackTrace();
        }
        return mSceneJson;
    }

    public interface IXiriManager {
        void setXiriToJs(String key, String action, String params);
    }

}
  1. XiriScene.java
package com.mychtech.himalayajs.service;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.Uri;
import android.util.Log;

import org.json.JSONObject;

public class XiriScene {
    private Context mContext;
    IntentFilter mIntentFilter;
    private XiriISceneListener mISceneListenner;
    public static final String ADDSCENECOMMAND_ACTION = "com.iflytek.xiri2.topActivity.QUERY";
    public static final String FUZZY_SCENE_SERVICE_ACTION = "com.iflytek.xiri2.scenes.EXECUTE";
    public static final String COMMIT_ACTION = "com.iflytek.xiri2.topActivity.COMMIT";
    public static final String NEW_COMMIT_ACTION = "tv.yuyin.topActivity.COMMIT";
    private int token;
    BroadcastReceiver mReceiver = new BroadcastReceiver() {
        public void onReceive(Context context, Intent intent) {
            String sceneId;
            Log.i("XiriScene", "onReceive__intent.getAction(): "+intent.getAction());
            if ("com.iflytek.xiri2.topActivity.QUERY".equals(intent.getAction())) {
                Log.d("XiriScene", "ADDSCENECOMMAND_ACTION 1 onReceive " + Uri.decode(intent.toURI()));
                sceneId = intent.getStringExtra("pkgname") == null ? "com.iflytek.xiri" : intent.getStringExtra("pkgname");
                //intent.putExtra("topActivity", "com.mychtech.himalayajs.ximalaya.");
                if ("com.iflytek.xiri".equals(sceneId)) {
                    intent.setAction("com.iflytek.xiri2.topActivity.COMMIT");
                    intent.putExtra("_scene", mISceneListenner.onQuery());
                    //intent.putExtra("_package", XiriScene.this.mContext.getPackageName());
                    //intent.putExtra("sw_caller_packagename", "com.mychtech.himalayajs.ximalaya");
                    intent.putExtra("_package", "com.mychtech.himalayajs.ximalaya");
                    intent.putExtra("_objhash", XiriScene.this.token);
                    intent.setPackage(sceneId);
                    XiriScene.this.mContext.startService(intent);
                } else {
                    intent.setAction("tv.yuyin.topActivity.COMMIT");
                    intent.putExtra("_scene", XiriScene.this.mISceneListenner.onQuery());
                    //intent.putExtra("_package", XiriScene.this.mContext.getPackageName());
                    //intent.putExtra("sw_caller_packagename", "com.mychtech.himalayajs.ximalaya");
                    intent.putExtra("_package", "com.mychtech.himalayajs.ximalaya");
                    intent.putExtra("_objhash", XiriScene.this.token);
                    intent.setPackage(sceneId);
                    XiriScene.this.mContext.startService(intent);
                }

                Log.d("XiriScene", "ADDSCENECOMMAND_ACTION startService " + Uri.decode(intent.toURI()));
            } else if ("com.iflytek.xiri2.scenes.EXECUTE".equals(intent.getAction())) {
                Log.d("XiriScene", "FUZZY_SCENE_SERVICE_ACTION " + Uri.decode(intent.toURI()));
                Log.d("SCENE_TIME", "StartTime " + System.currentTimeMillis());
                Log.d("XiriScene", "mContext getPackagename " +  XiriScene.this.mContext.getPackageName());
                if (intent.hasExtra("_objhash") && intent.getStringExtra("_objhash").equals(XiriScene.this.token + "")) {
                    if (intent.hasExtra("_scene")) {
                        sceneId = intent.getStringExtra("_scene");
                        Log.d("SCENE_TIME", "fromIntent sceneId " + sceneId);

                        try {
                            JSONObject mJsonObject = new JSONObject(XiriScene.this.mISceneListenner.onQuery());
                            String userSceneId = mJsonObject.getString("_scene");
                            Log.d("SCENE_TIME", "userSceneId  " + sceneId);
                            if (userSceneId.equals(sceneId)) {
                                XiriScene.this.mISceneListenner.onExecute(intent);
                                Log.d("SCENE_TIME", "EndTime " + System.currentTimeMillis());
                                Log.d("XiriScene", "FUZZY_SCENE_SERVICE_ACTION exe " + Uri.decode(intent.toURI()));
                            }
                        } catch (Exception var6) {
                        }
                    } else {
                        XiriScene.this.mISceneListenner.onExecute(intent);
                        Log.d("XiriScene", "else Scene exe " + Uri.decode(intent.toURI()));
                    }
                }
            }

        }
    };

    public XiriScene(Context context) {
        this.mContext = context;
        this.token = this.hashCode();
        this.mIntentFilter = new IntentFilter();
        this.mIntentFilter.addAction("com.iflytek.xiri2.scenes.EXECUTE");
        this.mIntentFilter.addAction("com.iflytek.xiri2.topActivity.QUERY");
    }

    public void init(XiriISceneListener listenner) {
        this.mContext.registerReceiver(this.mReceiver, this.mIntentFilter);
        this.mISceneListenner = listenner;
    }

    public void release() {
        this.mContext.unregisterReceiver(this.mReceiver);
    }
}

然后在 main目录下新建一个名为”XiriSceneText.json”的文件

android apk内语音控制

XiriSceneText.json的内容如下:

{
    "_commands": {
        "key1": [
            "打开",
            "打开详情"
        ],
        "key2": [
            "$P(_PLAY)"
        ],
        "key3": [
            "$P(_PAGE)"
        ],
        "key4": [
            "$W(video)"
        ],
        "key5":[
            "$P(_EPISODE)"
        ],
        "key6":[
            "$P(_SELECT)"
        ],
        "key7":[
            "退出当前页面"
        ]
    },
    "_fuzzy_words": {
        "video": [
        ]
    },
    "_scene": "com.mychtech.himalayajs.activity.AudioDetailActivity"
}

然后在AudioDetailActivity的onCreate方法里面调用:

XiriManager.getInstance().onCreate(this, new XiriManager.IXiriManager() {
            @Override
            public void setXiriToJs(String key, String action, String params) {
                //预定义槽 $P(_PLAY)  $P(_PAGE) $P(_EPISODE) $P(_SELECT)
                mKey = key;
                Log.i(TAG, "setXiriToJs--key:" + key + "---action:" + action + "---param:" + params);
                if (null != mMediaPlayer) {
                    switch (key) {
                        case "$P(_PLAY)":// 播放控制
                            if ("PAUSE".equals(action)) {
                                if (mMediaPlayer.isPlaying()) {
                                    ivPlay.setImageResource(R.drawable.bg_play_slt);
                                    mMediaPlayer.pause();
                                }
                            } else if ("PLAY".equals(action)) {
                                ivPlay.setImageResource(R.drawable.bg_pause_slt);
                                mMediaPlayer.start();
                                mHandler.sendEmptyMessage(123);
                                mAudioChapterAdapter.setPlay(false);
                            } else if ("RESUME".equals(action)) {
                                mMediaPlayer.start();
                                ivPlay.setImageResource(R.drawable.bg_pause_slt);
                            } else if ("RESTART".equals(action)) {
                                mMediaPlayer.seekTo(0);
                                mMediaPlayer.start();
                            } else if ("SEEK".equals(action)) {//跳到指定位置 例如:跳到1分30秒播放
                                if (!TextUtils.isEmpty(params)) {
                                    if (params.contains("position")) {
                                        int position = JSONUtils.getInt(params, "position", 0);
                                        Log.i(TAG, "setXiriToJs--position: " + position);
                                        mMediaPlayer.seekTo(position * 1000);
                                    }
                                }

                            } else if ("FORWARD".equals(action)) {//快进指定时间 例如:快进30秒

                                if (!TextUtils.isEmpty(params)) {
                                    if (params.contains("offset")) {
                                        int offset = JSONUtils.getInt(params, "offset", 0);
                                        Log.i(TAG, "setXiriToJs--offset: " + offset);
                                        mMediaPlayer.seekTo(mMediaPlayer.getCurrentPosition() + offset * 1000);
                                    } else {
                                        Log.i(TAG, "setXiriToJs--offset: " + "not contain offset");
                                        mMediaPlayer.seekTo(mMediaPlayer.getCurrentPosition() + 3000);//快进
                                    }
                                } else {
                                    mMediaPlayer.seekTo(mMediaPlayer.getCurrentPosition() + 3000);//快进
                                }

                            } else if ("BACKWARD".equals(action)) {//后退指定时间 例如:快退30秒
                                if (!TextUtils.isEmpty(params)) {
                                    if (params.contains("offset")) {
                                        int offset = JSONUtils.getInt(params, "offset", 0);
                                        Log.i(TAG, "setXiriToJs--offset: " + offset);
                                        mMediaPlayer.seekTo(mMediaPlayer.getCurrentPosition() - offset * 1000);
                                    } else {
                                        Log.i(TAG, "setXiriToJs--offset: " + "not contain offset");
                                        mMediaPlayer.seekTo(mMediaPlayer.getCurrentPosition() - 3000);//快进
                                    }
                                } else {
                                    mMediaPlayer.seekTo(mMediaPlayer.getCurrentPosition() - 3000);//快进
                                }
                            } else if ("EXIT".equals(action)) {//退出
                                exitAudioActivity();
                            }
                            break;
                        case "$P(_PAGE)"://翻页控制
                            //TODO
                            if ("NEXT".equals(action)) {//跳到下一页

                            } else if ("PREV".equals(action)) {//跳到上一页

                            } else if ("INDEX".equals(action)) {//index 页号(整数值型,负数表示倒数)

                            }

                            break;

                        case "$P(_EPISODE)"://选集控制
                            if ("NEXT".equals(action)) {//跳到下一集/期
                                isNext = true;
                                nextMusic();
                            } else if ("PREV".equals(action)) {//跳到上一集/期
                                previousEpisode();
                            } else if ("INDEX".equals(action)) {//跳到指定集/期 index 集/期号(整数值型,负数表示倒数)
                                if (!TextUtils.isEmpty(params)) {
                                    if (params.contains("index")) {
                                        int index = JSONUtils.getInt(params, "index", 0);
                                        Log.i(TAG, "setXiriToJs--index: " + index);
                                        changeMusicForIndex(index - 1);
                                    }
                                }
                            } else {

                            }
                            break;
                        case "$P(_SELECT)"://选择 例如:第二行第三个
                            //row:第 x 行(整数值型,负数表示倒数)可选
                            //index:第 x 个(整数值型,负数表示倒数)

                            break;
                        case "退出":
                            exitAudioActivity();
                            finish();
                            break;
                    }

                }
            }
        });

在对应的OnDestory里面调用:

XiriManager.getInstance().onPause();

以上!

Original: https://blog.csdn.net/Android_Amelia/article/details/122626261
Author: Android_Amelia
Title: android apk内语音控制

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/498184/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球