科大讯飞语音唤醒

August 19, 2015


转载请说明出处! 作者:kqw攻城狮 出处:个人站 | CSDN


语音唤醒

唤醒功能,顾名思义,通过语音,唤醒服务,做我们想做的事情。

效果图

开启应用后说讯飞语音或者讯飞语点唤醒

效果图

源码下载

地址:http://download.csdn.net/detail/q4878802/9023213

步骤

1. 创建应用,开通服务

地址:http://blog.csdn.net/q4878802/article/details/47762169

2. 下载SDK

我们要使用的是讯飞的付费功能,选择唤醒服务,点击下载以后,会提示没有购买。点击“购买服务

购买服务

点击购买一会看到付费情况,有项目需要,就必须购买,我们写Demo,讯飞给提供了体验版的SDK,和正式版的没有功能上的区别,但是只能试用35天,装机量只有3个,唤醒词不能改,只有“讯飞语音”和“讯飞语点”两个唤醒词。

下载体验版SDK

3. 解压SDK

assets目录下是一些图片资源文件 doc目录下是一些开发文档 libs目录下是一些jar包和so库 res目录下是语音的资源文件,非常重要 sample目录下是Demo

解压SDK

开发步骤

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>

注意

  1. 如果你直接用我的Demo,我用的是测试版的离线包,只有35天的试用期,而且装机量只有3个,如果大家都用,很可能是不能正常运行的
  2. 如果是参考我的demo自己写一个,千万不要忘记替换appid和资源文件。