1. 程式人生 > >Android——訊飛語音喚醒簡介及實現

Android——訊飛語音喚醒簡介及實現

前段時間寫了一個關於百度語音喚醒文章,最近有做了一個訊飛語音的應用,在這裡把學習的資料整理一下。
喚醒的整個過程如下:
這裡寫圖片描述(圖源自訊飛官網)
訊飛的語音喚醒功能實現起來挺方便的(相比百度,百度語音Android端的語音喚醒是基於service實現的)百度語音喚醒識別效果對於不建議使用的喚醒詞識別較差,而訊飛相對較容易。並且訊飛語音喚醒可以自己設定很多引數,來提高識別率,百度提供給使用者的設定介面很少。俗話說“魚和熊掌不可兼得”,一句話總結這兩個平臺就是——百度免費,訊飛收費。
這裡寫圖片描述
這裡寫圖片描述
大家可以根據自己專案的實際需求作抉擇。
下面我們就言歸正傳:
我們先來講一講訊飛語音喚醒的引數設定。下面是訊飛官方文件的內容這裡寫圖片描述


喚醒業務型別,分為如下幾種:
喚醒:wakeup;(單喚醒詞,多喚醒詞,或特定人喚醒)
註冊:enroll;(特定人喚醒註冊,又稱為“訓練”,用於特定人喚醒時,註冊使用者喚醒詞)
喚醒識別:oneshot;

喚醒門限值:
格式:id:門限值;* (*代表可多個),根據資源攜帶的喚醒詞個數按照“id:門限;id:門限” 的格式傳入。門限值越高,則要求匹配度越高,才能喚醒。
是否必須設定:否
預設值:0
值範圍:[-150, 150]

持續喚醒:
在持續喚醒時,喚醒一次後,當前會話依然繼續,錄音還在繼續,當有匹配的喚醒 時,會返回結果;否則,喚醒一次後,當前會話已結束,錄音也結束,不會再監聽。
此引數對喚醒識別不起作用,見IVW_SST。
是否必須設定:否
預設值:0
值範圍:{null, 0, 1}

喚醒資源路徑:
喚醒需要使用本地資源,通過此引數設定本地資源所在的路徑。多個資源間,以英文分號”;”分隔。 與IVW_ENROLL_RES_PATH一樣,用於使用的資源,需要通過 ResourceUtil.generateResourcePath(Context, com.iflytek.cloud.util.ResourceUtil.RESOURCE_TYPE, java.lang.String)生成標準的資源路徑值。 請參考 ResourceUtil.generateResourcePath(Context, com.iflytek.cloud.util.ResourceUtil.RESOURCE_TYPE, java.lang.String)。
是否必須設定:是(在非註冊時)
預設值:null
值範圍:有效的資原始檔路徑

引擎型別:
設定使用的引擎型別:線上、離線、混合。在申請了離線合成資源和許可權, 或使用語記方式時,可以選擇使用本地或線上的方式進行語音服務。使用線上模式(又稱雲端模式)時,需要使用網路,產生一定流量,但有更好的識別 或合成的效果,如更高的識別匹配度,更多的發音人等。使用離線模式(又稱本地模式)時,不需要使用網路,且識別和合成的速度更快,但同 時要求使用對應的離線資源或安裝“語記”(安卓或iOS平臺)。在混合模式時,可以通過混合型別、 雲端超時、本地置信門限 使用對應的策略,提高識別準確度與成功率。詳情參見前面的幾個引數說明。
在離線或混合模式下,需要設定對應的資源。請參考
合成資源路徑:ResourceUtil.TTS_RES_PATH;
識別資源路徑:ResourceUtil.ASR_RES_PATH;
喚醒資源路徑:IVW_RES_PATH;
關於離線資源的其他介紹,參考ResourceUtil類的說明。
是否必須設定:否
預設值:”cloud”
值範圍:{ “cloud”, “local”,”mixed” }

訊飛 語音喚醒實現起來相當簡單,具體步驟如下

  • 申請賬號

首先需要去訊飛開放平臺申請一個賬號,之後註冊一個自己的應用,這裡我們以Android端為例來說明。對於第一次使用訊飛語音的人,首先先要建立一個應用
這裡寫圖片描述

  • 開通服務

大家可以根據自己的實際需求開通相應的服務。
這裡寫圖片描述
這裡大家一定要記住Appid很重要,這就相當於你應用的身份證號碼。

  • 下載SDK

下載分為組合下載和單個服務SDK下載
這裡寫圖片描述

  • 檔案拷貝

我們下載的SDK正常情況下為
這裡寫圖片描述
assets資料夾下面主要是訊飛語音的一些介面圖示,如果你需要使用訊飛的語音輸入介面,可以將這個資料夾下面的內容拷貝到你相應的Android工程目錄下。doc下面為文件libs下面使我們需要的.so檔案和jar檔案,libs下面有不同cpu下的so檔案,不同的cpu平臺需要不同的so檔案,這裡面的so檔案是使用c/c++寫的,根據需求自己選擇,並將相應的檔案拷貝到自己的Android工程對應的目錄下。如果Android工程中沒有libs目錄,需要我們自己建立一個目錄。res下面是一些訊飛語音的資原始檔,需要將這些檔案拷貝到自己Android工程的assets檔案中,res中的ivw檔案為喚醒詞的資原始檔。sample檔案是一個demo工程,大家可以參考demo完成自己的功能需求。

  • 程式碼實現

程式碼實現之前我們還需要新增一些許可權,Android6.0以及之後的版本需要動態申請許可權,這裡大家自行學習,我不在贅述。
在AndroidManifest.xml檔案中新增如下許可權

    <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" />
    <uses-permission android:name="android.permission.WRITE_SETTINGS" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

