add parameter control to AlwaysOnHotwordDetector

Per-model control to AlwaysOnHotwordDetector interface.
Models are selected by keyphrase and locale associated with the
AlwaysOnHotwordDetector instance.

Bug: 141929369
Test: tested manually with test app
Change-Id: Iffeb0954059fa030d8a4fefb934a3e665323be37
This commit is contained in:
Nicholas Ambur
2019-12-08 19:04:06 -08:00
parent aff43dbc03
commit f94db1c822
12 changed files with 493 additions and 90 deletions

View File

@@ -42617,9 +42617,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
@@ -42644,6 +42648,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);

View File

@@ -3535,7 +3535,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;
@@ -4349,9 +4348,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);
}

View File

@@ -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;

View File

@@ -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);
}
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
@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);

View File

@@ -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;
@@ -197,6 +213,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}.
*/
@@ -444,6 +507,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)}.
@@ -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;

View File

@@ -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,

View File

@@ -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

View File

@@ -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();
}

View File

@@ -611,65 +611,91 @@ 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 mModule.setParameter(modelData.getHandle(), modelParam, value);
return setParameterLocked(mModelDataMap.get(modelId), modelParam, value);
}
}
int getParameter(@NonNull UUID modelId, @ModelParams int modelParam)
throws UnsupportedOperationException, IllegalArgumentException {
int setKeyphraseParameter(int keyphraseId, @ModelParams int modelParam, int value) {
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);
return setParameterLocked(getKeyphraseModelDataLocked(keyphraseId), modelParam, value);
}
}
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) {
return getParameterLocked(mModelDataMap.get(modelId), modelParam);
}
}
int getKeyphraseParameter(int keyphraseId, @ModelParams int modelParam) {
synchronized (mLock) {
return getParameterLocked(getKeyphraseModelDataLocked(keyphraseId), 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 mModule.queryParameter(modelData.getHandle(), modelParam);
return queryParameterLocked(mModelDataMap.get(modelId), 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
@Override
public void onRecognition(RecognitionEvent event) {

View File

@@ -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;
@@ -70,6 +70,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
*/

View File

@@ -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);
}

View File

@@ -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();