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

Commit b8df4eaa authored by Eric Laurent's avatar Eric Laurent Committed by Automerger Merge Worker
Browse files

Merge "SoundTriggerHelper: improve in call behavior" into rvc-dev am:...

Merge "SoundTriggerHelper: improve in call behavior" into rvc-dev am: b6c403b0 am: 0185e6d6 am: e479d941

Change-Id: If39332fea928fadbe5c71a5cf43a426b6b79a546
parents 16c7d19b e479d941
Loading
Loading
Loading
Loading
+108 −50
Original line number Diff line number Diff line
@@ -40,6 +40,9 @@ import android.hardware.soundtrigger.SoundTrigger.SoundModelEvent;
import android.hardware.soundtrigger.SoundTriggerModule;
import android.os.Binder;
import android.os.DeadObjectException;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.os.PowerManager;
import android.os.PowerManager.ServiceType;
import android.os.RemoteException;
@@ -113,6 +116,13 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {

    private PowerSaveModeListener mPowerSaveModeListener;

    // Handler to process call state changes will delay to allow time for the audio
    // and sound trigger HALs to process the end of call notifications
    // before we re enable pending recognition requests.
    private final Handler mHandler;
    private static final int MSG_CALL_STATE_CHANGED = 0;
    private static final int CALL_INACTIVE_MSG_DELAY_MS = 1000;

    SoundTriggerHelper(Context context) {
        ArrayList <ModuleProperties> modules = new ArrayList<>();
        int status = SoundTrigger.listModules(modules);
@@ -130,6 +140,31 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
            // TODO: Figure out how to determine which module corresponds to the DSP hardware.
            mModuleProperties = modules.get(0);
        }

        Looper looper = Looper.myLooper();
        if (looper == null) {
            looper = Looper.getMainLooper();
        }
        if (looper != null) {
            mHandler = new Handler(looper) {
                @Override
                public void handleMessage(Message msg) {
                    switch (msg.what) {
                        case MSG_CALL_STATE_CHANGED:
                            synchronized (mLock) {
                                onCallStateChangedLocked(
                                        TelephonyManager.CALL_STATE_OFFHOOK == msg.arg1);
                            }
                            break;
                        default:
                            Slog.e(TAG, "unknown message in handler:" + msg.what);
                            break;
                    }
                }
            };
        } else {
            mHandler = null;
        }
    }

    /**
@@ -227,6 +262,37 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
        return status;
    }

    private int prepareForRecognition(ModelData modelData) {
        if (mModule == null) {
            mModule = SoundTrigger.attachModule(mModuleProperties.getId(), this, null);
            if (mModule == null) {
                Slog.w(TAG, "prepareForRecognition: cannot attach to sound trigger module");
                return STATUS_ERROR;
            }
        }
        // Load the model if it is not loaded.
        if (!modelData.isModelLoaded()) {
            // Before we try and load this model, we should first make sure that any other
            // models that don't have an active recognition/dead callback are unloaded. Since
            // there is a finite limit on the number of models that the hardware may be able to
            // have loaded, we want to make sure there's room for our model.
            stopAndUnloadDeadModelsLocked();
            int[] handle = new int[] { 0 };
            int status = mModule.loadSoundModel(modelData.getSoundModel(), handle);
            if (status != SoundTrigger.STATUS_OK) {
                Slog.w(TAG, "prepareForRecognition: loadSoundModel failed with status: " + status);
                return status;
            }
            modelData.setHandle(handle[0]);
            modelData.setLoaded();
            if (DBG) {
                Slog.d(TAG, "prepareForRecognition: Sound model loaded with handle:" + handle[0]);
            }
        }
        return STATUS_OK;
    }


    /**
     * Starts recognition for the given sound model. A single routine for both keyphrase and
     * generic sound models.
@@ -248,12 +314,17 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
                Slog.w(TAG, "Attempting startRecognition without the capability");
                return STATUS_ERROR;
            }
            if (mModule == null) {
                mModule = SoundTrigger.attachModule(mModuleProperties.getId(), this, null);
                if (mModule == null) {
                    Slog.w(TAG, "startRecognition cannot attach to sound trigger module");
                    return STATUS_ERROR;

            IRecognitionStatusCallback oldCallback = modelData.getCallback();
            if (oldCallback != null && oldCallback.asBinder() != callback.asBinder()) {
                Slog.w(TAG, "Canceling previous recognition for model id: "
                        + modelData.getModelId());
                try {
                    oldCallback.onError(STATUS_ERROR);
                } catch (RemoteException e) {
                    Slog.w(TAG, "RemoteException in onDetectionStopped", e);
                }
                modelData.clearCallback();
            }

            // If the existing SoundModel is different (for the same UUID for Generic and same
@@ -287,45 +358,22 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
                }
            }

            IRecognitionStatusCallback oldCallback = modelData.getCallback();
            if (oldCallback != null && oldCallback.asBinder() != callback.asBinder()) {
                Slog.w(TAG, "Canceling previous recognition for model id: " +
                        modelData.getModelId());
                try {
                    oldCallback.onError(STATUS_ERROR);
                } catch (RemoteException e) {
                    Slog.w(TAG, "RemoteException in onDetectionStopped", e);
                }
                modelData.clearCallback();
            }

            // Load the model if it is not loaded.
            if (!modelData.isModelLoaded()) {
                // Before we try and load this model, we should first make sure that any other
                // models that don't have an active recognition/dead callback are unloaded. Since
                // there is a finite limit on the number of models that the hardware may be able to
                // have loaded, we want to make sure there's room for our model.
                stopAndUnloadDeadModelsLocked();
                int[] handle = new int[] { INVALID_VALUE };
                int status = mModule.loadSoundModel(soundModel, handle);
                if (status != SoundTrigger.STATUS_OK) {
                    Slog.w(TAG, "loadSoundModel call failed with " + status);
                    return status;
                }
                if (handle[0] == INVALID_VALUE) {
                    Slog.w(TAG, "loadSoundModel call returned invalid sound model handle");
                    return STATUS_ERROR;
                }
                modelData.setHandle(handle[0]);
                modelData.setLoaded();
                Slog.d(TAG, "Sound model loaded with handle:" + handle[0]);
            }
            modelData.setCallback(callback);
            modelData.setRequested(true);
            modelData.setRecognitionConfig(recognitionConfig);
            modelData.setSoundModel(soundModel);

            int status = startRecognitionLocked(modelData,
            if (!isRecognitionAllowed()) {
                initializeTelephonyAndPowerStateListeners();
                return STATUS_OK;
            }

            int status = prepareForRecognition(modelData);
            if (status != STATUS_OK) {
                Slog.w(TAG, "startRecognition failed to prepare model for recognition");
                return status;
            }
            status = startRecognitionLocked(modelData,
                    false /* Don't notify for synchronous calls */);

            // Initialize power save, call active state monitoring logic.
