Add initialAudio field to HotwordAudioStream
Bug: 262433819 Test: atest HotwordAudioStreamTest Change-Id: Ic95b701409656034a31724d50fb8bebf555cdab4 Merged-In: Ic95b701409656034a31724d50fb8bebf555cdab4
This commit is contained in:
@@ -27,6 +27,7 @@ import android.os.ParcelFileDescriptor;
|
|||||||
import android.os.Parcelable;
|
import android.os.Parcelable;
|
||||||
import android.os.PersistableBundle;
|
import android.os.PersistableBundle;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -59,8 +60,17 @@ public final class HotwordAudioStream implements Parcelable {
|
|||||||
private final AudioFormat mAudioFormat;
|
private final AudioFormat mAudioFormat;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This stream starts with the audio bytes used for hotword detection, but continues streaming
|
* This stream typically starts with the audio bytes used for hotword detection, but continues
|
||||||
* the audio until the stream is shutdown by the {@link HotwordDetectionService}.
|
* streaming the audio (e.g., with the query) until the stream is shutdown by the
|
||||||
|
* {@link HotwordDetectionService}. The data format is expected to match
|
||||||
|
* {@link #getAudioFormat()}.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* Alternatively, the {@link HotwordDetectionService} may use {@link #getInitialAudio()}
|
||||||
|
* to pass the start of the audio instead of streaming it here. This may prevent added latency
|
||||||
|
* caused by the streaming buffer (see {@link #KEY_AUDIO_STREAM_COPY_BUFFER_LENGTH_BYTES}) not
|
||||||
|
* being large enough to handle this initial chunk of audio.
|
||||||
|
* </p>
|
||||||
*/
|
*/
|
||||||
@NonNull
|
@NonNull
|
||||||
@UnsupportedAppUsage
|
@UnsupportedAppUsage
|
||||||
@@ -138,6 +148,32 @@ public final class HotwordAudioStream implements Parcelable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The start of the audio used for hotword detection. The data format is expected to match
|
||||||
|
* {@link #getAudioFormat()}.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* The {@link HotwordDetectionService} may use this instead of using
|
||||||
|
* {@link #getAudioStreamParcelFileDescriptor()} to stream these initial bytes of audio. This
|
||||||
|
* may prevent added latency caused by the streaming buffer (see
|
||||||
|
* {@link #KEY_AUDIO_STREAM_COPY_BUFFER_LENGTH_BYTES}) not being large enough to handle this
|
||||||
|
* initial chunk of audio.
|
||||||
|
* </p>
|
||||||
|
*/
|
||||||
|
@NonNull
|
||||||
|
@UnsupportedAppUsage
|
||||||
|
private final byte[] mInitialAudio;
|
||||||
|
|
||||||
|
private static final byte[] DEFAULT_INITIAL_EMPTY_AUDIO = {};
|
||||||
|
|
||||||
|
private static byte[] defaultInitialAudio() {
|
||||||
|
return DEFAULT_INITIAL_EMPTY_AUDIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String initialAudioToString() {
|
||||||
|
return "length=" + mInitialAudio.length;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides an instance of {@link Builder} with state corresponding to this instance.
|
* Provides an instance of {@link Builder} with state corresponding to this instance.
|
||||||
* @hide
|
* @hide
|
||||||
@@ -145,7 +181,8 @@ public final class HotwordAudioStream implements Parcelable {
|
|||||||
public Builder buildUpon() {
|
public Builder buildUpon() {
|
||||||
return new Builder(mAudioFormat, mAudioStreamParcelFileDescriptor)
|
return new Builder(mAudioFormat, mAudioStreamParcelFileDescriptor)
|
||||||
.setTimestamp(mTimestamp)
|
.setTimestamp(mTimestamp)
|
||||||
.setMetadata(mMetadata);
|
.setMetadata(mMetadata)
|
||||||
|
.setInitialAudio(mInitialAudio);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* package-private */
|
/* package-private */
|
||||||
@@ -153,7 +190,8 @@ public final class HotwordAudioStream implements Parcelable {
|
|||||||
@NonNull AudioFormat audioFormat,
|
@NonNull AudioFormat audioFormat,
|
||||||
@NonNull ParcelFileDescriptor audioStreamParcelFileDescriptor,
|
@NonNull ParcelFileDescriptor audioStreamParcelFileDescriptor,
|
||||||
@Nullable AudioTimestamp timestamp,
|
@Nullable AudioTimestamp timestamp,
|
||||||
@NonNull PersistableBundle metadata) {
|
@NonNull PersistableBundle metadata,
|
||||||
|
@NonNull byte[] initialAudio) {
|
||||||
this.mAudioFormat = audioFormat;
|
this.mAudioFormat = audioFormat;
|
||||||
com.android.internal.util.AnnotationValidations.validate(
|
com.android.internal.util.AnnotationValidations.validate(
|
||||||
NonNull.class, null, mAudioFormat);
|
NonNull.class, null, mAudioFormat);
|
||||||
@@ -164,6 +202,9 @@ public final class HotwordAudioStream implements Parcelable {
|
|||||||
this.mMetadata = metadata;
|
this.mMetadata = metadata;
|
||||||
com.android.internal.util.AnnotationValidations.validate(
|
com.android.internal.util.AnnotationValidations.validate(
|
||||||
NonNull.class, null, mMetadata);
|
NonNull.class, null, mMetadata);
|
||||||
|
this.mInitialAudio = initialAudio;
|
||||||
|
com.android.internal.util.AnnotationValidations.validate(
|
||||||
|
NonNull.class, null, mInitialAudio);
|
||||||
|
|
||||||
// onConstructed(); // You can define this method to get a callback
|
// onConstructed(); // You can define this method to get a callback
|
||||||
}
|
}
|
||||||
@@ -178,8 +219,17 @@ public final class HotwordAudioStream implements Parcelable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This stream starts with the audio bytes used for hotword detection, but continues streaming
|
* This stream typically starts with the audio bytes used for hotword detection, but continues
|
||||||
* the audio until the stream is shutdown by the {@link HotwordDetectionService}.
|
* streaming the audio (e.g., with the query) until the stream is shutdown by the
|
||||||
|
* {@link HotwordDetectionService}. The data format is expected to match
|
||||||
|
* {@link #getAudioFormat()}.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* Alternatively, the {@link HotwordDetectionService} may use {@link #getInitialAudio()}
|
||||||
|
* to pass the start of the audio instead of streaming it here. This may prevent added latency
|
||||||
|
* caused by the streaming buffer (see {@link #KEY_AUDIO_STREAM_COPY_BUFFER_LENGTH_BYTES}) not
|
||||||
|
* being large enough to handle this initial chunk of audio.
|
||||||
|
* </p>
|
||||||
*/
|
*/
|
||||||
@UnsupportedAppUsage
|
@UnsupportedAppUsage
|
||||||
@NonNull
|
@NonNull
|
||||||
@@ -220,6 +270,24 @@ public final class HotwordAudioStream implements Parcelable {
|
|||||||
return mMetadata;
|
return mMetadata;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The start of the audio used for hotword detection. The data format is expected to match
|
||||||
|
* {@link #getAudioFormat()}.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* The {@link HotwordDetectionService} may use this instead of using
|
||||||
|
* {@link #getAudioStreamParcelFileDescriptor()} to stream these initial bytes of audio. This
|
||||||
|
* may prevent added latency caused by the streaming buffer (see
|
||||||
|
* {@link #KEY_AUDIO_STREAM_COPY_BUFFER_LENGTH_BYTES}) not being large enough to handle this
|
||||||
|
* initial chunk of audio.
|
||||||
|
* </p>
|
||||||
|
*/
|
||||||
|
@UnsupportedAppUsage
|
||||||
|
@NonNull
|
||||||
|
public byte[] getInitialAudio() {
|
||||||
|
return mInitialAudio;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
// You can override field toString logic by defining methods like:
|
// You can override field toString logic by defining methods like:
|
||||||
@@ -229,7 +297,8 @@ public final class HotwordAudioStream implements Parcelable {
|
|||||||
+ "audioFormat = " + mAudioFormat + ", "
|
+ "audioFormat = " + mAudioFormat + ", "
|
||||||
+ "audioStreamParcelFileDescriptor = " + mAudioStreamParcelFileDescriptor + ", "
|
+ "audioStreamParcelFileDescriptor = " + mAudioStreamParcelFileDescriptor + ", "
|
||||||
+ "timestamp = " + timestampToString() + ", "
|
+ "timestamp = " + timestampToString() + ", "
|
||||||
+ "metadata = " + mMetadata + " }";
|
+ "metadata = " + mMetadata + ", "
|
||||||
|
+ "initialAudio = " + initialAudioToString() + " }";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -247,7 +316,8 @@ public final class HotwordAudioStream implements Parcelable {
|
|||||||
&& Objects.equals(mAudioStreamParcelFileDescriptor,
|
&& Objects.equals(mAudioStreamParcelFileDescriptor,
|
||||||
that.mAudioStreamParcelFileDescriptor)
|
that.mAudioStreamParcelFileDescriptor)
|
||||||
&& Objects.equals(mTimestamp, that.mTimestamp)
|
&& Objects.equals(mTimestamp, that.mTimestamp)
|
||||||
&& Objects.equals(mMetadata, that.mMetadata);
|
&& Objects.equals(mMetadata, that.mMetadata)
|
||||||
|
&& Arrays.equals(mInitialAudio, that.mInitialAudio);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -260,6 +330,7 @@ public final class HotwordAudioStream implements Parcelable {
|
|||||||
_hash = 31 * _hash + Objects.hashCode(mAudioStreamParcelFileDescriptor);
|
_hash = 31 * _hash + Objects.hashCode(mAudioStreamParcelFileDescriptor);
|
||||||
_hash = 31 * _hash + Objects.hashCode(mTimestamp);
|
_hash = 31 * _hash + Objects.hashCode(mTimestamp);
|
||||||
_hash = 31 * _hash + Objects.hashCode(mMetadata);
|
_hash = 31 * _hash + Objects.hashCode(mMetadata);
|
||||||
|
_hash = 31 * _hash + Arrays.hashCode(mInitialAudio);
|
||||||
return _hash;
|
return _hash;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -275,6 +346,7 @@ public final class HotwordAudioStream implements Parcelable {
|
|||||||
dest.writeTypedObject(mAudioStreamParcelFileDescriptor, flags);
|
dest.writeTypedObject(mAudioStreamParcelFileDescriptor, flags);
|
||||||
parcelTimestamp(dest, flags);
|
parcelTimestamp(dest, flags);
|
||||||
dest.writeTypedObject(mMetadata, flags);
|
dest.writeTypedObject(mMetadata, flags);
|
||||||
|
dest.writeByteArray(mInitialAudio);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -296,6 +368,7 @@ public final class HotwordAudioStream implements Parcelable {
|
|||||||
AudioTimestamp timestamp = unparcelTimestamp(in);
|
AudioTimestamp timestamp = unparcelTimestamp(in);
|
||||||
PersistableBundle metadata = (PersistableBundle) in.readTypedObject(
|
PersistableBundle metadata = (PersistableBundle) in.readTypedObject(
|
||||||
PersistableBundle.CREATOR);
|
PersistableBundle.CREATOR);
|
||||||
|
byte[] initialAudio = in.createByteArray();
|
||||||
|
|
||||||
this.mAudioFormat = audioFormat;
|
this.mAudioFormat = audioFormat;
|
||||||
com.android.internal.util.AnnotationValidations.validate(
|
com.android.internal.util.AnnotationValidations.validate(
|
||||||
@@ -307,6 +380,9 @@ public final class HotwordAudioStream implements Parcelable {
|
|||||||
this.mMetadata = metadata;
|
this.mMetadata = metadata;
|
||||||
com.android.internal.util.AnnotationValidations.validate(
|
com.android.internal.util.AnnotationValidations.validate(
|
||||||
NonNull.class, null, mMetadata);
|
NonNull.class, null, mMetadata);
|
||||||
|
this.mInitialAudio = initialAudio;
|
||||||
|
com.android.internal.util.AnnotationValidations.validate(
|
||||||
|
NonNull.class, null, mInitialAudio);
|
||||||
|
|
||||||
// onConstructed(); // You can define this method to get a callback
|
// onConstructed(); // You can define this method to get a callback
|
||||||
}
|
}
|
||||||
@@ -339,17 +415,29 @@ public final class HotwordAudioStream implements Parcelable {
|
|||||||
private AudioTimestamp mTimestamp;
|
private AudioTimestamp mTimestamp;
|
||||||
@NonNull
|
@NonNull
|
||||||
private PersistableBundle mMetadata;
|
private PersistableBundle mMetadata;
|
||||||
|
@NonNull
|
||||||
|
private byte[] mInitialAudio;
|
||||||
|
|
||||||
private long mBuilderFieldsSet = 0L;
|
private long mBuilderFieldsSet = 0L;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new Builder.
|
* Creates a new Builder.
|
||||||
*
|
*
|
||||||
* @param audioFormat The {@link AudioFormat} of the audio stream.
|
* @param audioFormat
|
||||||
* @param audioStreamParcelFileDescriptor This stream starts with the audio bytes used for
|
* The {@link AudioFormat} of the audio stream.
|
||||||
* hotword detection, but continues streaming
|
* @param audioStreamParcelFileDescriptor
|
||||||
* the audio until the stream is shutdown by the
|
* This stream typically starts with the audio bytes used for hotword detection, but
|
||||||
* {@link HotwordDetectionService}.
|
* continues streaming the audio (e.g., with the query) until the stream is shutdown by
|
||||||
|
* the {@link HotwordDetectionService}. The data format is expected to match
|
||||||
|
* {@link #getAudioFormat()}.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* Alternatively, the {@link HotwordDetectionService} may use {@link #getInitialAudio()}
|
||||||
|
* to pass the start of the audio instead of streaming it here. This may prevent added
|
||||||
|
* latency caused by the streaming buffer
|
||||||
|
* (see {@link #KEY_AUDIO_STREAM_COPY_BUFFER_LENGTH_BYTES}) not being large enough to
|
||||||
|
* handle this initial chunk of audio.
|
||||||
|
* </p>
|
||||||
*/
|
*/
|
||||||
@UnsupportedAppUsage
|
@UnsupportedAppUsage
|
||||||
public Builder(
|
public Builder(
|
||||||
@@ -376,9 +464,18 @@ public final class HotwordAudioStream implements Parcelable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This stream starts with the audio bytes used for hotword detection, but continues
|
* This stream typically starts with the audio bytes used for hotword detection, but
|
||||||
* streaming
|
* continues streaming the audio (e.g., with the query) until the stream is shutdown by the
|
||||||
* the audio until the stream is shutdown by the {@link HotwordDetectionService}.
|
* {@link HotwordDetectionService}. The data format is expected to match
|
||||||
|
* {@link #getAudioFormat()}.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* Alternatively, the {@link HotwordDetectionService} may use {@link #getInitialAudio()}
|
||||||
|
* to pass the start of the audio instead of streaming it here. This may prevent added
|
||||||
|
* latency caused by the streaming buffer
|
||||||
|
* (see {@link #KEY_AUDIO_STREAM_COPY_BUFFER_LENGTH_BYTES}) not being large enough to handle
|
||||||
|
* this initial chunk of audio.
|
||||||
|
* </p>
|
||||||
*/
|
*/
|
||||||
@UnsupportedAppUsage
|
@UnsupportedAppUsage
|
||||||
@NonNull
|
@NonNull
|
||||||
@@ -428,12 +525,33 @@ public final class HotwordAudioStream implements Parcelable {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The start of the audio used for hotword detection. The data format is expected to match
|
||||||
|
* {@link #getAudioFormat()}.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* The {@link HotwordDetectionService} may use this instead of using
|
||||||
|
* {@link #getAudioStreamParcelFileDescriptor()} to stream these initial bytes of audio.
|
||||||
|
* This may prevent added latency caused by the streaming buffer (see
|
||||||
|
* {@link #KEY_AUDIO_STREAM_COPY_BUFFER_LENGTH_BYTES}) not being large enough to handle this
|
||||||
|
* initial chunk of audio.
|
||||||
|
* </p>
|
||||||
|
*/
|
||||||
|
@UnsupportedAppUsage
|
||||||
|
@NonNull
|
||||||
|
public Builder setInitialAudio(@NonNull byte[] value) {
|
||||||
|
checkNotUsed();
|
||||||
|
mBuilderFieldsSet |= 0x10;
|
||||||
|
mInitialAudio = value;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
/** Builds the instance. This builder should not be touched after calling this! */
|
/** Builds the instance. This builder should not be touched after calling this! */
|
||||||
@UnsupportedAppUsage
|
@UnsupportedAppUsage
|
||||||
@NonNull
|
@NonNull
|
||||||
public HotwordAudioStream build() {
|
public HotwordAudioStream build() {
|
||||||
checkNotUsed();
|
checkNotUsed();
|
||||||
mBuilderFieldsSet |= 0x10; // Mark builder used
|
mBuilderFieldsSet |= 0x20; // Mark builder used
|
||||||
|
|
||||||
if ((mBuilderFieldsSet & 0x4) == 0) {
|
if ((mBuilderFieldsSet & 0x4) == 0) {
|
||||||
mTimestamp = defaultTimestamp();
|
mTimestamp = defaultTimestamp();
|
||||||
@@ -441,16 +559,20 @@ public final class HotwordAudioStream implements Parcelable {
|
|||||||
if ((mBuilderFieldsSet & 0x8) == 0) {
|
if ((mBuilderFieldsSet & 0x8) == 0) {
|
||||||
mMetadata = defaultMetadata();
|
mMetadata = defaultMetadata();
|
||||||
}
|
}
|
||||||
|
if ((mBuilderFieldsSet & 0x10) == 0) {
|
||||||
|
mInitialAudio = defaultInitialAudio();
|
||||||
|
}
|
||||||
HotwordAudioStream o = new HotwordAudioStream(
|
HotwordAudioStream o = new HotwordAudioStream(
|
||||||
mAudioFormat,
|
mAudioFormat,
|
||||||
mAudioStreamParcelFileDescriptor,
|
mAudioStreamParcelFileDescriptor,
|
||||||
mTimestamp,
|
mTimestamp,
|
||||||
mMetadata);
|
mMetadata,
|
||||||
|
mInitialAudio);
|
||||||
return o;
|
return o;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkNotUsed() {
|
private void checkNotUsed() {
|
||||||
if ((mBuilderFieldsSet & 0x10) != 0) {
|
if ((mBuilderFieldsSet & 0x20) != 0) {
|
||||||
throw new IllegalStateException(
|
throw new IllegalStateException(
|
||||||
"This Builder should not be reused. Use a new Builder instance instead");
|
"This Builder should not be reused. Use a new Builder instance instead");
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user