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

Commit 7d383d1a authored by Ytai Ben-Tsvi's avatar Ytai Ben-Tsvi
Browse files

Migrate SoundTrigger implementation to new service

The API offered by SoundTrigger.java is now implemented on top of
the new soundtrigger_middleware service.
There is no longer any need for JNI - the API now talks directly
with the AIDL interface of the new service.

In the process, some annotations and input validation have been added
to improve the overall quality of this API.

Change-Id: I731ffd5a275b88f38d84dd3daa022a13f97a5ee1
Bug: 142070343
parent 93c117c8
Loading
Loading
Loading
Loading
+329 −0
Original line number Diff line number Diff line
/*
 * 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;

import android.hardware.soundtrigger.ModelParams;
import android.media.AudioFormat;
import android.media.audio.common.AudioConfig;
import android.media.soundtrigger_middleware.ConfidenceLevel;
import android.media.soundtrigger_middleware.ModelParameterRange;
import android.media.soundtrigger_middleware.Phrase;
import android.media.soundtrigger_middleware.PhraseRecognitionEvent;
import android.media.soundtrigger_middleware.PhraseRecognitionExtra;
import android.media.soundtrigger_middleware.PhraseSoundModel;
import android.media.soundtrigger_middleware.RecognitionConfig;
import android.media.soundtrigger_middleware.RecognitionEvent;
import android.media.soundtrigger_middleware.RecognitionMode;
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;

/** @hide */
class ConversionUtil {
    public static SoundTrigger.ModuleProperties aidl2apiModuleDescriptor(
            SoundTriggerModuleDescriptor aidlDesc) {
        SoundTriggerModuleProperties properties = aidlDesc.properties;
        return new SoundTrigger.ModuleProperties(
                aidlDesc.handle,
                properties.implementor,
                properties.description,
                properties.uuid,
                properties.version,
                properties.maxSoundModels,
                properties.maxKeyPhrases,
                properties.maxUsers,
                aidl2apiRecognitionModes(properties.recognitionModes),
                properties.captureTransition,
                properties.maxBufferMs,
                properties.concurrentCapture,
                properties.powerConsumptionMw,
                properties.triggerInEvent
        );
    }

    public static int aidl2apiRecognitionModes(int aidlModes) {
        int result = 0;
        if ((aidlModes & RecognitionMode.VOICE_TRIGGER) != 0) {
            result |= SoundTrigger.RECOGNITION_MODE_VOICE_TRIGGER;
        }
        if ((aidlModes & RecognitionMode.USER_IDENTIFICATION) != 0) {
            result |= SoundTrigger.RECOGNITION_MODE_USER_IDENTIFICATION;
        }
        if ((aidlModes & RecognitionMode.USER_AUTHENTICATION) != 0) {
            result |= SoundTrigger.RECOGNITION_MODE_USER_AUTHENTICATION;
        }
        if ((aidlModes & RecognitionMode.GENERIC_TRIGGER) != 0) {
            result |= SoundTrigger.RECOGNITION_MODE_GENERIC;
        }
        return result;
    }

    public static int api2aidlRecognitionModes(int apiModes) {
        int result = 0;
        if ((apiModes & SoundTrigger.RECOGNITION_MODE_VOICE_TRIGGER) != 0) {
            result |= RecognitionMode.VOICE_TRIGGER;
        }
        if ((apiModes & SoundTrigger.RECOGNITION_MODE_USER_IDENTIFICATION) != 0) {
            result |= RecognitionMode.USER_IDENTIFICATION;
        }
        if ((apiModes & SoundTrigger.RECOGNITION_MODE_USER_AUTHENTICATION) != 0) {
            result |= RecognitionMode.USER_AUTHENTICATION;
        }
        if ((apiModes & SoundTrigger.RECOGNITION_MODE_GENERIC) != 0) {
            result |= RecognitionMode.GENERIC_TRIGGER;
        }
        return result;
    }


    public static SoundModel api2aidlGenericSoundModel(SoundTrigger.GenericSoundModel apiModel) {
        return api2aidlSoundModel(apiModel);
    }

    public static SoundModel api2aidlSoundModel(SoundTrigger.SoundModel apiModel) {
        SoundModel aidlModel = new SoundModel();
        aidlModel.type = apiModel.type;
        aidlModel.uuid = api2aidlUuid(apiModel.uuid);
        aidlModel.vendorUuid = api2aidlUuid(apiModel.vendorUuid);
        aidlModel.data = Arrays.copyOf(apiModel.data, apiModel.data.length);
        return aidlModel;
    }

