Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f94db1c8 authored by Nicholas Ambur's avatar Nicholas Ambur
Browse files

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
parent aff43dbc
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -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);
+2 −3
Original line number Diff line number Diff line
@@ -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);
  }
+1 −2
Original line number Diff line number Diff line
@@ -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;

+51 −17
Original line number Diff line number Diff line
@@ -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,13 +609,15 @@ 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>() {
        public static final Creator<ModelParamRange> CREATOR =
                new Creator<ModelParamRange>() {
                    @Override
                    @NonNull
                    public ModelParamRange createFromParcel(@NonNull Parcel in) {
@@ -629,11 +631,43 @@ public class SoundTrigger {
                    }
                };

        /** @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);
+181 −0
Original line number Diff line number Diff line
@@ -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;
Loading