12/08/2018, 16:57

Android - Speech Recognition

Tiếp nối bài viết về Web Speech Recognition, bài viết này của mình sẽ viết về Speech Recognition trên Android. Trên viblo cũng có mấy bài viết hướng dẫn sử dụng Speech Recognition trên Android, tuy nhiên các ví dụ trong đó đều yêu cầu sử dụng popup để bắt đầu nhận dạng giọng nói và chỉ cho phép ...

Tiếp nối bài viết về Web Speech Recognition, bài viết này của mình sẽ viết về Speech Recognition trên Android.

Trên viblo cũng có mấy bài viết hướng dẫn sử dụng Speech Recognition trên Android, tuy nhiên các ví dụ trong đó đều yêu cầu sử dụng popup để bắt đầu nhận dạng giọng nói và chỉ cho phép chúng ta xem kết quả sau khi hoàn thành câu nói. Trong bài viết này mình sẽ hướng dẫn các bạn thực hiện nhận diện giọng nói mà không phải bật popup và có thể xem các partial results.

Giới thiệu

Trong những bộ phim khoa học viễn tưởng, chúng ta rất thường hay thấy cảnh con người tương tác với các thiết bị điện tử bằng giọng nói. Giấc mơ này đã có từ khá lâu và bây giờ nó đang dần trở thành hiện thực. Những chiếc smartphone, tablet giờ đây đều có tính năng điều khiển bằng giọng nói, một số sản phẩm thậm chí còn trả lời lại người dùng như thể hai người đang nói chuyện với nhau. Sự ra đời của công nghệ này đã trở thành một xu hướng mới mẻ trong thị trường ứng dụng di động.

Các bạn có thể thấy ứng dụng của nó ở khắp nơi, dễ nhìn thấy nhất là từ các ông lớn Google (Google Voice), Apple (Siri), Microsoft (Cortana), Amazon (Alexa)... Tất nhiên, hiện nay công nghệ giọng nói vẫn chỉ mới ở giai đoạn đầu chứ chưa thể nào thay thế hoàn toàn bàn phím ảo/vật lý hoặc các nút trên màn hình. Tuy nhiên, chúng ta đang dần tiến đến một kỉ nguyên hiện đại hơn, các ứng dụng giọng nói cũng dần dần được hoàn thiện. Nó đang dần chuyển thành xu thế mới của các ứng dụng ngày nay.

Xây dựng ứng dụng

Chúng ta bắt đầu xây dựng ứng dụng nhận dạng giọng nói trên Android.

Đầu tiên chúng ta cần có:

  • class SpeechRecognitionListener dùng để lắng nghe các sự kiện được implements từ class RecognitionListener
  • class SpeechRecognizerManager dùng để quản lý cũng như xử lý các hành động
  • interface onResultsReady như một callback để trả dữ liệu về cho activity

Bắt đầu với onResultsReady

   public interface onResultsReady
   {
       // Trả về dữ liệu khi hoàn thành nhận dạng hoặc gặp lỗi
       public void onResults(ArrayList<String> results);
       
       // Trả về dữ liệu mỗi khi chúng ta nói
       public void onStreamingResult(ArrayList<String> partialResults);
   }

interface này được sử dụng để chúng ta trả dữ liệu về cho activity. Nó trả về 2 kiểu kết quả

  • Từng kết quả mà nó nhận điện được trong quá trình chúng ta nói (onStreamingResult)
  • Kết quả cuối cùng của cả câu (đoạn) mà chúng ta đã nói (onResults)

SpeechRecognitionListener

protected class SpeechRecognitionListener implements RecognitionListener
{
   @Override
   public void onBeginningOfSpeech() {}

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

   @Override
   public void onEndOfSpeech() {}

   @Override
   public synchronized void onError(int error) { }

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

   @Override
   public void onPartialResults(Bundle partialResults) { }

   @Override
   public void onReadyForSpeech(Bundle params) {}

   @Override
   public void onResults(Bundle results)  { }

   @Override
   public void onRmsChanged(float rmsdB) {}
}

Class SpeechRecognitionListener chúng ta implements từ RecognitionListener, nó cho phép chúng ta tham gia vào quá trình xử lý dữ liệu của SpeechRecognizer. Có 3 phương thức chúng ta cần phải viết lại, bao gồm onError (khi gặp lỗi), onPartialResults (khi nhận kết quả UNSTABLE), onResults (khi nhận kết quả cuối cùng).

Phương thức onError cho phép chúng ta xử lý các lỗi sau:

  • SpeechRecognizer.ERROR_AUDIO: Audio recording error.
  • SpeechRecognizer.ERROR_CLIENT: Other client side errors.
  • SpeechRecognizer.ERROR_INSUFFICIENT_PERMISSIONS: Insufficient permissions
  • SpeechRecognizer.ERROR_NETWORK: Other network related errors.
  • SpeechRecognizer.ERROR_NETWORK_TIMEOUT: Network operation timed out.
  • SpeechRecognizer.ERROR_NO_MATCH: No recognition result matched.
  • SpeechRecognizer.ERROR_RECOGNIZER_BUSY: RecognitionService busy.
  • SpeechRecognizer.ERROR_SERVER: Server sends error status.
  • SpeechRecognizer.ERROR_SPEECH_TIMEOUT: No speech input
