diff options
| author | 2023-03-17 23:07:45 +0000 | |
|---|---|---|
| committer | 2023-03-17 23:07:45 +0000 | |
| commit | 65a2a1e7fd0c482419f1c4616668b91d0a7f0f44 (patch) | |
| tree | 53379ba73268cfb6ed5e9df21b44917dde0b6841 | |
| parent | 6b0bb05b69af579d30da2bd6f4de1d5cb9bcb734 (diff) | |
| parent | 471556d1a1fbea9926f08de353d66fbe7cd50437 (diff) | |
Merge changes from topic "cherrypicker-L13400000959215506:N79400001348786532" into udc-dev
* changes:
RecognitionEvent.getHalEventTimestampMillis API
AOHD.EventPayload.getHalEventTimestampMillis API
| -rw-r--r-- | core/api/system-current.txt | 2 | ||||
| -rw-r--r-- | core/api/test-current.txt | 5 | ||||
| -rw-r--r-- | core/java/android/hardware/soundtrigger/ConversionUtil.java | 27 | ||||
| -rw-r--r-- | core/java/android/hardware/soundtrigger/SoundTrigger.java | 117 | ||||
| -rw-r--r-- | core/java/android/service/voice/AlwaysOnHotwordDetector.java | 50 | ||||
| -rw-r--r-- | tests/SoundTriggerTests/src/android/hardware/soundtrigger/SoundTriggerTest.java | 108 |
6 files changed, 228 insertions, 81 deletions
diff --git a/core/api/system-current.txt b/core/api/system-current.txt index 5a8ee9456f87..ee6606768afc 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -5967,6 +5967,7 @@ package android.hardware.soundtrigger { method @Nullable public android.media.AudioFormat getCaptureFormat(); method public int getCaptureSession(); method public byte[] getData(); + method public long getHalEventReceivedMillis(); method public boolean isCaptureAvailable(); } @@ -13042,6 +13043,7 @@ package android.service.voice { method @Nullable public android.media.AudioFormat getCaptureAudioFormat(); method @Nullable public byte[] getData(); method public int getDataFormat(); + method public long getHalEventReceivedMillis(); method @Nullable public android.service.voice.HotwordDetectedResult getHotwordDetectedResult(); method @NonNull public java.util.List<android.hardware.soundtrigger.SoundTrigger.KeyphraseRecognitionExtra> getKeyphraseRecognitionExtras(); method @Deprecated @Nullable public byte[] getTriggerAudio(); diff --git a/core/api/test-current.txt b/core/api/test-current.txt index c2c7180f22ef..b856bc2ce853 100644 --- a/core/api/test-current.txt +++ b/core/api/test-current.txt @@ -1639,7 +1639,7 @@ package android.hardware.soundtrigger { } public static class SoundTrigger.RecognitionEvent { - ctor public SoundTrigger.RecognitionEvent(int, int, boolean, int, int, int, boolean, @NonNull android.media.AudioFormat, @Nullable byte[]); + ctor public SoundTrigger.RecognitionEvent(int, int, boolean, int, int, int, boolean, @NonNull android.media.AudioFormat, @Nullable byte[], long); } } @@ -2876,7 +2876,7 @@ package android.service.voice { public class AlwaysOnHotwordDetector implements android.service.voice.HotwordDetector { method public void overrideAvailability(int); method public void resetAvailability(); - 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[], @NonNull java.util.List<android.hardware.soundtrigger.SoundTrigger.KeyphraseRecognitionExtra>); + method @RequiresPermission(allOf={android.Manifest.permission.RECORD_AUDIO, android.Manifest.permission.CAPTURE_AUDIO_HOTWORD}) public void triggerHardwareRecognitionEventForTest(int, int, long, boolean, int, int, int, boolean, @NonNull android.media.AudioFormat, @Nullable byte[], @NonNull java.util.List<android.hardware.soundtrigger.SoundTrigger.KeyphraseRecognitionExtra>); } public static final class AlwaysOnHotwordDetector.EventPayload.Builder { @@ -2888,6 +2888,7 @@ package android.service.voice { method @NonNull public android.service.voice.AlwaysOnHotwordDetector.EventPayload.Builder setCaptureSession(int); method @NonNull public android.service.voice.AlwaysOnHotwordDetector.EventPayload.Builder setData(@NonNull byte[]); method @NonNull public android.service.voice.AlwaysOnHotwordDetector.EventPayload.Builder setDataFormat(int); + method @NonNull public android.service.voice.AlwaysOnHotwordDetector.EventPayload.Builder setHalEventReceivedMillis(long); method @NonNull public android.service.voice.AlwaysOnHotwordDetector.EventPayload.Builder setHotwordDetectedResult(@NonNull android.service.voice.HotwordDetectedResult); method @NonNull public android.service.voice.AlwaysOnHotwordDetector.EventPayload.Builder setKeyphraseRecognitionExtras(@NonNull java.util.List<android.hardware.soundtrigger.SoundTrigger.KeyphraseRecognitionExtra>); } diff --git a/core/java/android/hardware/soundtrigger/ConversionUtil.java b/core/java/android/hardware/soundtrigger/ConversionUtil.java index 58e7f01b2b08..888047d95f80 100644 --- a/core/java/android/hardware/soundtrigger/ConversionUtil.java +++ b/core/java/android/hardware/soundtrigger/ConversionUtil.java @@ -223,13 +223,13 @@ public class ConversionUtil { int modelHandle, int captureSession, RecognitionEvent aidlEvent) { // The API recognition event doesn't allow for a null audio format, even though it doesn't // always make sense. We thus replace it with a default. - AudioFormat audioFormat = aidl2apiAudioFormatWithDefault( - aidlEvent.audioConfig, true /*isInput*/); - return new SoundTrigger.GenericRecognitionEvent( - aidlEvent.status, - modelHandle, aidlEvent.captureAvailable, captureSession, - aidlEvent.captureDelayMs, aidlEvent.capturePreambleMs, aidlEvent.triggerInData, - audioFormat, aidlEvent.data, aidlEvent.recognitionStillActive); + AudioFormat audioFormat = aidl2apiAudioFormatWithDefault(aidlEvent.audioConfig, + true /*isInput*/); + // TODO(b/265852186) propagate a timestamp from aidl interfaces + return new SoundTrigger.GenericRecognitionEvent(aidlEvent.status, modelHandle, + aidlEvent.captureAvailable, captureSession, aidlEvent.captureDelayMs, + aidlEvent.capturePreambleMs, aidlEvent.triggerInData, audioFormat, aidlEvent.data, + aidlEvent.recognitionStillActive, -1 /* halEventReceivedMillis */); } public static SoundTrigger.RecognitionEvent aidl2apiPhraseRecognitionEvent( @@ -242,14 +242,13 @@ public class ConversionUtil { } // The API recognition event doesn't allow for a null audio format, even though it doesn't // always make sense. We thus replace it with a default. - AudioFormat audioFormat = aidl2apiAudioFormatWithDefault( - aidlEvent.common.audioConfig, true /*isInput*/); + AudioFormat audioFormat = aidl2apiAudioFormatWithDefault(aidlEvent.common.audioConfig, + true /*isInput*/); + // TODO(b/265852186) propagate a timestamp from aidl interfaces return new SoundTrigger.KeyphraseRecognitionEvent(aidlEvent.common.status, modelHandle, - aidlEvent.common.captureAvailable, - captureSession, aidlEvent.common.captureDelayMs, - aidlEvent.common.capturePreambleMs, aidlEvent.common.triggerInData, - audioFormat, aidlEvent.common.data, - apiExtras); + aidlEvent.common.captureAvailable, captureSession, aidlEvent.common.captureDelayMs, + aidlEvent.common.capturePreambleMs, aidlEvent.common.triggerInData, audioFormat, + aidlEvent.common.data, apiExtras, -1 /* halEventReceivedMillis */); } // In case of a null input returns a non-null valid output. diff --git a/core/java/android/hardware/soundtrigger/SoundTrigger.java b/core/java/android/hardware/soundtrigger/SoundTrigger.java index 55939896ab98..cbbd16b21f0d 100644 --- a/core/java/android/hardware/soundtrigger/SoundTrigger.java +++ b/core/java/android/hardware/soundtrigger/SoundTrigger.java @@ -28,6 +28,7 @@ import static android.system.OsConstants.EPIPE; import static java.util.Objects.requireNonNull; +import android.annotation.ElapsedRealtimeLong; import android.annotation.IntDef; import android.annotation.IntRange; import android.annotation.NonNull; @@ -36,17 +37,13 @@ import android.annotation.RequiresPermission; import android.annotation.SuppressLint; import android.annotation.SystemApi; import android.annotation.TestApi; -import android.app.ActivityThread; import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.media.AudioFormat; -import android.media.permission.ClearCallingIdentityContext; import android.media.permission.Identity; -import android.media.permission.SafeCloseable; import android.media.soundtrigger.Status; import android.media.soundtrigger_middleware.ISoundTriggerMiddlewareService; import android.media.soundtrigger_middleware.SoundTriggerModuleDescriptor; -import android.os.Binder; import android.os.Build; import android.os.Handler; import android.os.IBinder; @@ -56,6 +53,7 @@ import android.os.Parcelable; import android.os.RemoteException; import android.os.ServiceManager; import android.os.ServiceSpecificException; +import android.os.SystemClock; import android.util.Log; import java.lang.annotation.Retention; @@ -1187,23 +1185,38 @@ public class SoundTrigger { * @hide */ public final boolean recognitionStillActive; + /** + * Timestamp of when the trigger event from SoundTriggerHal was received by the + * framework. + * + * <p>Clock monotonic including suspend time or its equivalent on the system, + * in the same units and timebase as {@link SystemClock#elapsedRealtime()}. + * + * <p>Value represents elapsed realtime in milliseconds when the event was received from the + * HAL. The value will be -1 if the event was not generated from the HAL. + * + * @hide + */ + @ElapsedRealtimeLong + public final long halEventReceivedMillis; /** @hide */ @TestApi @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public RecognitionEvent(int status, int soundModelHandle, boolean captureAvailable, int captureSession, int captureDelayMs, int capturePreambleMs, - boolean triggerInData, @NonNull AudioFormat captureFormat, @Nullable byte[] data) { - this(status, soundModelHandle, captureAvailable, captureSession, captureDelayMs, - capturePreambleMs, triggerInData, captureFormat, data, - status == RECOGNITION_STATUS_GET_STATE_RESPONSE); + boolean triggerInData, @NonNull AudioFormat captureFormat, @Nullable byte[] data, + @ElapsedRealtimeLong long halEventReceivedMillis) { + this(status, soundModelHandle, captureAvailable, + captureSession, captureDelayMs, capturePreambleMs, triggerInData, captureFormat, + data, status == RECOGNITION_STATUS_GET_STATE_RESPONSE, halEventReceivedMillis); } /** @hide */ public RecognitionEvent(int status, int soundModelHandle, boolean captureAvailable, int captureSession, int captureDelayMs, int capturePreambleMs, boolean triggerInData, @NonNull AudioFormat captureFormat, @Nullable byte[] data, - boolean recognitionStillActive) { + boolean recognitionStillActive, @ElapsedRealtimeLong long halEventReceivedMillis) { this.status = status; this.soundModelHandle = soundModelHandle; this.captureAvailable = captureAvailable; @@ -1214,6 +1227,7 @@ public class SoundTrigger { this.captureFormat = requireNonNull(captureFormat); this.data = data != null ? data : new byte[0]; this.recognitionStillActive = recognitionStillActive; + this.halEventReceivedMillis = halEventReceivedMillis; } /** @@ -1256,6 +1270,21 @@ public class SoundTrigger { return data; } + /** + * Timestamp of when the trigger event from SoundTriggerHal was received by the + * framework. + * + * Clock monotonic including suspend time or its equivalent on the system, + * in the same units and timebase as {@link SystemClock#elapsedRealtime()}. + * + * @return Elapsed realtime in milliseconds when the event was received from the HAL. + * Returns -1 if the event was not generated from the HAL. + */ + @ElapsedRealtimeLong + public long getHalEventReceivedMillis() { + return halEventReceivedMillis; + } + /** @hide */ public static final @android.annotation.NonNull Parcelable.Creator<RecognitionEvent> CREATOR = new Parcelable.Creator<RecognitionEvent>() { @@ -1290,9 +1319,10 @@ public class SoundTrigger { } byte[] data = in.readBlob(); boolean recognitionStillActive = in.readBoolean(); + long halEventReceivedMillis = in.readLong(); return new RecognitionEvent(status, soundModelHandle, captureAvailable, captureSession, captureDelayMs, capturePreambleMs, triggerInData, captureFormat, data, - recognitionStillActive); + recognitionStillActive, halEventReceivedMillis); } /** @hide */ @@ -1319,6 +1349,7 @@ public class SoundTrigger { } dest.writeBlob(data); dest.writeBoolean(recognitionStillActive); + dest.writeLong(halEventReceivedMillis); } @Override public int hashCode() { @@ -1338,6 +1369,7 @@ public class SoundTrigger { result = prime * result + soundModelHandle; result = prime * result + status; result = result + (recognitionStillActive ? 1289 : 1291); + result = prime * result + Long.hashCode(halEventReceivedMillis); return result; } @@ -1364,6 +1396,9 @@ public class SoundTrigger { return false; if (soundModelHandle != other.soundModelHandle) return false; + if (halEventReceivedMillis != other.halEventReceivedMillis) { + return false; + } if (status != other.status) return false; if (triggerInData != other.triggerInData) @@ -1400,6 +1435,7 @@ public class SoundTrigger { (", channelMask=" + captureFormat.getChannelMask())) + ", data=" + (data == null ? 0 : data.length) + ", recognitionStillActive=" + recognitionStillActive + + ", halEventReceivedMillis=" + halEventReceivedMillis + "]"; } } @@ -1820,19 +1856,22 @@ public class SoundTrigger { public KeyphraseRecognitionEvent(int status, int soundModelHandle, boolean captureAvailable, int captureSession, int captureDelayMs, int capturePreambleMs, boolean triggerInData, @NonNull AudioFormat captureFormat, @Nullable byte[] data, - @Nullable KeyphraseRecognitionExtra[] keyphraseExtras) { + @Nullable KeyphraseRecognitionExtra[] keyphraseExtras, + @ElapsedRealtimeLong long halEventReceivedMillis) { this(status, soundModelHandle, captureAvailable, captureSession, captureDelayMs, capturePreambleMs, triggerInData, captureFormat, data, keyphraseExtras, - status == RECOGNITION_STATUS_GET_STATE_RESPONSE); + status == RECOGNITION_STATUS_GET_STATE_RESPONSE, halEventReceivedMillis); } - public KeyphraseRecognitionEvent(int status, int soundModelHandle, boolean captureAvailable, + public KeyphraseRecognitionEvent(int status, int soundModelHandle, + boolean captureAvailable, int captureSession, int captureDelayMs, int capturePreambleMs, boolean triggerInData, @NonNull AudioFormat captureFormat, @Nullable byte[] data, @Nullable KeyphraseRecognitionExtra[] keyphraseExtras, - boolean recognitionStillActive) { - super(status, soundModelHandle, captureAvailable, captureSession, captureDelayMs, - capturePreambleMs, triggerInData, captureFormat, data, recognitionStillActive); + boolean recognitionStillActive, @ElapsedRealtimeLong long halEventReceivedMillis) { + super(status, soundModelHandle, captureAvailable, + captureSession, captureDelayMs, capturePreambleMs, triggerInData, captureFormat, + data, recognitionStillActive, halEventReceivedMillis); this.keyphraseExtras = keyphraseExtras != null ? keyphraseExtras : new KeyphraseRecognitionExtra[0]; } @@ -1869,11 +1908,13 @@ public class SoundTrigger { } byte[] data = in.readBlob(); boolean recognitionStillActive = in.readBoolean(); + long halEventReceivedMillis = in.readLong(); KeyphraseRecognitionExtra[] keyphraseExtras = in.createTypedArray(KeyphraseRecognitionExtra.CREATOR); - return new KeyphraseRecognitionEvent(status, soundModelHandle, captureAvailable, - captureSession, captureDelayMs, capturePreambleMs, triggerInData, - captureFormat, data, keyphraseExtras, recognitionStillActive); + return new KeyphraseRecognitionEvent(status, soundModelHandle, + captureAvailable, captureSession, captureDelayMs, capturePreambleMs, + triggerInData, captureFormat, data, keyphraseExtras, recognitionStillActive, + halEventReceivedMillis); } @Override @@ -1895,6 +1936,7 @@ public class SoundTrigger { } dest.writeBlob(data); dest.writeBoolean(recognitionStillActive); + dest.writeLong(halEventReceivedMillis); dest.writeTypedArray(keyphraseExtras, flags); } @@ -1929,9 +1971,11 @@ public class SoundTrigger { public String toString() { return "KeyphraseRecognitionEvent [keyphraseExtras=" + Arrays.toString(keyphraseExtras) + ", status=" + status - + ", soundModelHandle=" + soundModelHandle + ", captureAvailable=" - + captureAvailable + ", captureSession=" + captureSession + ", captureDelayMs=" - + captureDelayMs + ", capturePreambleMs=" + capturePreambleMs + + ", soundModelHandle=" + soundModelHandle + + ", captureAvailable=" + captureAvailable + + ", captureSession=" + captureSession + + ", captureDelayMs=" + captureDelayMs + + ", capturePreambleMs=" + capturePreambleMs + ", triggerInData=" + triggerInData + ((captureFormat == null) ? "" : (", sampleRate=" + captureFormat.getSampleRate())) @@ -1941,6 +1985,7 @@ public class SoundTrigger { (", channelMask=" + captureFormat.getChannelMask())) + ", data=" + (data == null ? 0 : data.length) + ", recognitionStillActive=" + recognitionStillActive + + ", halEventReceivedMillis=" + halEventReceivedMillis + "]"; } } @@ -1953,21 +1998,23 @@ public class SoundTrigger { */ public static class GenericRecognitionEvent extends RecognitionEvent implements Parcelable { @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public GenericRecognitionEvent(int status, int soundModelHandle, - boolean captureAvailable, int captureSession, int captureDelayMs, - int capturePreambleMs, boolean triggerInData, @NonNull AudioFormat captureFormat, - @Nullable byte[] data) { - this(status, soundModelHandle, captureAvailable, captureSession, captureDelayMs, + public GenericRecognitionEvent(int status, int soundModelHandle, boolean captureAvailable, + int captureSession, int captureDelayMs, int capturePreambleMs, + boolean triggerInData, @NonNull AudioFormat captureFormat, @Nullable byte[] data, + @ElapsedRealtimeLong long halEventReceivedMillis) { + this(status, soundModelHandle, captureAvailable, + captureSession, captureDelayMs, capturePreambleMs, triggerInData, captureFormat, data, - status == RECOGNITION_STATUS_GET_STATE_RESPONSE); + status == RECOGNITION_STATUS_GET_STATE_RESPONSE, halEventReceivedMillis); } - public GenericRecognitionEvent(int status, int soundModelHandle, - boolean captureAvailable, int captureSession, int captureDelayMs, - int capturePreambleMs, boolean triggerInData, @NonNull AudioFormat captureFormat, - @Nullable byte[] data, boolean recognitionStillActive) { - super(status, soundModelHandle, captureAvailable, captureSession, captureDelayMs, - capturePreambleMs, triggerInData, captureFormat, data, recognitionStillActive); + public GenericRecognitionEvent(int status, int soundModelHandle, boolean captureAvailable, + int captureSession, int captureDelayMs, int capturePreambleMs, + boolean triggerInData, @NonNull AudioFormat captureFormat, @Nullable byte[] data, + boolean recognitionStillActive, @ElapsedRealtimeLong long halEventReceivedMillis) { + super(status, soundModelHandle, captureAvailable, + captureSession, captureDelayMs, capturePreambleMs, triggerInData, captureFormat, + data, recognitionStillActive, halEventReceivedMillis); } public static final @android.annotation.NonNull Parcelable.Creator<GenericRecognitionEvent> CREATOR @@ -1986,7 +2033,7 @@ public class SoundTrigger { return new GenericRecognitionEvent(event.status, event.soundModelHandle, event.captureAvailable, event.captureSession, event.captureDelayMs, event.capturePreambleMs, event.triggerInData, event.captureFormat, event.data, - event.recognitionStillActive); + event.recognitionStillActive, event.halEventReceivedMillis); } @Override diff --git a/core/java/android/service/voice/AlwaysOnHotwordDetector.java b/core/java/android/service/voice/AlwaysOnHotwordDetector.java index ffa15f065a02..e69e03e1fac3 100644 --- a/core/java/android/service/voice/AlwaysOnHotwordDetector.java +++ b/core/java/android/service/voice/AlwaysOnHotwordDetector.java @@ -20,6 +20,7 @@ import static android.Manifest.permission.CAPTURE_AUDIO_HOTWORD; import static android.Manifest.permission.RECORD_AUDIO; import static android.service.voice.VoiceInteractionService.MULTIPLE_ACTIVE_HOTWORD_DETECTORS; +import android.annotation.ElapsedRealtimeLong; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; @@ -54,6 +55,7 @@ import android.os.ParcelFileDescriptor; import android.os.PersistableBundle; import android.os.RemoteException; import android.os.SharedMemory; +import android.os.SystemClock; import android.text.TextUtils; import android.util.Log; import android.util.Slog; @@ -401,6 +403,9 @@ public class AlwaysOnHotwordDetector extends AbstractDetector { private final ParcelFileDescriptor mAudioStream; private final List<KeyphraseRecognitionExtra> mKephraseExtras; + @ElapsedRealtimeLong + private final long mHalEventReceivedMillis; + private EventPayload(boolean captureAvailable, @Nullable AudioFormat audioFormat, int captureSession, @@ -408,7 +413,8 @@ public class AlwaysOnHotwordDetector extends AbstractDetector { @Nullable byte[] data, @Nullable HotwordDetectedResult hotwordDetectedResult, @Nullable ParcelFileDescriptor audioStream, - @NonNull List<KeyphraseRecognitionExtra> keyphraseExtras) { + @NonNull List<KeyphraseRecognitionExtra> keyphraseExtras, + @ElapsedRealtimeLong long halEventReceivedMillis) { mCaptureAvailable = captureAvailable; mCaptureSession = captureSession; mAudioFormat = audioFormat; @@ -417,6 +423,7 @@ public class AlwaysOnHotwordDetector extends AbstractDetector { mHotwordDetectedResult = hotwordDetectedResult; mAudioStream = audioStream; mKephraseExtras = keyphraseExtras; + mHalEventReceivedMillis = halEventReceivedMillis; } /** @@ -546,6 +553,21 @@ public class AlwaysOnHotwordDetector extends AbstractDetector { } /** + * Timestamp of when the trigger event from SoundTriggerHal was received by the system + * server. + * + * Clock monotonic including suspend time or its equivalent on the system, + * in the same units and timebase as {@link SystemClock#elapsedRealtime()}. + * + * @return Elapsed realtime in milliseconds when the event was received from the HAL. + * Returns -1 if the event was not generated from the HAL. + */ + @ElapsedRealtimeLong + public long getHalEventReceivedMillis() { + return mHalEventReceivedMillis; + } + + /** * Builder class for {@link EventPayload} objects * * @hide @@ -561,6 +583,8 @@ public class AlwaysOnHotwordDetector extends AbstractDetector { private HotwordDetectedResult mHotwordDetectedResult = null; private ParcelFileDescriptor mAudioStream = null; private List<KeyphraseRecognitionExtra> mKeyphraseExtras = Collections.emptyList(); + @ElapsedRealtimeLong + private long mHalEventReceivedMillis = -1; public Builder() {} @@ -579,6 +603,7 @@ public class AlwaysOnHotwordDetector extends AbstractDetector { setKeyphraseRecognitionExtras( Arrays.asList(keyphraseRecognitionEvent.keyphraseExtras)); } + setHalEventReceivedMillis(keyphraseRecognitionEvent.getHalEventReceivedMillis()); } /** @@ -682,13 +707,27 @@ public class AlwaysOnHotwordDetector extends AbstractDetector { } /** + * Timestamp of when the trigger event from SoundTriggerHal was received by the + * framework. + * + * Clock monotonic including suspend time or its equivalent on the system, + * in the same units and timebase as {@link SystemClock#elapsedRealtime()}. + */ + @NonNull + public Builder setHalEventReceivedMillis( + @ElapsedRealtimeLong long halEventReceivedMillis) { + mHalEventReceivedMillis = halEventReceivedMillis; + return this; + } + + /** * Builds an {@link EventPayload} instance */ @NonNull public EventPayload build() { return new EventPayload(mCaptureAvailable, mAudioFormat, mCaptureSession, mDataFormat, mData, mHotwordDetectedResult, mAudioStream, - mKeyphraseExtras); + mKeyphraseExtras, mHalEventReceivedMillis); } } } @@ -897,8 +936,9 @@ public class AlwaysOnHotwordDetector extends AbstractDetector { @TestApi @RequiresPermission(allOf = {RECORD_AUDIO, CAPTURE_AUDIO_HOTWORD}) public void triggerHardwareRecognitionEventForTest(int status, int soundModelHandle, - boolean captureAvailable, int captureSession, int captureDelayMs, int capturePreambleMs, - boolean triggerInData, @NonNull AudioFormat captureFormat, @Nullable byte[] data, + @ElapsedRealtimeLong long halEventReceivedMillis, boolean captureAvailable, + int captureSession, int captureDelayMs, int capturePreambleMs, boolean triggerInData, + @NonNull AudioFormat captureFormat, @Nullable byte[] data, @NonNull List<KeyphraseRecognitionExtra> keyphraseRecognitionExtras) { Log.d(TAG, "triggerHardwareRecognitionEventForTest()"); synchronized (mLock) { @@ -911,7 +951,7 @@ public class AlwaysOnHotwordDetector extends AbstractDetector { new KeyphraseRecognitionEvent(status, soundModelHandle, captureAvailable, captureSession, captureDelayMs, capturePreambleMs, triggerInData, captureFormat, data, keyphraseRecognitionExtras.toArray( - new KeyphraseRecognitionExtra[0])), + new KeyphraseRecognitionExtra[0]), halEventReceivedMillis), mInternalCallback); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); diff --git a/tests/SoundTriggerTests/src/android/hardware/soundtrigger/SoundTriggerTest.java b/tests/SoundTriggerTests/src/android/hardware/soundtrigger/SoundTriggerTest.java index e36f398c53ea..f49d9c9f1431 100644 --- a/tests/SoundTriggerTests/src/android/hardware/soundtrigger/SoundTriggerTest.java +++ b/tests/SoundTriggerTests/src/android/hardware/soundtrigger/SoundTriggerTest.java @@ -219,10 +219,18 @@ 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, false, null, null); - - // Write to a parcel + RecognitionEvent re = new RecognitionEvent(SoundTrigger.RECOGNITION_STATUS_SUCCESS, + 1 /* soundModelHandle */, + true /* captureAvailable */, + 2 /* captureSession */, + 3 /* captureDelayMs */, + 4 /* capturePreambleMs */, + false /* triggerInData */, + null /* captureFormat */, + null /* data */, + 12345678 /* halEventReceivedMillis */); + + // Write to a parcel Parcel parcel = Parcel.obtain(); re.writeToParcel(parcel, 0); @@ -236,10 +244,18 @@ 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, false, null, new byte[1]); - - // Write to a parcel + RecognitionEvent re = new RecognitionEvent(SoundTrigger.RECOGNITION_STATUS_FAILURE, + 1 /* soundModelHandle */, + true /* captureAvailable */, + 2 /* captureSession */, + 3 /* captureDelayMs */, + 4 /* capturePreambleMs */, + false /* triggerInData */, + null /* captureFormat */, + new byte[1] /* data */, + 12345678 /* halEventReceivedMillis */); + + // Write to a parcel Parcel parcel = Parcel.obtain(); re.writeToParcel(parcel, 0); @@ -255,10 +271,18 @@ public class SoundTriggerTest extends InstrumentationTestCase { public void testRecognitionEventParcelUnparcel_largeData() throws Exception { byte[] data = new byte[200 * 1024]; mRandom.nextBytes(data); - RecognitionEvent re = new RecognitionEvent(SoundTrigger.RECOGNITION_STATUS_ABORT, 1, - false, 2, 3, 4, false, null, data); - - // Write to a parcel + RecognitionEvent re = new RecognitionEvent(SoundTrigger.RECOGNITION_STATUS_ABORT, + 1 /* soundModelHandle */, + false /* captureAvailable */, + 2 /* captureSession */, + 3 /* captureDelayMs */, + 4 /* capturePreambleMs */, + false /* triggerInData */, + null /* captureFormat */, + data, + 12345678 /* halEventReceivedMillis */); + + // Write to a parcel Parcel parcel = Parcel.obtain(); re.writeToParcel(parcel, 0); @@ -274,14 +298,20 @@ public class SoundTriggerTest extends InstrumentationTestCase { 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); + RecognitionEvent re = new RecognitionEvent(SoundTrigger.RECOGNITION_STATUS_ABORT, + 1 /* soundModelHandle */, + false /* captureAvailable */, + 2 /* captureSession */, + 3 /* captureDelayMs */, + 4 /* capturePreambleMs */, + true /* triggerInData */, + new AudioFormat.Builder() + .setChannelMask(AudioFormat.CHANNEL_IN_MONO) + .setEncoding(AudioFormat.ENCODING_PCM_16BIT) + .setSampleRate(16000) + .build(), + data, + 12345678 /* halEventReceivedMillis */); // Write to a parcel Parcel parcel = Parcel.obtain(); @@ -298,7 +328,17 @@ 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, false, null, null, null); + SoundTrigger.RECOGNITION_STATUS_SUCCESS, + 1 /* soundModelHandle */, + true /* captureAvailable */, + 2 /* captureSession */, + 3 /* captureDelayMs */, + 4 /* capturePreambleMs */, + false /* triggerInData */, + null /* captureFormat */, + null /* data */, + null /* keyphraseExtras */, + 12345678 /* halEventReceivedMillis */); // Write to a parcel Parcel parcel = Parcel.obtain(); @@ -317,8 +357,17 @@ 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, false, null, new byte[1], - kpExtra); + SoundTrigger.RECOGNITION_STATUS_FAILURE, + 2 /* soundModelHandle */, + true /* captureAvailable */, + 2 /* captureSession */, + 3 /* captureDelayMs */, + 4 /* capturePreambleMs */, + false /* triggerInData */, + null /* captureFormat */, + new byte[1] /* data */, + kpExtra, + 12345678 /* halEventReceivedMillis */); // Write to a parcel Parcel parcel = Parcel.obtain(); @@ -353,8 +402,17 @@ public class SoundTriggerTest extends InstrumentationTestCase { new ConfidenceLevel[0]); KeyphraseRecognitionEvent re = new KeyphraseRecognitionEvent( - SoundTrigger.RECOGNITION_STATUS_FAILURE, 1, true, 2, 3, 4, false, null, data, - kpExtra); + SoundTrigger.RECOGNITION_STATUS_FAILURE, + 1 /* soundModelHandle */, + true /* captureAvailable */, + 2 /* captureSession */, + 3 /* captureDelayMs */, + 4 /* capturePreambleMs */, + false /* triggerInData */, + null /* captureFormat */, + data, + kpExtra, + 12345678 /* halEventReceivedMillis */); // Write to a parcel Parcel parcel = Parcel.obtain(); |