唤醒功能,顾名思义,通过语音,唤醒服务,做我们想做的事情。
- 效果图(开启应用后说讯飞语音或者讯飞语点唤醒)
- 源码下载
地址:http://download.csdn.net/detail/q4878802/9023213
步骤
1. 创建应用,开通服务
2. 下载SDK
我们要使用的是讯飞的付费功能,选择唤醒服务,点击下载以后,会提示没有购买。点击“购买服务”
点击购买一会看到付费情况,有项目需要,就必须购买,我们写Demo,讯飞给提供了体验版的SDK,和正式版的没有功能上的区别,但是只能试用35天,装机量只有3个,唤醒词不能改,只有“讯飞语音”和“讯飞语点”两个唤醒词。
3. 解压SDK
assets目录下是一些图片资源文件
doc目录下是一些开发文档
libs目录下是一些jar包和so库
res目录下是语音的资源文件,非常重要
sample目录下是Demo
4. 集成语音唤醒
可以按照开发文档的介绍,一步一步跟着做,实现唤醒功能
地址:http://www.xfyun.cn/doccenter/awd
我个人的习惯是看Demo,开发文档只是做一个参考,我个人感觉这样更直接,开发效率更高。
步骤
1. 将Demo导入IDE,跑起来。
2. 在手机上找到功能的入口,根据一些界面上显示的关键字,找到控件。
3. 根据控件ID,在代码找到对应功能的的代码。
4. 找到功能的核心代码以后,看看当前的方法或者类在哪里有用到,怎么用的,是如何初始化的然后集成到自己的工程里,就OK了。
5. 下载的SDK里给的一些资源不是白给的,是和你的appid对应的,你要将demo的appid换成你自己的appid,资源文件也要拷贝到的你的工程里,才能正常使用。
开发步骤
1. 添加权限
这里用到的唤醒功能不是所有的权限都用到的,具体用到了哪些权限,可以看上面的链接,用到哪写权限就加哪些权限,这个为了快速方便测试,把讯飞用到的权限都加上了。
<uses-permission android:name="android.permission.RECORD_AUDIO" /> <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" /> <uses-permission android:name="android.permission.READ_PHONE_STATE" /> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <uses-permission android:name="android.permission.READ_CONTACTS" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
2. 初始化appid
我是将appid的初始化放在的Applicaiton下,具体可以下载源码
// 应用程序入口处调用,避免手机内存过小,杀死后台进程后通过历史intent进入Activity造成SpeechUtility对象为null // 如在Application中调用初始化,需要在Mainifest中注册该Applicaiton // 注意:此接口在非主进程调用会返回null对象,如需在非主进程使用语音功能,请增加参数:SpeechConstant.FORCE_LOGIN+"=true" // 参数间使用“,”分隔。 // 设置你申请的应用appid StringBuffer param = new StringBuffer(); param.append("appid=55d33f09"); param.append(","); param.append(SpeechConstant.ENGINE_MODE + "=" + SpeechConstant.MODE_MSC); // param.append(","); // param.append(SpeechConstant.FORCE_LOGIN + "=true"); SpeechUtility.createUtility(InitKqwSpeech.this, param.toString());
3. 工具类
初始化好了以后直接复制工具类就可以用了
package com.example.kqwspeechdemo.engine; import org.json.JSONException; import org.json.JSONObject; import com.iflytek.cloud.SpeechConstant; import com.iflytek.cloud.SpeechError; import com.iflytek.cloud.SpeechUtility; import com.iflytek.cloud.VoiceWakeuper; import com.iflytek.cloud.WakeuperListener; import com.iflytek.cloud.WakeuperResult; import com.iflytek.cloud.util.ResourceUtil; import com.iflytek.cloud.util.ResourceUtil.RESOURCE_TYPE; import android.content.Context; import android.os.Bundle; import android.util.Log; import android.widget.Toast; /** * 语音唤醒 * * @author kongqw * */ public abstract class KqwWake { /** * 唤醒的回调 */ public abstract void kqwWake(); // Log标签 private static final String TAG = "KqwWake"; // 上下文 private Context mContext; // 语音唤醒对象 private VoiceWakeuper mIvw; /* * TODO 设置门限值 : 门限值越低越容易被唤醒,需要自己反复测试,根据不同的使用场景,设置一个比较合适的唤醒门限 */ // private final static int MAX = 60; // private final static int MIN = -20; private int curThresh = 40; public KqwWake(Context context) { mContext = context; // 加载识唤醒地资源,resPath为本地识别资源路径 StringBuffer param = new StringBuffer(); String resPath = ResourceUtil.generateResourcePath(context, RESOURCE_TYPE.assets, "ivw/55d33f09.jet"); param.append(ResourceUtil.IVW_RES_PATH + "=" + resPath); param.append("," + ResourceUtil.ENGINE_START + "=" + SpeechConstant.ENG_IVW); boolean ret = SpeechUtility.getUtility().setParameter(ResourceUtil.ENGINE_START, param.toString()); if (!ret) { Log.d(TAG, "启动本地引擎失败!"); } // 初始化唤醒对象 mIvw = VoiceWakeuper.createWakeuper(context, null); }; /** * 唤醒 */ public void wake() { // 非空判断,防止因空指针使程序崩溃 mIvw = VoiceWakeuper.getWakeuper(); if (mIvw != null) { // textView.setText(resultString); // 清空参数 mIvw.setParameter(SpeechConstant.PARAMS, null); // 唤醒门限值,根据资源携带的唤醒词个数按照“id:门限;id:门限”的格式传入 mIvw.setParameter(SpeechConstant.IVW_THRESHOLD, "0:" + curThresh); // 设置唤醒模式 mIvw.setParameter(SpeechConstant.IVW_SST, "wakeup"); // 设置持续进行唤醒 mIvw.setParameter(SpeechConstant.KEEP_ALIVE, "1"); mIvw.startListening(mWakeuperListener); } else { Toast.makeText(mContext, "唤醒未初始化", Toast.LENGTH_SHORT).show(); } } public void stopWake() { mIvw = VoiceWakeuper.getWakeuper(); if (mIvw != null) { mIvw.stopListening(); } else { Toast.makeText(mContext, "唤醒未初始化", Toast.LENGTH_SHORT).show(); } } String resultString = ""; private WakeuperListener mWakeuperListener = new WakeuperListener() { @Override public void onResult(WakeuperResult result) { try { String text = result.getResultString(); JSONObject object; object = new JSONObject(text); StringBuffer buffer = new StringBuffer(); buffer.append("【RAW】 " + text); buffer.append("\n"); buffer.append("【操作类型】" + object.optString("sst")); buffer.append("\n"); buffer.append("【唤醒词id】" + object.optString("id")); buffer.append("\n"); buffer.append("【得分】" + object.optString("score")); buffer.append("\n"); buffer.append("【前端点】" + object.optString("bos")); buffer.append("\n"); buffer.append("【尾端点】" + object.optString("eos")); resultString = buffer.toString(); stopWake(); kqwWake(); } catch (JSONException e) { resultString = "结果解析出错"; e.printStackTrace(); } } @Override public void onError(SpeechError error) { Log.i(TAG, error.getPlainDescription(true)); } @Override public void onBeginOfSpeech() { Log.i(TAG, "开始说话"); } @Override public void onEvent(int eventType, int isLast, int arg2, Bundle obj) { } }; }
测试类 package com.example.kqwspeechdemo; import com.example.kqwspeechdemo.engine.KqwWake; import android.app.Activity; import android.os.Bundle; import android.widget.TextView; import android.widget.Toast; public class MainActivity extends Activity { private TextView mTvLog; private TextView mTvResult; private KqwWake kqwWake; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mTvLog = (TextView) findViewById(R.id.tv_log); mTvResult = (TextView) findViewById(R.id.tv_result); kqwWake = new KqwWake(this) { @Override public void kqwWake() { Toast.makeText(MainActivity.this, "Debug:\n唤醒成功", Toast.LENGTH_SHORT).show(); // 开启唤醒 kqwWake.wake(); } }; // 开启唤醒 kqwWake.wake(); } }
页面布局
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context="com.example.kqwspeechdemo.MainActivity" > <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:background="#FF000000" android:gravity="center" android:padding="10dp" android:text="唤醒词:讯飞语音、讯飞语点" android:textColor="#FFFFFFFF" android:textSize="20dp" /> <View android:layout_width="match_parent" android:layout_height="1dp" android:background="#FFFFFFFF" /> <TextView android:id="@+id/tv_log" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="#FF000000" android:gravity="center" android:padding="10dp" android:text="录音信息" android:textColor="#FFFFFFFF" android:textSize="10dp" /> <View android:layout_width="match_parent" android:layout_height="1dp" android:background="#FFFFFFFF" /> <TextView android:id="@+id/tv_result" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#FF000000" android:padding="10dp" android:text="返回结果" android:textColor="#FFFFFFFF" android:textSize="10dp" /> </LinearLayout>
注意
- 如果你直接用的Demo,demo用的是测试版的离线包,只有35天的试用期,而且装机量只有3个,如果大家都用,很可能是不能正常运行的
- 如果是参考demo自己写一个,千万不要忘记替换appid和资源文件。