diff options
author | Sandeep Siddhartha <sansid@google.com> | 2014-08-01 11:32:03 -0700 |
---|---|---|
committer | Sandeep Siddhartha <sansid@google.com> | 2014-08-01 17:46:27 -0700 |
commit | 2c0273e50a3162595e9a54030166f2369b039a5a (patch) | |
tree | 6075295a33de952b996038ffdf10f22594a1cf4b | |
parent | fc0fc0e341f2a2d707d5a8eafd65db34bdffb35c (diff) | |
download | frameworks_base-2c0273e50a3162595e9a54030166f2369b039a5a.zip frameworks_base-2c0273e50a3162595e9a54030166f2369b039a5a.tar.gz frameworks_base-2c0273e50a3162595e9a54030166f2369b039a5a.tar.bz2 |
Add a flag for multiple triggers with same recognition session
Also annotate the flags with @IntDef to make things clearer and safer
Add more debug logging
Revert to start/stop being synchronous since telephony and microphone will
need to be handled internally.
Bug: 16731586
Bug: 16514535
Bug: 16549061
Change-Id: I83695d52e9547269c95d443e4d921c9238b7401e
5 files changed, 146 insertions, 161 deletions
diff --git a/api/current.txt b/api/current.txt index 031c6b7..851d20f 100644 --- a/api/current.txt +++ b/api/current.txt @@ -27493,11 +27493,12 @@ package android.service.voice { public class AlwaysOnHotwordDetector { method public android.content.Intent getManageIntent(int); method public int getSupportedRecognitionModes(); - method public void startRecognition(int); - method public void stopRecognition(); + method public boolean startRecognition(int); + method public boolean stopRecognition(); field public static final int MANAGE_ACTION_ENROLL = 0; // 0x0 field public static final int MANAGE_ACTION_RE_ENROLL = 1; // 0x1 field public static final int MANAGE_ACTION_UN_ENROLL = 2; // 0x2 + field public static final int RECOGNITION_FLAG_ALLOW_MULTIPLE_TRIGGERS = 2; // 0x2 field public static final int RECOGNITION_FLAG_CAPTURE_TRIGGER_AUDIO = 1; // 0x1 field public static final int RECOGNITION_FLAG_NONE = 0; // 0x0 field public static final int RECOGNITION_MODE_USER_IDENTIFICATION = 2; // 0x2 @@ -27510,12 +27511,15 @@ package android.service.voice { public static abstract interface AlwaysOnHotwordDetector.Callback { method public abstract void onAvailabilityChanged(int); - method public abstract void onDetected(byte[]); - method public abstract void onDetectionStarted(); - method public abstract void onDetectionStopped(); + method public abstract void onDetected(android.service.voice.AlwaysOnHotwordDetector.TriggerAudio); method public abstract void onError(); } + public static class AlwaysOnHotwordDetector.TriggerAudio { + field public final android.media.AudioFormat audioFormat; + field public final byte[] data; + } + public class VoiceInteractionService extends android.app.Service { ctor public VoiceInteractionService(); method public final android.service.voice.AlwaysOnHotwordDetector createAlwaysOnHotwordDetector(java.lang.String, java.lang.String, android.service.voice.AlwaysOnHotwordDetector.Callback); diff --git a/core/java/android/hardware/soundtrigger/SoundTrigger.java b/core/java/android/hardware/soundtrigger/SoundTrigger.java index 4498789..adee740 100644 --- a/core/java/android/hardware/soundtrigger/SoundTrigger.java +++ b/core/java/android/hardware/soundtrigger/SoundTrigger.java @@ -524,6 +524,11 @@ public class SoundTrigger { /** True if the DSP should capture the trigger sound and make it available for further * capture. */ public final boolean captureRequested; + /** + * True if the service should restart listening after the DSP triggers. + * Note: This config flag is currently used at the service layer rather than by the DSP. + */ + public final boolean allowMultipleTriggers; /** List of all keyphrases in the sound model for which recognition should be performed with * options for each keyphrase. */ public final KeyphraseRecognitionExtra keyphrases[]; @@ -531,9 +536,10 @@ public class SoundTrigger { * typically during enrollment. */ public final byte[] data; - public RecognitionConfig(boolean captureRequested, + public RecognitionConfig(boolean captureRequested, boolean allowMultipleTriggers, KeyphraseRecognitionExtra keyphrases[], byte[] data) { this.captureRequested = captureRequested; + this.allowMultipleTriggers = allowMultipleTriggers; this.keyphrases = keyphrases; this.data = data; } @@ -551,15 +557,17 @@ public class SoundTrigger { private static RecognitionConfig fromParcel(Parcel in) { boolean captureRequested = in.readByte() == 1; + boolean allowMultipleTriggers = in.readByte() == 1; KeyphraseRecognitionExtra[] keyphrases = in.createTypedArray(KeyphraseRecognitionExtra.CREATOR); byte[] data = in.readBlob(); - return new RecognitionConfig(captureRequested, keyphrases, data); + return new RecognitionConfig(captureRequested, allowMultipleTriggers, keyphrases, data); } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeByte((byte) (captureRequested ? 1 : 0)); + dest.writeByte((byte) (allowMultipleTriggers ? 1 : 0)); dest.writeTypedArray(keyphrases, flags); dest.writeBlob(data); } @@ -571,9 +579,9 @@ public class SoundTrigger { @Override public String toString() { - return "RecognitionConfig [captureRequested=" + captureRequested + ", keyphrases=" - + Arrays.toString(keyphrases) - + ", data=" + (data == null ? 0 : data.length) + "]"; + return "RecognitionConfig [captureRequested=" + captureRequested + + ", allowMultipleTriggers=" + allowMultipleTriggers + ", keyphrases=" + + Arrays.toString(keyphrases) + ", data=" + Arrays.toString(data) + "]"; } } diff --git a/core/java/android/service/voice/AlwaysOnHotwordDetector.java b/core/java/android/service/voice/AlwaysOnHotwordDetector.java index 5248131..279bf40 100644 --- a/core/java/android/service/voice/AlwaysOnHotwordDetector.java +++ b/core/java/android/service/voice/AlwaysOnHotwordDetector.java @@ -16,6 +16,9 @@ package android.service.voice; +import android.annotation.IntDef; +import android.annotation.NonNull; +import android.annotation.Nullable; import android.content.Intent; import android.hardware.soundtrigger.IRecognitionStatusCallback; import android.hardware.soundtrigger.KeyphraseEnrollmentInfo; @@ -27,6 +30,7 @@ import android.hardware.soundtrigger.SoundTrigger.KeyphraseRecognitionExtra; import android.hardware.soundtrigger.SoundTrigger.KeyphraseSoundModel; import android.hardware.soundtrigger.SoundTrigger.ModuleProperties; import android.hardware.soundtrigger.SoundTrigger.RecognitionConfig; +import android.media.AudioFormat; import android.os.AsyncTask; import android.os.Handler; import android.os.Message; @@ -35,6 +39,9 @@ import android.util.Slog; import com.android.internal.app.IVoiceInteractionManagerService; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + /** * A class that lets a VoiceInteractionService implementation interact with * always-on keyphrase detection APIs. @@ -82,7 +89,17 @@ public class AlwaysOnHotwordDetector { /** Indicates that we need to un-enroll. */ public static final int MANAGE_ACTION_UN_ENROLL = 2; - //-- Flags for startRecogntion ----// + //-- Flags for startRecognition ----// + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(flag = true, + value = { + RECOGNITION_FLAG_NONE, + RECOGNITION_FLAG_CAPTURE_TRIGGER_AUDIO, + RECOGNITION_FLAG_ALLOW_MULTIPLE_TRIGGERS + }) + public @interface RecognitionFlags {} + /** Empty flag for {@link #startRecognition(int)}. */ public static final int RECOGNITION_FLAG_NONE = 0; /** @@ -90,10 +107,28 @@ public class AlwaysOnHotwordDetector { * whether the trigger audio for hotword needs to be captured. */ public static final int RECOGNITION_FLAG_CAPTURE_TRIGGER_AUDIO = 0x1; + /** + * Recognition flag for {@link #startRecognition(int)} that indicates + * whether the recognition should keep going on even after the keyphrase triggers. + * If this flag is specified, it's possible to get multiple triggers after a + * call to {@link #startRecognition(int)} if the user speaks the keyphrase multiple times. + * When this isn't specified, the default behavior is to stop recognition once the + * keyphrase is spoken, till the caller starts recognition again. + */ + public static final int RECOGNITION_FLAG_ALLOW_MULTIPLE_TRIGGERS = 0x2; //---- Recognition mode flags. Return codes for getSupportedRecognitionModes() ----// // Must be kept in sync with the related attribute defined as searchKeyphraseRecognitionFlags. + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(flag = true, + value = { + RECOGNITION_MODE_VOICE_TRIGGER, + RECOGNITION_MODE_USER_IDENTIFICATION, + }) + public @interface RecognitionModes {} + /** * Simple recognition of the key phrase. * Returned by {@link #getSupportedRecognitionModes()} @@ -114,16 +149,9 @@ public class AlwaysOnHotwordDetector { private static final int STATUS_ERROR = SoundTrigger.STATUS_ERROR; private static final int STATUS_OK = SoundTrigger.STATUS_OK; - private static final int MSG_STATE_CHANGED = 1; + private static final int MSG_AVAILABILITY_CHANGED = 1; private static final int MSG_HOTWORD_DETECTED = 2; - private static final int MSG_DETECTION_STARTED = 3; - private static final int MSG_DETECTION_STOPPED = 4; - private static final int MSG_DETECTION_ERROR = 5; - - private static final int FLAG_REQUESTED = 0x1; - private static final int FLAG_STARTED = 0x2; - private static final int FLAG_CALL_ACTIVE = 0x4; - private static final int FLAG_MICROPHONE_OPEN = 0x8; + private static final int MSG_DETECTION_ERROR = 3; private final String mText; private final String mLocale; @@ -141,8 +169,27 @@ public class AlwaysOnHotwordDetector { private final Handler mHandler; private int mAvailability = STATE_NOT_READY; - private int mInternalState = 0; - private int mRecognitionFlags = RECOGNITION_FLAG_NONE; + + /** + * Details of the audio that triggered the keyphrase. + */ + public static class TriggerAudio { + /** + * Format of {@code data}. + */ + @NonNull + public final AudioFormat audioFormat; + /** + * Raw audio data that triggered they keyphrase. + */ + @NonNull + public final byte[] data; + + private TriggerAudio(AudioFormat _audioFormat, byte[] _data) { + audioFormat = _audioFormat; + data = _data; + } + } /** * Callbacks for always-on hotword detection. @@ -168,22 +215,10 @@ public class AlwaysOnHotwordDetector { * Clients should start a recognition again once they are done handling this * detection. * - * @param data Optional trigger audio data, if it was requested during + * @param triggerAudio Optional trigger audio data, if it was requested during * {@link AlwaysOnHotwordDetector#startRecognition(int)}. */ - void onDetected(byte[] data); - /** - * Called when the detection for the associated keyphrase starts. - * This is called as a result of a successful call to - * {@link AlwaysOnHotwordDetector#startRecognition(int)}. - */ - void onDetectionStarted(); - /** - * Called when the detection for the associated keyphrase stops. - * This is called as a result of a successful call to - * {@link AlwaysOnHotwordDetector#stopRecognition()}. - */ - void onDetectionStopped(); + void onDetected(@Nullable TriggerAudio triggerAudio); /** * Called when the detection fails due to an error. */ @@ -228,7 +263,8 @@ public class AlwaysOnHotwordDetector { * This may happen if another detector has been instantiated or the * {@link VoiceInteractionService} hosting this detector has been shut down. */ - public int getSupportedRecognitionModes() { + public @RecognitionModes int getSupportedRecognitionModes() { + if (DBG) Slog.d(TAG, "getSupportedRecognitionModes()"); synchronized (mLock) { return getSupportedRecognitionModesLocked(); } @@ -254,8 +290,10 @@ public class AlwaysOnHotwordDetector { * Starts recognition for the associated keyphrase. * * @param recognitionFlags The flags to control the recognition properties. - * The allowed flags are {@link #RECOGNITION_FLAG_NONE} and - * {@link #RECOGNITION_FLAG_CAPTURE_TRIGGER_AUDIO}. + * The allowed flags are {@link #RECOGNITION_FLAG_NONE}, + * {@link #RECOGNITION_FLAG_CAPTURE_TRIGGER_AUDIO} and + * {@link #RECOGNITION_FLAG_ALLOW_MULTIPLE_TRIGGERS}. + * @return Indicates whether the call succeeded or not. * @throws UnsupportedOperationException if the recognition isn't supported. * Callers should only call this method after a supported state callback on * {@link Callback#onAvailabilityChanged(int)} to avoid this exception. @@ -263,7 +301,8 @@ public class AlwaysOnHotwordDetector { * This may happen if another detector has been instantiated or the * {@link VoiceInteractionService} hosting this detector has been shut down. */ - public void startRecognition(int recognitionFlags) { + public boolean startRecognition(@RecognitionFlags int recognitionFlags) { + if (DBG) Slog.d(TAG, "startRecognition(" + recognitionFlags + ")"); synchronized (mLock) { if (mAvailability == STATE_INVALID) { throw new IllegalStateException("startRecognition called on an invalid detector"); @@ -275,15 +314,14 @@ public class AlwaysOnHotwordDetector { "Recognition for the given keyphrase is not supported"); } - mInternalState |= FLAG_REQUESTED; - mRecognitionFlags = recognitionFlags; - updateRecognitionLocked(); + return startRecognitionLocked(recognitionFlags) == STATUS_OK; } } /** * Stops recognition for the associated keyphrase. * + * @return Indicates whether the call succeeded or not. * @throws UnsupportedOperationException if the recognition isn't supported. * Callers should only call this method after a supported state callback on * {@link Callback#onAvailabilityChanged(int)} to avoid this exception. @@ -291,7 +329,8 @@ public class AlwaysOnHotwordDetector { * This may happen if another detector has been instantiated or the * {@link VoiceInteractionService} hosting this detector has been shut down. */ - public void stopRecognition() { + public boolean stopRecognition() { + if (DBG) Slog.d(TAG, "stopRecognition()"); synchronized (mLock) { if (mAvailability == STATE_INVALID) { throw new IllegalStateException("stopRecognition called on an invalid detector"); @@ -303,9 +342,7 @@ public class AlwaysOnHotwordDetector { "Recognition for the given keyphrase is not supported"); } - mInternalState &= ~FLAG_REQUESTED; - mRecognitionFlags = RECOGNITION_FLAG_NONE; - updateRecognitionLocked(); + return stopRecognitionLocked() == STATUS_OK; } } @@ -324,6 +361,7 @@ public class AlwaysOnHotwordDetector { * {@link VoiceInteractionService} hosting this detector has been shut down. */ public Intent getManageIntent(int action) { + if (DBG) Slog.d(TAG, "getManageIntent(" + action + ")"); synchronized (mLock) { return getManageIntentLocked(action); } @@ -370,7 +408,7 @@ public class AlwaysOnHotwordDetector { */ void onSoundModelsChanged() { synchronized (mLock) { - // TODO: This should stop the recognition if it was using an enrolled sound model + // FIXME: This should stop the recognition if it was using an enrolled sound model // that's no longer available. if (mAvailability == STATE_INVALID || mAvailability == STATE_HARDWARE_UNAVAILABLE @@ -384,87 +422,21 @@ public class AlwaysOnHotwordDetector { } } - @SuppressWarnings("unused") - private void onCallStateChanged(boolean active) { - synchronized (mLock) { - if (active) { - mInternalState |= FLAG_CALL_ACTIVE; - } else { - mInternalState &= ~FLAG_CALL_ACTIVE; - } - - updateRecognitionLocked(); - } - } - - @SuppressWarnings("unused") - private void onMicrophoneStateChanged(boolean open) { - synchronized (mLock) { - if (open) { - mInternalState |= FLAG_MICROPHONE_OPEN; - } else { - mInternalState &= ~FLAG_MICROPHONE_OPEN; - } - - updateRecognitionLocked(); - } - } - - private void updateRecognitionLocked() { - // Don't attempt to update the recognition state if keyphrase isn't enrolled. - if (mAvailability != STATE_KEYPHRASE_ENROLLED) { - return; - } - - // Start recognition if requested and not in a call/reading from the microphone - boolean start = (mInternalState&FLAG_REQUESTED) != 0 - && (mInternalState&FLAG_CALL_ACTIVE) == 0 - && (mInternalState&FLAG_MICROPHONE_OPEN) == 0; - boolean requested = (mInternalState&FLAG_REQUESTED) != 0; - - if (start && (mInternalState&FLAG_STARTED) == 0) { - // Start recognition. - if (DBG) Slog.d(TAG, "starting recognition..."); - int status = startRecognitionLocked(); - if (status == STATUS_OK) { - mHandler.sendEmptyMessage(MSG_DETECTION_STARTED); - } else { - if (DBG) Slog.d(TAG, "failed to start recognition: " + status); - mHandler.sendEmptyMessage(MSG_DETECTION_ERROR); - } - // Post the callback - return; - } - - if (!start && (mInternalState&FLAG_STARTED) != 0) { - // Stop recognition - // Only notify the callback if a recognition was *not* requested. - // For internal stoppages, don't notify the callback. - if (DBG) Slog.d(TAG, "stopping recognition..."); - int status = stopRecognitionLocked(); - if (status == STATUS_OK) { - if (!requested) mHandler.sendEmptyMessage(MSG_DETECTION_STOPPED); - } else { - if (!requested) mHandler.sendEmptyMessage(MSG_DETECTION_ERROR); - if (DBG) Slog.d(TAG, "failed to stop recognition: " + status); - } - return; - } - } - - private int startRecognitionLocked() { + private int startRecognitionLocked(int recognitionFlags) { KeyphraseRecognitionExtra[] recognitionExtra = new KeyphraseRecognitionExtra[1]; // TODO: Do we need to do something about the confidence level here? recognitionExtra[0] = new KeyphraseRecognitionExtra(mKeyphraseMetadata.id, mKeyphraseMetadata.recognitionModeFlags, new ConfidenceLevel[0]); boolean captureTriggerAudio = - (mRecognitionFlags&RECOGNITION_FLAG_CAPTURE_TRIGGER_AUDIO) != 0; + (recognitionFlags&RECOGNITION_FLAG_CAPTURE_TRIGGER_AUDIO) != 0; + boolean allowMultipleTriggers = + (recognitionFlags&RECOGNITION_FLAG_ALLOW_MULTIPLE_TRIGGERS) != 0; int code = STATUS_ERROR; try { code = mModelManagementService.startRecognition(mVoiceInteractionService, mKeyphraseMetadata.id, mInternalCallback, - new RecognitionConfig( - captureTriggerAudio, recognitionExtra, null /* additional data */)); + new RecognitionConfig(captureTriggerAudio, allowMultipleTriggers, + recognitionExtra, null /* additional data */)); } catch (RemoteException e) { Slog.w(TAG, "RemoteException in startRecognition!"); } @@ -490,7 +462,7 @@ public class AlwaysOnHotwordDetector { } private void notifyStateChangedLocked() { - Message message = Message.obtain(mHandler, MSG_STATE_CHANGED); + Message message = Message.obtain(mHandler, MSG_AVAILABILITY_CHANGED); message.arg1 = mAvailability; message.sendToTarget(); } @@ -505,9 +477,22 @@ public class AlwaysOnHotwordDetector { @Override public void onDetected(KeyphraseRecognitionEvent event) { - Slog.i(TAG, "onDetected"); + if (DBG) { + Slog.d(TAG, "OnDetected(" + event + ")"); + } else { + Slog.i(TAG, "onDetected"); + } Message message = Message.obtain(mHandler, MSG_HOTWORD_DETECTED); - message.obj = event.data; + // FIXME: Check whether the event contains trigger data or not. + // FIXME: Read the audio format from the event. + if (event.data != null) { + AudioFormat audioFormat = new AudioFormat.Builder() + .setChannelMask(AudioFormat.CHANNEL_IN_MONO) + .setEncoding(AudioFormat.ENCODING_PCM_16BIT) + .setSampleRate(16000) + .build(); + message.obj = new TriggerAudio(audioFormat, event.data); + } message.sendToTarget(); } @@ -529,34 +514,13 @@ public class AlwaysOnHotwordDetector { } switch (msg.what) { - case MSG_STATE_CHANGED: + case MSG_AVAILABILITY_CHANGED: mExternalCallback.onAvailabilityChanged(msg.arg1); break; case MSG_HOTWORD_DETECTED: - synchronized (mLock) { - mInternalState &= ~FLAG_REQUESTED; - mInternalState &= ~FLAG_STARTED; - } - mExternalCallback.onDetected((byte[]) msg.obj); - break; - case MSG_DETECTION_STARTED: - synchronized (mLock) { - mInternalState |= FLAG_STARTED; - } - mExternalCallback.onDetectionStarted(); - break; - case MSG_DETECTION_STOPPED: - synchronized (mLock) { - mInternalState &= ~FLAG_REQUESTED; - mInternalState &= ~FLAG_STARTED; - } - mExternalCallback.onDetectionStopped(); + mExternalCallback.onDetected((TriggerAudio) msg.obj); break; case MSG_DETECTION_ERROR: - synchronized (mLock) { - mInternalState &= ~FLAG_REQUESTED; - mInternalState &= ~FLAG_STARTED; - } mExternalCallback.onError(); break; default: diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/SoundTriggerHelper.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/SoundTriggerHelper.java index 0eac1c4..938efaa 100644 --- a/services/voiceinteraction/java/com/android/server/voiceinteraction/SoundTriggerHelper.java +++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/SoundTriggerHelper.java @@ -65,6 +65,8 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener { private int mCurrentSoundModelHandle = INVALID_SOUND_MODEL_HANDLE; private UUID mCurrentSoundModelUuid = null; + // FIXME: Ideally this should not be stored if allowMultipleTriggers happens at a lower layer. + private RecognitionConfig mRecognitionConfig = null; SoundTriggerHelper() { ArrayList <ModuleProperties> modules = new ArrayList<>(); @@ -174,6 +176,7 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener { // Everything went well! mCurrentSoundModelHandle = soundModelHandle; mCurrentSoundModelUuid = soundModel.uuid; + mRecognitionConfig = recognitionConfig; // Register the new listener. This replaces the old one. // There can only be a maximum of one active listener for a keyphrase // at any given time. @@ -221,12 +224,12 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener { int status = mModule.stopRecognition(mCurrentSoundModelHandle); if (status != SoundTrigger.STATUS_OK) { Slog.w(TAG, "stopRecognition call failed with " + status); - return STATUS_ERROR; + return status; } status = mModule.unloadSoundModel(mCurrentSoundModelHandle); if (status != SoundTrigger.STATUS_OK) { Slog.w(TAG, "unloadSoundModel call failed with " + status); - return STATUS_ERROR; + return status; } mCurrentSoundModelHandle = INVALID_SOUND_MODEL_HANDLE; @@ -284,6 +287,17 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener { Slog.w(TAG, "received onRecognition event without any listener for it"); return; } + + // FIXME: Remove this block if the lower layer supports multiple triggers. + if (mRecognitionConfig != null + && mRecognitionConfig.allowMultipleTriggers) { + int status = mModule.startRecognition( + mCurrentSoundModelHandle, mRecognitionConfig); + if (status != STATUS_OK) { + Slog.w(TAG, "Error in restarting recognition after a trigger"); + listener.onError(status); + } + } } } catch (RemoteException e) { Slog.w(TAG, "RemoteException in onDetectionStopped"); diff --git a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionService.java b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionService.java index b43ad6f..02610f8 100644 --- a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionService.java +++ b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionService.java @@ -20,6 +20,7 @@ import android.content.Intent; import android.os.Bundle; import android.service.voice.AlwaysOnHotwordDetector; import android.service.voice.AlwaysOnHotwordDetector.Callback; +import android.service.voice.AlwaysOnHotwordDetector.TriggerAudio; import android.service.voice.VoiceInteractionService; import android.util.Log; @@ -36,21 +37,11 @@ public class MainInteractionService extends VoiceInteractionService { } @Override - public void onDetected(byte[] data) { + public void onDetected(TriggerAudio triggerAudio) { Log.i(TAG, "onDetected"); } @Override - public void onDetectionStarted() { - Log.i(TAG, "onDetectionStarted"); - } - - @Override - public void onDetectionStopped() { - Log.i(TAG, "onDetectionStopped"); - } - - @Override public void onError() { Log.i(TAG, "onError"); } @@ -95,8 +86,12 @@ public class MainInteractionService extends VoiceInteractionService { break; case AlwaysOnHotwordDetector.STATE_KEYPHRASE_ENROLLED: Log.i(TAG, "STATE_KEYPHRASE_ENROLLED - starting recognition"); - mHotwordDetector.startRecognition( - AlwaysOnHotwordDetector.RECOGNITION_FLAG_NONE); + if (mHotwordDetector.startRecognition( + AlwaysOnHotwordDetector.RECOGNITION_FLAG_NONE)) { + Log.i(TAG, "startRecognition succeeded"); + } else { + Log.i(TAG, "startRecognition failed"); + } break; } } |