在程式碼實現過程中,首先我們需要初始化訊飛語音,程式碼如下:

     /**
      * 初始化訊飛語音
      */
     private void initializeIflytek()
     {
        StringBuffer param = new StringBuffer();
        //IflytekAPP_id為我們申請的Appid
        param.append("appid="+getString(R.string.IflytekAPP_id));
        param.append(",");
        // 設定使用v5+
        param.append(SpeechConstant.ENGINE_MODE+"="+SpeechConstant.MODE_MSC);
        SpeechUtility.createUtility(DWEApplication.this, param.toString());
     }

初始化最好放在APP初始化階段,也就是所繼承Application類,然後把訊飛初始化的內容放到該類裡面。

前面說的內容適合於訊飛的所有語音產品,下面我講給出訊飛語音喚醒的程式碼實現。

import org.json.JSONException;
import org.json.JSONObject;
import com.iflytek.cloud.SpeechConstant;
import com.iflytek.cloud.SpeechError;
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.content.Intent;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
/**
 * 訊飛語音喚醒
 * @author Administrator
 *
 */
public class IflytekWakeUp {

    private Context mContext;
    //喚醒的閾值,就相當於門限值,當用戶輸入的語音的置信度大於這一個值的時候,才被認定為成功喚醒。
    private int curThresh = 10;
    //是否持續喚醒
    private String keep_alive = "1";
    /**
      * 閉環優化網路模式有三種:
      * 模式0:關閉閉環優化功能
      * 
      * 模式1:開啟閉環優化功能,允許上傳優化資料。需開發者自行管理優化資源。
      * sdk提供相應的查詢和下載介面,請開發者參考API文件,具體使用請參考本示例
      * queryResource及downloadResource方法;
      * 
      * 模式2:開啟閉環優化功能,允許上傳優化資料及啟動喚醒時進行資源查詢下載;
      * 本示例為方便開發者使用僅展示模式0和模式2;
     */
    private String ivwNetMode = "0";
    // 語音喚醒物件
    private VoiceWakeuper mIvw;
    //儲存喚醒詞的ID
    private String wordID = "";

    public IflytekWakeUp(Context context)
    {
        this.mContext = context;
        // 初始化喚醒物件
        mIvw = VoiceWakeuper.createWakeuper(mContext, null);
    }
    /**
     * 開啟喚醒功能
     */
    public void startWakeuper()
    {
        //非空判斷,防止因空指標使程式崩潰
        mIvw = VoiceWakeuper.getWakeuper();
        if(mIvw != null) {
            // 清空引數
            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, keep_alive);
            // 設定閉環優化網路模式
            mIvw.setParameter(SpeechConstant.IVW_NET_MODE, ivwNetMode);
            // 設定喚醒資源路徑
            mIvw.setParameter(SpeechConstant.IVW_RES_PATH, getResource());
            // 設定喚醒錄音儲存路徑,儲存最近一分鐘的音訊
            mIvw.setParameter( SpeechConstant.IVW_AUDIO_PATH, Environment.getExternalStorageDirectory().getPath()+"/msc/ivw.wav" );
            mIvw.setParameter( SpeechConstant.AUDIO_FORMAT, "wav" );
            // 如有需要,設定 NOTIFY_RECORD_DATA 以實時通過 onEvent 返回錄音音訊流位元組
            //mIvw.setParameter( SpeechConstant.NOTIFY_RECORD_DATA, "1" );

            // 啟動喚醒
            mIvw.startListening(new MyWakeuperListener());
        }
    }
    /**
     * 獲取喚醒詞功能
     * @return 返回檔案位置
     */
    private String getResource() {
        final String resPath = ResourceUtil.generateResourcePath(mContext, RESOURCE_TYPE.assets, "ivw/"+mContext.getString(R.string.IflytekAPP_id)+".jet");
        return resPath;
    }

    /**
     * 銷燬喚醒功能
     */
    public void destroyWakeuper()
    {
        // 銷燬合成物件
        mIvw = VoiceWakeuper.getWakeuper();
        if (mIvw != null) {
            mIvw.destroy();
        }
    }
    /**
     * 停止喚醒
     */
    public void stopWakeuper()
    {
        mIvw.stopListening();
    }

    /**
     * 喚醒詞監聽類
     * @author Administrator
     *
     */
    private class MyWakeuperListener implements WakeuperListener
    {
        //開始說話
        @Override
        public void onBeginOfSpeech() {

        }
        //錯誤碼返回
        @Override
        public void onError(SpeechError arg0) {

        }

        @Override
        public void onEvent(int arg0, int arg1, int arg2, Bundle arg3) {

        }

        @Override
        public void onResult(WakeuperResult result) {

            if(!"1".equalsIgnoreCase(keep_alive)) {
                //setRadioEnable(true);
            }
            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();
            } catch (JSONException e) {
                e.printStackTrace();
        }
        /**
         *聲音改變回調
        */
        @Override
        public void onVolumeChanged(int arg0) {

        }
    }
}

訊飛語音喚醒大體實現過程就是如上所述,其他功能也類似。我這裡知識簡單的實現了一下,語音喚醒裡面還有其他方法,我把文件截圖放在這裡,大幾可以參考一下。
這裡寫圖片描述
這裡寫圖片描述

原創文章不容易,轉載請註明出處!!Thank you!

(昨天晚上寫到凌晨,今天總算把後面的內容寫完了,這樣一來總算把國內做語音喚醒的比較好的平臺介紹完了,今天放五一假,是不是應該出去走走呢?)