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

Commit 04585786 authored by android-build-team Robot's avatar android-build-team Robot Committed by Android (Google) Code Review
Browse files

Merge "Simulate handling of event when throttling" into pi-dev

parents 88cc74cd a5b4403a
Loading
Loading
Loading
Loading
+127 −23
Original line number Original line Diff line number Diff line
@@ -46,6 +46,10 @@ import android.hardware.soundtrigger.SoundTrigger.KeyphraseSoundModel;
import android.hardware.soundtrigger.SoundTrigger.ModuleProperties;
import android.hardware.soundtrigger.SoundTrigger.ModuleProperties;
import android.hardware.soundtrigger.SoundTrigger.RecognitionConfig;
import android.hardware.soundtrigger.SoundTrigger.RecognitionConfig;
import android.hardware.soundtrigger.SoundTrigger.SoundModel;
import android.hardware.soundtrigger.SoundTrigger.SoundModel;
import android.media.AudioAttributes;
import android.media.AudioFormat;
import android.media.AudioRecord;
import android.media.MediaRecorder;
import android.media.soundtrigger.ISoundTriggerDetectionService;
import android.media.soundtrigger.ISoundTriggerDetectionService;
import android.media.soundtrigger.ISoundTriggerDetectionServiceClient;
import android.media.soundtrigger.ISoundTriggerDetectionServiceClient;
import android.media.soundtrigger.SoundTriggerDetectionService;
import android.media.soundtrigger.SoundTriggerDetectionService;
@@ -654,10 +658,47 @@ public class SoundTriggerService extends SystemService {
        }
        }
    }
    }


    private interface Operation {
    /**
     * A single operation run in a {@link RemoteSoundTriggerDetectionService}.
     *
     * <p>Once the remote service is connected either setup + execute or setup + stop is executed.
     */
    private static class Operation {
        private interface ExecuteOp {
            void run(int opId, ISoundTriggerDetectionService service) throws RemoteException;
            void run(int opId, ISoundTriggerDetectionService service) throws RemoteException;
        }
        }


        private final @Nullable Runnable mSetupOp;
        private final @NonNull ExecuteOp mExecuteOp;
        private final @Nullable Runnable mDropOp;

        private Operation(@Nullable Runnable setupOp, @NonNull ExecuteOp executeOp,
                @Nullable Runnable cancelOp) {
            mSetupOp = setupOp;
            mExecuteOp = executeOp;
            mDropOp = cancelOp;
        }

        private void setup() {
            if (mSetupOp != null) {
                mSetupOp.run();
            }
        }

        void run(int opId, @NonNull ISoundTriggerDetectionService service) throws RemoteException {
            setup();
            mExecuteOp.run(opId, service);
        }

        void drop() {
            setup();

            if (mDropOp != null) {
                mDropOp.run();
            }
        }
    }

    /**
    /**
     * Local end for a {@link SoundTriggerDetectionService}. Operations are queued up and executed
     * Local end for a {@link SoundTriggerDetectionService}. Operations are queued up and executed
     * when the service connects.
     * when the service connects.
@@ -902,6 +943,10 @@ public class SoundTriggerService extends SystemService {
        private void runOrAddOperation(Operation op) {
        private void runOrAddOperation(Operation op) {
            synchronized (mRemoteServiceLock) {
            synchronized (mRemoteServiceLock) {
                if (mIsDestroyed || mDestroyOnceRunningOpsDone) {
                if (mIsDestroyed || mDestroyOnceRunningOpsDone) {
                    Slog.w(TAG, mPuuid + ": Dropped operation as already destroyed or marked for "
                            + "destruction");

                    op.drop();
                    return;
                    return;
                }
                }


@@ -922,9 +967,15 @@ public class SoundTriggerService extends SystemService {


                    int opsAdded = mNumOps.getOpsAdded();
                    int opsAdded = mNumOps.getOpsAdded();
                    if (mNumOps.getOpsAdded() >= opsAllowed) {
                    if (mNumOps.getOpsAdded() >= opsAllowed) {
                        try {
                            if (DEBUG || opsAllowed + 10 > opsAdded) {
                            if (DEBUG || opsAllowed + 10 > opsAdded) {
                            Slog.w(TAG, mPuuid + ": Dropped operation as too many operations were "
                                Slog.w(TAG, mPuuid + ": Dropped operation as too many operations "
                                    + "run in last 24 hours");
                                        + "were run in last 24 hours");
                            }

                            op.drop();
                        } catch (Exception e) {
                            Slog.e(TAG, mPuuid + ": Could not drop operation", e);
                        }
                        }
                    } else {
                    } else {
                        mNumOps.addOp(currentTime);
                        mNumOps.addOp(currentTime);
@@ -972,34 +1023,87 @@ public class SoundTriggerService extends SystemService {
                    + ")");
                    + ")");
        }
        }


        /**
         * Create an AudioRecord enough for starting and releasing the data buffered for the event.
         *
         * @param event The event that was received
         * @return The initialized AudioRecord
         */
        private @NonNull AudioRecord createAudioRecordForEvent(
                @NonNull SoundTrigger.GenericRecognitionEvent event) {
            AudioAttributes.Builder attributesBuilder = new AudioAttributes.Builder();
            attributesBuilder.setInternalCapturePreset(MediaRecorder.AudioSource.HOTWORD);
            AudioAttributes attributes = attributesBuilder.build();

            // Use same AudioFormat processing as in RecognitionEvent.fromParcel
            AudioFormat originalFormat = event.getCaptureFormat();
            AudioFormat captureFormat = (new AudioFormat.Builder())
                    .setChannelMask(originalFormat.getChannelMask())
                    .setEncoding(originalFormat.getEncoding())
                    .setSampleRate(originalFormat.getSampleRate())
                    .build();

            int bufferSize = AudioRecord.getMinBufferSize(
                    captureFormat.getSampleRate() == AudioFormat.SAMPLE_RATE_UNSPECIFIED
                            ? AudioFormat.SAMPLE_RATE_HZ_MAX
                            : captureFormat.getSampleRate(),
                    captureFormat.getChannelCount() == 2
                            ? AudioFormat.CHANNEL_IN_STEREO
                            : AudioFormat.CHANNEL_IN_MONO,
                    captureFormat.getEncoding());

            return new AudioRecord(attributes, captureFormat, bufferSize,
                    event.getCaptureSession());
        }

        @Override
        @Override
        public void onGenericSoundTriggerDetected(SoundTrigger.GenericRecognitionEvent event) {
        public void onGenericSoundTriggerDetected(SoundTrigger.GenericRecognitionEvent event) {
            if (DEBUG) Slog.v(TAG, mPuuid + ": Generic sound trigger event: " + event);
            if (DEBUG) Slog.v(TAG, mPuuid + ": Generic sound trigger event: " + event);


            runOrAddOperation((opId, service) -> {
            runOrAddOperation(new Operation(
                    // always execute:
                    () -> {
                        if (!mRecognitionConfig.allowMultipleTriggers) {
                        if (!mRecognitionConfig.allowMultipleTriggers) {
                            // Unregister this remoteService once op is done
                            synchronized (mCallbacksLock) {
                            synchronized (mCallbacksLock) {
                                mCallbacks.remove(mPuuid.getUuid());
                                mCallbacks.remove(mPuuid.getUuid());
                            }
                            }
                            mDestroyOnceRunningOpsDone = true;
                            mDestroyOnceRunningOpsDone = true;
                        }
                        }
                    },
                    // execute if not throttled:
                    (opId, service) -> service.onGenericRecognitionEvent(mPuuid, opId, event),
                    // execute if throttled:
                    () -> {
                        if (event.isCaptureAvailable()) {
                            AudioRecord capturedData = createAudioRecordForEvent(event);


                service.onGenericRecognitionEvent(mPuuid, opId, event);
                            // Currently we need to start and release the audio record to reset
            });
                            // the DSP even if we don't want to process the event
                            capturedData.startRecording();
                            capturedData.release();
                        }
                    }));
        }
        }


        @Override
        @Override
        public void onError(int status) {
        public void onError(int status) {
            if (DEBUG) Slog.v(TAG, mPuuid + ": onError: " + status);
            if (DEBUG) Slog.v(TAG, mPuuid + ": onError: " + status);


            runOrAddOperation((opId, service) -> {
            runOrAddOperation(
                    new Operation(
                            // always execute:
                            () -> {
                                // Unregister this remoteService once op is done
                                synchronized (mCallbacksLock) {
                                synchronized (mCallbacksLock) {
                                    mCallbacks.remove(mPuuid.getUuid());
                                    mCallbacks.remove(mPuuid.getUuid());
                                }
                                }
                                mDestroyOnceRunningOpsDone = true;
                                mDestroyOnceRunningOpsDone = true;

                            },
                service.onError(mPuuid, opId, status);
                            // execute if not throttled:
            });
                            (opId, service) -> service.onError(mPuuid, opId, status),
                            // nothing to do if throttled
                            null));
        }
        }


        @Override
        @Override