1. 程式人生 > >訊飛語音——喚醒

訊飛語音——喚醒

訊飛語音喚醒

喚醒功能,顧名思義,通過語音,喚醒服務,做我們想做的事情。

  • 效果圖(開啟應用後說訊飛語音或者訊飛語點喚醒)

P4

  • 原始碼下載

步驟

1. 建立應用,開通服務

2. 下載SDK

我們要使用的是訊飛的付費功能,選擇喚醒服務,點選下載以後,會提示沒有購買。點選“購買服務
P1

點選購買一會看到付費情況,有專案需要,就必須購買,我們寫Demo,訊飛給提供了體驗版的SDK,和正式版的沒有功能上的區別,但是隻能試用35天,裝機量只有3個,喚醒詞不能改,只有“訊飛語音”和“訊飛語點”兩個喚醒詞。
P2

3. 解壓SDK

assets目錄下是一些圖片資原始檔

doc目錄下是一些開發文件

libs目錄下是一些jar包和so庫

res目錄下是語音的資原始檔,非常重要

sample目錄下是Demo

P3

4. 整合語音喚醒

可以按照開發文件的介紹,一步一步跟著做,實現喚醒功能

我個人的習慣是看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>

注意

  1. 如果你直接用我的Demo,我用的是測試版的離線包,只有35天的試用期,而且裝機量只有3個,如果大家都用,很可能是不能正常執行的
  2. 如果是參考我的demo自己寫一個,千萬不要忘記替換appid和資原始檔。