Loading core/java/android/hardware/soundtrigger/SoundTrigger.java +246 −29 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package android.hardware.soundtrigger; import android.media.AudioFormat; import android.os.Handler; import android.os.Parcel; import android.os.Parcelable; Loading Loading @@ -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; Loading @@ -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 Loading Loading @@ -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 Loading @@ -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 Loading @@ -167,7 +175,8 @@ public class SoundTrigger { + maxUsers + ", recognitionModes=" + recognitionModes + ", supportsCaptureTransition=" + supportsCaptureTransition + ", maxBufferMs=" + maxBufferMs + ", supportsConcurrentCapture=" + supportsConcurrentCapture + ", powerConsumptionMw=" + powerConsumptionMw + "]"; + ", powerConsumptionMw=" + powerConsumptionMw + ", returnsTriggerInEvent=" + returnsTriggerInEvent + "]"; } } Loading @@ -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; } Loading Loading @@ -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; } Loading @@ -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 Loading @@ -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) + "]"; } } Loading Loading @@ -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; } Loading @@ -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 Loading @@ -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); } Loading @@ -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; Loading Loading @@ -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; } Loading @@ -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) + "]"; } } Loading Loading @@ -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, public KeyphraseRecognitionExtra(int id, int recognitionModes, int coarseConfidenceLevel, ConfidenceLevel[] confidenceLevels) { this.id = id; this.recognitionModes = recognitionModes; this.coarseConfidenceLevel = coarseConfidenceLevel; this.confidenceLevels = confidenceLevels; } Loading @@ -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); } Loading @@ -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; } Loading @@ -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) + "]"; } } Loading @@ -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; } Loading @@ -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 Loading @@ -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); } Loading @@ -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; } Loading @@ -833,22 +934,126 @@ 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. Loading Loading @@ -890,6 +1095,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 */ Loading core/java/android/hardware/soundtrigger/SoundTriggerModule.java +15 −4 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -133,11 +136,8 @@ public class SoundTriggerModule { 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) { Loading @@ -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(); Loading core/java/android/service/voice/AlwaysOnHotwordDetector.java +1 −1 Original line number Diff line number Diff line Loading @@ -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 = Loading core/jni/android_hardware_SoundTrigger.cpp +118 −18 File changed.Preview size limit exceeded, changes collapsed. Show changes media/java/android/media/AudioFormat.java +14 −0 Original line number Diff line number Diff line Loading @@ -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 */ Loading Loading
core/java/android/hardware/soundtrigger/SoundTrigger.java +246 −29 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package android.hardware.soundtrigger; import android.media.AudioFormat; import android.os.Handler; import android.os.Parcel; import android.os.Parcelable; Loading Loading @@ -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; Loading @@ -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 Loading Loading @@ -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 Loading @@ -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 Loading @@ -167,7 +175,8 @@ public class SoundTrigger { + maxUsers + ", recognitionModes=" + recognitionModes + ", supportsCaptureTransition=" + supportsCaptureTransition + ", maxBufferMs=" + maxBufferMs + ", supportsConcurrentCapture=" + supportsConcurrentCapture + ", powerConsumptionMw=" + powerConsumptionMw + "]"; + ", powerConsumptionMw=" + powerConsumptionMw + ", returnsTriggerInEvent=" + returnsTriggerInEvent + "]"; } } Loading @@ -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; } Loading Loading @@ -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; } Loading @@ -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 Loading @@ -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) + "]"; } } Loading Loading @@ -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; } Loading @@ -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 Loading @@ -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); } Loading @@ -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; Loading Loading @@ -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; } Loading @@ -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) + "]"; } } Loading Loading @@ -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, public KeyphraseRecognitionExtra(int id, int recognitionModes, int coarseConfidenceLevel, ConfidenceLevel[] confidenceLevels) { this.id = id; this.recognitionModes = recognitionModes; this.coarseConfidenceLevel = coarseConfidenceLevel; this.confidenceLevels = confidenceLevels; } Loading @@ -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); } Loading @@ -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; } Loading @@ -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) + "]"; } } Loading @@ -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; } Loading @@ -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 Loading @@ -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); } Loading @@ -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; } Loading @@ -833,22 +934,126 @@ 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. Loading Loading @@ -890,6 +1095,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 */ Loading
core/java/android/hardware/soundtrigger/SoundTriggerModule.java +15 −4 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -133,11 +136,8 @@ public class SoundTriggerModule { 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) { Loading @@ -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(); Loading
core/java/android/service/voice/AlwaysOnHotwordDetector.java +1 −1 Original line number Diff line number Diff line Loading @@ -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 = Loading
core/jni/android_hardware_SoundTrigger.cpp +118 −18 File changed.Preview size limit exceeded, changes collapsed. Show changes
media/java/android/media/AudioFormat.java +14 −0 Original line number Diff line number Diff line Loading @@ -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 */ Loading