add audioCapabilities to SoundTrigger properties
Bug: 146363190
Test: atest SoundTriggerMiddlewareImplTest
&& GTS assist test suite
Change-Id: Ib8a3b809fa6738152d31499b5072a2e9d39ab0a0
diff --git a/core/java/android/hardware/soundtrigger/ConversionUtil.java b/core/java/android/hardware/soundtrigger/ConversionUtil.java
index 43f3787..d43a619 100644
--- a/core/java/android/hardware/soundtrigger/ConversionUtil.java
+++ b/core/java/android/hardware/soundtrigger/ConversionUtil.java
@@ -20,6 +20,7 @@
import android.hardware.soundtrigger.ModelParams;
import android.media.AudioFormat;
import android.media.audio.common.AudioConfig;
+import android.media.soundtrigger_middleware.AudioCapabilities;
import android.media.soundtrigger_middleware.ConfidenceLevel;
import android.media.soundtrigger_middleware.ModelParameterRange;
import android.media.soundtrigger_middleware.Phrase;
@@ -56,7 +57,8 @@
properties.maxBufferMs,
properties.concurrentCapture,
properties.powerConsumptionMw,
- properties.triggerInEvent
+ properties.triggerInEvent,
+ aidl2apiAudioCapabilities(properties.audioCapabilities)
);
}
@@ -145,6 +147,7 @@
apiConfig.keyphrases[i]);
}
aidlConfig.data = Arrays.copyOf(apiConfig.data, apiConfig.data.length);
+ aidlConfig.audioCapabilities = api2aidlAudioCapabilities(apiConfig.audioCapabilities);
return aidlConfig;
}
@@ -326,4 +329,26 @@
}
return new SoundTrigger.ModelParamRange(aidlRange.minInclusive, aidlRange.maxInclusive);
}
+
+ public static int aidl2apiAudioCapabilities(int aidlCapabilities) {
+ int result = 0;
+ if ((aidlCapabilities & AudioCapabilities.ECHO_CANCELLATION) != 0) {
+ result |= SoundTrigger.ModuleProperties.CAPABILITY_ECHO_CANCELLATION;
+ }
+ if ((aidlCapabilities & AudioCapabilities.NOISE_SUPPRESSION) != 0) {
+ result |= SoundTrigger.ModuleProperties.CAPABILITY_NOISE_SUPPRESSION;
+ }
+ return result;
+ }
+
+ public static int api2aidlAudioCapabilities(int apiCapabilities) {
+ int result = 0;
+ if ((apiCapabilities & SoundTrigger.ModuleProperties.CAPABILITY_ECHO_CANCELLATION) != 0) {
+ result |= AudioCapabilities.ECHO_CANCELLATION;
+ }
+ if ((apiCapabilities & SoundTrigger.ModuleProperties.CAPABILITY_NOISE_SUPPRESSION) != 0) {
+ result |= AudioCapabilities.NOISE_SUPPRESSION;
+ }
+ return result;
+ }
}
diff --git a/core/java/android/hardware/soundtrigger/SoundTrigger.java b/core/java/android/hardware/soundtrigger/SoundTrigger.java
index d872009..60e466e 100644
--- a/core/java/android/hardware/soundtrigger/SoundTrigger.java
+++ b/core/java/android/hardware/soundtrigger/SoundTrigger.java
@@ -24,6 +24,7 @@
import static java.util.Objects.requireNonNull;
+import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
@@ -42,6 +43,8 @@
import android.os.ServiceManager;
import android.util.Log;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.UUID;
@@ -83,6 +86,30 @@
*
****************************************************************************/
public static final class ModuleProperties implements Parcelable {
+
+ /**
+ * Bit field values of AudioCapabilities supported by the implemented HAL
+ * driver.
+ * @hide
+ */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(flag = true, prefix = { "AUDIO_CAPABILITY_" }, value = {
+ CAPABILITY_ECHO_CANCELLATION,
+ CAPABILITY_NOISE_SUPPRESSION
+ })
+ public @interface AudioCapabilities {}
+
+ /**
+ * If set the underlying module supports AEC.
+ * Describes bit field {@link ModuleProperties#audioCapabilities}
+ */
+ public static final int CAPABILITY_ECHO_CANCELLATION = 0x1;
+ /**
+ * If set, the underlying module supports noise suppression.
+ * Describes bit field {@link ModuleProperties#audioCapabilities}
+ */
+ public static final int CAPABILITY_NOISE_SUPPRESSION = 0x2;
+
/** Unique module ID provided by the native service */
public final int id;
@@ -137,12 +164,19 @@
* recognition callback event */
public final boolean returnsTriggerInEvent;
+ /**
+ * Bit field encoding of the AudioCapabilities
+ * supported by the firmware.
+ */
+ @AudioCapabilities
+ public final int audioCapabilities;
+
ModuleProperties(int id, @NonNull String implementor, @NonNull String description,
@NonNull String uuid, int version, @NonNull String supportedModelArch,
int maxSoundModels, int maxKeyphrases, int maxUsers, int recognitionModes,
boolean supportsCaptureTransition, int maxBufferMs,
boolean supportsConcurrentCapture, int powerConsumptionMw,
- boolean returnsTriggerInEvent) {
+ boolean returnsTriggerInEvent, int audioCapabilities) {
this.id = id;
this.implementor = requireNonNull(implementor);
this.description = requireNonNull(description);
@@ -158,6 +192,7 @@
this.supportsConcurrentCapture = supportsConcurrentCapture;
this.powerConsumptionMw = powerConsumptionMw;
this.returnsTriggerInEvent = returnsTriggerInEvent;
+ this.audioCapabilities = audioCapabilities;
}
public static final @android.annotation.NonNull Parcelable.Creator<ModuleProperties> CREATOR
@@ -187,10 +222,11 @@
boolean supportsConcurrentCapture = in.readByte() == 1;
int powerConsumptionMw = in.readInt();
boolean returnsTriggerInEvent = in.readByte() == 1;
+ int audioCapabilities = in.readInt();
return new ModuleProperties(id, implementor, description, uuid, version,
supportedModelArch, maxSoundModels, maxKeyphrases, maxUsers, recognitionModes,
supportsCaptureTransition, maxBufferMs, supportsConcurrentCapture,
- powerConsumptionMw, returnsTriggerInEvent);
+ powerConsumptionMw, returnsTriggerInEvent, audioCapabilities);
}
@Override
@@ -210,6 +246,7 @@
dest.writeByte((byte) (supportsConcurrentCapture ? 1 : 0));
dest.writeInt(powerConsumptionMw);
dest.writeByte((byte) (returnsTriggerInEvent ? 1 : 0));
+ dest.writeInt(audioCapabilities);
}
@Override
@@ -227,7 +264,8 @@
+ ", supportsCaptureTransition=" + supportsCaptureTransition + ", maxBufferMs="
+ maxBufferMs + ", supportsConcurrentCapture=" + supportsConcurrentCapture
+ ", powerConsumptionMw=" + powerConsumptionMw
- + ", returnsTriggerInEvent=" + returnsTriggerInEvent + "]";
+ + ", returnsTriggerInEvent=" + returnsTriggerInEvent
+ + ", audioCapabilities=" + audioCapabilities + "]";
}
}
@@ -1049,13 +1087,27 @@
@NonNull
public final byte[] data;
- @UnsupportedAppUsage
+ /**
+ * Bit field encoding of the AudioCapabilities
+ * supported by the firmware.
+ */
+ @ModuleProperties.AudioCapabilities
+ public final int audioCapabilities;
+
public RecognitionConfig(boolean captureRequested, boolean allowMultipleTriggers,
- @Nullable KeyphraseRecognitionExtra[] keyphrases, @Nullable byte[] data) {
+ @Nullable KeyphraseRecognitionExtra[] keyphrases, @Nullable byte[] data,
+ int audioCapabilities) {
this.captureRequested = captureRequested;
this.allowMultipleTriggers = allowMultipleTriggers;
this.keyphrases = keyphrases != null ? keyphrases : new KeyphraseRecognitionExtra[0];
this.data = data != null ? data : new byte[0];
+ this.audioCapabilities = audioCapabilities;
+ }
+
+ @UnsupportedAppUsage
+ public RecognitionConfig(boolean captureRequested, boolean allowMultipleTriggers,
+ @Nullable KeyphraseRecognitionExtra[] keyphrases, @Nullable byte[] data) {
+ this(captureRequested, allowMultipleTriggers, keyphrases, data, 0);
}
public static final @android.annotation.NonNull Parcelable.Creator<RecognitionConfig> CREATOR
@@ -1075,7 +1127,9 @@
KeyphraseRecognitionExtra[] keyphrases =
in.createTypedArray(KeyphraseRecognitionExtra.CREATOR);
byte[] data = in.readBlob();
- return new RecognitionConfig(captureRequested, allowMultipleTriggers, keyphrases, data);
+ int audioCapabilities = in.readInt();
+ return new RecognitionConfig(captureRequested, allowMultipleTriggers, keyphrases, data,
+ audioCapabilities);
}
@Override
@@ -1084,6 +1138,7 @@
dest.writeByte((byte) (allowMultipleTriggers ? 1 : 0));
dest.writeTypedArray(keyphrases, flags);
dest.writeBlob(data);
+ dest.writeInt(audioCapabilities);
}
@Override
@@ -1095,7 +1150,8 @@
public String toString() {
return "RecognitionConfig [captureRequested=" + captureRequested
+ ", allowMultipleTriggers=" + allowMultipleTriggers + ", keyphrases="
- + Arrays.toString(keyphrases) + ", data=" + Arrays.toString(data) + "]";
+ + Arrays.toString(keyphrases) + ", data=" + Arrays.toString(data)
+ + ", audioCapabilities=" + Integer.toHexString(audioCapabilities) + "]";
}
}
diff --git a/core/java/android/service/voice/AlwaysOnHotwordDetector.java b/core/java/android/service/voice/AlwaysOnHotwordDetector.java
index d7c6d0f..0f33998 100644
--- a/core/java/android/service/voice/AlwaysOnHotwordDetector.java
+++ b/core/java/android/service/voice/AlwaysOnHotwordDetector.java
@@ -119,7 +119,9 @@
@IntDef(flag = true, prefix = { "RECOGNITION_FLAG_" }, value = {
RECOGNITION_FLAG_NONE,
RECOGNITION_FLAG_CAPTURE_TRIGGER_AUDIO,
- RECOGNITION_FLAG_ALLOW_MULTIPLE_TRIGGERS
+ RECOGNITION_FLAG_ALLOW_MULTIPLE_TRIGGERS,
+ RECOGNITION_FLAG_ENABLE_AUDIO_ECHO_CANCELLATION,
+ RECOGNITION_FLAG_ENABLE_AUDIO_NOISE_SUPPRESSION,
})
public @interface RecognitionFlags {}
@@ -144,6 +146,26 @@
*/
public static final int RECOGNITION_FLAG_ALLOW_MULTIPLE_TRIGGERS = 0x2;
+ /**
+ * Audio capabilities flag for {@link #startRecognition(int)} that indicates
+ * if the underlying recognition should use AEC.
+ * This capability may or may not be supported by the system, and support can be queried
+ * by calling {@link #getSupportedAudioCapabilities()}. The corresponding capabilities field for
+ * this flag is {@link #AUDIO_CAPABILITY_ECHO_CANCELLATION}. If this flag is passed without the
+ * audio capability supported, there will be no audio effect applied.
+ */
+ public static final int RECOGNITION_FLAG_ENABLE_AUDIO_ECHO_CANCELLATION = 0x4;
+
+ /**
+ * Audio capabilities flag for {@link #startRecognition(int)} that indicates
+ * if the underlying recognition should use noise suppression.
+ * This capability may or may not be supported by the system, and support can be queried
+ * by calling {@link #getSupportedAudioCapabilities()}. The corresponding capabilities field for
+ * this flag is {@link #AUDIO_CAPABILITY_NOISE_SUPPRESSION}. If this flag is passed without the
+ * audio capability supported, there will be no audio effect applied.
+ */
+ public static final int RECOGNITION_FLAG_ENABLE_AUDIO_NOISE_SUPPRESSION = 0x8;
+
//---- Recognition mode flags. Return codes for getSupportedRecognitionModes() ----//
// Must be kept in sync with the related attribute defined as searchKeyphraseRecognitionFlags.
@@ -168,6 +190,30 @@
public static final int RECOGNITION_MODE_USER_IDENTIFICATION
= SoundTrigger.RECOGNITION_MODE_USER_IDENTIFICATION;
+ //-- Audio capabilities. Values in returned bit field for getSupportedAudioCapabilities() --//
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(flag = true, prefix = { "AUDIO_CAPABILITY_" }, value = {
+ AUDIO_CAPABILITY_ECHO_CANCELLATION,
+ AUDIO_CAPABILITY_NOISE_SUPPRESSION,
+ })
+ public @interface AudioCapabilities {}
+
+ /**
+ * If set the underlying module supports AEC.
+ * Returned by {@link #getSupportedAudioCapabilities()}
+ */
+ public static final int AUDIO_CAPABILITY_ECHO_CANCELLATION =
+ SoundTrigger.ModuleProperties.CAPABILITY_ECHO_CANCELLATION;
+
+ /**
+ * If set, the underlying module supports noise suppression.
+ * Returned by {@link #getSupportedAudioCapabilities()}
+ */
+ public static final int AUDIO_CAPABILITY_NOISE_SUPPRESSION =
+ SoundTrigger.ModuleProperties.CAPABILITY_NOISE_SUPPRESSION;
+
/** @hide */
@Retention(RetentionPolicy.SOURCE)
@IntDef(flag = true, prefix = { "MODEL_PARAM_" }, value = {
@@ -448,6 +494,37 @@
}
/**
+ * Get the audio capabilities supported by the platform which can be enabled when
+ * starting a recognition.
+ *
+ * @see #AUDIO_CAPABILITY_ECHO_CANCELLATION
+ * @see #AUDIO_CAPABILITY_NOISE_SUPPRESSION
+ *
+ * @return Bit field encoding of the AudioCapabilities supported.
+ */
+ @AudioCapabilities
+ public int getSupportedAudioCapabilities() {
+ if (DBG) Slog.d(TAG, "getSupportedAudioCapabilities()");
+ synchronized (mLock) {
+ return getSupportedAudioCapabilitiesLocked();
+ }
+ }
+
+ private int getSupportedAudioCapabilitiesLocked() {
+ try {
+ ModuleProperties properties =
+ mModelManagementService.getDspModuleProperties(mVoiceInteractionService);
+ if (properties != null) {
+ return properties.audioCapabilities;
+ }
+
+ return 0;
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Starts recognition for the associated keyphrase.
*
* @see #RECOGNITION_FLAG_CAPTURE_TRIGGER_AUDIO
@@ -711,12 +788,21 @@
(recognitionFlags&RECOGNITION_FLAG_CAPTURE_TRIGGER_AUDIO) != 0;
boolean allowMultipleTriggers =
(recognitionFlags&RECOGNITION_FLAG_ALLOW_MULTIPLE_TRIGGERS) != 0;
+
+ int audioCapabilities = 0;
+ if ((recognitionFlags & RECOGNITION_FLAG_ENABLE_AUDIO_ECHO_CANCELLATION) != 0) {
+ audioCapabilities |= AUDIO_CAPABILITY_ECHO_CANCELLATION;
+ }
+ if ((recognitionFlags & RECOGNITION_FLAG_ENABLE_AUDIO_NOISE_SUPPRESSION) != 0) {
+ audioCapabilities |= AUDIO_CAPABILITY_NOISE_SUPPRESSION;
+ }
+
int code = STATUS_ERROR;
try {
code = mModelManagementService.startRecognition(mVoiceInteractionService,
mKeyphraseMetadata.id, mLocale.toLanguageTag(), mInternalCallback,
new RecognitionConfig(captureTriggerAudio, allowMultipleTriggers,
- recognitionExtra, null /* additional data */));
+ recognitionExtra, null /* additional data */, audioCapabilities));
} catch (RemoteException e) {
Slog.w(TAG, "RemoteException in startRecognition!", e);
}