    public static String api2aidlUuid(UUID apiUuid) {
        return apiUuid.toString();
    }

    public static PhraseSoundModel api2aidlPhraseSoundModel(
            SoundTrigger.KeyphraseSoundModel apiModel) {
        PhraseSoundModel aidlModel = new PhraseSoundModel();
        aidlModel.common = api2aidlSoundModel(apiModel);
        aidlModel.phrases = new Phrase[apiModel.keyphrases.length];
        for (int i = 0; i < apiModel.keyphrases.length; ++i) {
            aidlModel.phrases[i] = api2aidlPhrase(apiModel.keyphrases[i]);
        }
        return aidlModel;
    }

    public static Phrase api2aidlPhrase(SoundTrigger.Keyphrase apiPhrase) {
        Phrase aidlPhrase = new Phrase();
        aidlPhrase.id = apiPhrase.id;
        aidlPhrase.recognitionModes = api2aidlRecognitionModes(apiPhrase.recognitionModes);
        aidlPhrase.users = Arrays.copyOf(apiPhrase.users, apiPhrase.users.length);
        aidlPhrase.locale = apiPhrase.locale;
        aidlPhrase.text = apiPhrase.text;
        return aidlPhrase;
    }

    public static RecognitionConfig api2aidlRecognitionConfig(
            SoundTrigger.RecognitionConfig apiConfig) {
        RecognitionConfig aidlConfig = new RecognitionConfig();
        aidlConfig.captureRequested = apiConfig.captureRequested;
        // apiConfig.allowMultipleTriggers is ignored by the lower layers.
        aidlConfig.phraseRecognitionExtras =
                new PhraseRecognitionExtra[apiConfig.keyphrases.length];
        for (int i = 0; i < apiConfig.keyphrases.length; ++i) {
            aidlConfig.phraseRecognitionExtras[i] = api2aidlPhraseRecognitionExtra(
                    apiConfig.keyphrases[i]);
        }
        aidlConfig.data = Arrays.copyOf(apiConfig.data, apiConfig.data.length);
        return aidlConfig;
    }

    public static PhraseRecognitionExtra api2aidlPhraseRecognitionExtra(
            SoundTrigger.KeyphraseRecognitionExtra apiExtra) {
        PhraseRecognitionExtra aidlExtra = new PhraseRecognitionExtra();
        aidlExtra.id = apiExtra.id;
        aidlExtra.recognitionModes = api2aidlRecognitionModes(apiExtra.recognitionModes);
        aidlExtra.confidenceLevel = apiExtra.coarseConfidenceLevel;
        aidlExtra.levels = new ConfidenceLevel[apiExtra.confidenceLevels.length];
        for (int i = 0; i < apiExtra.confidenceLevels.length; ++i) {
            aidlExtra.levels[i] = api2aidlConfidenceLevel(apiExtra.confidenceLevels[i]);
        }
        return aidlExtra;
    }

    public static SoundTrigger.KeyphraseRecognitionExtra aidl2apiPhraseRecognitionExtra(
            PhraseRecognitionExtra aidlExtra) {
        SoundTrigger.ConfidenceLevel[] apiLevels =
                new SoundTrigger.ConfidenceLevel[aidlExtra.levels.length];
        for (int i = 0; i < aidlExtra.levels.length; ++i) {
            apiLevels[i] = aidl2apiConfidenceLevel(aidlExtra.levels[i]);
        }
        return new SoundTrigger.KeyphraseRecognitionExtra(aidlExtra.id,
                aidl2apiRecognitionModes(aidlExtra.recognitionModes),
                aidlExtra.confidenceLevel, apiLevels);
    }

    public static ConfidenceLevel api2aidlConfidenceLevel(
            SoundTrigger.ConfidenceLevel apiLevel) {
        ConfidenceLevel aidlLevel = new ConfidenceLevel();
        aidlLevel.levelPercent = apiLevel.confidenceLevel;
        aidlLevel.userId = apiLevel.userId;
        return aidlLevel;
    }

    public static SoundTrigger.ConfidenceLevel aidl2apiConfidenceLevel(
            ConfidenceLevel apiLevel) {
        return new SoundTrigger.ConfidenceLevel(apiLevel.userId, apiLevel.levelPercent);
    }

