Offline Speech Recognition In Android (JellyBean)
Asked Answered
I

8

78

It looks as though Google has made offline speech recognition available from Google Now for third-party apps. It is being used by the app named Utter.

Has anyone seen any implementations of how to do simple voice commands with this offline speech rec? Do you just use the regular SpeechRecognizer API and it works automatically?

Ila answered 12/7, 2013 at 14:14 Comment(1)
So as long as we download the language, we dont need to change our code?Mande
S
74

Google did quietly enable offline recognition in that Search update, but there is (as yet) no API or additional parameters available within the SpeechRecognizer class. {See Edit at the bottom of this post} The functionality is available with no additional coding, however the user’s device will need to be configured correctly for it to begin working and this is where the problem lies and I would imagine why a lot of developers assume they are ‘missing something’.

Also, Google have restricted certain Jelly Bean devices from using the offline recognition due to hardware constraints. Which devices this applies to is not documented, in fact, nothing is documented, so configuring the capabilities for the user has proved to be a matter of trial and error (for them). It works for some straight away – For those that it doesn't, this is the ‘guide’ I supply them with.

  1. Make sure the default Android Voice Recogniser is set to Google not Samsung/Vlingo
  2. Uninstall any offline recognition files you already have installed from the Google Voice Search Settings
  3. Go to your Android Application Settings and see if you can uninstall the updates for the Google Search and Google Voice Search applications.
  4. If you can't do the above, go to the Play Store see if you have the option there.
  5. Reboot (if you achieved 2, 3 or 4)
  6. Update Google Search and Google Voice Search from the Play Store (if you achieved 3 or 4 or if an update is available anyway).
  7. Reboot (if you achieved 6)
  8. Install English UK offline language files
  9. Reboot
  10. Use utter! with a connection
  11. Switch to aeroplane mode and give it a try
  12. Once it is working, the offline recognition of other languages, such as English US should start working too.

EDIT: Temporarily changing the device locale to English UK also seems to kickstart this to work for some.

Some users reported they still had to reboot a number of times before it would begin working, but they all get there eventually, often inexplicably to what was the trigger, the key to which are inside the Google Search APK, so not in the public domain or part of AOSP.

From what I can establish, Google tests the availability of a connection prior to deciding whether to use offline or online recognition. If a connection is available initially but is lost prior to the response, Google will supply a connection error, it won’t fall-back to offline. As a side note, if a request for the network synthesised voice has been made, there is no error supplied it if fails – You get silence.

The Google Search update enabled no additional features in Google Now and in fact if you try to use it with no internet connection, it will error. I mention this as I wondered if the ability would be withdrawn as quietly as it appeared and therefore shouldn't be relied upon in production.

If you intend to start using the SpeechRecognizer class, be warned, there is a pretty major bug associated with it, which require your own implementation to handle.

Not being able to specifically request offline = true, makes controlling this feature impossible without manipulating the data connection. Rubbish. You’ll get hundreds of user emails asking you why you haven’t enabled something so simple!

EDIT: Since API level 23 a new parameter has been added EXTRA_PREFER_OFFLINE which the Google recognition service does appear to adhere to.

Hope the above helps.

Severalty answered 16/7, 2013 at 10:52 Comment(6)
This works great for me and it was very easy to implement. I used this sample here as a starting point. jameselsey.co.uk/blogs/techblog/…Ila
@Severalty I wonder whether can I choose the language which I do the recognition? The offline language file support my language (vietnamese) now! I want to create an app which do offline speech recognition FOR my language (vietnamese) ! Is that possible?? Much obliged!Hettiehetty
@truongmn - Does this help? https://mcmap.net/q/266304/-how-to-set-the-language-in-speech-recognition-on-android/1256219 If not, ask a new question and link me to it and I'll see if I can helpSeveralty
On my Samsung Galaxy Grand Prime running Kitkat 4.4, I had to disable the Google Search (and Google+) apps from the Application Manager, then turn on "Restrict background data" (or make sure I had no available connection), then re-enable the Google Search (and Google+) apps (possibly I also had to clear all data for those apps just before disabling them). Whereas when I had tried to turn on "Restrict background data" while those apps were enabled, then the microphone didn't display in the dialer. Apparently re-enabling with no connection (or restricted) forces use of offline.Pickett
Hi help me on this #32866739Cousteau
So as long as we download the language, we dont need to change our code?Mande
T
20

