diff options
| author | 2020-01-10 17:08:00 +0000 | |
|---|---|---|
| committer | 2020-01-10 17:08:00 +0000 | |
| commit | b2a5c297964caccb07345beef5ca6fd9a583a7df (patch) | |
| tree | f00fceeda8a5343eedcb1803e36380bab01160e0 | |
| parent | 9785b64c1194ab0a69c10310ac72830c9184f5e3 (diff) | |
| parent | f94db1c8228edbbb3efc94dee29f5f789623be3e (diff) | |
Merge "add parameter control to AlwaysOnHotwordDetector"
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(); |