diff options
10 files changed, 540 insertions, 12 deletions
diff --git a/api/system-current.txt b/api/system-current.txt index 6b51eabf6f34..713d77d2a88f 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -3410,6 +3410,14 @@ package android.hardware.soundtrigger { field public static final int STATUS_OK = 0; // 0x0 } + 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; + field public final int start; + } + public static final class SoundTrigger.ModuleProperties implements android.os.Parcelable { method public int describeContents(); method public void writeToParcel(android.os.Parcel, int); @@ -4198,8 +4206,11 @@ package android.media.soundtrigger { method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_SOUND_TRIGGER) public android.media.soundtrigger.SoundTriggerDetector createSoundTriggerDetector(java.util.UUID, @NonNull android.media.soundtrigger.SoundTriggerDetector.Callback, @Nullable android.os.Handler); method @RequiresPermission(android.Manifest.permission.MANAGE_SOUND_TRIGGER) public void deleteModel(java.util.UUID); method public int getDetectionServiceOperationsTimeout(); - method @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.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 @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 void updateModel(android.media.soundtrigger.SoundTriggerManager.Model); } diff --git a/core/java/android/hardware/soundtrigger/ModelParams.aidl b/core/java/android/hardware/soundtrigger/ModelParams.aidl new file mode 100644 index 000000000000..d90dc811fc32 --- /dev/null +++ b/core/java/android/hardware/soundtrigger/ModelParams.aidl @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.hardware.soundtrigger; + +/** + * Model specific parameters to be used with parameter set and get APIs + * {@hide} + */ +@Backing(type="int") +enum ModelParams { + /** + * Placeholder for invalid model parameter used for returning error or + * passing an invalid value. + */ + INVALID = -1, + /** + * 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. + */ + THRESHOLD_FACTOR = 0, +} diff --git a/core/java/android/hardware/soundtrigger/SoundTrigger.aidl b/core/java/android/hardware/soundtrigger/SoundTrigger.aidl index 325a9addc8ff..94c4216227bc 100644 --- a/core/java/android/hardware/soundtrigger/SoundTrigger.aidl +++ b/core/java/android/hardware/soundtrigger/SoundTrigger.aidl @@ -24,5 +24,6 @@ parcelable SoundTrigger.GenericRecognitionEvent; parcelable SoundTrigger.KeyphraseRecognitionExtra; parcelable SoundTrigger.KeyphraseSoundModel; parcelable SoundTrigger.GenericSoundModel; +parcelable SoundTrigger.ModelParamRange; parcelable SoundTrigger.ModuleProperties; parcelable SoundTrigger.RecognitionConfig; diff --git a/core/java/android/hardware/soundtrigger/SoundTrigger.java b/core/java/android/hardware/soundtrigger/SoundTrigger.java index b1134e120df2..86f3eec4109e 100644 --- a/core/java/android/hardware/soundtrigger/SoundTrigger.java +++ b/core/java/android/hardware/soundtrigger/SoundTrigger.java @@ -567,6 +567,65 @@ 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 + */ + public final int start; + + /** + * end of supported range inclusive + */ + public final int end; + + ModelParamRange(int start, int end) { + this.start = start; + this.end = end; + } + + 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]; + } + }; + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(@NonNull Parcel dest, int flags) { + dest.writeInt(start); + dest.writeInt(end); + } + + @Override + @NonNull + public String toString() { + return "ModelParamRange [start=" + start + ", end=" + end + "]"; + } + } + /** * Modes for key phrase recognition */ diff --git a/core/java/android/hardware/soundtrigger/SoundTriggerModule.java b/core/java/android/hardware/soundtrigger/SoundTriggerModule.java index 911354862ff4..b16ef5c43346 100644 --- a/core/java/android/hardware/soundtrigger/SoundTriggerModule.java +++ b/core/java/android/hardware/soundtrigger/SoundTriggerModule.java @@ -16,7 +16,9 @@ package android.hardware.soundtrigger; +import android.annotation.Nullable; import android.annotation.UnsupportedAppUsage; +import android.hardware.soundtrigger.SoundTrigger.ModelParamRange; import android.os.Handler; import android.os.Looper; import android.os.Message; @@ -150,6 +152,57 @@ public class SoundTriggerModule { */ public native int getModelState(int soundModelHandle); + /** + * 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 SoundTriggerModule#isParameterSupported} should be checked first before calling this + * method. + * + * @param soundModelHandle handle of model to apply parameter + * @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 native int setParameter(int soundModelHandle, + @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 {@link ModelParams} for parameter default values. + * {@link SoundTriggerModule#isParameterSupported} should be checked first before + * calling this method. Otherwise, an exception can be thrown. + * + * @param soundModelHandle handle 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 SoundTriggerModule#isParameterSupported} should be checked first. + * @throws IllegalArgumentException if invalid model handle or parameter is passed. + * {@link SoundTriggerModule#isParameterSupported} should be checked first. + */ + public native int getParameter(int soundModelHandle, + @ModelParams int modelParam) + throws UnsupportedOperationException, IllegalArgumentException; + + /** + * Determine if parameter control is supported for the given model handle. + * This method should be checked prior to calling {@link SoundTriggerModule#setParameter} or + * {@link SoundTriggerModule#getParameter}. + * + * @param soundModelHandle handle of model to get parameter + * @param modelParam {@link ModelParams} + * @return supported range of parameter, null if not supported + */ + @Nullable + public native ModelParamRange queryParameter(int soundModelHandle, @ModelParams int modelParam); + private class NativeEventHandlerDelegate { private final Handler mHandler; diff --git a/core/java/com/android/internal/app/ISoundTriggerService.aidl b/core/java/com/android/internal/app/ISoundTriggerService.aidl index ea24d5fbb2f7..d94294f0aa22 100644 --- a/core/java/com/android/internal/app/ISoundTriggerService.aidl +++ b/core/java/com/android/internal/app/ISoundTriggerService.aidl @@ -20,6 +20,7 @@ import android.app.PendingIntent; import android.content.ComponentName; import android.hardware.soundtrigger.IRecognitionStatusCallback; import android.hardware.soundtrigger.SoundTrigger; +import android.hardware.soundtrigger.ModelParams; import android.os.Bundle; import android.os.ParcelUuid; @@ -56,4 +57,16 @@ interface ISoundTriggerService { int getModelState(in ParcelUuid soundModelId); @nullable SoundTrigger.ModuleProperties getModuleProperties(); + + 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, + in ModelParams modelParam); } diff --git a/core/jni/android_hardware_SoundTrigger.cpp b/core/jni/android_hardware_SoundTrigger.cpp index 0002f8b4048a..4376b0b4ac42 100644 --- a/core/jni/android_hardware_SoundTrigger.cpp +++ b/core/jni/android_hardware_SoundTrigger.cpp @@ -44,6 +44,13 @@ static struct { jmethodID toString; } gUUIDMethods; +static const char* const kUnsupportedOperationExceptionClassPathName = + "java/lang/UnsupportedOperationException"; +static jclass gUnsupportedOperationExceptionClass; +static const char* const kIllegalArgumentExceptionClassPathName = + "java/lang/IllegalArgumentException"; +static jclass gIllegalArgumentExceptionClass; + static const char* const kSoundTriggerClassPathName = "android/hardware/soundtrigger/SoundTrigger"; static jclass gSoundTriggerClass; @@ -91,6 +98,11 @@ static struct { jfieldID keyphrases; } gKeyphraseSoundModelFields; +static const char* const kModelParamRangeClassPathName = + "android/hardware/soundtrigger/SoundTrigger$ModelParamRange"; +static jclass gModelParamRangeClass; +static jmethodID gModelParamRangeCstor; + static const char* const kRecognitionConfigClassPathName = "android/hardware/soundtrigger/SoundTrigger$RecognitionConfig"; static jclass gRecognitionConfigClass; @@ -164,6 +176,16 @@ enum { SOUNDTRIGGER_EVENT_SERVICE_STATE_CHANGE = 4, }; +static jint throwUnsupportedOperationException(JNIEnv *env) +{ + return env->ThrowNew(gUnsupportedOperationExceptionClass, nullptr); +} + +static jint throwIllegalArgumentException(JNIEnv *env) +{ + return env->ThrowNew(gIllegalArgumentExceptionClass, nullptr); +} + // ---------------------------------------------------------------------------- // ref-counted object for callbacks class JNISoundTriggerCallback: public SoundTriggerCallback @@ -822,6 +844,69 @@ android_hardware_SoundTrigger_getModelState(JNIEnv *env, jobject thiz, return status; } +static jint +android_hardware_SoundTrigger_setParameter(JNIEnv *env, jobject thiz, + jint jHandle, jint jModelParam, jint jValue) +{ + ALOGV("setParameter"); + sp<SoundTrigger> module = getSoundTrigger(env, thiz); + if (module == NULL) { + return SOUNDTRIGGER_STATUS_NO_INIT; + } + return module->setParameter(jHandle, (sound_trigger_model_parameter_t) jModelParam, jValue); +} + +static jint +android_hardware_SoundTrigger_getParameter(JNIEnv *env, jobject thiz, + jint jHandle, jint jModelParam) +{ + ALOGV("getParameter"); + sp<SoundTrigger> module = getSoundTrigger(env, thiz); + if (module == NULL) { + throwUnsupportedOperationException(env); + return -1; + } + + jint nValue; + jint status = module->getParameter(jHandle, + (sound_trigger_model_parameter_t) jModelParam, &nValue); + + switch (status) { + case 0: + return nValue; + case -EINVAL: + throwIllegalArgumentException(env); + break; + default: + throwUnsupportedOperationException(env); + break; + } + + return -1; +} + +static jobject +android_hardware_SoundTrigger_queryParameter(JNIEnv *env, jobject thiz, + jint jHandle, jint jModelParam) +{ + ALOGV("queryParameter"); + sp<SoundTrigger> module = getSoundTrigger(env, thiz); + if (module == nullptr) { + return nullptr; + } + + sound_trigger_model_parameter_range_t nRange; + jint nValue = module->queryParameter(jHandle, + (sound_trigger_model_parameter_t) jModelParam, &nRange); + + if (nValue != 0) { + ALOGE("failed to query parameter error code: %d", nValue); + return nullptr; + } + + return env->NewObject(gModelParamRangeClass, gModelParamRangeCstor, nRange.start, nRange.end); +} + static const JNINativeMethod gMethods[] = { {"listModules", "(Ljava/lang/String;Ljava/util/ArrayList;)I", @@ -854,6 +939,15 @@ static const JNINativeMethod gModuleMethods[] = { {"getModelState", "(I)I", (void *)android_hardware_SoundTrigger_getModelState}, + {"setParameter", + "(III)I", + (void *)android_hardware_SoundTrigger_setParameter}, + {"getParameter", + "(II)I", + (void *)android_hardware_SoundTrigger_getParameter}, + {"queryParameter", + "(II)Landroid/hardware/soundtrigger/SoundTrigger$ModelParamRange;", + (void *)android_hardware_SoundTrigger_queryParameter} }; int register_android_hardware_SoundTrigger(JNIEnv *env) @@ -866,6 +960,12 @@ int register_android_hardware_SoundTrigger(JNIEnv *env) gUUIDClass = MakeGlobalRefOrDie(env, uuidClass); gUUIDMethods.toString = GetMethodIDOrDie(env, uuidClass, "toString", "()Ljava/lang/String;"); + jclass exUClass = FindClassOrDie(env, kUnsupportedOperationExceptionClassPathName); + gUnsupportedOperationExceptionClass = MakeGlobalRefOrDie(env, exUClass); + + jclass exIClass = FindClassOrDie(env, kIllegalArgumentExceptionClassPathName); + gIllegalArgumentExceptionClass = MakeGlobalRefOrDie(env, exIClass); + jclass lClass = FindClassOrDie(env, kSoundTriggerClassPathName); gSoundTriggerClass = MakeGlobalRefOrDie(env, lClass); @@ -906,6 +1006,10 @@ int register_android_hardware_SoundTrigger(JNIEnv *env) "keyphrases", "[Landroid/hardware/soundtrigger/SoundTrigger$Keyphrase;"); + jclass modelParamRangeClass = FindClassOrDie(env, kModelParamRangeClassPathName); + gModelParamRangeClass = MakeGlobalRefOrDie(env, modelParamRangeClass); + gModelParamRangeCstor = GetMethodIDOrDie(env, modelParamRangeClass, "<init>", "(II)V"); + jclass recognitionEventClass = FindClassOrDie(env, kRecognitionEventClassPathName); gRecognitionEventClass = MakeGlobalRefOrDie(env, recognitionEventClass); gRecognitionEventCstor = GetMethodIDOrDie(env, recognitionEventClass, "<init>", diff --git a/media/java/android/media/soundtrigger/SoundTriggerManager.java b/media/java/android/media/soundtrigger/SoundTriggerManager.java index dc400ad26eed..61b3e76e7cee 100644 --- a/media/java/android/media/soundtrigger/SoundTriggerManager.java +++ b/media/java/android/media/soundtrigger/SoundTriggerManager.java @@ -26,9 +26,11 @@ import android.annotation.SystemService; import android.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.Context; +import android.hardware.soundtrigger.ModelParams; import android.hardware.soundtrigger.SoundTrigger; import android.hardware.soundtrigger.SoundTrigger.GenericSoundModel; import android.hardware.soundtrigger.SoundTrigger.KeyphraseSoundModel; +import android.hardware.soundtrigger.SoundTrigger.ModelParamRange; import android.hardware.soundtrigger.SoundTrigger.RecognitionConfig; import android.hardware.soundtrigger.SoundTrigger.SoundModel; import android.os.Bundle; @@ -67,7 +69,7 @@ public final class SoundTriggerManager { /** * @hide */ - public SoundTriggerManager(Context context, ISoundTriggerService soundTriggerService ) { + public SoundTriggerManager(Context context, ISoundTriggerService soundTriggerService) { if (DBG) { Slog.i(TAG, "SoundTriggerManager created."); } @@ -89,14 +91,22 @@ public final class SoundTriggerManager { } /** - * Returns the sound trigger model represented by the given UUID. An instance of {@link Model} - * is returned. + * Get {@link SoundTriggerManager.Model} which is registered with the passed UUID + * + * @param soundModelId UUID associated with a loaded model + * @return {@link SoundTriggerManager.Model} associated with UUID soundModelId */ @RequiresPermission(android.Manifest.permission.MANAGE_SOUND_TRIGGER) + @Nullable public Model getModel(UUID soundModelId) { try { - return new Model(mSoundTriggerService.getSoundModel( - new ParcelUuid(soundModelId))); + GenericSoundModel model = + mSoundTriggerService.getSoundModel(new ParcelUuid(soundModelId)); + if (model == null) { + return null; + } + + return new Model(model); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -399,4 +409,80 @@ public final class SoundTriggerManager { throw e.rethrowFromSystemServer(); } } + + /** + * 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 SoundTriggerManager#queryParameter} should be checked first before calling this + * method. + * + * @param soundModelId UUID of model to apply the parameter value to. + * @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 + */ + @RequiresPermission(android.Manifest.permission.MANAGE_SOUND_TRIGGER) + public int setParameter(@Nullable UUID soundModelId, + @ModelParams int modelParam, int value) + throws UnsupportedOperationException, IllegalArgumentException { + try { + return mSoundTriggerService.setParameter(new ParcelUuid(soundModelId), modelParam, + value); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * 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 SoundTriggerManager#queryParameter} should be checked first before + * calling this method. Otherwise, an exception can be thrown. + * + * @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 { + try { + return mSoundTriggerService.getParameter(new ParcelUuid(soundModelId), modelParam); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Determine if parameter control is supported for the given model handle. + * This method should be checked prior to calling {@link SoundTriggerManager#setParameter} or + * {@link SoundTriggerManager#getParameter}. + * + * @param soundModelId handle of model to get parameter + * @param modelParam {@link ModelParams} + * @return supported range of parameter, null if not supported + */ + @RequiresPermission(android.Manifest.permission.MANAGE_SOUND_TRIGGER) + @Nullable + public ModelParamRange queryParameter(@Nullable UUID soundModelId, + @ModelParams int modelParam) { + try { + 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 735b9a1dcf2e..198b4c31249a 100644 --- a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java +++ b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java @@ -16,11 +16,14 @@ package com.android.server.soundtrigger; +import android.annotation.NonNull; +import android.annotation.Nullable; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.hardware.soundtrigger.IRecognitionStatusCallback; +import android.hardware.soundtrigger.ModelParams; import android.hardware.soundtrigger.SoundTrigger; import android.hardware.soundtrigger.SoundTrigger.GenericRecognitionEvent; import android.hardware.soundtrigger.SoundTrigger.GenericSoundModel; @@ -28,6 +31,7 @@ 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; @@ -605,6 +609,67 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener { return STATUS_ERROR; } + 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 mModule.setParameter(modelData.getHandle(), modelParam, value); + } + } + + int getParameter(@NonNull UUID modelId, @ModelParams int modelParam) + throws UnsupportedOperationException, IllegalArgumentException { + synchronized (mLock) { + MetricsLogger.count(mContext, "sth_get_parameter", 1); + if (mModule == null) { + throw new UnsupportedOperationException("SoundTriggerModule not initialized"); + } + + 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); + } + + 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 mModule.queryParameter(modelData.getHandle(), modelParam); + } + } + //---- SoundTrigger.StatusListener methods @Override public void onRecognition(RecognitionEvent event) { @@ -653,15 +718,15 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener { } ModelData model = getModelDataForLocked(event.soundModelHandle); if (model == null || !model.isGenericModel()) { - Slog.w(TAG, "Generic recognition event: Model does not exist for handle: " + - event.soundModelHandle); + Slog.w(TAG, "Generic recognition event: Model does not exist for handle: " + + event.soundModelHandle); return; } IRecognitionStatusCallback callback = model.getCallback(); if (callback == null) { - Slog.w(TAG, "Generic recognition event: Null callback for model handle: " + - event.soundModelHandle); + Slog.w(TAG, "Generic recognition event: Null callback for model handle: " + + event.soundModelHandle); return; } @@ -678,8 +743,8 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener { RecognitionConfig config = model.getRecognitionConfig(); if (config == null) { - Slog.w(TAG, "Generic recognition event: Null RecognitionConfig for model handle: " + - event.soundModelHandle); + Slog.w(TAG, "Generic recognition event: Null RecognitionConfig for model handle: " + + event.soundModelHandle); return; } diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java index 1dd3972b56b4..96d2df125a3c 100644 --- a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java +++ b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java @@ -22,7 +22,9 @@ import static android.content.Context.BIND_FOREGROUND_SERVICE; import static android.content.pm.PackageManager.GET_META_DATA; import static android.content.pm.PackageManager.GET_SERVICES; import static android.content.pm.PackageManager.MATCH_DEBUG_TRIAGED_MISSING; +import static android.hardware.soundtrigger.SoundTrigger.STATUS_BAD_VALUE; import static android.hardware.soundtrigger.SoundTrigger.STATUS_ERROR; +import static android.hardware.soundtrigger.SoundTrigger.STATUS_NO_INIT; import static android.hardware.soundtrigger.SoundTrigger.STATUS_OK; import static android.provider.Settings.Global.MAX_SOUND_TRIGGER_DETECTION_SERVICE_OPS_PER_DAY; import static android.provider.Settings.Global.SOUND_TRIGGER_DETECTION_SERVICE_OP_TIMEOUT; @@ -39,9 +41,11 @@ import android.content.ServiceConnection; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.hardware.soundtrigger.IRecognitionStatusCallback; +import android.hardware.soundtrigger.ModelParams; import android.hardware.soundtrigger.SoundTrigger; import android.hardware.soundtrigger.SoundTrigger.GenericSoundModel; 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.SoundModel; @@ -683,6 +687,101 @@ public class SoundTriggerService extends SystemService { return properties; } } + + @Override + public int setParameter(ParcelUuid soundModelId, + @ModelParams int modelParam, int value) { + enforceCallingPermission(Manifest.permission.MANAGE_SOUND_TRIGGER); + if (!isInitialized()) return STATUS_NO_INIT; + if (DEBUG) { + Slog.d(TAG, "setParameter(): id=" + soundModelId + + ", param=" + modelParam + + ", value=" + value); + } + + sEventLogger.log(new SoundTriggerLogger.StringEvent( + "setParameter(): id=" + soundModelId + + ", param=" + modelParam + + ", value=" + value)); + + synchronized (mLock) { + SoundModel soundModel = mLoadedModels.get(soundModelId.getUuid()); + if (soundModel == null) { + Slog.e(TAG, soundModelId + " is not loaded. Loaded models: " + + mLoadedModels.toString()); + + sEventLogger.log(new SoundTriggerLogger.StringEvent("setParameter(): " + + soundModelId + " is not loaded")); + + return STATUS_BAD_VALUE; + } + + return mSoundTriggerHelper.setParameter(soundModel.uuid, modelParam, value); + } + } + + @Override + public int getParameter(@NonNull ParcelUuid soundModelId, + @ModelParams int modelParam) + throws UnsupportedOperationException, IllegalArgumentException { + enforceCallingPermission(Manifest.permission.MANAGE_SOUND_TRIGGER); + if (!isInitialized()) { + throw new UnsupportedOperationException("SoundTriggerHelper not initialized"); + } + if (DEBUG) { + Slog.d(TAG, "getParameter(): id=" + soundModelId + + ", param=" + modelParam); + } + + sEventLogger.log(new SoundTriggerLogger.StringEvent( + "getParameter(): id=" + soundModelId + + ", param=" + modelParam)); + + synchronized (mLock) { + SoundModel soundModel = mLoadedModels.get(soundModelId.getUuid()); + if (soundModel == null) { + Slog.e(TAG, soundModelId + " is not loaded"); + + sEventLogger.log(new SoundTriggerLogger.StringEvent("getParameter(): " + + soundModelId + " is not loaded")); + + throw new IllegalArgumentException("sound model is not loaded"); + } + + return mSoundTriggerHelper.getParameter(soundModel.uuid, modelParam); + } + } + + @Override + @Nullable + public ModelParamRange queryParameter(@NonNull ParcelUuid soundModelId, + @ModelParams int modelParam) { + enforceCallingPermission(Manifest.permission.MANAGE_SOUND_TRIGGER); + if (!isInitialized()) return null; + if (DEBUG) { + Slog.d(TAG, "queryParameter(): id=" + soundModelId + + ", param=" + modelParam); + } + + sEventLogger.log(new SoundTriggerLogger.StringEvent( + "queryParameter(): id=" + soundModelId + + ", param=" + modelParam)); + + synchronized (mLock) { + SoundModel soundModel = mLoadedModels.get(soundModelId.getUuid()); + if (soundModel == null) { + Slog.e(TAG, soundModelId + " is not loaded"); + + sEventLogger.log(new SoundTriggerLogger.StringEvent( + "queryParameter(): " + + soundModelId + " is not loaded")); + + return null; + } + + return mSoundTriggerHelper.queryParameter(soundModel.uuid, modelParam); + } + } } /** |