1. 程式人生 > >Android 科大訊飛 線上和離線語音聽寫

Android 科大訊飛 線上和離線語音聽寫

效果圖:

這裡寫圖片描述

參考資料

專案裡要用語音聽寫,想到了科大訊飛,參考上面的資料完成了最簡單的線上有UI的語音識別,後面想要改成離線也可以使用。參考下面的文章

下載好語記和離線資源之後,想要改成有UI的RecognizerDialog離線語音聽寫,但是沒成功,試了一下沒有UI的SpeechRecognizer,發現可以,只需在設定引數的時候加上一句

recognizer.setParameter(SpeechConstant.ENGINE_TYPE,SpeechConstant.TYPE_LOCAL);//呼叫語記介面

就可以使用了。可能是RecognizerDialog帶有UI介面,已經預設寫成線上的了吧
下面只貼出主活動的程式碼,其他參考上面的資料

package com.example.administrator.voicerecognition;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;

import com.iflytek.cloud.ErrorCode;
import com.iflytek.cloud.InitListener;
import
com.iflytek.cloud.RecognizerListener; import com.iflytek.cloud.RecognizerResult; import com.iflytek.cloud.SpeechConstant; import com.iflytek.cloud.SpeechError; import com.iflytek.cloud.SpeechRecognizer; import com.iflytek.cloud.SpeechUtility; import com.iflytek.cloud.ui.RecognizerDialog; import com.iflytek.cloud.ui.RecognizerDialogListener; public
class MainActivity extends AppCompatActivity { private Button btn_voiceRec,btn_voiceRecOffline; private RecognizerDialog iatDialog=null; private SpeechRecognizer recognizer=null; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); SpeechUtility.createUtility(this, "appid=xxx");//替換為實際的appid btn_voiceRec = (Button) findViewById(R.id.btn_voiceRec); btn_voiceRec.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { if (iatDialog!=null){ iatDialog.cancel(); iatDialog.destroy(); } startDialogOnline(); } }); btn_voiceRecOffline= (Button) findViewById(R.id.btn_voiceRecOffline); btn_voiceRecOffline.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { // if (recognizer!=null){ // recognizer.cancel(); // recognizer.destroy(); // } startNoDialogOffline(); } }); } /** * 初始化監聽器。 */ private InitListener mInitListener = new InitListener() { @Override public void onInit(int code) { Log.d("tag", "SpeechRecognizer init() code = " + code); if (code != ErrorCode.SUCCESS) { Log.d("tag", "初始化失敗,錯誤碼:" + code); } } }; public void startDialogOnline() { //1.建立SpeechRecognizer物件,第二個引數:本地聽寫時傳InitListener iatDialog = new RecognizerDialog(this, mInitListener); //2.設定聽寫引數 iatDialog.setParameter(SpeechConstant.LANGUAGE, "zh_cn"); iatDialog.setParameter(SpeechConstant.ACCENT, "mandarin "); //3.設定回撥介面 iatDialog.setListener(new RecognizerDialogListener() { @Override public void onResult(RecognizerResult recognizerResult, boolean b) { if (!b) { String json = recognizerResult.getResultString(); String str = JsonParser.parseIatResult(json); Toast.makeText(MainActivity.this, str, Toast.LENGTH_SHORT).show(); } } @Override public void onError(SpeechError speechError) { Log.d("error", speechError.toString()); } }); //4.開始聽寫 iatDialog.show(); } private void startNoDialogOffline(){ //1.建立SpeechRecognizer物件,第二個引數:本地聽寫時傳InitListener recognizer = SpeechRecognizer.createRecognizer(this,null); //2.設定聽寫引數 recognizer.setParameter(SpeechConstant.ENGINE_TYPE,SpeechConstant.TYPE_LOCAL);//呼叫語記介面 recognizer.setParameter(SpeechConstant.DOMAIN, "iat");//引數設為語音聽寫 recognizer.setParameter(SpeechConstant.LANGUAGE, "zh_cn");//中文 recognizer.setParameter(SpeechConstant.ACCENT, "mandarin ");//普通話 //3.設定回撥介面 recognizer.startListening(new RecognizerListener() { @Override public void onVolumeChanged(int i, byte[] bytes) { } @Override public void onBeginOfSpeech() { } @Override public void onEndOfSpeech() { } @Override public void onResult(RecognizerResult recognizerResult, boolean isLast) { if (isLast) { String json = recognizerResult.getResultString(); String str = JsonParser.parseIatResult(json); Log.d("tag",str); Toast.makeText(MainActivity.this, str, Toast.LENGTH_SHORT).show(); } } @Override public void onError(SpeechError speechError) { Log.d("error", speechError.toString()); } @Override public void onEvent(int i, int i1, int i2, Bundle bundle) { } }); } }

