diff options
8 files changed, 462 insertions, 72 deletions
diff --git a/core/java/android/hardware/soundtrigger/SoundTrigger.java b/core/java/android/hardware/soundtrigger/SoundTrigger.java index adee740..7a49eb5 100644 --- a/core/java/android/hardware/soundtrigger/SoundTrigger.java +++ b/core/java/android/hardware/soundtrigger/SoundTrigger.java @@ -16,6 +16,7 @@ package android.hardware.soundtrigger; +import android.media.AudioFormat; import android.os.Handler; import android.os.Parcel; import android.os.Parcelable; @@ -86,11 +87,15 @@ public class SoundTrigger { /** Rated power consumption when detection is active with TDB silence/sound/speech ratio */ public final int powerConsumptionMw; + /** Returns the trigger (key phrase) capture in the binary data of the + * recognition callback event */ + public final boolean returnsTriggerInEvent; + 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) { + int powerConsumptionMw, boolean returnsTriggerInEvent) { this.id = id; this.implementor = implementor; this.description = description; @@ -104,6 +109,7 @@ public class SoundTrigger { this.maxBufferMs = maxBufferMs; this.supportsConcurrentCapture = supportsConcurrentCapture; this.powerConsumptionMw = powerConsumptionMw; + this.returnsTriggerInEvent = returnsTriggerInEvent; } public static final Parcelable.Creator<ModuleProperties> CREATOR @@ -131,10 +137,11 @@ public class SoundTrigger { int maxBufferMs = in.readInt(); boolean supportsConcurrentCapture = in.readByte() == 1; int powerConsumptionMw = in.readInt(); + boolean returnsTriggerInEvent = in.readByte() == 1; return new ModuleProperties(id, implementor, description, uuid, version, maxSoundModels, maxKeyphrases, maxUsers, recognitionModes, supportsCaptureTransition, maxBufferMs, supportsConcurrentCapture, - powerConsumptionMw); + powerConsumptionMw, returnsTriggerInEvent); } @Override @@ -152,6 +159,7 @@ public class SoundTrigger { dest.writeInt(maxBufferMs); dest.writeByte((byte) (supportsConcurrentCapture ? 1 : 0)); dest.writeInt(powerConsumptionMw); + dest.writeByte((byte) (returnsTriggerInEvent ? 1 : 0)); } @Override @@ -167,7 +175,8 @@ public class SoundTrigger { + maxUsers + ", recognitionModes=" + recognitionModes + ", supportsCaptureTransition=" + supportsCaptureTransition + ", maxBufferMs=" + maxBufferMs + ", supportsConcurrentCapture=" + supportsConcurrentCapture - + ", powerConsumptionMw=" + powerConsumptionMw + "]"; + + ", powerConsumptionMw=" + powerConsumptionMw + + ", returnsTriggerInEvent=" + returnsTriggerInEvent + "]"; } } @@ -190,11 +199,15 @@ public class SoundTrigger { /** Sound model type (e.g. TYPE_KEYPHRASE); */ public final int type; + /** Unique sound model vendor identifier */ + public final UUID vendorUuid; + /** Opaque data. For use by vendor implementation and enrollment application */ public final byte[] data; - public SoundModel(UUID uuid, int type, byte[] data) { + public SoundModel(UUID uuid, UUID vendorUuid, int type, byte[] data) { this.uuid = uuid; + this.vendorUuid = vendorUuid; this.type = type; this.data = data; } @@ -329,8 +342,9 @@ public class SoundTrigger { /** Key phrases in this sound model */ public final Keyphrase[] keyphrases; // keyword phrases in model - public KeyphraseSoundModel(UUID id, byte[] data, Keyphrase[] keyphrases) { - super(id, TYPE_KEYPHRASE, data); + public KeyphraseSoundModel( + UUID uuid, UUID vendorUuid, byte[] data, Keyphrase[] keyphrases) { + super(uuid, vendorUuid, TYPE_KEYPHRASE, data); this.keyphrases = keyphrases; } @@ -347,9 +361,14 @@ public class SoundTrigger { private static KeyphraseSoundModel fromParcel(Parcel in) { UUID uuid = UUID.fromString(in.readString()); + UUID vendorUuid = null; + int length = in.readInt(); + if (length >= 0) { + vendorUuid = UUID.fromString(in.readString()); + } byte[] data = in.readBlob(); Keyphrase[] keyphrases = in.createTypedArray(Keyphrase.CREATOR); - return new KeyphraseSoundModel(uuid, data, keyphrases); + return new KeyphraseSoundModel(uuid, vendorUuid, data, keyphrases); } @Override @@ -360,14 +379,21 @@ public class SoundTrigger { @Override public void writeToParcel(Parcel dest, int flags) { dest.writeString(uuid.toString()); + if (vendorUuid == null) { + dest.writeInt(-1); + } else { + dest.writeInt(vendorUuid.toString().length()); + dest.writeString(vendorUuid.toString()); + } dest.writeBlob(data); dest.writeTypedArray(keyphrases, flags); } @Override public String toString() { - return "KeyphraseSoundModel [keyphrases=" + Arrays.toString(keyphrases) + ", uuid=" - + uuid + ", type=" + type + ", data=" + (data == null ? 0 : data.length) + "]"; + return "KeyphraseSoundModel [keyphrases=" + Arrays.toString(keyphrases) + + ", uuid=" + uuid + ", vendorUuid=" + vendorUuid + + ", type=" + type + ", data=" + (data == null ? 0 : data.length) + "]"; } } @@ -411,18 +437,26 @@ public class SoundTrigger { public final int captureDelayMs; /** Duration in ms of audio captured before the start of the trigger. 0 if none. */ public final int capturePreambleMs; + /** True if the trigger (key phrase capture is present in binary data */ + public final boolean triggerInData; + /** Audio format of either the trigger in event data or to use for capture of the + * rest of the utterance */ + public AudioFormat captureFormat; /** Opaque data for use by system applications who know about voice engine internals, * typically during enrollment. */ public final byte[] data; public RecognitionEvent(int status, int soundModelHandle, boolean captureAvailable, - int captureSession, int captureDelayMs, int capturePreambleMs, byte[] data) { + int captureSession, int captureDelayMs, int capturePreambleMs, + boolean triggerInData, AudioFormat captureFormat, byte[] data) { this.status = status; this.soundModelHandle = soundModelHandle; this.captureAvailable = captureAvailable; this.captureSession = captureSession; this.captureDelayMs = captureDelayMs; this.capturePreambleMs = capturePreambleMs; + this.triggerInData = triggerInData; + this.captureFormat = captureFormat; this.data = data; } @@ -444,9 +478,21 @@ public class SoundTrigger { int captureSession = in.readInt(); int captureDelayMs = in.readInt(); int capturePreambleMs = in.readInt(); + boolean triggerInData = in.readByte() == 1; + AudioFormat captureFormat = null; + if (triggerInData) { + int sampleRate = in.readInt(); + int encoding = in.readInt(); + int channelMask = in.readInt(); + captureFormat = (new AudioFormat.Builder()) + .setChannelMask(channelMask) + .setEncoding(encoding) + .setSampleRate(sampleRate) + .build(); + } byte[] data = in.readBlob(); return new RecognitionEvent(status, soundModelHandle, captureAvailable, captureSession, - captureDelayMs, capturePreambleMs, data); + captureDelayMs, capturePreambleMs, triggerInData, captureFormat, data); } @Override @@ -462,6 +508,14 @@ public class SoundTrigger { dest.writeInt(captureSession); dest.writeInt(captureDelayMs); dest.writeInt(capturePreambleMs); + if (triggerInData && (captureFormat != null)) { + dest.writeByte((byte)1); + dest.writeInt(captureFormat.getSampleRate()); + dest.writeInt(captureFormat.getEncoding()); + dest.writeInt(captureFormat.getChannelMask()); + } else { + dest.writeByte((byte)0); + } dest.writeBlob(data); } @@ -473,6 +527,12 @@ public class SoundTrigger { result = prime * result + captureDelayMs; result = prime * result + capturePreambleMs; result = prime * result + captureSession; + result = prime * result + (triggerInData ? 1231 : 1237); + if (captureFormat != null) { + result = prime * result + captureFormat.getSampleRate(); + result = prime * result + captureFormat.getEncoding(); + result = prime * result + captureFormat.getChannelMask(); + } result = prime * result + Arrays.hashCode(data); result = prime * result + soundModelHandle; result = prime * result + status; @@ -502,6 +562,14 @@ public class SoundTrigger { return false; if (status != other.status) return false; + if (triggerInData != other.triggerInData) + return false; + if (captureFormat.getSampleRate() != other.captureFormat.getSampleRate()) + return false; + if (captureFormat.getEncoding() != other.captureFormat.getEncoding()) + return false; + if (captureFormat.getChannelMask() != other.captureFormat.getChannelMask()) + return false; return true; } @@ -511,6 +579,13 @@ public class SoundTrigger { + ", captureAvailable=" + captureAvailable + ", captureSession=" + captureSession + ", captureDelayMs=" + captureDelayMs + ", capturePreambleMs=" + capturePreambleMs + + ", triggerInData=" + triggerInData + + ((captureFormat == null) ? "" : + (", sampleRate=" + captureFormat.getSampleRate())) + + ((captureFormat == null) ? "" : + (", encoding=" + captureFormat.getEncoding())) + + ((captureFormat == null) ? "" : + (", channelMask=" + captureFormat.getChannelMask())) + ", data=" + (data == null ? 0 : data.length) + "]"; } } @@ -673,14 +748,19 @@ public class SoundTrigger { /** Recognition modes matched for this event */ public final int recognitionModes; + /** Confidence level for mode RECOGNITION_MODE_VOICE_TRIGGER when user identification + * is not performed */ + public final int coarseConfidenceLevel; + /** Confidence levels for all users recognized (KeyphraseRecognitionEvent) or to * be recognized (RecognitionConfig) */ public final ConfidenceLevel[] confidenceLevels; - public KeyphraseRecognitionExtra(int id, int recognitionModes, - ConfidenceLevel[] confidenceLevels) { + public KeyphraseRecognitionExtra(int id, int recognitionModes, int coarseConfidenceLevel, + ConfidenceLevel[] confidenceLevels) { this.id = id; this.recognitionModes = recognitionModes; + this.coarseConfidenceLevel = coarseConfidenceLevel; this.confidenceLevels = confidenceLevels; } @@ -698,14 +778,17 @@ public class SoundTrigger { private static KeyphraseRecognitionExtra fromParcel(Parcel in) { int id = in.readInt(); int recognitionModes = in.readInt(); + int coarseConfidenceLevel = in.readInt(); ConfidenceLevel[] confidenceLevels = in.createTypedArray(ConfidenceLevel.CREATOR); - return new KeyphraseRecognitionExtra(id, recognitionModes, confidenceLevels); + return new KeyphraseRecognitionExtra(id, recognitionModes, coarseConfidenceLevel, + confidenceLevels); } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeInt(id); dest.writeInt(recognitionModes); + dest.writeInt(coarseConfidenceLevel); dest.writeTypedArray(confidenceLevels, flags); } @@ -721,6 +804,7 @@ public class SoundTrigger { result = prime * result + Arrays.hashCode(confidenceLevels); result = prime * result + id; result = prime * result + recognitionModes; + result = prime * result + coarseConfidenceLevel; return result; } @@ -739,12 +823,15 @@ public class SoundTrigger { return false; if (recognitionModes != other.recognitionModes) return false; + if (coarseConfidenceLevel != other.coarseConfidenceLevel) + return false; return true; } @Override public String toString() { return "KeyphraseRecognitionExtra [id=" + id + ", recognitionModes=" + recognitionModes + + ", coarseConfidenceLevel=" + coarseConfidenceLevel + ", confidenceLevels=" + Arrays.toString(confidenceLevels) + "]"; } } @@ -756,15 +843,12 @@ public class SoundTrigger { /** 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; - public KeyphraseRecognitionEvent(int status, int soundModelHandle, boolean captureAvailable, - int captureSession, int captureDelayMs, int capturePreambleMs, byte[] data, - boolean keyphraseInCapture, KeyphraseRecognitionExtra[] keyphraseExtras) { + int captureSession, int captureDelayMs, int capturePreambleMs, + boolean triggerInData, AudioFormat captureFormat, byte[] data, + KeyphraseRecognitionExtra[] keyphraseExtras) { super(status, soundModelHandle, captureAvailable, captureSession, captureDelayMs, - capturePreambleMs, data); - this.keyphraseInCapture = keyphraseInCapture; + capturePreambleMs, triggerInData, captureFormat, data); this.keyphraseExtras = keyphraseExtras; } @@ -786,13 +870,24 @@ public class SoundTrigger { int captureSession = in.readInt(); int captureDelayMs = in.readInt(); int capturePreambleMs = in.readInt(); + boolean triggerInData = in.readByte() == 1; + AudioFormat captureFormat = null; + if (triggerInData) { + int sampleRate = in.readInt(); + int encoding = in.readInt(); + int channelMask = in.readInt(); + captureFormat = (new AudioFormat.Builder()) + .setChannelMask(channelMask) + .setEncoding(encoding) + .setSampleRate(sampleRate) + .build(); + } byte[] data = in.readBlob(); - boolean keyphraseInCapture = in.readByte() == 1; KeyphraseRecognitionExtra[] keyphraseExtras = in.createTypedArray(KeyphraseRecognitionExtra.CREATOR); return new KeyphraseRecognitionEvent(status, soundModelHandle, captureAvailable, - captureSession, captureDelayMs, capturePreambleMs, data, keyphraseInCapture, - keyphraseExtras); + captureSession, captureDelayMs, capturePreambleMs, triggerInData, + captureFormat, data, keyphraseExtras); } @Override @@ -803,8 +898,15 @@ public class SoundTrigger { dest.writeInt(captureSession); dest.writeInt(captureDelayMs); dest.writeInt(capturePreambleMs); + if (triggerInData && (captureFormat != null)) { + dest.writeByte((byte)1); + dest.writeInt(captureFormat.getSampleRate()); + dest.writeInt(captureFormat.getEncoding()); + dest.writeInt(captureFormat.getChannelMask()); + } else { + dest.writeByte((byte)0); + } dest.writeBlob(data); - dest.writeByte((byte) (keyphraseInCapture ? 1 : 0)); dest.writeTypedArray(keyphraseExtras, flags); } @@ -818,7 +920,6 @@ public class SoundTrigger { final int prime = 31; int result = super.hashCode(); result = prime * result + Arrays.hashCode(keyphraseExtras); - result = prime * result + (keyphraseInCapture ? 1231 : 1237); return result; } @@ -833,23 +934,127 @@ public class SoundTrigger { KeyphraseRecognitionEvent other = (KeyphraseRecognitionEvent) obj; if (!Arrays.equals(keyphraseExtras, other.keyphraseExtras)) return false; - if (keyphraseInCapture != other.keyphraseInCapture) - return false; return true; } @Override public String toString() { return "KeyphraseRecognitionEvent [keyphraseExtras=" + Arrays.toString(keyphraseExtras) - + ", keyphraseInCapture=" + keyphraseInCapture + ", status=" + status + + ", status=" + status + ", soundModelHandle=" + soundModelHandle + ", captureAvailable=" + captureAvailable + ", captureSession=" + captureSession + ", captureDelayMs=" + captureDelayMs + ", capturePreambleMs=" + capturePreambleMs + + ", triggerInData=" + triggerInData + + ((captureFormat == null) ? "" : + (", sampleRate=" + captureFormat.getSampleRate())) + + ((captureFormat == null) ? "" : + (", encoding=" + captureFormat.getEncoding())) + + ((captureFormat == null) ? "" : + (", channelMask=" + captureFormat.getChannelMask())) + ", data=" + (data == null ? 0 : data.length) + "]"; } } /** + * Status codes for {@link SoundModelEvent} + */ + /** Sound Model was updated */ + public static final int SOUNDMODEL_STATUS_UPDATED = 0; + + /** + * A SoundModelEvent is provided by the + * {@link StatusListener#onSoundModelUpdate(SoundModelEvent)} + * callback when a sound model has been updated by the implementation + */ + public static class SoundModelEvent implements Parcelable { + /** Status e.g {@link #SOUNDMODEL_STATUS_UPDATED} */ + public final int status; + /** The updated sound model handle */ + public final int soundModelHandle; + /** New sound model data */ + public final byte[] data; + + SoundModelEvent(int status, int soundModelHandle, byte[] data) { + this.status = status; + this.soundModelHandle = soundModelHandle; + this.data = data; + } + + public static final Parcelable.Creator<SoundModelEvent> CREATOR + = new Parcelable.Creator<SoundModelEvent>() { + public SoundModelEvent createFromParcel(Parcel in) { + return SoundModelEvent.fromParcel(in); + } + + public SoundModelEvent[] newArray(int size) { + return new SoundModelEvent[size]; + } + }; + + private static SoundModelEvent fromParcel(Parcel in) { + int status = in.readInt(); + int soundModelHandle = in.readInt(); + byte[] data = in.readBlob(); + return new SoundModelEvent(status, soundModelHandle, data); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(status); + dest.writeInt(soundModelHandle); + dest.writeBlob(data); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + Arrays.hashCode(data); + result = prime * result + soundModelHandle; + result = prime * result + status; + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + SoundModelEvent other = (SoundModelEvent) obj; + if (!Arrays.equals(data, other.data)) + return false; + if (soundModelHandle != other.soundModelHandle) + return false; + if (status != other.status) + return false; + return true; + } + + @Override + public String toString() { + return "SoundModelEvent [status=" + status + ", soundModelHandle=" + soundModelHandle + + ", data=" + (data == null ? 0 : data.length) + "]"; + } + } + + /** + * Native service state. {@link StatusListener#onServiceStateChange(int)} + */ + // Keep in sync with system/core/include/system/sound_trigger.h + /** Sound trigger service is enabled */ + public static final int SERVICE_STATE_ENABLED = 0; + /** Sound trigger service is disabled */ + public static final int SERVICE_STATE_DISABLED = 1; + + /** * 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 @@ -891,6 +1096,18 @@ public class SoundTrigger { public abstract void onRecognition(RecognitionEvent event); /** + * Called when a sound model has been updated + */ + public abstract void onSoundModelUpdate(SoundModelEvent event); + + /** + * Called when the sound trigger native service state changes. + * @param state Native service state. One of {@link SoundTrigger#SERVICE_STATE_ENABLED}, + * {@link SoundTrigger#SERVICE_STATE_DISABLED} + */ + public abstract void onServiceStateChange(int state); + + /** * 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 index 4a54fd8..1a8723d 100644 --- a/core/java/android/hardware/soundtrigger/SoundTriggerModule.java +++ b/core/java/android/hardware/soundtrigger/SoundTriggerModule.java @@ -36,8 +36,11 @@ public class SoundTriggerModule { private int mId; private NativeEventHandlerDelegate mEventHandlerDelegate; + // to be kept in sync with core/jni/android_hardware_SoundTrigger.cpp private static final int EVENT_RECOGNITION = 1; private static final int EVENT_SERVICE_DIED = 2; + private static final int EVENT_SOUNDMODEL = 3; + private static final int EVENT_SERVICE_STATE_CHANGE = 4; SoundTriggerModule(int moduleId, SoundTrigger.StatusListener listener, Handler handler) { mId = moduleId; @@ -133,10 +136,7 @@ public class SoundTriggerModule { if (handler != null) { looper = handler.getLooper(); } else { - looper = Looper.myLooper(); - if (looper == null) { - looper = Looper.getMainLooper(); - } + looper = Looper.getMainLooper(); } // construct the event handler with this looper @@ -152,6 +152,17 @@ public class SoundTriggerModule { (SoundTrigger.RecognitionEvent)msg.obj); } break; + case EVENT_SOUNDMODEL: + if (listener != null) { + listener.onSoundModelUpdate( + (SoundTrigger.SoundModelEvent)msg.obj); + } + break; + case EVENT_SERVICE_STATE_CHANGE: + if (listener != null) { + listener.onServiceStateChange(msg.arg1); + } + break; case EVENT_SERVICE_DIED: if (listener != null) { listener.onServiceDied(); diff --git a/core/java/android/service/voice/AlwaysOnHotwordDetector.java b/core/java/android/service/voice/AlwaysOnHotwordDetector.java index 279bf40..b9fce85 100644 --- a/core/java/android/service/voice/AlwaysOnHotwordDetector.java +++ b/core/java/android/service/voice/AlwaysOnHotwordDetector.java @@ -426,7 +426,7 @@ public class AlwaysOnHotwordDetector { 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]); + mKeyphraseMetadata.recognitionModeFlags, 0, new ConfidenceLevel[0]); boolean captureTriggerAudio = (recognitionFlags&RECOGNITION_FLAG_CAPTURE_TRIGGER_AUDIO) != 0; boolean allowMultipleTriggers = diff --git a/core/jni/android_hardware_SoundTrigger.cpp b/core/jni/android_hardware_SoundTrigger.cpp index c9a0b1e..f0d7a35 100644 --- a/core/jni/android_hardware_SoundTrigger.cpp +++ b/core/jni/android_hardware_SoundTrigger.cpp @@ -29,6 +29,7 @@ #include <utils/Vector.h> #include <binder/IMemory.h> #include <binder/MemoryDealer.h> +#include "android_media_AudioFormat.h" using namespace android; @@ -63,6 +64,7 @@ static const char* const kSoundModelClassPathName = static jclass gSoundModelClass; static struct { jfieldID uuid; + jfieldID vendorUuid; jfieldID data; } gSoundModelFields; @@ -110,6 +112,7 @@ static jmethodID gKeyphraseRecognitionExtraCstor; static struct { jfieldID id; jfieldID recognitionModes; + jfieldID coarseConfidenceLevel; jfieldID confidenceLevels; } gKeyphraseRecognitionExtraFields; @@ -122,6 +125,16 @@ static struct { jfieldID confidenceLevel; } gConfidenceLevelFields; +static const char* const kAudioFormatClassPathName = + "android/media/AudioFormat"; +static jclass gAudioFormatClass; +static jmethodID gAudioFormatCstor; + +static const char* const kSoundModelEventClassPathName = + "android/hardware/soundtrigger/SoundTrigger$SoundModelEvent"; +static jclass gSoundModelEventClass; +static jmethodID gSoundModelEventCstor; + static Mutex gLock; enum { @@ -137,6 +150,8 @@ enum { enum { SOUNDTRIGGER_EVENT_RECOGNITION = 1, SOUNDTRIGGER_EVENT_SERVICE_DIED = 2, + SOUNDTRIGGER_EVENT_SOUNDMODEL = 3, + SOUNDTRIGGER_EVENT_SERVICE_STATE_CHANGE = 4, }; // ---------------------------------------------------------------------------- @@ -148,6 +163,8 @@ public: ~JNISoundTriggerCallback(); virtual void onRecognitionEvent(struct sound_trigger_recognition_event *event); + virtual void onSoundModelEvent(struct sound_trigger_model_event *event); + virtual void onServiceStateChange(sound_trigger_service_state_t state); virtual void onServiceDied(); private: @@ -183,10 +200,9 @@ JNISoundTriggerCallback::~JNISoundTriggerCallback() void JNISoundTriggerCallback::onRecognitionEvent(struct sound_trigger_recognition_event *event) { JNIEnv *env = AndroidRuntime::getJNIEnv(); - - jobject jEvent; - + jobject jEvent = NULL; jbyteArray jData = NULL; + if (event->data_size) { jData = env->NewByteArray(event->data_size); jbyte *nData = env->GetByteArrayElements(jData, NULL); @@ -194,6 +210,15 @@ void JNISoundTriggerCallback::onRecognitionEvent(struct sound_trigger_recognitio env->ReleaseByteArrayElements(jData, nData, 0); } + jobject jAudioFormat = NULL; + if (event->trigger_in_data) { + jAudioFormat = env->NewObject(gAudioFormatClass, + gAudioFormatCstor, + audioFormatFromNative(event->audio_config.format), + event->audio_config.sample_rate, + inChannelMaskFromNative(event->audio_config.channel_mask)); + + } if (event->type == SOUND_MODEL_TYPE_KEYPHRASE) { struct sound_trigger_phrase_recognition_event *phraseEvent = (struct sound_trigger_phrase_recognition_event *)event; @@ -225,6 +250,7 @@ void JNISoundTriggerCallback::onRecognitionEvent(struct sound_trigger_recognitio gKeyphraseRecognitionExtraCstor, phraseEvent->phrase_extras[i].id, phraseEvent->phrase_extras[i].recognition_modes, + phraseEvent->phrase_extras[i].confidence_level, jConfidenceLevels); if (jNewExtra == NULL) { @@ -236,19 +262,63 @@ void JNISoundTriggerCallback::onRecognitionEvent(struct sound_trigger_recognitio } jEvent = env->NewObject(gKeyphraseRecognitionEventClass, gKeyphraseRecognitionEventCstor, event->status, event->model, event->capture_available, - event->capture_session, event->capture_delay_ms, - event->capture_preamble_ms, jData, - phraseEvent->key_phrase_in_capture, jExtras); + event->capture_session, event->capture_delay_ms, + event->capture_preamble_ms, event->trigger_in_data, + jAudioFormat, jData, jExtras); + env->DeleteLocalRef(jAudioFormat); + env->DeleteLocalRef(jData); } else { jEvent = env->NewObject(gRecognitionEventClass, gRecognitionEventCstor, event->status, event->model, event->capture_available, event->capture_session, event->capture_delay_ms, - event->capture_preamble_ms, jData); + event->capture_preamble_ms, event->trigger_in_data, + jAudioFormat, jData); + env->DeleteLocalRef(jAudioFormat); + env->DeleteLocalRef(jData); } env->CallStaticVoidMethod(mClass, gPostEventFromNative, mObject, SOUNDTRIGGER_EVENT_RECOGNITION, 0, 0, jEvent); + + env->DeleteLocalRef(jEvent); + if (env->ExceptionCheck()) { + ALOGW("An exception occurred while notifying an event."); + env->ExceptionClear(); + } +} + +void JNISoundTriggerCallback::onSoundModelEvent(struct sound_trigger_model_event *event) +{ + JNIEnv *env = AndroidRuntime::getJNIEnv(); + jobject jEvent = NULL; + jbyteArray jData = NULL; + + if (event->data_size) { + jData = env->NewByteArray(event->data_size); + jbyte *nData = env->GetByteArrayElements(jData, NULL); + memcpy(nData, (char *)event + event->data_offset, event->data_size); + env->ReleaseByteArrayElements(jData, nData, 0); + } + + jEvent = env->NewObject(gSoundModelEventClass, gSoundModelEventCstor, + event->status, event->model, jData); + + env->DeleteLocalRef(jData); + env->CallStaticVoidMethod(mClass, gPostEventFromNative, mObject, + SOUNDTRIGGER_EVENT_SOUNDMODEL, 0, 0, jEvent); + env->DeleteLocalRef(jEvent); + if (env->ExceptionCheck()) { + ALOGW("An exception occurred while notifying an event."); + env->ExceptionClear(); + } +} + +void JNISoundTriggerCallback::onServiceStateChange(sound_trigger_service_state_t state) +{ + JNIEnv *env = AndroidRuntime::getJNIEnv(); + env->CallStaticVoidMethod(mClass, gPostEventFromNative, mObject, + SOUNDTRIGGER_EVENT_SERVICE_STATE_CHANGE, state, 0, NULL); if (env->ExceptionCheck()) { ALOGW("An exception occurred while notifying an event."); env->ExceptionClear(); @@ -336,7 +406,7 @@ android_hardware_SoundTrigger_listModules(JNIEnv *env, jobject clazz, SOUND_TRIGGER_MAX_STRING_LEN); jstring uuid = env->NewStringUTF(str); - ALOGV("listModules module %d id %d description %s maxSoundModels %d", + ALOGV("listModules module %zu id %d description %s maxSoundModels %d", i, nModules[i].handle, nModules[i].properties.description, nModules[i].properties.max_sound_models); @@ -351,7 +421,8 @@ android_hardware_SoundTrigger_listModules(JNIEnv *env, jobject clazz, nModules[i].properties.capture_transition, nModules[i].properties.max_buffer_ms, nModules[i].properties.concurrent_capture, - nModules[i].properties.power_consumption_mw); + nModules[i].properties.power_consumption_mw, + nModules[i].properties.trigger_in_event); env->DeleteLocalRef(implementor); env->DeleteLocalRef(description); @@ -463,6 +534,18 @@ android_hardware_SoundTrigger_loadSoundModel(JNIEnv *env, jobject thiz, env->ReleaseStringUTFChars(jUuidString, nUuidString); env->DeleteLocalRef(jUuidString); + sound_trigger_uuid_t nVendorUuid; + jUuid = env->GetObjectField(jSoundModel, gSoundModelFields.vendorUuid); + if (jUuid != NULL) { + jUuidString = (jstring)env->CallObjectMethod(jUuid, gUUIDMethods.toString); + nUuidString = env->GetStringUTFChars(jUuidString, NULL); + SoundTrigger::stringToGuid(nUuidString, &nVendorUuid); + env->ReleaseStringUTFChars(jUuidString, nUuidString); + env->DeleteLocalRef(jUuidString); + } else { + SoundTrigger::stringToGuid("00000000-0000-0000-0000-000000000000", &nVendorUuid); + } + jData = (jbyteArray)env->GetObjectField(jSoundModel, gSoundModelFields.data); if (jData == NULL) { status = SOUNDTRIGGER_STATUS_BAD_VALUE; @@ -491,6 +574,7 @@ android_hardware_SoundTrigger_loadSoundModel(JNIEnv *env, jobject thiz, nSoundModel->type = type; nSoundModel->uuid = nUuid; + nSoundModel->vendor_uuid = nVendorUuid; nSoundModel->data_size = size; nSoundModel->data_offset = offset; memcpy((char *)nSoundModel + offset, nData, size); @@ -507,7 +591,7 @@ android_hardware_SoundTrigger_loadSoundModel(JNIEnv *env, jobject thiz, size_t numPhrases = env->GetArrayLength(jPhrases); phraseModel->num_phrases = numPhrases; - ALOGV("loadSoundModel numPhrases %d", numPhrases); + ALOGV("loadSoundModel numPhrases %zu", numPhrases); for (size_t i = 0; i < numPhrases; i++) { jobject jPhrase = env->GetObjectArrayElement(jPhrases, i); phraseModel->phrases[i].id = @@ -539,7 +623,7 @@ android_hardware_SoundTrigger_loadSoundModel(JNIEnv *env, jobject thiz, env->DeleteLocalRef(jLocale); env->ReleaseStringUTFChars(jText, nText); env->DeleteLocalRef(jText); - ALOGV("loadSoundModel phrases %d text %s locale %s", + ALOGV("loadSoundModel phrases %zu text %s locale %s", i, phraseModel->phrases[i].text, phraseModel->phrases[i].locale); env->DeleteLocalRef(jPhrase); } @@ -640,13 +724,15 @@ android_hardware_SoundTrigger_startRecognition(JNIEnv *env, jobject thiz, gKeyphraseRecognitionExtraFields.id); config->phrases[i].recognition_modes = env->GetIntField(jPhrase, gKeyphraseRecognitionExtraFields.recognitionModes); + config->phrases[i].confidence_level = env->GetIntField(jPhrase, + gKeyphraseRecognitionExtraFields.coarseConfidenceLevel); config->phrases[i].num_levels = 0; jobjectArray jConfidenceLevels = (jobjectArray)env->GetObjectField(jPhrase, gKeyphraseRecognitionExtraFields.confidenceLevels); if (jConfidenceLevels != NULL) { config->phrases[i].num_levels = env->GetArrayLength(jConfidenceLevels); } - ALOGV("startRecognition phrase %d num_levels %d", i, config->phrases[i].num_levels); + ALOGV("startRecognition phrase %zu num_levels %d", i, config->phrases[i].num_levels); for (size_t j = 0; j < config->phrases[i].num_levels; j++) { jobject jConfidenceLevel = env->GetObjectArrayElement(jConfidenceLevels, j); config->phrases[i].levels[j].user_id = env->GetIntField(jConfidenceLevel, @@ -655,7 +741,7 @@ android_hardware_SoundTrigger_startRecognition(JNIEnv *env, jobject thiz, gConfidenceLevelFields.confidenceLevel); env->DeleteLocalRef(jConfidenceLevel); } - ALOGV("startRecognition phrases %d", i); + ALOGV("startRecognition phrases %zu", i); env->DeleteLocalRef(jConfidenceLevels); env->DeleteLocalRef(jPhrase); } @@ -734,11 +820,12 @@ int register_android_hardware_SoundTrigger(JNIEnv *env) jclass modulePropertiesClass = env->FindClass(kModulePropertiesClassPathName); gModulePropertiesClass = (jclass) env->NewGlobalRef(modulePropertiesClass); gModulePropertiesCstor = env->GetMethodID(modulePropertiesClass, "<init>", - "(ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;IIIIIZIZI)V"); + "(ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;IIIIIZIZIZ)V"); jclass soundModelClass = env->FindClass(kSoundModelClassPathName); gSoundModelClass = (jclass) env->NewGlobalRef(soundModelClass); gSoundModelFields.uuid = env->GetFieldID(soundModelClass, "uuid", "Ljava/util/UUID;"); + gSoundModelFields.vendorUuid = env->GetFieldID(soundModelClass, "vendorUuid", "Ljava/util/UUID;"); gSoundModelFields.data = env->GetFieldID(soundModelClass, "data", "[B"); jclass keyphraseClass = env->FindClass(kKeyphraseClassPathName); @@ -759,12 +846,12 @@ int register_android_hardware_SoundTrigger(JNIEnv *env) jclass recognitionEventClass = env->FindClass(kRecognitionEventClassPathName); gRecognitionEventClass = (jclass) env->NewGlobalRef(recognitionEventClass); gRecognitionEventCstor = env->GetMethodID(recognitionEventClass, "<init>", - "(IIZIII[B)V"); + "(IIZIIIZLandroid/media/AudioFormat;[B)V"); jclass keyphraseRecognitionEventClass = env->FindClass(kKeyphraseRecognitionEventClassPathName); gKeyphraseRecognitionEventClass = (jclass) env->NewGlobalRef(keyphraseRecognitionEventClass); gKeyphraseRecognitionEventCstor = env->GetMethodID(keyphraseRecognitionEventClass, "<init>", - "(IIZIII[BZ[Landroid/hardware/soundtrigger/SoundTrigger$KeyphraseRecognitionExtra;)V"); + "(IIZIIIZLandroid/media/AudioFormat;[B[Landroid/hardware/soundtrigger/SoundTrigger$KeyphraseRecognitionExtra;)V"); jclass keyRecognitionConfigClass = env->FindClass(kRecognitionConfigClassPathName); @@ -782,9 +869,12 @@ int register_android_hardware_SoundTrigger(JNIEnv *env) jclass keyphraseRecognitionExtraClass = env->FindClass(kKeyphraseRecognitionExtraClassPathName); gKeyphraseRecognitionExtraClass = (jclass) env->NewGlobalRef(keyphraseRecognitionExtraClass); gKeyphraseRecognitionExtraCstor = env->GetMethodID(keyphraseRecognitionExtraClass, "<init>", - "(II[Landroid/hardware/soundtrigger/SoundTrigger$ConfidenceLevel;)V"); + "(III[Landroid/hardware/soundtrigger/SoundTrigger$ConfidenceLevel;)V"); gKeyphraseRecognitionExtraFields.id = env->GetFieldID(gKeyphraseRecognitionExtraClass, "id", "I"); - gKeyphraseRecognitionExtraFields.recognitionModes = env->GetFieldID(gKeyphraseRecognitionExtraClass, "recognitionModes", "I"); + gKeyphraseRecognitionExtraFields.recognitionModes = env->GetFieldID(gKeyphraseRecognitionExtraClass, + "recognitionModes", "I"); + gKeyphraseRecognitionExtraFields.coarseConfidenceLevel = env->GetFieldID(gKeyphraseRecognitionExtraClass, + "coarseConfidenceLevel", "I"); gKeyphraseRecognitionExtraFields.confidenceLevels = env->GetFieldID(gKeyphraseRecognitionExtraClass, "confidenceLevels", "[Landroid/hardware/soundtrigger/SoundTrigger$ConfidenceLevel;"); @@ -796,6 +886,16 @@ int register_android_hardware_SoundTrigger(JNIEnv *env) gConfidenceLevelFields.confidenceLevel = env->GetFieldID(confidenceLevelClass, "confidenceLevel", "I"); + jclass audioFormatClass = env->FindClass(kAudioFormatClassPathName); + gAudioFormatClass = (jclass) env->NewGlobalRef(audioFormatClass); + gAudioFormatCstor = env->GetMethodID(audioFormatClass, "<init>", "(III)V"); + + jclass soundModelEventClass = env->FindClass(kSoundModelEventClassPathName); + gSoundModelEventClass = (jclass) env->NewGlobalRef(soundModelEventClass); + gSoundModelEventCstor = env->GetMethodID(soundModelEventClass, "<init>", + "(II[B)V"); + + int status = AndroidRuntime::registerNativeMethods(env, kSoundTriggerClassPathName, gMethods, NELEM(gMethods)); diff --git a/media/java/android/media/AudioFormat.java b/media/java/android/media/AudioFormat.java index 8d99d6a..d93d81b 100644 --- a/media/java/android/media/AudioFormat.java +++ b/media/java/android/media/AudioFormat.java @@ -249,6 +249,20 @@ public class AudioFormat { private AudioFormat(int ignoredArgument) { } + /** + * Constructor used by the JNI + */ + // Update sound trigger JNI in core/jni/android_hardware_SoundTrigger.cpp when modifying this + // constructor + private AudioFormat(int encoding, int sampleRate, int channelMask) { + mEncoding = encoding; + mSampleRate = sampleRate; + mChannelMask = channelMask; + mPropertySetMask = AUDIO_FORMAT_HAS_PROPERTY_ENCODING | + AUDIO_FORMAT_HAS_PROPERTY_SAMPLE_RATE | + AUDIO_FORMAT_HAS_PROPERTY_CHANNEL_MASK; + } + /** @hide */ public final static int AUDIO_FORMAT_HAS_PROPERTY_NONE = 0x0; /** @hide */ diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/DatabaseHelper.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/DatabaseHelper.java index 8913eb9..b4c221f 100644 --- a/services/voiceinteraction/java/com/android/server/voiceinteraction/DatabaseHelper.java +++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/DatabaseHelper.java @@ -195,7 +195,8 @@ public class DatabaseHelper extends SQLiteOpenHelper { Keyphrase[] keyphrases = new Keyphrase[1]; keyphrases[0] = new Keyphrase( keyphraseId, recognitionModes, locale, text, users); - return new KeyphraseSoundModel(UUID.fromString(modelUuid), data, keyphrases); + return new KeyphraseSoundModel(UUID.fromString(modelUuid), + null /* FIXME use vendor UUID */, data, keyphrases); } Slog.w(TAG, "No SoundModel available for the given keyphrase"); } finally { diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/SoundTriggerHelper.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/SoundTriggerHelper.java index f3ede88..fd36bfc 100644 --- a/services/voiceinteraction/java/com/android/server/voiceinteraction/SoundTriggerHelper.java +++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/SoundTriggerHelper.java @@ -25,6 +25,7 @@ import android.hardware.soundtrigger.SoundTrigger.KeyphraseSoundModel; import android.hardware.soundtrigger.SoundTrigger.ModuleProperties; import android.hardware.soundtrigger.SoundTrigger.RecognitionConfig; import android.hardware.soundtrigger.SoundTrigger.RecognitionEvent; +import android.hardware.soundtrigger.SoundTrigger.SoundModelEvent; import android.hardware.soundtrigger.SoundTriggerModule; import android.os.RemoteException; import android.util.Slog; @@ -330,6 +331,23 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener { } } + public void onSoundModelUpdate(SoundModelEvent event) { + if (event == null) { + Slog.w(TAG, "Invalid sound model event!"); + return; + } + + if (DBG) Slog.d(TAG, "onSoundModelUpdate: " + event); + + //TODO: implement sound model update + } + + public void onServiceStateChange(int state) { + if (DBG) Slog.d(TAG, "onServiceStateChange, state: " + state); + + //TODO: implement service state update + } + @Override public void onServiceDied() { synchronized (this) { diff --git a/tests/SoundTriggerTests/src/android/hardware/soundtrigger/SoundTriggerTest.java b/tests/SoundTriggerTests/src/android/hardware/soundtrigger/SoundTriggerTest.java index 4372ff9..65a3d8a 100644 --- a/tests/SoundTriggerTests/src/android/hardware/soundtrigger/SoundTriggerTest.java +++ b/tests/SoundTriggerTests/src/android/hardware/soundtrigger/SoundTriggerTest.java @@ -23,6 +23,7 @@ import android.hardware.soundtrigger.SoundTrigger.KeyphraseRecognitionEvent; import android.hardware.soundtrigger.SoundTrigger.KeyphraseRecognitionExtra; import android.hardware.soundtrigger.SoundTrigger.KeyphraseSoundModel; import android.hardware.soundtrigger.SoundTrigger.RecognitionEvent; +import android.media.AudioFormat; import android.os.Parcel; import android.test.InstrumentationTestCase; import android.test.suitebuilder.annotation.LargeTest; @@ -97,7 +98,8 @@ public class SoundTriggerTest extends InstrumentationTestCase { Keyphrase[] keyphrases = new Keyphrase[2]; keyphrases[0] = new Keyphrase(1, 0, "en-US", "hello", new int[] {0}); keyphrases[1] = new Keyphrase(2, 0, "fr-FR", "there", new int[] {1, 2}); - KeyphraseSoundModel ksm = new KeyphraseSoundModel(UUID.randomUUID(), null, keyphrases); + KeyphraseSoundModel ksm = new KeyphraseSoundModel(UUID.randomUUID(), UUID.randomUUID(), + null, keyphrases); // Write to a parcel Parcel parcel = Parcel.obtain(); @@ -119,8 +121,8 @@ public class SoundTriggerTest extends InstrumentationTestCase { Keyphrase[] keyphrases = new Keyphrase[2]; keyphrases[0] = new Keyphrase(1, 0, "en-US", "hello", new int[] {0}); keyphrases[1] = new Keyphrase(2, 0, "fr-FR", "there", new int[] {1, 2}); - KeyphraseSoundModel ksm = new KeyphraseSoundModel(UUID.randomUUID(), new byte[0], - keyphrases); + KeyphraseSoundModel ksm = new KeyphraseSoundModel(UUID.randomUUID(), UUID.randomUUID(), + new byte[0], keyphrases); // Write to a parcel Parcel parcel = Parcel.obtain(); @@ -141,7 +143,8 @@ public class SoundTriggerTest extends InstrumentationTestCase { public void testKeyphraseSoundModelParcelUnparcel_noKeyphrases() throws Exception { byte[] data = new byte[10]; mRandom.nextBytes(data); - KeyphraseSoundModel ksm = new KeyphraseSoundModel(UUID.randomUUID(), data, null); + KeyphraseSoundModel ksm = new KeyphraseSoundModel(UUID.randomUUID(), UUID.randomUUID(), + data, null); // Write to a parcel Parcel parcel = Parcel.obtain(); @@ -162,8 +165,8 @@ public class SoundTriggerTest extends InstrumentationTestCase { public void testKeyphraseSoundModelParcelUnparcel_zeroKeyphrases() throws Exception { byte[] data = new byte[10]; mRandom.nextBytes(data); - KeyphraseSoundModel ksm = new KeyphraseSoundModel(UUID.randomUUID(), data, - new Keyphrase[0]); + KeyphraseSoundModel ksm = new KeyphraseSoundModel(UUID.randomUUID(), UUID.randomUUID(), + data, new Keyphrase[0]); // Write to a parcel Parcel parcel = Parcel.obtain(); @@ -187,7 +190,8 @@ public class SoundTriggerTest extends InstrumentationTestCase { keyphrases[1] = new Keyphrase(2, 0, "fr-FR", "there", new int[] {1, 2}); byte[] data = new byte[200 * 1024]; mRandom.nextBytes(data); - KeyphraseSoundModel ksm = new KeyphraseSoundModel(UUID.randomUUID(), data, keyphrases); + KeyphraseSoundModel ksm = new KeyphraseSoundModel(UUID.randomUUID(), UUID.randomUUID(), + data, keyphrases); // Write to a parcel Parcel parcel = Parcel.obtain(); @@ -207,7 +211,7 @@ public class SoundTriggerTest extends InstrumentationTestCase { @SmallTest public void testRecognitionEventParcelUnparcel_noData() throws Exception { RecognitionEvent re = new RecognitionEvent(SoundTrigger.RECOGNITION_STATUS_SUCCESS, 1, - true, 2, 3, 4, null); + true, 2, 3, 4, false, null, null); // Write to a parcel Parcel parcel = Parcel.obtain(); @@ -224,7 +228,7 @@ public class SoundTriggerTest extends InstrumentationTestCase { @SmallTest public void testRecognitionEventParcelUnparcel_zeroData() throws Exception { RecognitionEvent re = new RecognitionEvent(SoundTrigger.RECOGNITION_STATUS_FAILURE, 1, - true, 2, 3, 4, new byte[1]); + true, 2, 3, 4, false, null, new byte[1]); // Write to a parcel Parcel parcel = Parcel.obtain(); @@ -243,7 +247,32 @@ public class SoundTriggerTest extends InstrumentationTestCase { byte[] data = new byte[200 * 1024]; mRandom.nextBytes(data); RecognitionEvent re = new RecognitionEvent(SoundTrigger.RECOGNITION_STATUS_ABORT, 1, - false, 2, 3, 4, data); + false, 2, 3, 4, false, null, data); + + // Write to a parcel + Parcel parcel = Parcel.obtain(); + re.writeToParcel(parcel, 0); + + // Read from it + parcel.setDataPosition(0); + RecognitionEvent unparceled = RecognitionEvent.CREATOR.createFromParcel(parcel); + + // Verify that they are the same + assertEquals(re, unparceled); + } + + @SmallTest + public void testRecognitionEventParcelUnparcel_largeAudioData() throws Exception { + byte[] data = new byte[200 * 1024]; + mRandom.nextBytes(data); + RecognitionEvent re = new RecognitionEvent(SoundTrigger.RECOGNITION_STATUS_ABORT, 1, + false, 2, 3, 4, true, + (new AudioFormat.Builder()) + .setChannelMask(AudioFormat.CHANNEL_IN_MONO) + .setEncoding(AudioFormat.ENCODING_PCM_16BIT) + .setSampleRate(16000) + .build(), + data); // Write to a parcel Parcel parcel = Parcel.obtain(); @@ -260,7 +289,7 @@ public class SoundTriggerTest extends InstrumentationTestCase { @SmallTest public void testKeyphraseRecognitionEventParcelUnparcel_noKeyphrases() throws Exception { KeyphraseRecognitionEvent re = new KeyphraseRecognitionEvent( - SoundTrigger.RECOGNITION_STATUS_SUCCESS, 1, true, 2, 3, 4, null, false, null); + SoundTrigger.RECOGNITION_STATUS_SUCCESS, 1, true, 2, 3, 4, false, null, null, null); // Write to a parcel Parcel parcel = Parcel.obtain(); @@ -279,8 +308,8 @@ public class SoundTriggerTest extends InstrumentationTestCase { public void testKeyphraseRecognitionEventParcelUnparcel_zeroData() throws Exception { KeyphraseRecognitionExtra[] kpExtra = new KeyphraseRecognitionExtra[0]; KeyphraseRecognitionEvent re = new KeyphraseRecognitionEvent( - SoundTrigger.RECOGNITION_STATUS_FAILURE, 2, true, 2, 3, 4, new byte[1], - true, kpExtra); + SoundTrigger.RECOGNITION_STATUS_FAILURE, 2, true, 2, 3, 4, false, null, new byte[1], + kpExtra); // Write to a parcel Parcel parcel = Parcel.obtain(); @@ -303,20 +332,20 @@ public class SoundTriggerTest extends InstrumentationTestCase { ConfidenceLevel cl1 = new ConfidenceLevel(1, 90); ConfidenceLevel cl2 = new ConfidenceLevel(2, 30); kpExtra[0] = new KeyphraseRecognitionExtra(1, - SoundTrigger.RECOGNITION_MODE_USER_IDENTIFICATION, + SoundTrigger.RECOGNITION_MODE_USER_IDENTIFICATION, 0, new ConfidenceLevel[] {cl1, cl2}); kpExtra[1] = new KeyphraseRecognitionExtra(1, - SoundTrigger.RECOGNITION_MODE_VOICE_TRIGGER, + SoundTrigger.RECOGNITION_MODE_VOICE_TRIGGER, 0, new ConfidenceLevel[] {cl2}); kpExtra[2] = new KeyphraseRecognitionExtra(1, - SoundTrigger.RECOGNITION_MODE_VOICE_TRIGGER, null); + SoundTrigger.RECOGNITION_MODE_VOICE_TRIGGER, 0, null); kpExtra[3] = new KeyphraseRecognitionExtra(1, - SoundTrigger.RECOGNITION_MODE_VOICE_TRIGGER, + SoundTrigger.RECOGNITION_MODE_VOICE_TRIGGER, 0, new ConfidenceLevel[0]); KeyphraseRecognitionEvent re = new KeyphraseRecognitionEvent( - SoundTrigger.RECOGNITION_STATUS_FAILURE, 1, true, 2, 3, 4, data, - false, kpExtra); + SoundTrigger.RECOGNITION_STATUS_FAILURE, 1, true, 2, 3, 4, false, null, data, + kpExtra); // Write to a parcel Parcel parcel = Parcel.obtain(); |