@@ -398,7 +446,8 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
            if (DBG) {
                Slog.d(TAG, "stopRecognition for keyphraseId=" + keyphraseId + ", callback =" +
                        callback.asBinder());
                Slog.d(TAG, "current callback=" + (modelData == null ? "null" :
                Slog.d(TAG, "current callback="
                        + ((modelData == null || modelData.getCallback() == null) ? "null" :
                            modelData.getCallback().asBinder()));
            }
            int status = stopRecognition(modelData, callback);
@@ -507,8 +556,8 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
        synchronized (mLock) {
            MetricsLogger.count(mContext, "sth_unload_keyphrase_sound_model", 1);
            ModelData modelData = getKeyphraseModelDataLocked(keyphraseId);
            if (mModule == null || modelData == null || modelData.getHandle() == INVALID_VALUE ||
                    !modelData.isKeyphraseModel()) {
            if (mModule == null || modelData == null || !modelData.isModelLoaded()
                    || !modelData.isKeyphraseModel()) {
                return STATUS_ERROR;
            }

@@ -943,6 +992,10 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
            return STATUS_OK;
        }
        if (start) {
            int status = prepareForRecognition(model);
            if (status != STATUS_OK) {
                return status;
            }
            return startRecognitionLocked(model, notify);
        } else {
            return stopRecognitionLocked(model, notify);
@@ -992,8 +1045,15 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
        @Override
        public void onCallStateChanged(int state, String arg1) {
            if (DBG) Slog.d(TAG, "onCallStateChanged: " + state);

            if (mHandler != null) {
                synchronized (mLock) {
                onCallStateChangedLocked(TelephonyManager.CALL_STATE_OFFHOOK == state);
                    mHandler.removeMessages(MSG_CALL_STATE_CHANGED);
                    Message msg = mHandler.obtainMessage(MSG_CALL_STATE_CHANGED, state, 0);
                    mHandler.sendMessageDelayed(
                            msg, (TelephonyManager.CALL_STATE_OFFHOOK == state) ? 0
                                    : CALL_INACTIVE_MSG_DELAY_MS);
                }
            }
        }
    }
@@ -1216,9 +1276,8 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
    // models.
    private int startRecognitionLocked(ModelData modelData, boolean notify) {
        IRecognitionStatusCallback callback = modelData.getCallback();
        int handle = modelData.getHandle();
        RecognitionConfig config = modelData.getRecognitionConfig();
        if (callback == null || handle == INVALID_VALUE || config == null) {
        if (callback == null || !modelData.isModelLoaded() || config == null) {
            // Nothing to do here.
            Slog.w(TAG, "startRecognition: Bad data passed in.");
            MetricsLogger.count(mContext, "sth_start_recognition_error", 1);
@@ -1235,7 +1294,7 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
        if (mModule == null) {
            return STATUS_ERROR;
        }
        int status = mModule.startRecognition(handle, config);
        int status = mModule.startRecognition(modelData.getHandle(), config);
        if (status != SoundTrigger.STATUS_OK) {
            Slog.w(TAG, "startRecognition failed with " + status);
            MetricsLogger.count(mContext, "sth_start_recognition_error", 1);
@@ -1376,7 +1435,7 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {

        // Model handle is an integer used by the HAL as an identifier for sound
        // models.
        private int mModelHandle = INVALID_VALUE;
        private int mModelHandle;

        // The SoundModel instance, one of KeyphraseSoundModel or GenericSoundModel.
        private SoundModel mSoundModel = null;
@@ -1436,7 +1495,6 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {

        synchronized void clearState() {
            mModelState = MODEL_NOTLOADED;
            mModelHandle = INVALID_VALUE;
            mRecognitionConfig = null;
            mRequested = false;
            mCallback = null;