summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author TreeHugger Robot <treehugger-gerrit@google.com> 2023-03-17 23:07:45 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2023-03-17 23:07:45 +0000
commit65a2a1e7fd0c482419f1c4616668b91d0a7f0f44 (patch)
tree53379ba73268cfb6ed5e9df21b44917dde0b6841
parent6b0bb05b69af579d30da2bd6f4de1d5cb9bcb734 (diff)
parent471556d1a1fbea9926f08de353d66fbe7cd50437 (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.txt2
-rw-r--r--core/api/test-current.txt5
-rw-r--r--core/java/android/hardware/soundtrigger/ConversionUtil.java27
-rw-r--r--core/java/android/hardware/soundtrigger/SoundTrigger.java117
-rw-r--r--core/java/android/service/voice/AlwaysOnHotwordDetector.java50
-rw-r--r--tests/SoundTriggerTests/src/android/hardware/soundtrigger/SoundTriggerTest.java108
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();