ai.api.unityhelper.RecognitionHelper.java Source code

Java tutorial

Introduction

Here is the source code for ai.api.unityhelper.RecognitionHelper.java

Source

package ai.api.unityhelper;

/***********************************************************************************************************************
 *
 * API.AI Unity SDK - client-side libraries for API.AI
 * =================================================
 *
 * Copyright (C) 2015 by Speaktoit, Inc. (https://www.speaktoit.com)
 * https://www.api.ai
 *
 ***********************************************************************************************************************
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
 * the License. You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
 * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations under the License.
 *
 ***********************************************************************************************************************/

import android.annotation.TargetApi;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.speech.RecognitionListener;
import android.speech.RecognizerIntent;
import android.speech.SpeechRecognizer;
import android.util.Log;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

public class RecognitionHelper {

    private static final String TAG = RecognitionHelper.class.getName();

    private SpeechRecognizer speechRecognizer;
    private final Object speechRecognizerLock = new Object();
    private volatile boolean recognitionActive = false;
    private Context context;
    private Handler handler;

    private RecognitionResultObject resultObject;

    private final Map<Integer, String> errorMessages = new HashMap<Integer, String>();

    {
        errorMessages.put(1, "Network operation timed out.");
        errorMessages.put(2, "Other network related errors.");
        errorMessages.put(3, "Audio recording error.");
        errorMessages.put(4, "Server sends error status.");
        errorMessages.put(5, "Other client side errors.");
        errorMessages.put(6, "No speech input.");
        errorMessages.put(7, "No recognition result matched.");
        errorMessages.put(8, "RecognitionService busy.");
        errorMessages.put(9, "Insufficient permissions.");
    }

    public RecognitionHelper() {
    }

    public void initialize(Context context) {
        this.context = context;
        handler = new Handler(context.getMainLooper());
    }

    public RecognitionResultObject recognize(final String lang) {
        try {
            if (!recognitionActive) {
                resultObject = new RecognitionResultObject();
                startListening(lang);
            }

            return resultObject;
        } catch (Exception e) {

            resultObject = null;

            JSONObject result = new JSONObject();

            try {
                result.put("status", "error");
                result.put("errorMessage", e.getMessage());
            } catch (JSONException jsonEx) {
                Log.e(TAG, jsonEx.getMessage(), jsonEx);
            }
            RecognitionResultObject errorResultObject = new RecognitionResultObject();
            errorResultObject.setResult(result.toString());
            return errorResultObject;
        }

    }

    public void clean() {
        resultObject = null;
    }

    /**
     *
     * @param lang recognition language
     */
    private void startListening(final String lang) {
        if (!recognitionActive) {

            final Intent sttIntent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
            sttIntent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM);

            final String language = lang.replace('-', '_');

            sttIntent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, language);
            sttIntent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_PREFERENCE, language);

            // WORKAROUND for https://code.google.com/p/android/issues/detail?id=75347
            // TODO Must be removed after fix in Android
            sttIntent.putExtra("android.speech.extra.EXTRA_ADDITIONAL_LANGUAGES", new String[] {});

            runInUiThread(new Runnable() {
                @Override
                public void run() {
                    initializeRecognizer();

                    speechRecognizer.startListening(sttIntent);
                    recognitionActive = true;
                }
            });

        } else {
            Log.w(TAG, "Trying to start recognition while another recognition active");
        }
    }

    protected void onError(final String errorMessage) {
        JSONObject resultJson = new JSONObject();

        try {
            resultJson.put("status", "error");
            resultJson.put("errorMessage", errorMessage);
        } catch (JSONException je) {
            Log.e(TAG, je.getMessage(), je);
        }

        String resultJsonString = resultJson.toString();
        if (resultObject != null) {
            resultObject.setResult(resultJsonString);
        }
    }

    protected void onResults(final Bundle results) {

        JSONObject resultJson = new JSONObject();

        try {

            resultJson.put("status", "success");

            final ArrayList<String> recognitionResults = results
                    .getStringArrayList(SpeechRecognizer.RESULTS_RECOGNITION);

            if (recognitionResults == null || recognitionResults.size() == 0) {
                resultJson.put("recognitionResults", new JSONArray());
            } else {
                resultJson.put("recognitionResults", new JSONArray(recognitionResults));

                float[] rates = null;

                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
                    rates = results.getFloatArray(SpeechRecognizer.CONFIDENCE_SCORES);
                    if (rates != null && rates.length > 0) {
                        final JSONArray ratesArray = new JSONArray();
                        for (int i = 0; i < rates.length; i++) {
                            ratesArray.put(rates[i]);
                        }
                        resultJson.put("confidence", ratesArray);
                    }
                }
            }

        } catch (JSONException je) {
            Log.e(TAG, je.getMessage(), je);
        }

        clearRecognizer();
        String resultJsonString = resultJson.toString();
        if (resultObject != null) {
            resultObject.setResult(resultJsonString);
        }
    }

    protected void initializeRecognizer() {
        synchronized (speechRecognizerLock) {
            if (speechRecognizer != null) {
                speechRecognizer.destroy();
                speechRecognizer = null;
            }

            final ComponentName googleRecognizerComponent = RecognizerChecker.findGoogleRecognizer(context);

            if (googleRecognizerComponent == null) {
                speechRecognizer = SpeechRecognizer.createSpeechRecognizer(context);
            } else {
                speechRecognizer = SpeechRecognizer.createSpeechRecognizer(context, googleRecognizerComponent);
            }

            speechRecognizer.setRecognitionListener(new InternalRecognitionListener());
        }
    }

    protected void clearRecognizer() {
        if (speechRecognizer != null) {
            synchronized (speechRecognizerLock) {
                if (speechRecognizer != null) {
                    speechRecognizer.destroy();
                    speechRecognizer = null;
                }
            }
        }
    }

    private void runInUiThread(final Runnable runnable) {
        handler.post(runnable);
    }

    private class InternalRecognitionListener implements RecognitionListener {

        @Override
        public void onReadyForSpeech(final Bundle params) {

        }

        @Override
        public void onBeginningOfSpeech() {

        }

        @Override
        public void onRmsChanged(final float rmsdB) {

        }

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

        }

        @Override
        public void onEndOfSpeech() {

        }

        @Override
        public void onError(final int error) {
            recognitionActive = false;

            String aiError;
            if (errorMessages.containsKey(error)) {
                final String description = errorMessages.get(error);
                aiError = "Speech recognition engine error: " + description;
            } else {
                aiError = "Speech recognition engine error: " + error;
            }
            RecognitionHelper.this.onError(aiError);
        }

        @TargetApi(14)
        @Override
        public void onResults(final Bundle results) {
            if (recognitionActive) {
                recognitionActive = false;

                RecognitionHelper.this.onResults(results);
            }
        }

        @Override
        public void onPartialResults(final Bundle partialResults) {

        }

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

        }
    }

}