    public static SoundTrigger.RecognitionEvent aidl2apiRecognitionEvent(
            int modelHandle, RecognitionEvent aidlEvent) {
        return new SoundTrigger.GenericRecognitionEvent(
                aidlEvent.status,
                modelHandle, aidlEvent.captureAvailable, aidlEvent.captureSession,
                aidlEvent.captureDelayMs, aidlEvent.capturePreambleMs, aidlEvent.triggerInData,
                aidl2apiAudioFormat(aidlEvent.audioConfig), aidlEvent.data);
    }

    public static SoundTrigger.RecognitionEvent aidl2apiPhraseRecognitionEvent(
            int modelHandle,
            PhraseRecognitionEvent aidlEvent) {
        SoundTrigger.KeyphraseRecognitionExtra[] apiExtras =
                new SoundTrigger.KeyphraseRecognitionExtra[aidlEvent.phraseExtras.length];
        for (int i = 0; i < aidlEvent.phraseExtras.length; ++i) {
            apiExtras[i] = aidl2apiPhraseRecognitionExtra(aidlEvent.phraseExtras[i]);
        }
        return new SoundTrigger.KeyphraseRecognitionEvent(aidlEvent.common.status, modelHandle,
                aidlEvent.common.captureAvailable,
                aidlEvent.common.captureSession, aidlEvent.common.captureDelayMs,
                aidlEvent.common.capturePreambleMs, aidlEvent.common.triggerInData,
                aidl2apiAudioFormat(aidlEvent.common.audioConfig), aidlEvent.common.data,
                apiExtras);
    }

    public static AudioFormat aidl2apiAudioFormat(AudioConfig audioConfig) {
        AudioFormat.Builder apiBuilder = new AudioFormat.Builder();
        apiBuilder.setSampleRate(audioConfig.sampleRateHz);
        apiBuilder.setChannelMask(aidl2apiChannelInMask(audioConfig.channelMask));
        apiBuilder.setEncoding(aidl2apiEncoding(audioConfig.format));
        return apiBuilder.build();
    }

    public static int aidl2apiEncoding(int aidlFormat) {
        switch (aidlFormat) {
            case android.media.audio.common.AudioFormat.PCM
                    | android.media.audio.common.AudioFormat.PCM_SUB_16_BIT:
                return AudioFormat.ENCODING_PCM_16BIT;

            case android.media.audio.common.AudioFormat.PCM
                    | android.media.audio.common.AudioFormat.PCM_SUB_8_BIT:
                return AudioFormat.ENCODING_PCM_8BIT;

            case android.media.audio.common.AudioFormat.PCM
                    | android.media.audio.common.AudioFormat.PCM_SUB_FLOAT:
            case android.media.audio.common.AudioFormat.PCM
                    | android.media.audio.common.AudioFormat.PCM_SUB_8_24_BIT:
            case android.media.audio.common.AudioFormat.PCM
                    | android.media.audio.common.AudioFormat.PCM_SUB_24_BIT_PACKED:
            case android.media.audio.common.AudioFormat.PCM
                    | android.media.audio.common.AudioFormat.PCM_SUB_32_BIT:
                return AudioFormat.ENCODING_PCM_FLOAT;

            case android.media.audio.common.AudioFormat.AC3:
                return AudioFormat.ENCODING_AC3;

            case android.media.audio.common.AudioFormat.E_AC3:
                return AudioFormat.ENCODING_E_AC3;

            case android.media.audio.common.AudioFormat.DTS:
                return AudioFormat.ENCODING_DTS;

            case android.media.audio.common.AudioFormat.DTS_HD:
                return AudioFormat.ENCODING_DTS_HD;

            case android.media.audio.common.AudioFormat.MP3:
                return AudioFormat.ENCODING_MP3;

            case android.media.audio.common.AudioFormat.AAC
                    | android.media.audio.common.AudioFormat.AAC_SUB_LC:
                return AudioFormat.ENCODING_AAC_LC;

            case android.media.audio.common.AudioFormat.AAC
                    | android.media.audio.common.AudioFormat.AAC_SUB_HE_V1:
                return AudioFormat.ENCODING_AAC_HE_V1;

            case android.media.audio.common.AudioFormat.AAC
                    | android.media.audio.common.AudioFormat.AAC_SUB_HE_V2:
                return AudioFormat.ENCODING_AAC_HE_V2;

            case android.media.audio.common.AudioFormat.IEC61937:
                return AudioFormat.ENCODING_IEC61937;

            case android.media.audio.common.AudioFormat.DOLBY_TRUEHD:
                return AudioFormat.ENCODING_DOLBY_TRUEHD;

            case android.media.audio.common.AudioFormat.AAC
                    | android.media.audio.common.AudioFormat.AAC_SUB_ELD:
                return AudioFormat.ENCODING_AAC_ELD;

            case android.media.audio.common.AudioFormat.AAC
                    | android.media.audio.common.AudioFormat.AAC_SUB_XHE:
                return AudioFormat.ENCODING_AAC_XHE;

            case android.media.audio.common.AudioFormat.AC4:
                return AudioFormat.ENCODING_AC4;

            case android.media.audio.common.AudioFormat.E_AC3
                    | android.media.audio.common.AudioFormat.E_AC3_SUB_JOC:
                return AudioFormat.ENCODING_E_AC3_JOC;

            case android.media.audio.common.AudioFormat.MAT:
            case android.media.audio.common.AudioFormat.MAT
                    | android.media.audio.common.AudioFormat.MAT_SUB_1_0:
            case android.media.audio.common.AudioFormat.MAT
                    | android.media.audio.common.AudioFormat.MAT_SUB_2_0:
            case android.media.audio.common.AudioFormat.MAT
                    | android.media.audio.common.AudioFormat.MAT_SUB_2_1:
                return AudioFormat.ENCODING_DOLBY_MAT;

            case android.media.audio.common.AudioFormat.DEFAULT:
                return AudioFormat.ENCODING_DEFAULT;

            default:
                return AudioFormat.ENCODING_INVALID;
        }
    }

