2014年11月20日 星期四

Android 語音辨識 App 程式開發 (二) - 不開語音辨識 dialog 的背景辨識方法


透過使用 SpeechRecognizer 來做語音辨識,它是個 Obvserver 的 Design Pattern,
此方式就不會像 Android 語音辨識 App 開發 (一) 這樣,開出內建的 Dialog。

雖然這篇用 Acitity 方式 Demo,但是用 SpeechRecognizer 方式可以做在 Services 裡,在背景一直聽一直辨識、一直聽一直辨識環境的講話聲。
首先,實作一個 RecognitionListener (Observer),之後餵給 SpeechRecognizer (Subject) 辨識完 callback 用...

   private class MyRecognizerListener implements RecognitionListener {

      @Override
      public void onResults(Bundle results) {
         List resList = results.getStringArrayList(SpeechRecognizer.RESULTS_RECOGNITION);
         StringBuffer sb = new StringBuffer();
         for(String res: resList) {
            sb.append(res + "\n");
         }
         textView2.setText("onResults: " + sb.toString());
         Log.d("RECOGNIZER", "onResults: " + sb.toString());
      }

      @Override
      public void onError(int error) {
         Log.d("RECOGNIZER", "Error Code: " + error);
      }

      @Override
      public void onReadyForSpeech(Bundle params) {
      }

      @Override
      public void onBeginningOfSpeech() {
      }

      @Override
      public void onRmsChanged(float rmsdB) {
      }

      @Override
      public void onBufferReceived(byte[] buffer) {
      }

      @Override
      public void onEndOfSpeech() {
      }

      @Override
      public void onPartialResults(Bundle partialResults) {
      }

      @Override
      public void onEvent(int eventType, Bundle params) {
      }
   }


這邊我們只 implement 了 onResult() 與 onError(),如果要做更多的控制可以 implement 其他的 method,例如開始說話的時候或結束說話的時候要做什麼,可以 implement onBeginningOfSpeech()與 onEndOfSpeech()。請參考 RecognitionListener API

接著,我們建立一個 SpeechRecognizer Instance與 RecognitionListener Instance,並呼叫 setRecognitionListener() 把 RecognitionListener 實體設給 SpeechListener。然後在按下 Button 時,讓 SpeechRecognizer 開始 Listen 。

   private Button btnStart;
   private TextView textView2;
   private SpeechRecognizer recognizer;

   @Override
   protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_listener);

      btnStart = (Button) this.findViewById(R.id.button1);
      textView2 = (TextView) this.findViewById(R.id.textView1);

      recognizer = SpeechRecognizer.createSpeechRecognizer(this);

      recognizer.setRecognitionListener(new MyRecognizerListener());

      //按 Button 時,呼叫 SpeechRecognizer 的 startListening()
      //Intent 為傳遞給 SpeechRecognizer 的參數
      btnStart.setOnClickListener(new OnClickListener() {
         @Override
         public void onClick(View v) {
            Intent intent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
            intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM);

            recognizer.startListening(intent);
         }
      });
   }

如果有辨識結果,RecognitionListener 的 onResult() 就會被呼叫。

最後,我們在 Activity 的 onDestroy() 時,把 SpeechRecognizer 也 destroy 掉。
   @Override
   protected void onDestroy() {
      recognizer.stopListening();
      recognizer.destroy();
      super.onDestroy();
   }

1 則留言:

KevinKuei 提到...

感謝您的分享.
有個問題想請教.
我想要作一個類似"Ok google" 的功能. 比方說 就叫做 "Ok myphone"

在我的應用裡, 可以假設用戶已經開啟了我的app
我的app 就呼叫 startListening() 開始聽... 看看是不是有關鍵字 "Ok myphone" 出現

問題來了.. 執行 startListening() 都會發出 "登登" 聲音.. 然後如果環境上有人講話, 就開始辨識, 然後講話停止時 onEndOfSpeech() 的時候又會發生3聲,

請問這些聲音可以消除掉嗎??
因為在我說出 "ok myphone" 之前, 我不希望他一直登登登發出聲音.

ps. 我正在研發的是機器人語音控制, 如果您有興趣歡迎和我聯絡. 謝謝