12

EDIT: I should have mentioned this already, but I'm running this code in a service. The entire app is turned on/off by a widget button and has no activity.


Update: I tried attaching the SDK sources to the project so I could get a more precise idea of where the failure was occurring, but from the looks of it, only public APIs are included, which seems to make them a lot less useful... can anyone suggest at least a debugging approach for solving this issue? I'm kind of stuck.


I'm trying to use Android's speech recognition package to record user speech and translate it to text. Unfortunately, when I attempt initiate listening, I get an ANR error that doesn't point to anything specific.

As the SpeechRecognizer API indicates, a RuntimeException is thrown if you attempt to call it from the main thread. This would make me wonder if the processing was just too demanding... but I know that other applications use the Android API for this purpose and it is typically pretty snappy.

java.lang.RuntimeException: SpeechRecognizer should be used only from the application's main thread

Here is a (trimmed) sample of the code I'm trying to call from my service. Is this the proper approach?

Thanks for taking the time to help. This has been a hurdle I haven't been able to get over yet.

Intent intent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL,
        RecognizerIntent.LANGUAGE_MODEL_FREE_FORM);
intent.putExtra(RecognizerIntent.EXTRA_CALLING_PACKAGE,
        "com.domain.app");

SpeechRecognizer recognizer = SpeechRecognizer
        .createSpeechRecognizer(this.getApplicationContext());
RecognitionListener listener = new RecognitionListener() {
    @Override
    public void onResults(Bundle results) {
        ArrayList<String> voiceResults = results
                .getStringArrayList(RecognizerIntent.EXTRA_RESULTS);
        if (voiceResults == null) {
            Log.e(getString(R.string.log_label), "No voice results");
        } else {
            Log.d(getString(R.string.log_label), "Printing matches: ");
            for (String match : voiceResults) {
                Log.d(getString(R.string.log_label), match);
            }
        }
    }

    @Override
    public void onReadyForSpeech(Bundle params) {
        Log.d(getString(R.string.log_label), "Ready for speech");
    }

    @Override
    public void onError(int error) {
        Log.d(getString(R.string.log_label),
                "Error listening for speech: " + error);
    }

    @Override
    public void onBeginningOfSpeech() {
        Log.d(getString(R.string.log_label), "Speech starting");
    }
};
recognizer.setRecognitionListener(listener);
recognizer.startListening(intent);
tnunamak
  • 2,069
  • 3
  • 22
  • 34
  • The software development tag is kind of redundant ;-) That's more for topics talking about the field in general. – SapphireSun Dec 30 '10 at 04:44

6 Answers6

5

Make Sure to use the RECORD_AUDIO permission.

Curtis Shovan
  • 51
  • 1
  • 1
4

From a service, you have to create the recognizer from looper running on the main thread. Also RecognizerIntent.EXTRA_RESULTS should be SpeechRecognizer.RESULTS_RECOGNITION.

psuedo code:

public class VoiceRecognition implements RecognitionListener, Runnable 
{
    @Override
    public void run()
    {
        recognizer = SpeechRecognizer.createSpeechRecognizer(yourContext);
        recognizer.setRecognitionListener((RecognitionListener) this);

         intent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
         //... all the intent stuff ...
         intent.putExtra(RecognizerIntent.EXTRA_MAX_RESULTS, 5);
         recognizer.startListening(intent);
    }
    @Override
    public void onResults(Bundle results)
    {
       ArrayList<String> matches;
       matches=results.getStringArrayList(SpeechRecognizer.RESULTS_RECOGNITION);
    }
 }

....
VoiceRecognition voiceRecognizer = new VoiceRecognition();
Handler loopHandler = new Handler(Looper.getMainLooper());
loopHandler.post(voiceRecognizer);
Matt Cobb
  • 405
  • 5
  • 13
4

You shouldn't need to create the SpeechRecognizer class yourself, nor do you need to implement a RecognizerListener. Google made them public to be nice, but they look pretty complicated and probably for use by experts only.

To get text from the users speech yo simply need to use the RecognizerIntent.ACTION_RECOGNIZE_SPEECH to launch the built-in speech recognizer Activity and then wait for the result to come back in onActivityResult. Take a look at the example code here:

http://developer.android.com/resources/samples/ApiDemos/src/com/example/android/apis/app/VoiceRecognition.html

I pulled it from this article.

http://developer.android.com/resources/articles/speech-input.html

Good Luck.

satur9nine
  • 13,927
  • 5
  • 80
  • 123
  • 1
    That was the road I started down. I went with the SpeechRecognizer approach because I'm running everything behind the scenes in a Service... it didn't seem right to start an Activity if my application didn't have focus (it runs in the background). If it comes down to it I just might have to use an Activity anyway. My application is intended to be used without user interactions on the screen. – tnunamak Jan 03 '11 at 02:23
  • From what I have read so far the Speech Recognition API is just an interface and that the implementation actually lives somewhere else, such as the "Voice Search" application. I believe that it is based on proprietary technology and is not open source. It looks like you are at the mercy of the interface provided. – satur9nine Jan 03 '11 at 05:34
  • That sounds right to me, but I think there is some sort of design flaw in my code because my intent should be handled by the same application/activity that would be used if I were to broadcast my intent with startActivityForResult(). The implementation should affect both techniques equally... I think I'll probably just go with an activity as an alternative solution. – tnunamak Jan 08 '11 at 22:36
1

Instead of getApplicationContext(), use this (i.e. your service instance). android.app.Service inherits from Context.

Al.
  • 2,285
  • 2
  • 22
  • 30
1

Here is the problem I ran into, which might be related to yours. I was getting null, no matter what, from this line:

  ArrayList<String> voiceResults = results                .getStringArrayList(RecognizerIntent.EXTRA_RESULTS);  

Changing it to this completely fixed the problem:

  ArrayList<String> voiceResults = results                .getStringArrayList("results_recognition");  

I printed out the keyset from the bundle, and that was the only value. Note that the value of "results_recognition" is not the value of the string stored at RecognizerIntent.EXTRA_RESULTS. I think that's a bug, or at least it should be, since using RecognizerIntent.EXTRA_RESULTS works fine in the Activity way of doing speech recognition, but not when someone uses SpeechRecognizer.

Anyways, i most likely won't check this website again, but please email me if you have any questions, since I now do have speech recognition working without any prompts, beeps, or anything else.

  • You need this: recognizerIntent.putExtra(RecognizerIntent.EXTRA_CALLING_PACKAGE, "Your.package"); recognizerIntent.putExtra(RecognizerIntent.EXTRA_PARTIAL_RESULTS, true); – gregm Sep 30 '11 at 17:13
  • Use getStringArrayList(SpeechRecognizer.RESULTS_RECOGNITION) instead of the hard coded string – Matt Cobb Jun 12 '15 at 17:39
1

I got this to work by installing the Google Voice App

oopscope
  • 11
  • 1