// private onResultsReady mListener;
// mListener là 1 biến private nằm trong SpeechRecognizerManager

@Override
public synchronized void onError(int error) {
   if (error == SpeechRecognizer.ERROR_NETWORK) {
       ArrayList<String> errorList = new ArrayList<String>(1);
       errorList.add("STOPPED LISTENING");
       if (mListener != null) {
           mListener.onResults(errorList);
           Toast.makeText(mContext, "NETWORK ERROR", Toast.LENGTH_SHORT).show();
       }
   }

   // Các lỗi khác các bạn check tương tự
}

@Override
public void onPartialResults(Bundle partialResults) {
   if (partialResults != null && mListener != null) {
       ArrayList<String> texts = partialResults.getStringArrayList("android.speech.extra.UNSTABLE_TEXT");
       mListener.onStreamingResult(texts);
   }
}

@Override
public void onResults(Bundle results) {
   if (results != null && mListener != null) {
       ArrayList<String> ahihi = results.getStringArrayList(SpeechRecognizer.RESULTS_RECOGNITION);
       mListener.onResults(ahihi);
   }
}

SpeechRecognizerManager Các bạn có thể check các ngôn ngữ mà google hỗ trợ ở đây: https://cloud.google.com/speech/docs/languages Đoạn code ở dưới mình đặt ngôn ngữ hỗ trợ là tiếng Nhật và thời gian dừng tối đa là 2s.

public class SpeechRecognizerManager {
   private final static String TAG = "SpeechRecognizerManager";
   protected SpeechRecognizer mSpeechRecognizer;
   protected Intent mSpeechRecognizerIntent;
   private Context mContext;
   protected boolean mIsListening;
   protected String language = "ja"; // các bạn có thể đổi sang ngôn ngữ khác theo như ý muốn
   protected long timeout = 2000l; // 2000 ms

   private onResultsReady mListener;

   public SpeechRecognizerManager(Context context, onResultsReady listener)
   {
       try {
           mListener = listener;
       } catch(ClassCastException e) {
           Log.e(TAG, e.toString());
       }

       mContext = context;
       mSpeechRecognizer = SpeechRecognizer.createSpeechRecognizer(context);
       mSpeechRecognizer.setRecognitionListener(new SpeechRecognitionListener());

       // Create new intent
       mSpeechRecognizerIntent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
       mSpeechRecognizerIntent.putExtra(RecognizerIntent.EXTRA_CALLING_PACKAGE, context.getPackageName());
       mSpeechRecognizerIntent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, language);
       mSpeechRecognizerIntent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_PREFERENCE, language);
       mSpeechRecognizerIntent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, language);
       mSpeechRecognizerIntent.putExtra(RecognizerIntent.EXTRA_ONLY_RETURN_LANGUAGE_PREFERENCE, language);
       mSpeechRecognizerIntent.putExtra(RecognizerIntent.EXTRA_PARTIAL_RESULTS, true); // For streaming result
       mSpeechRecognizerIntent.putExtra(RecognizerIntent.EXTRA_SPEECH_INPUT_COMPLETE_SILENCE_LENGTH_MILLIS, timeout); 

       // Start listening
       startListening();
   }

   private void startListening()
   {
       if (!mIsListening) {
           mIsListening = true;
           mSpeechRecognizer.startListening(mSpeechRecognizerIntent);
       }
   }

   public void stop() {
       if (mIsListening && mSpeechRecognizer != null) {
           mSpeechRecognizer.stopListening();
           mSpeechRecognizer.cancel();
           mSpeechRecognizer.destroy();
           mSpeechRecognizer = null;
       }

       mIsListening = false;
   }

   public void destroy()
   {
       mIsListening = false;
       if (mSpeechRecognizer != null) {
           mSpeechRecognizer.stopListening();
           mSpeechRecognizer.cancel();
           mSpeechRecognizer.destroy();
           mSpeechRecognizer = null;
       }

   }

   public boolean ismIsListening() {
       return mIsListening;
   }
}

Giải thích 1 chút về đoạn code trên:

  • từ Activity chúng ta khởi tạo một SpeechRecognizerManager với 2 tham số ContextonResultsReady
  • Trong constructor của SpeechRecognizerManager, chúng ta tạo mới một SpeechRecognizer sử dụng SpeechRecognitionListener ở trên. Tiếp theo tạo một Intent và startListening. Thế là xong @@

Code: các bạn có thể check full code ở SpeechRecognizerManager.java

0