I would like to improve the guide that the answer https://mcmap.net/q/264094/-offline-speech-recognition-in-android-jellybean sends to its users, with images. It is the sentence "For those that it doesn't, this is the ‘guide’ I supply them with." that I want to improve.

The user should click on the four buttons highlighted in blue in these images:

Go to your Android Application Settings, select Languages and input, edit Settings of Google Voice typing, select Download Offline speech recognition, select your languages in the ALL tab.

Then the user can select any desired languages. When the download is done, he should disconnect from network, and then click on the "microphone" button of the keyboard.

It worked for me (android 4.1.2), then language recognition worked out of the box, without rebooting. I can now dictates instructions to the shell of Terminal Emulator ! And it is twice faster offline than online, on a padfone 2 from ASUS.

These images are licensed under cc by-sa 3.0 with attribution required to https://mcmap.net/q/264094/-offline-speech-recognition-in-android-jellybean ; you may hence add these images anywhere along with this attribution.

(This the standard policy of all images and texts at stackoverflow.com)

Tetrapody answered 24/1, 2014 at 10:9 Comment(0)
B
19

A simple and flexible offline recognition on Android is implemented by CMUSphinx, an open source speech recognition toolkit. It works purely offline, fast and configurable It can listen continuously for keyword, for example.

You can find latest code and tutorial here.

Update in 2019: Time goes fast, CMUSphinx is not that accurate anymore. I recommend to try Kaldi toolkit instead. The demo is here.

Bourbon answered 1/9, 2014 at 7:45 Comment(6)
I've just tried demo and it works pretty well. Fast and easy to use.Tuyettv
Hi, does CMUSphinx works for Indian accent english too ?Ephrayim
@Kedarnath it seems it's high on their list, see the poll here: cmusphinx.sourceforge.netIdiom
Thanks, trying it now!Hook
Does it work for Arabic? Do you know any that work for arabic?Basilio
@YoussefSherif Yes, it works for Arabic, contact me for details!Bourbon
P
7

In short, I don't have the implementation, but the explanation.

Google did not make offline speech recognition available to third party apps. Offline recognition is only accessable via the keyboard. Ben Randall (the developer of utter!) explains his workaround in an article at Android Police:

I had implemented my own keyboard and was switching between Google Voice Typing and the users default keyboard with an invisible edit text field and transparent Activity to get the input. Dirty hack!

This was the only way to do it, as offline Voice Typing could only be triggered by an IME or a system application (that was my root hack) . The other type of recognition API … didn't trigger it and just failed with a server error. … A lot of work wasted for me on the workaround! But at least I was ready for the implementation...

From Utter! Claims To Be The First Non-IME App To Utilize Offline Voice Recognition In Jelly Bean

Positively answered 12/7, 2013 at 14:41 Comment(1)
I thought thats what he said he used to do before the latest update. Following your quote: "Randall went on to explain that Utter! now uses SpeechRecognizer, which has been updated allowing developers to use offline recognition in a range of applications, whereas Recognizerintent, the previous offline voice typing code, required a valid IME token."Ila
H
3

I successfully implemented my Speech-Service with offline capabilities by using onPartialResults when offline and onResults when online.

Heda answered 9/6, 2015 at 13:58 Comment(1)
Can i know more about it please. i have post related bug here #32866739Cousteau
D
2

I was dealing with this and I noticed that you need to install the offline package for your Language. My language setting was "Español (Estados Unidos)" but there is not offline package for that language, so when I turned off all network connectivity I was getting an alert from RecognizerIntent saying that can't reach Google, then I change the language to "English (US)" (because I already have the offline package) and launched the RecognizerIntent it just worked out.

Keys: Language setting == Offline Voice Recognizer Package

Davidadavidde answered 8/4, 2014 at 22:55 Comment(1)
Can i know which device you used. Does it support rather than google device. Like samsung, Asus etc. I working on it and offline not support in other device.Cousteau
F
1

