Merge "SoundTrigger API update." into lmp-dev
This commit is contained in:
@ -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,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.
|
||||
@ -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
|
||||
*/
|
||||
|
@ -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();
|
||||
|
@ -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 =
|
||||
|
@ -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));
|
||||
|
||||
|
@ -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 */
|
||||
|
@ -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 {
|
||||
|
@ -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) {
|
||||
|
@ -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();
|
||||
|
Reference in New Issue
Block a user