diff --git a/core/api/system-current.txt b/core/api/system-current.txt index 321ebcf42ea56..4b3d0a4d23751 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -11755,8 +11755,12 @@ package android.service.voice { public static class AlwaysOnHotwordDetector.EventPayload { method @Nullable public android.os.ParcelFileDescriptor getAudioStream(); method @Nullable public android.media.AudioFormat getCaptureAudioFormat(); + method @Nullable public byte[] getData(); + method public int getDataFormat(); method @Nullable public android.service.voice.HotwordDetectedResult getHotwordDetectedResult(); - method @Nullable public byte[] getTriggerAudio(); + method @Deprecated @Nullable public byte[] getTriggerAudio(); + field public static final int DATA_FORMAT_RAW = 0; // 0x0 + field public static final int DATA_FORMAT_TRIGGER_AUDIO = 1; // 0x1 } public static final class AlwaysOnHotwordDetector.ModelParamRange { diff --git a/core/api/test-current.txt b/core/api/test-current.txt index ff4ec311349cb..d85f20582b496 100644 --- a/core/api/test-current.txt +++ b/core/api/test-current.txt @@ -2398,6 +2398,10 @@ package android.service.voice { method @RequiresPermission(allOf={android.Manifest.permission.RECORD_AUDIO, android.Manifest.permission.CAPTURE_AUDIO_HOTWORD}) public void triggerHardwareRecognitionEventForTest(int, int, boolean, int, int, int, boolean, @NonNull android.media.AudioFormat, @Nullable byte[]); } + public static class AlwaysOnHotwordDetector.EventPayload { + ctor public AlwaysOnHotwordDetector.EventPayload(boolean, boolean, @Nullable android.media.AudioFormat, int, @Nullable byte[], @Nullable android.service.voice.HotwordDetectedResult, @Nullable android.os.ParcelFileDescriptor); + } + public final class VisibleActivityInfo implements android.os.Parcelable { ctor public VisibleActivityInfo(int, @NonNull android.os.IBinder); } diff --git a/core/java/android/service/voice/AlwaysOnHotwordDetector.java b/core/java/android/service/voice/AlwaysOnHotwordDetector.java index c9daf52b56853..69f771bbac4a7 100644 --- a/core/java/android/service/voice/AlwaysOnHotwordDetector.java +++ b/core/java/android/service/voice/AlwaysOnHotwordDetector.java @@ -336,7 +336,39 @@ public class AlwaysOnHotwordDetector extends AbstractHotwordDetector { * Additional payload for {@link Callback#onDetected}. */ public static class EventPayload { - private final boolean mTriggerAvailable; + + /** + * Flags for describing the data format provided in the event payload. + * + * @hide + */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = {"DATA_FORMAT_"}, value = { + DATA_FORMAT_RAW, + DATA_FORMAT_TRIGGER_AUDIO, + }) + public @interface DataFormat { + } + + /** + * Data format is not strictly defined by the framework, and the + * {@link android.hardware.soundtrigger.SoundTriggerModule} voice engine may populate this + * field in any format. + */ + public static final int DATA_FORMAT_RAW = 0; + + /** + * Data format is defined as trigger audio. + * + *
When this format is used, {@link #getCaptureAudioFormat()} can be used to understand + * further the audio format for reading the data. + * + * @see AlwaysOnHotwordDetector#RECOGNITION_FLAG_CAPTURE_TRIGGER_AUDIO + */ + public static final int DATA_FORMAT_TRIGGER_AUDIO = 1; + + @DataFormat + private final int mDataFormat; // Indicates if {@code captureSession} can be used to continue capturing more audio // from the DSP hardware. private final boolean mCaptureAvailable; @@ -349,16 +381,16 @@ public class AlwaysOnHotwordDetector extends AbstractHotwordDetector { private final HotwordDetectedResult mHotwordDetectedResult; private final ParcelFileDescriptor mAudioStream; - EventPayload(boolean triggerAvailable, boolean captureAvailable, + EventPayload(boolean triggerInData, boolean captureAvailable, AudioFormat audioFormat, int captureSession, byte[] data) { - this(triggerAvailable, captureAvailable, audioFormat, captureSession, data, null, + this(triggerInData, captureAvailable, audioFormat, captureSession, data, null, null); } - EventPayload(boolean triggerAvailable, boolean captureAvailable, + EventPayload(boolean triggerInData, boolean captureAvailable, AudioFormat audioFormat, int captureSession, byte[] data, HotwordDetectedResult hotwordDetectedResult) { - this(triggerAvailable, captureAvailable, audioFormat, captureSession, data, + this(triggerInData, captureAvailable, audioFormat, captureSession, data, hotwordDetectedResult, null); } @@ -372,13 +404,20 @@ public class AlwaysOnHotwordDetector extends AbstractHotwordDetector { this(false, false, audioFormat, -1, null, hotwordDetectedResult, audioStream); } - private EventPayload(boolean triggerAvailable, boolean captureAvailable, - AudioFormat audioFormat, int captureSession, byte[] data, - HotwordDetectedResult hotwordDetectedResult, ParcelFileDescriptor audioStream) { - mTriggerAvailable = triggerAvailable; + /** @hide */ + @TestApi + public EventPayload(boolean triggerInData, boolean captureAvailable, + @Nullable AudioFormat audioFormat, int captureSession, @Nullable byte[] data, + @Nullable HotwordDetectedResult hotwordDetectedResult, + @Nullable ParcelFileDescriptor audioStream) { mCaptureAvailable = captureAvailable; mCaptureSession = captureSession; mAudioFormat = audioFormat; + if (triggerInData) { + mDataFormat = DATA_FORMAT_TRIGGER_AUDIO; + } else { + mDataFormat = DATA_FORMAT_RAW; + } mData = data; mHotwordDetectedResult = hotwordDetectedResult; mAudioStream = audioStream; @@ -400,16 +439,48 @@ public class AlwaysOnHotwordDetector extends AbstractHotwordDetector { * {@link #getCaptureAudioFormat()}. * * @see AlwaysOnHotwordDetector#RECOGNITION_FLAG_CAPTURE_TRIGGER_AUDIO + * @deprecated Use {@link #getData()} instead. */ + @Deprecated @Nullable public byte[] getTriggerAudio() { - if (mTriggerAvailable) { + if (mDataFormat == DATA_FORMAT_TRIGGER_AUDIO) { return mData; } else { return null; } } + /** + * Conveys the format of the additional data that is triggered with the keyphrase event. + * + * @see AlwaysOnHotwordDetector#RECOGNITION_FLAG_CAPTURE_TRIGGER_AUDIO + * @see DataFormat + */ + @DataFormat + public int getDataFormat() { + return mDataFormat; + } + + /** + * Gets additional raw data that is triggered with the keyphrase event. + * + *
A {@link android.hardware.soundtrigger.SoundTriggerModule} may populate this + * field with opaque data for use by system applications who know about voice + * engine internals. Data may be null if the field is not populated by the + * {@link android.hardware.soundtrigger.SoundTriggerModule}. + * + *
If {@link #getDataFormat()} is {@link #DATA_FORMAT_TRIGGER_AUDIO}, then the + * entirety of this buffer is expected to be of the format from + * {@link #getCaptureAudioFormat()}. + * + * @see AlwaysOnHotwordDetector#RECOGNITION_FLAG_CAPTURE_TRIGGER_AUDIO + */ + @Nullable + public byte[] getData() { + return mData; + } + /** * Gets the session ID to start a capture from the DSP. * This may be null if streaming capture isn't possible.