It is apparently possible to manually install offline voice recognition by downloading the files directly and installing them in the right locations manually. I guess this is just a way to bypass Google hardware requirements. However, personally I didn't have to reboot or anything, simply changing to UK and back again did it.

Fungosity answered 25/5, 2014 at 2:31 Comment(0)
D
0

Working example is given below,

MyService.class

public class MyService extends Service implements SpeechDelegate, Speech.stopDueToDelay {

  public static SpeechDelegate delegate;

  @Override
  public int onStartCommand(Intent intent, int flags, int startId) {
    //TODO do something useful
    try {
      if (VERSION.SDK_INT >= VERSION_CODES.KITKAT) {
        ((AudioManager) Objects.requireNonNull(
          getSystemService(Context.AUDIO_SERVICE))).setStreamMute(AudioManager.STREAM_SYSTEM, true);
      }
    } catch (Exception e) {
      e.printStackTrace();
    }

    Speech.init(this);
    delegate = this;
    Speech.getInstance().setListener(this);

    if (Speech.getInstance().isListening()) {
      Speech.getInstance().stopListening();
    } else {
      System.setProperty("rx.unsafe-disable", "True");
      RxPermissions.getInstance(this).request(permission.RECORD_AUDIO).subscribe(granted -> {
        if (granted) { // Always true pre-M
          try {
            Speech.getInstance().stopTextToSpeech();
            Speech.getInstance().startListening(null, this);
          } catch (SpeechRecognitionNotAvailable exc) {
            //showSpeechNotSupportedDialog();

          } catch (GoogleVoiceTypingDisabledException exc) {
            //showEnableGoogleVoiceTyping();
          }
        } else {
          Toast.makeText(this, R.string.permission_required, Toast.LENGTH_LONG).show();
        }
      });
    }
    return Service.START_STICKY;
  }

  @Override
  public IBinder onBind(Intent intent) {
    //TODO for communication return IBinder implementation
    return null;
  }

  @Override
  public void onStartOfSpeech() {
  }

  @Override
  public void onSpeechRmsChanged(float value) {

  }

  @Override
  public void onSpeechPartialResults(List<String> results) {
    for (String partial : results) {
      Log.d("Result", partial+"");
    }
  }

  @Override
  public void onSpeechResult(String result) {
    Log.d("Result", result+"");
    if (!TextUtils.isEmpty(result)) {
      Toast.makeText(this, result, Toast.LENGTH_SHORT).show();
    }
  }

  @Override
  public void onSpecifiedCommandPronounced(String event) {
    try {
      if (VERSION.SDK_INT >= VERSION_CODES.KITKAT) {
        ((AudioManager) Objects.requireNonNull(
          getSystemService(Context.AUDIO_SERVICE))).setStreamMute(AudioManager.STREAM_SYSTEM, true);
      }
    } catch (Exception e) {
      e.printStackTrace();
    }
    if (Speech.getInstance().isListening()) {
      Speech.getInstance().stopListening();
    } else {
      RxPermissions.getInstance(this).request(permission.RECORD_AUDIO).subscribe(granted -> {
        if (granted) { // Always true pre-M
          try {
            Speech.getInstance().stopTextToSpeech();
            Speech.getInstance().startListening(null, this);
          } catch (SpeechRecognitionNotAvailable exc) {
            //showSpeechNotSupportedDialog();

          } catch (GoogleVoiceTypingDisabledException exc) {
            //showEnableGoogleVoiceTyping();
          }
        } else {
          Toast.makeText(this, R.string.permission_required, Toast.LENGTH_LONG).show();
        }
      });
    }
  }


  @Override
  public void onTaskRemoved(Intent rootIntent) {
    //Restarting the service if it is removed.
    PendingIntent service =
      PendingIntent.getService(getApplicationContext(), new Random().nextInt(),
        new Intent(getApplicationContext(), MyService.class), PendingIntent.FLAG_ONE_SHOT);

    AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
    assert alarmManager != null;
    alarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, 1000, service);
    super.onTaskRemoved(rootIntent);
  }
}

For more details,

https://github.com/sachinvarma/Speech-Recognizer

Hope this will help someone in future.

Dynode answered 21/6, 2018 at 12:50 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.