diff options
author | Eric Laurent <elaurent@google.com> | 2014-04-18 17:44:11 -0700 |
---|---|---|
committer | Eric Laurent <elaurent@google.com> | 2014-06-04 17:58:56 -0700 |
commit | e48188ce35f613f64b513e5d8ce24fada1212d8e (patch) | |
tree | a0e4e8a4d17215511edbb81adfa5812f9f2e085d /core/java/android/hardware | |
parent | f3bbf2b80167faa0091ad31511405283792408a9 (diff) | |
download | frameworks_base-e48188ce35f613f64b513e5d8ce24fada1212d8e.zip frameworks_base-e48188ce35f613f64b513e5d8ce24fada1212d8e.tar.gz frameworks_base-e48188ce35f613f64b513e5d8ce24fada1212d8e.tar.bz2 |
Add SoundTrigger native service interface
Add JAVA framework interface for native sound trigger service.
The interface allows for:
- enumeration of sound trigger hardware modules and their properties
- load/unload sound models
- start, stop and receive recognition events on sound models.
Change-Id: I51542f38f5359ffbbf79d2cbd7c9ea1ee10c9c18
Diffstat (limited to 'core/java/android/hardware')
-rw-r--r-- | core/java/android/hardware/soundtrigger/SoundTrigger.java | 310 | ||||
-rw-r--r-- | core/java/android/hardware/soundtrigger/SoundTriggerModule.java | 192 |
2 files changed, 502 insertions, 0 deletions
diff --git a/core/java/android/hardware/soundtrigger/SoundTrigger.java b/core/java/android/hardware/soundtrigger/SoundTrigger.java new file mode 100644 index 0000000..2d7af85 --- /dev/null +++ b/core/java/android/hardware/soundtrigger/SoundTrigger.java @@ -0,0 +1,310 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * 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. + */ + +package android.hardware.soundtrigger; + +import android.content.Context; +import android.content.Intent; +import android.os.Handler; + +import java.util.ArrayList; +import java.util.UUID; + +/** + * The SoundTrigger class provides access via JNI to the native service managing + * the sound trigger HAL. + * + * @hide + */ +public class SoundTrigger { + + public static final int STATUS_OK = 0; + public static final int STATUS_ERROR = Integer.MIN_VALUE; + public static final int STATUS_PERMISSION_DENIED = -1; + public static final int STATUS_NO_INIT = -19; + public static final int STATUS_BAD_VALUE = -22; + public static final int STATUS_DEAD_OBJECT = -32; + public static final int STATUS_INVALID_OPERATION = -38; + + /***************************************************************************** + * A ModuleProperties describes a given sound trigger hardware module + * managed by the native sound trigger service. Each module has a unique + * ID used to target any API call to this paricular module. Module + * properties are returned by listModules() method. + ****************************************************************************/ + public static class ModuleProperties { + /** Unique module ID provided by the native service */ + public final int id; + + /** human readable voice detection engine implementor */ + public final String implementor; + + /** human readable voice detection engine description */ + public final String description; + + /** Unique voice engine Id (changes with each version) */ + public final UUID uuid; + + /** Voice detection engine version */ + public final int version; + + /** Maximum number of active sound models */ + public final int maxSoundModels; + + /** Maximum number of key phrases */ + public final int maxKeyPhrases; + + /** Maximum number of users per key phrase */ + public final int maxUsers; + + /** Supported recognition modes (bit field, RECOGNITION_MODE_VOICE_TRIGGER ...) */ + public final int recognitionModes; + + /** Supports seamless transition to capture mode after recognition */ + public final boolean supportsCaptureTransition; + + /** Maximum buffering capacity in ms if supportsCaptureTransition() is true */ + public final int maxBufferMs; + + /** Supports capture by other use cases while detection is active */ + public final boolean supportsConcurrentCapture; + + /** Rated power consumption when detection is active with TDB silence/sound/speech ratio */ + public final int powerConsumptionMw; + + ModuleProperties(int id, String implementor, String description, + String uuid, int version, int maxSoundModels, int maxKeyPhrases, + int maxUsers, int recognitionModes, boolean supportsCaptureTransition, + int maxBufferMs, boolean supportsConcurrentCapture, + int powerConsumptionMw) { + this.id = id; + this.implementor = implementor; + this.description = description; + this.uuid = UUID.fromString(uuid); + this.version = version; + this.maxSoundModels = maxSoundModels; + this.maxKeyPhrases = maxKeyPhrases; + this.maxUsers = maxUsers; + this.recognitionModes = recognitionModes; + this.supportsCaptureTransition = supportsCaptureTransition; + this.maxBufferMs = maxBufferMs; + this.supportsConcurrentCapture = supportsConcurrentCapture; + this.powerConsumptionMw = powerConsumptionMw; + } + } + + /***************************************************************************** + * A SoundModel describes the attributes and contains the binary data used by the hardware + * implementation to detect a particular sound pattern. + * A specialized version {@link KeyPhraseSoundModel} is defined for key phrase + * sound models. + ****************************************************************************/ + public static class SoundModel { + /** Undefined sound model type */ + public static final int TYPE_UNKNOWN = -1; + + /** Keyphrase sound model */ + public static final int TYPE_KEYPHRASE = 0; + + /** Sound model type (e.g. TYPE_KEYPHRASE); */ + public final int type; + + /** Opaque data. For use by vendor implementation and enrollment application */ + public final byte[] data; + + public SoundModel(int type, byte[] data) { + this.type = type; + this.data = data; + } + } + + /***************************************************************************** + * A KeyPhrase describes a key phrase that can be detected by a + * {@link KeyPhraseSoundModel} + ****************************************************************************/ + public static class KeyPhrase { + /** Recognition modes supported for this key phrase in the model */ + public final int recognitionModes; + + /** Locale of the keyphrase. JAVA Locale string e.g en_US */ + public final String locale; + + /** Key phrase text */ + public final String text; + + /** Number of users this key phrase has been trained for */ + public final int numUsers; + + public KeyPhrase(int recognitionModes, String locale, String text, int numUsers) { + this.recognitionModes = recognitionModes; + this.locale = locale; + this.text = text; + this.numUsers = numUsers; + } + } + + /***************************************************************************** + * A KeyPhraseSoundModel is a specialized {@link SoundModel} for key phrases. + * It contains data needed by the hardware to detect a certain number of key phrases + * and the list of corresponding {@link KeyPhrase} descriptors. + ****************************************************************************/ + public static class KeyPhraseSoundModel extends SoundModel { + /** Key phrases in this sound model */ + public final KeyPhrase[] keyPhrases; // keyword phrases in model + + public KeyPhraseSoundModel(byte[] data, KeyPhrase[] keyPhrases) { + super(TYPE_KEYPHRASE, data); + this.keyPhrases = keyPhrases; + } + } + + /** + * Modes for key phrase recognition + */ + /** Simple recognition of the key phrase */ + public static final int RECOGNITION_MODE_VOICE_TRIGGER = 0x1; + /** Trigger only if one user is identified */ + public static final int RECOGNITION_MODE_USER_IDENTIFICATION = 0x2; + /** Trigger only if one user is authenticated */ + public static final int RECOGNITION_MODE_USER_AUTHENTICATION = 0x4; + + /** + * Status codes for {@link RecognitionEvent} + */ + /** Recognition success */ + public static final int RECOGNITION_STATUS_SUCCESS = 0; + /** Recognition aborted (e.g. capture preempted by anotehr use case */ + public static final int RECOGNITION_STATUS_ABORT = 1; + /** Recognition failure */ + public static final int RECOGNITION_STATUS_FAILURE = 2; + + /** + * A RecognitionEvent is provided by the + * {@link StatusListener#onRecognition(RecognitionEvent)} + * callback upon recognition success or failure. + */ + public static class RecognitionEvent { + /** Recognition status e.g {@link #RECOGNITION_STATUS_SUCCESS} */ + public final int status; + /** Sound Model corresponding to this event callback */ + public final int soundModelHandle; + /** True if it is possible to capture audio from this utterance buffered by the hardware */ + public final boolean captureAvailable; + /** Audio session ID to be used when capturing the utterance with an AudioRecord + * if captureAvailable() is true. */ + public final int captureSession; + /** Delay in ms between end of model detection and start of audio available for capture. + * A negative value is possible (e.g. if keyphrase is also available for capture) */ + public final int captureDelayMs; + /** Opaque data for use by system applications who know about voice engine internals, + * typically during enrollment. */ + public final byte[] data; + + RecognitionEvent(int status, int soundModelHandle, boolean captureAvailable, + int captureSession, int captureDelayMs, byte[] data) { + this.status = status; + this.soundModelHandle = soundModelHandle; + this.captureAvailable = captureAvailable; + this.captureSession = captureSession; + this.captureDelayMs = captureDelayMs; + this.data = data; + } + } + + /** + * Additional data conveyed by a {@link KeyPhraseRecognitionEvent} + * for a key phrase detection. + */ + public static class KeyPhraseRecognitionExtra { + /** Confidence level for each user defined in the key phrase in the same order as + * users in the key phrase. The confidence level is expressed in percentage (0% -100%) */ + public final int[] confidenceLevels; + + /** Recognition modes matched for this event */ + public final int recognitionModes; + + KeyPhraseRecognitionExtra(int[] confidenceLevels, int recognitionModes) { + this.confidenceLevels = confidenceLevels; + this.recognitionModes = recognitionModes; + } + } + + /** + * Specialized {@link RecognitionEvent} for a key phrase detection. + */ + public static class KeyPhraseRecognitionEvent extends RecognitionEvent { + /** Indicates if the key phrase is present in the buffered audio available for capture */ + public final KeyPhraseRecognitionExtra[] keyPhraseExtras; + + /** Additional data available for each recognized key phrases in the model */ + public final boolean keyPhraseInCapture; + + KeyPhraseRecognitionEvent(int status, int soundModelHandle, boolean captureAvailable, + int captureSession, int captureDelayMs, byte[] data, + boolean keyPhraseInCapture, KeyPhraseRecognitionExtra[] keyPhraseExtras) { + super(status, soundModelHandle, captureAvailable, captureSession, captureDelayMs, data); + this.keyPhraseInCapture = keyPhraseInCapture; + this.keyPhraseExtras = keyPhraseExtras; + } + } + + /** + * Returns a list of descriptors for all harware modules loaded. + * @param modules A ModuleProperties array where the list will be returned. + * @return - {@link #STATUS_OK} in case of success + * - {@link #STATUS_ERROR} in case of unspecified error + * - {@link #STATUS_PERMISSION_DENIED} if the caller does not have system permission + * - {@link #STATUS_NO_INIT} if the native service cannot be reached + * - {@link #STATUS_BAD_VALUE} if modules is null + * - {@link #STATUS_DEAD_OBJECT} if the binder transaction to the native service fails + */ + public static native int listModules(ArrayList <ModuleProperties> modules); + + /** + * Get an interface on a hardware module to control sound models and recognition on + * this module. + * @param moduleId Sound module system identifier {@link ModuleProperties#id}. mandatory. + * @param listener {@link StatusListener} interface. Mandatory. + * @param handler the Handler that will receive the callabcks. Can be null if default handler + * is OK. + * @return a valid sound module in case of success or null in case of error. + */ + public static SoundTriggerModule attachModule(int moduleId, + StatusListener listener, + Handler handler) { + if (listener == null) { + return null; + } + SoundTriggerModule module = new SoundTriggerModule(moduleId, listener, handler); + return module; + } + + /** + * Interface provided by the client application when attaching to a {@link SoundTriggerModule} + * to received recognition and error notifications. + */ + public static interface StatusListener { + /** + * Called when recognition succeeds of fails + */ + public abstract void onRecognition(RecognitionEvent event); + + /** + * Called when the sound trigger native service dies + */ + public abstract void onServiceDied(); + } +} diff --git a/core/java/android/hardware/soundtrigger/SoundTriggerModule.java b/core/java/android/hardware/soundtrigger/SoundTriggerModule.java new file mode 100644 index 0000000..776f85d --- /dev/null +++ b/core/java/android/hardware/soundtrigger/SoundTriggerModule.java @@ -0,0 +1,192 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * 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. + */ + +package android.hardware.soundtrigger; + +import android.content.Context; +import android.content.Intent; +import android.os.Handler; +import android.os.Looper; +import android.os.Message; +import java.lang.ref.WeakReference; +import java.util.UUID; + +/** + * The SoundTriggerModule provides APIs to control sound models and sound detection + * on a given sound trigger hardware module. + * + * @hide + */ +public class SoundTriggerModule { + private long mNativeContext; + + private int mId; + private NativeEventHandlerDelegate mEventHandlerDelegate; + + private static final int EVENT_RECOGNITION = 1; + private static final int EVENT_SERVICE_DIED = 2; + + SoundTriggerModule(int moduleId, SoundTrigger.StatusListener listener, Handler handler) { + mId = moduleId; + mEventHandlerDelegate = new NativeEventHandlerDelegate(listener, handler); + native_setup(new WeakReference<SoundTriggerModule>(this)); + } + private native void native_setup(Object module_this); + + @Override + protected void finalize() { + native_finalize(); + } + private native void native_finalize(); + + /** + * Detach from this module. The {@link SoundTrigger.StatusListener} callback will not be called + * anymore and associated resources will be released. + * */ + public native void detach(); + + /** + * Load a {@link SoundTrigger.SoundModel} to the hardware. A sound model must be loaded in + * order to start listening to a key phrase in this model. + * @param model The sound model to load. + * @param soundModelHandle an array of int where the sound model handle will be returned. + * @return - {@link SoundTrigger#STATUS_OK} in case of success + * - {@link SoundTrigger#STATUS_ERROR} in case of unspecified error + * - {@link SoundTrigger#STATUS_PERMISSION_DENIED} if the caller does not have + * system permission + * - {@link SoundTrigger#STATUS_NO_INIT} if the native service cannot be reached + * - {@link SoundTrigger#STATUS_BAD_VALUE} if parameters are invalid + * - {@link SoundTrigger#STATUS_DEAD_OBJECT} if the binder transaction to the native + * service fails + * - {@link SoundTrigger#STATUS_INVALID_OPERATION} if the call is out of sequence + */ + public native int loadSoundModel(SoundTrigger.SoundModel model, int[] soundModelHandle); + + /** + * Unload a {@link SoundTrigger.SoundModel} and abort any pendiong recognition + * @param soundModelHandle The sound model handle + * @return - {@link SoundTrigger#STATUS_OK} in case of success + * - {@link SoundTrigger#STATUS_ERROR} in case of unspecified error + * - {@link SoundTrigger#STATUS_PERMISSION_DENIED} if the caller does not have + * system permission + * - {@link SoundTrigger#STATUS_NO_INIT} if the native service cannot be reached + * - {@link SoundTrigger#STATUS_BAD_VALUE} if the sound model handle is invalid + * - {@link SoundTrigger#STATUS_DEAD_OBJECT} if the binder transaction to the native + * service fails + */ + public native int unloadSoundModel(int soundModelHandle); + + /** + * Start listening to all key phrases in a {@link SoundTrigger.SoundModel}. + * Recognition must be restarted after each callback (success or failure) received on + * the {@link SoundTrigger.StatusListener}. + * @param soundModelHandle The sound model handle to start listening to + * @param data Opaque data for use by the implementation for this recognition + * @return - {@link SoundTrigger#STATUS_OK} in case of success + * - {@link SoundTrigger#STATUS_ERROR} in case of unspecified error + * - {@link SoundTrigger#STATUS_PERMISSION_DENIED} if the caller does not have + * system permission + * - {@link SoundTrigger#STATUS_NO_INIT} if the native service cannot be reached + * - {@link SoundTrigger#STATUS_BAD_VALUE} if the sound model handle is invalid + * - {@link SoundTrigger#STATUS_DEAD_OBJECT} if the binder transaction to the native + * service fails + * - {@link SoundTrigger#STATUS_INVALID_OPERATION} if the call is out of sequence + */ + public native int startRecognition(int soundModelHandle, byte[] data); + + /** + * Stop listening to all key phrases in a {@link SoundTrigger.SoundModel} + * @param soundModelHandle The sound model handle to stop listening to + * @return - {@link SoundTrigger#STATUS_OK} in case of success + * - {@link SoundTrigger#STATUS_ERROR} in case of unspecified error + * - {@link SoundTrigger#STATUS_PERMISSION_DENIED} if the caller does not have + * system permission + * - {@link SoundTrigger#STATUS_NO_INIT} if the native service cannot be reached + * - {@link SoundTrigger#STATUS_BAD_VALUE} if the sound model handle is invalid + * - {@link SoundTrigger#STATUS_DEAD_OBJECT} if the binder transaction to the native + * service fails + * - {@link SoundTrigger#STATUS_INVALID_OPERATION} if the call is out of sequence + */ + public native int stopRecognition(int soundModelHandle); + + private class NativeEventHandlerDelegate { + private final Handler mHandler; + + NativeEventHandlerDelegate(final SoundTrigger.StatusListener listener, + Handler handler) { + // find the looper for our new event handler + Looper looper; + if (handler != null) { + looper = handler.getLooper(); + } else { + looper = Looper.myLooper(); + if (looper == null) { + looper = Looper.getMainLooper(); + } + } + + // construct the event handler with this looper + if (looper != null) { + // implement the event handler delegate + mHandler = new Handler(looper) { + @Override + public void handleMessage(Message msg) { + switch(msg.what) { + case EVENT_RECOGNITION: + if (listener != null) { + listener.onRecognition( + (SoundTrigger.RecognitionEvent)msg.obj); + } + break; + case EVENT_SERVICE_DIED: + if (listener != null) { + listener.onServiceDied(); + } + break; + default: + break; + } + } + }; + } else { + mHandler = null; + } + } + + Handler handler() { + return mHandler; + } + } + + @SuppressWarnings("unused") + private static void postEventFromNative(Object module_ref, + int what, int arg1, int arg2, Object obj) { + SoundTriggerModule module = (SoundTriggerModule)((WeakReference)module_ref).get(); + if (module == null) { + return; + } + + NativeEventHandlerDelegate delegate = module.mEventHandlerDelegate; + if (delegate != null) { + Handler handler = delegate.handler(); + if (handler != null) { + Message m = handler.obtainMessage(what, arg1, arg2, obj); + handler.sendMessage(m); + } + } + } +} + |