summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Nicholas Ambur <nambur@google.com> 2020-01-10 17:08:00 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2020-01-10 17:08:00 +0000
commitb2a5c297964caccb07345beef5ca6fd9a583a7df (patch)
treef00fceeda8a5343eedcb1803e36380bab01160e0
parent9785b64c1194ab0a69c10310ac72830c9184f5e3 (diff)
parentf94db1c8228edbbb3efc94dee29f5f789623be3e (diff)
Merge "add parameter control to AlwaysOnHotwordDetector"
-rw-r--r--api/current.txt9
-rwxr-xr-xapi/system-current.txt5
-rw-r--r--core/java/android/hardware/soundtrigger/ConversionUtil.java3
-rw-r--r--core/java/android/hardware/soundtrigger/SoundTrigger.java68
-rw-r--r--core/java/android/service/voice/AlwaysOnHotwordDetector.java181
-rw-r--r--core/java/com/android/internal/app/ISoundTriggerService.aidl4
-rw-r--r--core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl44
-rw-r--r--media/java/android/media/soundtrigger/SoundTriggerManager.java13
-rw-r--r--services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java110
-rw-r--r--services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerInternal.java62
-rw-r--r--services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java27
-rw-r--r--services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java51
12 files changed, 490 insertions, 87 deletions
diff --git a/api/current.txt b/api/current.txt
index edb31dfdf444..b5448f906e17 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -42675,9 +42675,13 @@ package android.service.voice {
method public android.content.Intent createEnrollIntent();
method public android.content.Intent createReEnrollIntent();
method public android.content.Intent createUnEnrollIntent();
+ method public int getParameter(int);
method public int getSupportedRecognitionModes();
+ method @Nullable public android.service.voice.AlwaysOnHotwordDetector.ModelParamRange queryParameter(int);
+ method public int setParameter(int, int);
method public boolean startRecognition(int);
method public boolean stopRecognition();
+ field public static final int MODEL_PARAM_THRESHOLD_FACTOR = 0; // 0x0
field public static final int RECOGNITION_FLAG_ALLOW_MULTIPLE_TRIGGERS = 2; // 0x2
field public static final int RECOGNITION_FLAG_CAPTURE_TRIGGER_AUDIO = 1; // 0x1
field public static final int RECOGNITION_MODE_USER_IDENTIFICATION = 2; // 0x2
@@ -42702,6 +42706,11 @@ package android.service.voice {
method @Nullable public byte[] getTriggerAudio();
}
+ public static final class AlwaysOnHotwordDetector.ModelParamRange {
+ method public int end();
+ method public int start();
+ }
+
public class VoiceInteractionService extends android.app.Service {
ctor public VoiceInteractionService();
method public final android.service.voice.AlwaysOnHotwordDetector createAlwaysOnHotwordDetector(String, java.util.Locale, android.service.voice.AlwaysOnHotwordDetector.Callback);
diff --git a/api/system-current.txt b/api/system-current.txt
index d2fa2c05961b..63a8b4d6ca91 100755
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -3546,7 +3546,6 @@ package android.hardware.soundtrigger {
}
public static final class SoundTrigger.ModelParamRange implements android.os.Parcelable {
- method public int describeContents();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.hardware.soundtrigger.SoundTrigger.ModelParamRange> CREATOR;
field public final int end;
@@ -4368,9 +4367,9 @@ package android.media.soundtrigger {
method public int getDetectionServiceOperationsTimeout();
method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_SOUND_TRIGGER) public android.media.soundtrigger.SoundTriggerManager.Model getModel(java.util.UUID);
method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_SOUND_TRIGGER) public android.hardware.soundtrigger.SoundTrigger.ModuleProperties getModuleProperties();
- method @RequiresPermission(android.Manifest.permission.MANAGE_SOUND_TRIGGER) public int getParameter(@NonNull java.util.UUID, int) throws java.lang.IllegalArgumentException, java.lang.UnsupportedOperationException;
+ method @RequiresPermission(android.Manifest.permission.MANAGE_SOUND_TRIGGER) public int getParameter(@NonNull java.util.UUID, int);
method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_SOUND_TRIGGER) public android.hardware.soundtrigger.SoundTrigger.ModelParamRange queryParameter(@Nullable java.util.UUID, int);
- method @RequiresPermission(android.Manifest.permission.MANAGE_SOUND_TRIGGER) public int setParameter(@Nullable java.util.UUID, int, int) throws java.lang.IllegalArgumentException, java.lang.UnsupportedOperationException;
+ method @RequiresPermission(android.Manifest.permission.MANAGE_SOUND_TRIGGER) public int setParameter(@Nullable java.util.UUID, int, int);
method @RequiresPermission(android.Manifest.permission.MANAGE_SOUND_TRIGGER) public void updateModel(android.media.soundtrigger.SoundTriggerManager.Model);
}
diff --git a/core/java/android/hardware/soundtrigger/ConversionUtil.java b/core/java/android/hardware/soundtrigger/ConversionUtil.java
index 8231c58a105e..d2721018ef52 100644
--- a/core/java/android/hardware/soundtrigger/ConversionUtil.java
+++ b/core/java/android/hardware/soundtrigger/ConversionUtil.java
@@ -16,6 +16,7 @@
package android.hardware.soundtrigger;
+import android.annotation.Nullable;
import android.hardware.soundtrigger.ModelParams;
import android.media.AudioFormat;
import android.media.audio.common.AudioConfig;
@@ -32,8 +33,6 @@ import android.media.soundtrigger_middleware.SoundModel;
import android.media.soundtrigger_middleware.SoundTriggerModuleDescriptor;
import android.media.soundtrigger_middleware.SoundTriggerModuleProperties;
-import android.annotation.Nullable;
-
import java.util.Arrays;
import java.util.UUID;
diff --git a/core/java/android/hardware/soundtrigger/SoundTrigger.java b/core/java/android/hardware/soundtrigger/SoundTrigger.java
index 55505ba2e278..2f0752b7c209 100644
--- a/core/java/android/hardware/soundtrigger/SoundTrigger.java
+++ b/core/java/android/hardware/soundtrigger/SoundTrigger.java
@@ -588,19 +588,19 @@ public class SoundTrigger {
}
}
- /*****************************************************************************
+ /**
* A ModelParamRange is a representation of supported parameter range for a
* given loaded model.
- ****************************************************************************/
+ */
public static final class ModelParamRange implements Parcelable {
/**
- * start of supported range inclusive
+ * The inclusive start of supported range.
*/
public final int start;
/**
- * end of supported range inclusive
+ * The inclusive end of supported range.
*/
public final int end;
@@ -609,31 +609,65 @@ public class SoundTrigger {
this.end = end;
}
+ /** @hide */
private ModelParamRange(@NonNull Parcel in) {
this.start = in.readInt();
this.end = in.readInt();
}
@NonNull
- public static final Creator<ModelParamRange> CREATOR = new Creator<ModelParamRange>() {
- @Override
- @NonNull
- public ModelParamRange createFromParcel(@NonNull Parcel in) {
- return new ModelParamRange(in);
- }
-
- @Override
- @NonNull
- public ModelParamRange[] newArray(int size) {
- return new ModelParamRange[size];
- }
- };
+ public static final Creator<ModelParamRange> CREATOR =
+ new Creator<ModelParamRange>() {
+ @Override
+ @NonNull
+ public ModelParamRange createFromParcel(@NonNull Parcel in) {
+ return new ModelParamRange(in);
+ }
+
+ @Override
+ @NonNull
+ public ModelParamRange[] newArray(int size) {
+ return new ModelParamRange[size];
+ }
+ };
+ /** @hide */
@Override
public int describeContents() {
return 0;
}
+ /** @hide */
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + (start);
+ result = prime * result + (end);
+ return result;
+ }
+
+ @Override
+ public boolean equals(@Nullable Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ ModelParamRange other = (ModelParamRange) obj;
+ if (start != other.start) {
+ return false;
+ }
+ if (end != other.end) {
+ return false;
+ }
+ return true;
+ }
+
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeInt(start);
diff --git a/core/java/android/service/voice/AlwaysOnHotwordDetector.java b/core/java/android/service/voice/AlwaysOnHotwordDetector.java
index 67925bfea2c2..d7c6d0f265c6 100644
--- a/core/java/android/service/voice/AlwaysOnHotwordDetector.java
+++ b/core/java/android/service/voice/AlwaysOnHotwordDetector.java
@@ -168,6 +168,22 @@ public class AlwaysOnHotwordDetector {
public static final int RECOGNITION_MODE_USER_IDENTIFICATION
= SoundTrigger.RECOGNITION_MODE_USER_IDENTIFICATION;
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(flag = true, prefix = { "MODEL_PARAM_" }, value = {
+ MODEL_PARAM_THRESHOLD_FACTOR,
+ })
+ public @interface ModelParams {}
+
+ /**
+ * Controls the sensitivity threshold adjustment factor for a given model.
+ * Negative value corresponds to less sensitive model (high threshold) and
+ * a positive value corresponds to a more sensitive model (low threshold).
+ * Default value is 0.
+ */
+ public static final int MODEL_PARAM_THRESHOLD_FACTOR =
+ android.hardware.soundtrigger.ModelParams.THRESHOLD_FACTOR;
+
static final String TAG = "AlwaysOnHotwordDetector";
static final boolean DBG = false;
@@ -198,6 +214,53 @@ public class AlwaysOnHotwordDetector {
private int mAvailability = STATE_NOT_READY;
/**
+ * A ModelParamRange is a representation of supported parameter range for a
+ * given loaded model.
+ */
+ public static final class ModelParamRange {
+ private final SoundTrigger.ModelParamRange mModelParamRange;
+
+ /** @hide */
+ ModelParamRange(SoundTrigger.ModelParamRange modelParamRange) {
+ mModelParamRange = modelParamRange;
+ }
+
+ /**
+ * The inclusive start of supported range.
+ *
+ * @return start of range
+ */
+ public int start() {
+ return mModelParamRange.start;
+ }
+
+ /**
+ * The inclusive end of supported range.
+ *
+ * @return end of range
+ */
+ public int end() {
+ return mModelParamRange.end;
+ }
+
+ @Override
+ @NonNull
+ public String toString() {
+ return mModelParamRange.toString();
+ }
+
+ @Override
+ public boolean equals(@Nullable Object obj) {
+ return mModelParamRange.equals(obj);
+ }
+
+ @Override
+ public int hashCode() {
+ return mModelParamRange.hashCode();
+ }
+ }
+
+ /**
* Additional payload for {@link Callback#onDetected}.
*/
public static class EventPayload {
@@ -445,6 +508,83 @@ public class AlwaysOnHotwordDetector {
}
/**
+ * Set a model specific {@link ModelParams} with the given value. This
+ * parameter will keep its value for the duration the model is loaded regardless of starting and
+ * stopping recognition. Once the model is unloaded, the value will be lost.
+ * {@link AlwaysOnHotwordDetector#queryParameter} should be checked first before calling this
+ * method.
+ *
+ * @param modelParam {@link ModelParams}
+ * @param value Value to set
+ * @return - {@link SoundTrigger#STATUS_OK} in case of success
+ * - {@link SoundTrigger#STATUS_NO_INIT} if the native service cannot be reached
+ * - {@link SoundTrigger#STATUS_BAD_VALUE} invalid input parameter
+ * - {@link SoundTrigger#STATUS_INVALID_OPERATION} if the call is out of sequence or
+ * if API is not supported by HAL
+ */
+ public int setParameter(@ModelParams int modelParam, int value) {
+ if (DBG) {
+ Slog.d(TAG, "setParameter(" + modelParam + ", " + value + ")");
+ }
+
+ synchronized (mLock) {
+ if (mAvailability == STATE_INVALID) {
+ throw new IllegalStateException("setParameter called on an invalid detector");
+ }
+
+ return setParameterLocked(modelParam, value);
+ }
+ }
+
+ /**
+ * Get a model specific {@link ModelParams}. This parameter will keep its value
+ * for the duration the model is loaded regardless of starting and stopping recognition.
+ * Once the model is unloaded, the value will be lost. If the value is not set, a default
+ * value is returned. See {@link ModelParams} for parameter default values.
+ * {@link AlwaysOnHotwordDetector#queryParameter} should be checked first before
+ * calling this method.
+ *
+ * @param modelParam {@link ModelParams}
+ * @return value of parameter
+ */
+ public int getParameter(@ModelParams int modelParam) {
+ if (DBG) {
+ Slog.d(TAG, "getParameter(" + modelParam + ")");
+ }
+
+ synchronized (mLock) {
+ if (mAvailability == STATE_INVALID) {
+ throw new IllegalStateException("getParameter called on an invalid detector");
+ }
+
+ return getParameterLocked(modelParam);
+ }
+ }
+
+ /**
+ * Determine if parameter control is supported for the given model handle.
+ * This method should be checked prior to calling {@link AlwaysOnHotwordDetector#setParameter}
+ * or {@link AlwaysOnHotwordDetector#getParameter}.
+ *
+ * @param modelParam {@link ModelParams}
+ * @return supported range of parameter, null if not supported
+ */
+ @Nullable
+ public ModelParamRange queryParameter(@ModelParams int modelParam) {
+ if (DBG) {
+ Slog.d(TAG, "queryParameter(" + modelParam + ")");
+ }
+
+ synchronized (mLock) {
+ if (mAvailability == STATE_INVALID) {
+ throw new IllegalStateException("queryParameter called on an invalid detector");
+ }
+
+ return queryParameterLocked(modelParam);
+ }
+ }
+
+ /**
* Creates an intent to start the enrollment for the associated keyphrase.
* This intent must be invoked using {@link Context#startForegroundService(Intent)}.
* Starting re-enrollment is only valid if the keyphrase is un-enrolled,
@@ -601,6 +741,47 @@ public class AlwaysOnHotwordDetector {
return code;
}
+ private int setParameterLocked(@ModelParams int modelParam, int value) {
+ try {
+ int code = mModelManagementService.setParameter(mVoiceInteractionService,
+ mKeyphraseMetadata.id, modelParam, value);
+
+ if (code != STATUS_OK) {
+ Slog.w(TAG, "setParameter failed with error code " + code);
+ }
+
+ return code;
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ private int getParameterLocked(@ModelParams int modelParam) {
+ try {
+ return mModelManagementService.getParameter(mVoiceInteractionService,
+ mKeyphraseMetadata.id, modelParam);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ @Nullable
+ private ModelParamRange queryParameterLocked(@ModelParams int modelParam) {
+ try {
+ SoundTrigger.ModelParamRange modelParamRange =
+ mModelManagementService.queryParameter(mVoiceInteractionService,
+ mKeyphraseMetadata.id, modelParam);
+
+ if (modelParamRange == null) {
+ return null;
+ }
+
+ return new ModelParamRange(modelParamRange);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
private void notifyStateChangedLocked() {
Message message = Message.obtain(mHandler, MSG_AVAILABILITY_CHANGED);
message.arg1 = mAvailability;
diff --git a/core/java/com/android/internal/app/ISoundTriggerService.aidl b/core/java/com/android/internal/app/ISoundTriggerService.aidl
index d94294f0aa22..74bfb963c6b0 100644
--- a/core/java/com/android/internal/app/ISoundTriggerService.aidl
+++ b/core/java/com/android/internal/app/ISoundTriggerService.aidl
@@ -61,10 +61,6 @@ interface ISoundTriggerService {
int setParameter(in ParcelUuid soundModelId, in ModelParams modelParam,
int value);
- /**
- * @throws UnsupportedOperationException if hal or model do not support this API.
- * @throws IllegalArgumentException if invalid model handle or parameter is passed.
- */
int getParameter(in ParcelUuid soundModelId, in ModelParams modelParam);
@nullable SoundTrigger.ModelParamRange queryParameter(in ParcelUuid soundModelId,
diff --git a/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl b/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl
index f462f5d2571d..be2d1d60e9a2 100644
--- a/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl
+++ b/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl
@@ -26,6 +26,7 @@ import com.android.internal.app.IVoiceInteractionSessionShowCallback;
import com.android.internal.app.IVoiceInteractor;
import com.android.internal.app.IVoiceInteractionSessionListener;
import android.hardware.soundtrigger.IRecognitionStatusCallback;
+import android.hardware.soundtrigger.ModelParams;
import android.hardware.soundtrigger.SoundTrigger;
import android.service.voice.IVoiceInteractionService;
import android.service.voice.IVoiceInteractionSession;
@@ -91,6 +92,49 @@ interface IVoiceInteractionManagerService {
*/
int stopRecognition(in IVoiceInteractionService service, int keyphraseId,
in IRecognitionStatusCallback callback);
+ /**
+ * Set a model specific ModelParams with the given value. This
+ * parameter will keep its value for the duration the model is loaded regardless of starting and
+ * stopping recognition. Once the model is unloaded, the value will be lost.
+ * queryParameter should be checked first before calling this method.
+ *
+ * @param service The current VoiceInteractionService.
+ * @param keyphraseId The unique identifier for the keyphrase.
+ * @param modelParam ModelParams
+ * @param value Value to set
+ * @return - {@link SoundTrigger#STATUS_OK} in case of success
+ * - {@link SoundTrigger#STATUS_NO_INIT} if the native service cannot be reached
+ * - {@link SoundTrigger#STATUS_BAD_VALUE} invalid input parameter
+ * - {@link SoundTrigger#STATUS_INVALID_OPERATION} if the call is out of sequence or
+ * if API is not supported by HAL
+ */
+ int setParameter(in IVoiceInteractionService service, int keyphraseId,
+ in ModelParams modelParam, int value);
+ /**
+ * Get a model specific ModelParams. This parameter will keep its value
+ * for the duration the model is loaded regardless of starting and stopping recognition.
+ * Once the model is unloaded, the value will be lost. If the value is not set, a default
+ * value is returned. See ModelParams for parameter default values.
+ * queryParameter should be checked first before calling this method.
+ *
+ * @param service The current VoiceInteractionService.
+ * @param keyphraseId The unique identifier for the keyphrase.
+ * @param modelParam ModelParams
+ * @return value of parameter
+ */
+ int getParameter(in IVoiceInteractionService service, int keyphraseId,
+ in ModelParams modelParam);
+ /**
+ * Determine if parameter control is supported for the given model handle.
+ * This method should be checked prior to calling setParameter or getParameter.
+ *
+ * @param service The current VoiceInteractionService.
+ * @param keyphraseId The unique identifier for the keyphrase.
+ * @param modelParam ModelParams
+ * @return supported range of parameter, null if not supported
+ */
+ @nullable SoundTrigger.ModelParamRange queryParameter(in IVoiceInteractionService service,
+ int keyphraseId, in ModelParams modelParam);
/**
* @return the component name for the currently active voice interaction service
diff --git a/media/java/android/media/soundtrigger/SoundTriggerManager.java b/media/java/android/media/soundtrigger/SoundTriggerManager.java
index 1c38301c7935..938ffcd5f731 100644
--- a/media/java/android/media/soundtrigger/SoundTriggerManager.java
+++ b/media/java/android/media/soundtrigger/SoundTriggerManager.java
@@ -428,8 +428,7 @@ public final class SoundTriggerManager {
*/
@RequiresPermission(android.Manifest.permission.MANAGE_SOUND_TRIGGER)
public int setParameter(@Nullable UUID soundModelId,
- @ModelParams int modelParam, int value)
- throws UnsupportedOperationException, IllegalArgumentException {
+ @ModelParams int modelParam, int value) {
try {
return mSoundTriggerService.setParameter(new ParcelUuid(soundModelId), modelParam,
value);
@@ -449,15 +448,10 @@ public final class SoundTriggerManager {
* @param soundModelId UUID of model to get parameter
* @param modelParam {@link ModelParams}
* @return value of parameter
- * @throws UnsupportedOperationException if hal or model do not support this API.
- * {@link SoundTriggerManager#queryParameter} should be checked first.
- * @throws IllegalArgumentException if invalid model handle or parameter is passed.
- * {@link SoundTriggerManager#queryParameter} should be checked first.
*/
@RequiresPermission(android.Manifest.permission.MANAGE_SOUND_TRIGGER)
public int getParameter(@NonNull UUID soundModelId,
- @ModelParams int modelParam)
- throws UnsupportedOperationException, IllegalArgumentException {
+ @ModelParams int modelParam) {
try {
return mSoundTriggerService.getParameter(new ParcelUuid(soundModelId), modelParam);
} catch (RemoteException e) {
@@ -479,8 +473,7 @@ public final class SoundTriggerManager {
public ModelParamRange queryParameter(@Nullable UUID soundModelId,
@ModelParams int modelParam) {
try {
- return mSoundTriggerService.queryParameter(new ParcelUuid(soundModelId),
- modelParam);
+ return mSoundTriggerService.queryParameter(new ParcelUuid(soundModelId), modelParam);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java
index 198b4c31249a..bde2cfd52c0f 100644
--- a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java
@@ -611,63 +611,89 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
int setParameter(UUID modelId, @ModelParams int modelParam, int value) {
synchronized (mLock) {
- MetricsLogger.count(mContext, "sth_set_parameter", 1);
- if (modelId == null || mModule == null) {
- return SoundTrigger.STATUS_ERROR;
- }
- ModelData modelData = mModelDataMap.get(modelId);
- if (modelData == null) {
- Slog.w(TAG, "SetParameter: Invalid model id:" + modelId);
- return SoundTrigger.STATUS_BAD_VALUE;
- }
- if (!modelData.isModelLoaded()) {
- Slog.i(TAG, "SetParameter: Given model is not loaded:" + modelId);
- return SoundTrigger.STATUS_BAD_VALUE;
- }
+ return setParameterLocked(mModelDataMap.get(modelId), modelParam, value);
+ }
+ }
- return mModule.setParameter(modelData.getHandle(), modelParam, value);
+ int setKeyphraseParameter(int keyphraseId, @ModelParams int modelParam, int value) {
+ synchronized (mLock) {
+ return setParameterLocked(getKeyphraseModelDataLocked(keyphraseId), modelParam, value);
}
}
- int getParameter(@NonNull UUID modelId, @ModelParams int modelParam)
- throws UnsupportedOperationException, IllegalArgumentException {
+ private int setParameterLocked(@Nullable ModelData modelData, @ModelParams int modelParam,
+ int value) {
+ MetricsLogger.count(mContext, "sth_set_parameter", 1);
+ if (mModule == null) {
+ return SoundTrigger.STATUS_NO_INIT;
+ }
+ if (modelData == null || !modelData.isModelLoaded()) {
+ Slog.i(TAG, "SetParameter: Given model is not loaded:" + modelData);
+ return SoundTrigger.STATUS_BAD_VALUE;
+ }
+
+ return mModule.setParameter(modelData.getHandle(), modelParam, value);
+ }
+
+ int getParameter(@NonNull UUID modelId, @ModelParams int modelParam) {
synchronized (mLock) {
- MetricsLogger.count(mContext, "sth_get_parameter", 1);
- if (mModule == null) {
- throw new UnsupportedOperationException("SoundTriggerModule not initialized");
- }
+ return getParameterLocked(mModelDataMap.get(modelId), modelParam);
+ }
+ }
- ModelData modelData = mModelDataMap.get(modelId);
- if (modelData == null) {
- throw new IllegalArgumentException("Invalid model id:" + modelId);
- }
- if (!modelData.isModelLoaded()) {
- throw new UnsupportedOperationException("Given model is not loaded:" + modelId);
- }
+ int getKeyphraseParameter(int keyphraseId, @ModelParams int modelParam) {
+ synchronized (mLock) {
+ return getParameterLocked(getKeyphraseModelDataLocked(keyphraseId), modelParam);
+ }
+ }
- return mModule.getParameter(modelData.getHandle(), modelParam);
+ private int getParameterLocked(@Nullable ModelData modelData, @ModelParams int modelParam) {
+ MetricsLogger.count(mContext, "sth_get_parameter", 1);
+ if (mModule == null) {
+ throw new UnsupportedOperationException("SoundTriggerModule not initialized");
}
+
+ if (modelData == null) {
+ throw new IllegalArgumentException("Invalid model id");
+ }
+ if (!modelData.isModelLoaded()) {
+ throw new UnsupportedOperationException("Given model is not loaded:" + modelData);
+ }
+
+ return mModule.getParameter(modelData.getHandle(), modelParam);
}
@Nullable
ModelParamRange queryParameter(@NonNull UUID modelId, @ModelParams int modelParam) {
synchronized (mLock) {
- MetricsLogger.count(mContext, "sth_query_parameter", 1);
- if (mModule == null) {
- return null;
- }
- ModelData modelData = mModelDataMap.get(modelId);
- if (modelData == null) {
- Slog.w(TAG, "queryParameter: Invalid model id:" + modelId);
- return null;
- }
- if (!modelData.isModelLoaded()) {
- Slog.i(TAG, "queryParameter: Given model is not loaded:" + modelId);
- return null;
- }
+ return queryParameterLocked(mModelDataMap.get(modelId), modelParam);
+ }
+ }
- return mModule.queryParameter(modelData.getHandle(), modelParam);
+ @Nullable
+ ModelParamRange queryKeyphraseParameter(int keyphraseId, @ModelParams int modelParam) {
+ synchronized (mLock) {
+ return queryParameterLocked(getKeyphraseModelDataLocked(keyphraseId), modelParam);
+ }
+ }
+
+ @Nullable
+ private ModelParamRange queryParameterLocked(@Nullable ModelData modelData,
+ @ModelParams int modelParam) {
+ MetricsLogger.count(mContext, "sth_query_parameter", 1);
+ if (mModule == null) {
+ return null;
+ }
+ if (modelData == null) {
+ Slog.w(TAG, "queryParameter: Invalid model id");
+ return null;
}
+ if (!modelData.isModelLoaded()) {
+ Slog.i(TAG, "queryParameter: Given model is not loaded:" + modelData);
+ return null;
+ }
+
+ return mModule.queryParameter(modelData.getHandle(), modelParam);
}
//---- SoundTrigger.StatusListener methods
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerInternal.java b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerInternal.java
index d05e044499ab..54dffdc4c13a 100644
--- a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerInternal.java
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerInternal.java
@@ -16,17 +16,17 @@
package com.android.server.soundtrigger;
+import android.annotation.Nullable;
import android.hardware.soundtrigger.IRecognitionStatusCallback;
+import android.hardware.soundtrigger.ModelParams;
import android.hardware.soundtrigger.SoundTrigger;
import android.hardware.soundtrigger.SoundTrigger.Keyphrase;
-import android.hardware.soundtrigger.SoundTrigger.KeyphraseRecognitionEvent;
-import android.hardware.soundtrigger.SoundTrigger.KeyphraseRecognitionExtra;
import android.hardware.soundtrigger.SoundTrigger.KeyphraseSoundModel;
+import android.hardware.soundtrigger.SoundTrigger.ModelParamRange;
import android.hardware.soundtrigger.SoundTrigger.ModuleProperties;
import android.hardware.soundtrigger.SoundTrigger.RecognitionConfig;
-import android.hardware.soundtrigger.SoundTrigger.RecognitionEvent;
-import android.hardware.soundtrigger.SoundTrigger.SoundModelEvent;
-import android.hardware.soundtrigger.SoundTriggerModule;
+
+import com.android.server.voiceinteraction.VoiceInteractionManagerService;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -71,6 +71,58 @@ public abstract class SoundTriggerInternal {
public abstract ModuleProperties getModuleProperties();
/**
+ * Set a model specific {@link ModelParams} with the given value. This
+ * parameter will keep its value for the duration the model is loaded regardless of starting and
+ * stopping recognition. Once the model is unloaded, the value will be lost.
+ * {@link SoundTriggerInternal#queryParameter} should be checked first before calling this
+ * method.
+ *
+ * @param keyphraseId The identifier of the keyphrase for which
+ * to modify model parameters
+ * @param modelParam {@link ModelParams}
+ * @param value Value to set
+ * @return - {@link SoundTrigger#STATUS_OK} in case of success
+ * - {@link SoundTrigger#STATUS_NO_INIT} if the native service cannot be reached
+ * - {@link SoundTrigger#STATUS_BAD_VALUE} invalid input parameter
+ * - {@link SoundTrigger#STATUS_INVALID_OPERATION} if the call is out of sequence or
+ * if API is not supported by HAL
+ */
+ public abstract int setParameter(int keyphraseId, @ModelParams int modelParam, int value);
+
+ /**
+ * Get a model specific {@link ModelParams}. This parameter will keep its value
+ * for the duration the model is loaded regardless of starting and stopping recognition.
+ * Once the model is unloaded, the value will be lost. If the value is not set, a default
+ * value is returned. See ModelParams for parameter default values.
+ * {@link SoundTriggerInternal#queryParameter} should be checked first before calling this
+ * method.
+ *
+ * @param keyphraseId The identifier of the keyphrase for which
+ * to modify model parameters
+ * @param modelParam {@link ModelParams}
+ * @return value of parameter
+ * @throws UnsupportedOperationException if hal or model do not support this API.
+ * queryParameter should be checked first.
+ * @throws IllegalArgumentException if invalid model handle or parameter is passed.
+ * queryParameter should be checked first.
+ */
+ public abstract int getParameter(int keyphraseId, @ModelParams int modelParam);
+
+ /**
+ * Determine if parameter control is supported for the given model handle.
+ * This method should be checked prior to calling {@link SoundTriggerInternal#setParameter}
+ * or {@link SoundTriggerInternal#getParameter}.
+ *
+ * @param keyphraseId The identifier of the keyphrase for which
+ * to modify model parameters
+ * @param modelParam {@link ModelParams}
+ * @return supported range of parameter, null if not supported
+ */
+ @Nullable
+ public abstract ModelParamRange queryParameter(int keyphraseId,
+ @ModelParams int modelParam);
+
+ /**
* Unloads (and stops if running) the given keyphraseId
*/
public abstract int unloadKeyphraseModel(int keyphaseId);
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java
index 68b16f39e149..e37755bddcaa 100644
--- a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java
@@ -1446,26 +1446,45 @@ public class SoundTriggerService extends SystemService {
@Override
public int startRecognition(int keyphraseId, KeyphraseSoundModel soundModel,
IRecognitionStatusCallback listener, RecognitionConfig recognitionConfig) {
- if (!isInitialized()) return STATUS_ERROR;
+ if (!isInitialized()) throw new UnsupportedOperationException();
return mSoundTriggerHelper.startKeyphraseRecognition(keyphraseId, soundModel, listener,
recognitionConfig);
}
@Override
public synchronized int stopRecognition(int keyphraseId, IRecognitionStatusCallback listener) {
- if (!isInitialized()) return STATUS_ERROR;
+ if (!isInitialized()) throw new UnsupportedOperationException();
return mSoundTriggerHelper.stopKeyphraseRecognition(keyphraseId, listener);
}
@Override
public ModuleProperties getModuleProperties() {
- if (!isInitialized()) return null;
+ if (!isInitialized()) throw new UnsupportedOperationException();
return mSoundTriggerHelper.getModuleProperties();
}
@Override
+ public int setParameter(int keyphraseId, @ModelParams int modelParam, int value) {
+ if (!isInitialized()) throw new UnsupportedOperationException();
+ return mSoundTriggerHelper.setKeyphraseParameter(keyphraseId, modelParam, value);
+ }
+
+ @Override
+ public int getParameter(int keyphraseId, @ModelParams int modelParam) {
+ if (!isInitialized()) throw new UnsupportedOperationException();
+ return mSoundTriggerHelper.getKeyphraseParameter(keyphraseId, modelParam);
+ }
+
+ @Override
+ @Nullable
+ public ModelParamRange queryParameter(int keyphraseId, @ModelParams int modelParam) {
+ if (!isInitialized()) throw new UnsupportedOperationException();
+ return mSoundTriggerHelper.queryKeyphraseParameter(keyphraseId, modelParam);
+ }
+
+ @Override
public int unloadKeyphraseModel(int keyphraseId) {
- if (!isInitialized()) return STATUS_ERROR;
+ if (!isInitialized()) throw new UnsupportedOperationException();
return mSoundTriggerHelper.unloadKeyphraseSoundModel(keyphraseId);
}
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
index e9db31ba3e25..06c807421d1a 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
@@ -41,7 +41,9 @@ import android.content.pm.UserInfo;
import android.content.res.Resources;
import android.database.ContentObserver;
import android.hardware.soundtrigger.IRecognitionStatusCallback;
+import android.hardware.soundtrigger.ModelParams;
import android.hardware.soundtrigger.SoundTrigger.KeyphraseSoundModel;
+import android.hardware.soundtrigger.SoundTrigger.ModelParamRange;
import android.hardware.soundtrigger.SoundTrigger.ModuleProperties;
import android.hardware.soundtrigger.SoundTrigger.RecognitionConfig;
import android.os.Binder;
@@ -1084,6 +1086,55 @@ public class VoiceInteractionManagerService extends SystemService {
}
}
+ @Override
+ public int setParameter(IVoiceInteractionService service, int keyphraseId,
+ @ModelParams int modelParam, int value) {
+ // Allow the call if this is the current voice interaction service.
+ synchronized (this) {
+ enforceIsCurrentVoiceInteractionService(service);
+ }
+
+ final long caller = Binder.clearCallingIdentity();
+ try {
+ return mSoundTriggerInternal.setParameter(keyphraseId, modelParam, value);
+ } finally {
+ Binder.restoreCallingIdentity(caller);
+ }
+ }
+
+ @Override
+ public int getParameter(IVoiceInteractionService service, int keyphraseId,
+ @ModelParams int modelParam) {
+ // Allow the call if this is the current voice interaction service.
+ synchronized (this) {
+ enforceIsCurrentVoiceInteractionService(service);
+ }
+
+ final long caller = Binder.clearCallingIdentity();
+ try {
+ return mSoundTriggerInternal.getParameter(keyphraseId, modelParam);
+ } finally {
+ Binder.restoreCallingIdentity(caller);
+ }
+ }
+
+ @Override
+ @Nullable
+ public ModelParamRange queryParameter(IVoiceInteractionService service,
+ int keyphraseId, @ModelParams int modelParam) {
+ // Allow the call if this is the current voice interaction service.
+ synchronized (this) {
+ enforceIsCurrentVoiceInteractionService(service);
+ }
+
+ final long caller = Binder.clearCallingIdentity();
+ try {
+ return mSoundTriggerInternal.queryParameter(keyphraseId, modelParam);
+ } finally {
+ Binder.restoreCallingIdentity(caller);
+ }
+ }
+
private synchronized void unloadAllKeyphraseModels() {
for (int i = 0; i < mLoadedKeyphraseIds.size(); i++) {
final long caller = Binder.clearCallingIdentity();