—————————————————————————————————

2016.11.2更新

離線語音做了個簡單的UI,效果如圖:

這裡寫圖片描述

完整程式碼如下,改動部分已註釋:

package com.example.administrator.voicerecognition;

import android.app.ProgressDialog;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.Gravity;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.Toast;

import com.iflytek.cloud.ErrorCode;
import com.iflytek.cloud.InitListener;
import com.iflytek.cloud.RecognizerListener;
import com.iflytek.cloud.RecognizerResult;
import com.iflytek.cloud.SpeechConstant;
import com.iflytek.cloud.SpeechError;
import com.iflytek.cloud.SpeechRecognizer;
import com.iflytek.cloud.SpeechUtility;
import com.iflytek.cloud.ui.RecognizerDialog;
import com.iflytek.cloud.ui.RecognizerDialogListener;

public class MainActivity extends AppCompatActivity {
    private Button btn_voiceRec,btn_voiceRecOffline;
    private RecognizerDialog iatDialog=null;
    private SpeechRecognizer recognizer=null;
    //新增對話方塊和語音聽寫完成標誌------------------
    private ProgressDialog pDialog=null;
    private boolean isFinish=false;
    //-----------------------------------
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        SpeechUtility.createUtility(this, "appid=xxx");//替換為實際的appid
        btn_voiceRec = (Button) findViewById(R.id.btn_voiceRec);
        btn_voiceRec.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if (iatDialog!=null){
                    iatDialog.cancel();
                    iatDialog.destroy();
                }
                startDialogOnline();
            }
        });
        btn_voiceRecOffline= (Button) findViewById(R.id.btn_voiceRecOffline);
        btn_voiceRecOffline.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
//                if (recognizer!=null){
//                    recognizer.cancel();
//                    recognizer.destroy();
//                }
                startNoDialogOffline();
                //顯示對話方塊----------------
                showProgressDialog();
                //----------------------
            }
        });
    }

    //對話方塊顯示方法-----------------------------------
    private void showProgressDialog() {
        pDialog = new ProgressDialog(MainActivity.this);

        pDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
        pDialog.setProgress(100);
        pDialog.setMessage("請稍等...");
        pDialog.setIndeterminate(false);
        pDialog.show();

        WindowManager.LayoutParams lp = pDialog.getWindow().getAttributes();
        lp.gravity = Gravity.CENTER;
        Window win = pDialog.getWindow();
        win.setAttributes(lp);

        new Thread(new Runnable() {

            @Override
            public void run() {
                //long startTime = System.currentTimeMillis();
                int progress = 0;

                //while (System.currentTimeMillis() - startTime < 1000) {
                //語音聽寫完成後,釋放對話方塊
                while (!isFinish) {
                    try {
                        progress += 10;
                        pDialog.setProgress(progress);
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        pDialog.dismiss();
                    }
                }

                pDialog.dismiss();
                isFinish=false;
            }
        }).start();
    }