    public static int api2aidlModelParameter(int apiParam) {
        switch (apiParam) {
            case ModelParams.THRESHOLD_FACTOR:
                return android.media.soundtrigger_middleware.ModelParameter.THRESHOLD_FACTOR;
            default:
                return android.media.soundtrigger_middleware.ModelParameter.INVALID;
        }
    }

    public static int aidl2apiChannelInMask(int aidlMask) {
        // We're assuming AudioFormat.CHANNEL_IN_* constants are kept in sync with
        // android.media.audio.common.AudioChannelMask.
        return aidlMask;
    }

    public static SoundTrigger.ModelParamRange aidl2apiModelParameterRange(
            @Nullable ModelParameterRange aidlRange) {
        if (aidlRange == null) {
            return null;
        }
        return new SoundTrigger.ModelParamRange(aidlRange.minInclusive, aidlRange.maxInclusive);
    }
}
+119 −57

File changed.

Preview size limit exceeded, changes collapsed.

+201 −103

File changed.

Preview size limit exceeded, changes collapsed.

+0 −2
Original line number Diff line number Diff line
@@ -177,7 +177,6 @@ cc_library_shared {
                "android_hardware_HardwareBuffer.cpp",
                "android_hardware_SensorManager.cpp",
                "android_hardware_SerialPort.cpp",
                "android_hardware_SoundTrigger.cpp",
                "android_hardware_UsbDevice.cpp",
                "android_hardware_UsbDeviceConnection.cpp",
                "android_hardware_UsbRequest.cpp",
@@ -259,7 +258,6 @@ cc_library_shared {
                "libpdfium",
                "libimg_utils",
                "libnetd_client",
                "libsoundtrigger",
                "libprocessgroup",
                "libnativebridge_lazy",
                "libnativeloader_lazy",
+0 −2
Original line number Diff line number Diff line
@@ -80,7 +80,6 @@ extern int register_android_hardware_camera2_DngCreator(JNIEnv *env);
extern int register_android_hardware_HardwareBuffer(JNIEnv *env);
extern int register_android_hardware_SensorManager(JNIEnv *env);
extern int register_android_hardware_SerialPort(JNIEnv *env);
extern int register_android_hardware_SoundTrigger(JNIEnv *env);
extern int register_android_hardware_UsbDevice(JNIEnv *env);
extern int register_android_hardware_UsbDeviceConnection(JNIEnv *env);
extern int register_android_hardware_UsbRequest(JNIEnv *env);
@@ -1508,7 +1507,6 @@ static const RegJNIRec gRegJNI[] = {
    REG_JNI(register_android_hardware_HardwareBuffer),
    REG_JNI(register_android_hardware_SensorManager),
    REG_JNI(register_android_hardware_SerialPort),
    REG_JNI(register_android_hardware_SoundTrigger),
    REG_JNI(register_android_hardware_UsbDevice),
    REG_JNI(register_android_hardware_UsbDeviceConnection),
    REG_JNI(register_android_hardware_UsbRequest),
Loading