Reconnaissance vocale Android en tant que service sur Android 4.1 & 4.2
j'ai réussi à obtenir la reconnaissance vocale continue de travail (en utilisant la classe SpeechRecognizer) comme un service sur toutes les versions Android jusqu'à 4.1. Ma question concerne le fait de le faire fonctionner sur les versions 4.1 et 4.2 comme on le sait, il y a un problème dans le fait que l'API ne fonctionne pas comme prévu, quelques secondes après le début de la reconnaissance vocale, si aucune entrée vocale n'a été détectée, alors c'est comme si l'appareil de reconnaissance vocale meurt silencieusement. ( http://code.google.com/p/android/issues/detail?id=37883 )
j'ai trouvé une question qui propose une solution de rechange à ce problème ( la reconnaissance vocale cesse d'écouter après quelques secondes ), mais je ne sais pas comment mettre en œuvre le Gestionnaire requis pour cette solution. Je suis conscient du " bip " qui se produira toutes les quelques secondes que cette solution provoquera, mais obtenir une reconnaissance vocale continue est plus important pour moi.
si quelqu'un a d'autres solutions de rechange, j'aimerais les entendre aussi.
4 réponses
il s'agit d'un work-around pour android version 4.1.1.
public class MyService extends Service
{
protected AudioManager mAudioManager;
protected SpeechRecognizer mSpeechRecognizer;
protected Intent mSpeechRecognizerIntent;
protected final Messenger mServerMessenger = new Messenger(new IncomingHandler(this));
protected boolean mIsListening;
protected volatile boolean mIsCountDownOn;
private boolean mIsStreamSolo;
static final int MSG_RECOGNIZER_START_LISTENING = 1;
static final int MSG_RECOGNIZER_CANCEL = 2;
@Override
public void onCreate()
{
super.onCreate();
mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
mSpeechRecognizer = SpeechRecognizer.createSpeechRecognizer(this);
mSpeechRecognizer.setRecognitionListener(new SpeechRecognitionListener());
mSpeechRecognizerIntent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
mSpeechRecognizerIntent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL,
RecognizerIntent.LANGUAGE_MODEL_FREE_FORM);
mSpeechRecognizerIntent.putExtra(RecognizerIntent.EXTRA_CALLING_PACKAGE,
this.getPackageName());
}
protected static class IncomingHandler extends Handler
{
private WeakReference<MyService> mtarget;
IncomingHandler(MyService target)
{
mtarget = new WeakReference<MyService>(target);
}
@Override
public void handleMessage(Message msg)
{
final MyService target = mtarget.get();
switch (msg.what)
{
case MSG_RECOGNIZER_START_LISTENING:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN)
{
// turn off beep sound
if (!mIsStreamSolo)
{
mAudioManager.setStreamSolo(AudioManager.STREAM_VOICE_CALL, true);
mIsStreamSolo = true;
}
}
if (!target.mIsListening)
{
target.mSpeechRecognizer.startListening(target.mSpeechRecognizerIntent);
target.mIsListening = true;
//Log.d(TAG, "message start listening"); //$NON-NLS-1$
}
break;
case MSG_RECOGNIZER_CANCEL:
if (mIsStreamSolo)
{
mAudioManager.setStreamSolo(AudioManager.STREAM_VOICE_CALL, false);
mIsStreamSolo = false;
}
target.mSpeechRecognizer.cancel();
target.mIsListening = false;
//Log.d(TAG, "message canceled recognizer"); //$NON-NLS-1$
break;
}
}
}
// Count down timer for Jelly Bean work around
protected CountDownTimer mNoSpeechCountDown = new CountDownTimer(5000, 5000)
{
@Override
public void onTick(long millisUntilFinished)
{
// TODO Auto-generated method stub
}
@Override
public void onFinish()
{
mIsCountDownOn = false;
Message message = Message.obtain(null, MSG_RECOGNIZER_CANCEL);
try
{
mServerMessenger.send(message);
message = Message.obtain(null, MSG_RECOGNIZER_START_LISTENING);
mServerMessenger.send(message);
}
catch (RemoteException e)
{
}
}
};
@Override
public void onDestroy()
{
super.onDestroy();
if (mIsCountDownOn)
{
mNoSpeechCountDown.cancel();
}
if (mSpeechRecognizer != null)
{
mSpeechRecognizer.destroy();
}
}
protected class SpeechRecognitionListener implements RecognitionListener
{
@Override
public void onBeginningOfSpeech()
{
// speech input will be processed, so there is no need for count down anymore
if (mIsCountDownOn)
{
mIsCountDownOn = false;
mNoSpeechCountDown.cancel();
}
//Log.d(TAG, "onBeginingOfSpeech"); //$NON-NLS-1$
}
@Override
public void onBufferReceived(byte[] buffer)
{
}
@Override
public void onEndOfSpeech()
{
//Log.d(TAG, "onEndOfSpeech"); //$NON-NLS-1$
}
@Override
public void onError(int error)
{
if (mIsCountDownOn)
{
mIsCountDownOn = false;
mNoSpeechCountDown.cancel();
}
mIsListening = false;
Message message = Message.obtain(null, MSG_RECOGNIZER_START_LISTENING);
try
{
mServerMessenger.send(message);
}
catch (RemoteException e)
{
}
//Log.d(TAG, "error = " + error); //$NON-NLS-1$
}
@Override
public void onEvent(int eventType, Bundle params)
{
}
@Override
public void onPartialResults(Bundle partialResults)
{
}
@Override
public void onReadyForSpeech(Bundle params)
{
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN)
{
mIsCountDownOn = true;
mNoSpeechCountDown.start();
}
Log.d(TAG, "onReadyForSpeech"); //$NON-NLS-1$
}
@Override
public void onResults(Bundle results)
{
//Log.d(TAG, "onResults"); //$NON-NLS-1$
}
@Override
public void onRmsChanged(float rmsdB)
{
}
}
}
02/16/2013 - Fix beep sound si vous utilisez du texte pour parler dans votre application, assurez-vous d'éteindre le flux Solo en onResults
si vous voulez vraiment mettre en œuvre l'écoute continue sans connexion internet, vous devez considérer les paquets tiers, L'un d'eux est CMUSphinx, cochez Pocketsphinx android demo par exemple comment écouter pour mot-clé efficacement dans offline et réagir sur les commandes spécifiques comme une phrase clé"oh mighty computer". Le code pour faire cela est simple:
vous créez un recognizer et il suffit d'ajouter le mot-clé spotting recherche:
recognizer = defaultSetup()
.setAcousticModel(new File(modelsDir, "hmm/en-us-semi"))
.setDictionary(new File(modelsDir, "lm/cmu07a.dic"))
.setKeywordThreshold(1e-5f)
.getRecognizer();
recognizer.addListener(this);
recognizer.addKeywordSearch(KWS_SEARCH_NAME, KEYPHRASE);
switchSearch(KWS_SEARCH_NAME);
et définir un auditeur:
@Override
public void onPartialResult(Hypothesis hypothesis) {
String text = hypothesis.getHypstr();
if (text.equals(KEYPHRASE))
// do something
}
pour tous ceux d'entre vous qui tentent de réduire au silence le son du bip, en reformulant la réponse de @HoanNguyen qui est très bonne, mais attention comme dit dans le jeu d'api setStreamSolo est cumulative donc s'il y a une erreur dans la reconnaissance vocale et sur l'erreur est appelé(par exemple pas de connexion internet) alors setStremSolo true est appelé encore et encore ce qui se traduira par votre application réduire au silence le téléphone entier (très mauvais)! la solution à cela est d'ajouter le setStremMute (false) au speechRecognizer onError.
Découvrez mon application de démonstration : https://github.com/galrom/ContinuesVoiceRecognition
je recommande D'utiliser PockeySphix et SpeechRecognizer.