//--------------------------------------------------------

    /**
     * 初始化監聽器。
     */
    private InitListener mInitListener = new InitListener() {

        @Override
        public void onInit(int code) {
            Log.d("tag", "SpeechRecognizer init() code = " + code);
            if (code != ErrorCode.SUCCESS) {
                Log.d("tag", "初始化失敗,錯誤碼:" + code);
            }
        }
    };

    public void startDialogOnline() {
        //1.建立SpeechRecognizer物件,第二個引數:本地聽寫時傳InitListener
        iatDialog = new RecognizerDialog(this, mInitListener);
        //2.設定聽寫引數

        iatDialog.setParameter(SpeechConstant.LANGUAGE, "zh_cn");
        iatDialog.setParameter(SpeechConstant.ACCENT, "mandarin ");


        //3.設定回撥介面
        iatDialog.setListener(new RecognizerDialogListener() {
            @Override
            public void onResult(RecognizerResult recognizerResult, boolean isLast) {
                if (!isLast) { 
                    String json = recognizerResult.getResultString();
                    String str = JsonParser.parseIatResult(json);
                    Toast.makeText(MainActivity.this, str, Toast.LENGTH_SHORT).show();
                }
            }

            @Override
            public void onError(SpeechError speechError) {
                Log.d("error", speechError.toString());
            }
        });
        //4.開始聽寫
        iatDialog.show();
    }


    private void startNoDialogOffline(){
        //1.建立SpeechRecognizer物件,第二個引數:本地聽寫時傳InitListener
        recognizer = SpeechRecognizer.createRecognizer(this,null);
        //2.設定聽寫引數

        recognizer.setParameter(SpeechConstant.ENGINE_TYPE,SpeechConstant.TYPE_LOCAL);//呼叫語記介面


        recognizer.setParameter(SpeechConstant.DOMAIN, "iat");//引數設為語音聽寫
        recognizer.setParameter(SpeechConstant.LANGUAGE, "zh_cn");//中文
        recognizer.setParameter(SpeechConstant.ACCENT, "mandarin ");//普通話

        //3.設定回撥介面
        recognizer.startListening(new RecognizerListener() {
            @Override
            public void onVolumeChanged(int i, byte[] bytes) {

            }

            @Override
            public void onBeginOfSpeech() {

            }

            @Override
            public void onEndOfSpeech() {

            }

            @Override
            public void onResult(RecognizerResult recognizerResult, boolean isLast) {
                if (isLast) {
                    String json = recognizerResult.getResultString();
                    String str = JsonParser.parseIatResult(json);
                    Log.d("tag",str);
                    Toast.makeText(MainActivity.this, str, Toast.LENGTH_SHORT).show();
                    //語音聽寫完成標誌---------------------------
                    isFinish=true;
                    //------------------------------------------
                }
            }

            @Override
            public void onError(SpeechError speechError) {
                Log.d("error", speechError.toString());
            }

            @Override
            public void onEvent(int i, int i1, int i2, Bundle bundle) {

            }
        });
    }
}

注:經過多次測試後發現,第一次點選按鈕離線語音聽寫無法識別,第二次點選按鈕才可正常實現聽寫,之後都可以正常聽寫,這個bug目前還沒有解決

—————————————————————————————————

2016.11.6 更新

第一次離線語音聽寫無反應bug的解決辦法:在onCreat()裡先執行一次,不顯示UI,這樣再點選就是第二次了。。。雖然很蠢,但是功能上算是實現了,後面有時間再仔細想想更好的辦法

protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        SpeechUtility.createUtility(this, "appid=xxx");//替換為實際的appid
        btn_voiceRec = (Button) findViewById(R.id.btn_voiceRec);
        btn_voiceRec.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                startDialogOnline();
            }
        });
        btn_voiceRecOffline = (Button) findViewById(R.id.btn_voiceRecOffline);
    //先聽寫一次----------------------------
        startNoDialogOffline();
        //------------------------------------
        btn_voiceRecOffline.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                startNoDialogOffline();
                showProgressDialog();
            }
        });
    }

注:除錯過程中又發現,在單獨使用線上的情況下,線上的RecognizerDialogListener的onResult()會呼叫兩次,輸出兩個str,第一個是聽寫內容,第二個是標點符號。如果是if (!isLast),那麼輸出的是聽寫內容,如果是if (isLast),輸出的是標點符號。很顯然,需要的是聽寫內容,這時要用if (!isLast)。

如果和離線的混用,就像上面一樣,在onCreat()裡先執行了一次startNoDialogOffline(),那麼經測試RecognizerDialogListener的onResult()只會呼叫一次,輸出一個str,聽寫內容和標點符號連在一起的(具體原因不清楚),這時候如果是if (!isLast),就不會有輸出了。所以這裡要用if (isLast)。

單獨使用離線的情況下,RecognizerListener的onResult()是隻會呼叫一次,輸出一個str。這時候如果是if (!isLast),就不會有輸出了。所以這裡要用if (isLast)。

所以說線上的要和離線的分開使用,本文只是個例子,實際使用過程中也不會同時使用。簡單來說,線上用if (!isLast)判斷,離線用if (isLast)判斷