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

Commit e70bc7fc authored by jiabin's avatar jiabin
Browse files

Support scaling haptic data in HapticGenerator

Move function of scaling haptic data from AudioMixer to vibrator
library. Scaling haptic data in HapticGenerator according to the haptic
intensity.

Bug: 136490803
Test: play audio-coupled-haptic files
Test: play audio with HapticGenerator effect
Change-Id: I6bac63c085332ea87cc6612a8f2f368ad7ef7826
parent eb3bda06
Loading
Loading
Loading
Loading
+3 −10
Original line number Diff line number Diff line
@@ -423,7 +423,7 @@ void AudioMixer::setParameter(int name, int target, int param, void *value)
            }
            } break;
        case HAPTIC_INTENSITY: {
            const haptic_intensity_t hapticIntensity = static_cast<haptic_intensity_t>(valueInt);
            const os::HapticScale hapticIntensity = static_cast<os::HapticScale>(valueInt);
            if (track->mHapticIntensity != hapticIntensity) {
                track->mHapticIntensity = hapticIntensity;
            }
@@ -545,7 +545,7 @@ status_t AudioMixer::postCreateTrack(TrackBase *track)
    t->mPlaybackRate = AUDIO_PLAYBACK_RATE_DEFAULT;
    // haptic
    t->mHapticPlaybackEnabled = false;
    t->mHapticIntensity = HAPTIC_SCALE_NONE;
    t->mHapticIntensity = os::HapticScale::NONE;
    t->mMixerHapticChannelMask = AUDIO_CHANNEL_NONE;
    t->mMixerHapticChannelCount = 0;
    t->mAdjustInChannelCount = t->channelCount + t->mHapticChannelCount;
@@ -590,19 +590,12 @@ void AudioMixer::postProcess()
            const std::shared_ptr<Track> &t = getTrack(name);
            if (t->mHapticPlaybackEnabled) {
                size_t sampleCount = mFrameCount * t->mMixerHapticChannelCount;
                float gamma = t->getHapticScaleGamma();
                float maxAmplitudeRatio = t->getHapticMaxAmplitudeRatio();
                uint8_t* buffer = (uint8_t*)pair.first + mFrameCount * audio_bytes_per_frame(
                        t->mMixerChannelCount, t->mMixerFormat);
                switch (t->mMixerFormat) {
                // Mixer format should be AUDIO_FORMAT_PCM_FLOAT.
                case AUDIO_FORMAT_PCM_FLOAT: {
                    float* fout = (float*) buffer;
                    for (size_t i = 0; i < sampleCount; i++) {
                        float mul = fout[i] >= 0 ? 1.0 : -1.0;
                        fout[i] = powf(fabsf(fout[i] / HAPTIC_MAX_AMPLITUDE_FLOAT), gamma)
                                * maxAmplitudeRatio * HAPTIC_MAX_AMPLITUDE_FLOAT * mul;
                    }
                    os::scaleHapticData((float*) buffer, sampleCount, t->mHapticIntensity);
                } break;
                default:
                    LOG_ALWAYS_FATAL("bad mMixerFormat: %#x", t->mMixerFormat);
+2 −60
Original line number Diff line number Diff line
@@ -22,10 +22,10 @@
#include <stdint.h>
#include <sys/types.h>

#include <android/os/IExternalVibratorService.h>
#include <media/AudioMixerBase.h>
#include <media/BufferProviders.h>
#include <utils/threads.h>
#include <vibrator/ExternalVibrationUtils.h>

// FIXME This is actually unity gain, which might not be max in future, expressed in U.12
#define MAX_GAIN_INT AudioMixerBase::UNITY_GAIN_INT
@@ -55,32 +55,6 @@ public:
                                  // parameter 'value' is a pointer to the new playback rate.
    };

    typedef enum { // Haptic intensity, should keep consistent with VibratorService
        HAPTIC_SCALE_MUTE = os::IExternalVibratorService::SCALE_MUTE,
        HAPTIC_SCALE_VERY_LOW = os::IExternalVibratorService::SCALE_VERY_LOW,
        HAPTIC_SCALE_LOW = os::IExternalVibratorService::SCALE_LOW,
        HAPTIC_SCALE_NONE = os::IExternalVibratorService::SCALE_NONE,
        HAPTIC_SCALE_HIGH = os::IExternalVibratorService::SCALE_HIGH,
        HAPTIC_SCALE_VERY_HIGH = os::IExternalVibratorService::SCALE_VERY_HIGH,
    } haptic_intensity_t;
    static constexpr float HAPTIC_SCALE_VERY_LOW_RATIO = 2.0f / 3.0f;
    static constexpr float HAPTIC_SCALE_LOW_RATIO = 3.0f / 4.0f;
    static const constexpr float HAPTIC_MAX_AMPLITUDE_FLOAT = 1.0f;

    static inline bool isValidHapticIntensity(haptic_intensity_t hapticIntensity) {
        switch (hapticIntensity) {
        case HAPTIC_SCALE_MUTE:
        case HAPTIC_SCALE_VERY_LOW:
        case HAPTIC_SCALE_LOW:
        case HAPTIC_SCALE_NONE:
        case HAPTIC_SCALE_HIGH:
        case HAPTIC_SCALE_VERY_HIGH:
            return true;
        default:
            return false;
        }
    }

    AudioMixer(size_t frameCount, uint32_t sampleRate)
            : AudioMixerBase(frameCount, sampleRate) {
        pthread_once(&sOnceControl, &sInitRoutine);
@@ -170,7 +144,7 @@ private:

        // Haptic
        bool                 mHapticPlaybackEnabled;
        haptic_intensity_t   mHapticIntensity;
        os::HapticScale      mHapticIntensity;
        audio_channel_mask_t mHapticChannelMask;
        uint32_t             mHapticChannelCount;
        audio_channel_mask_t mMixerHapticChannelMask;
@@ -180,38 +154,6 @@ private:
        uint32_t             mAdjustNonDestructiveInChannelCount;
        uint32_t             mAdjustNonDestructiveOutChannelCount;
        bool                 mKeepContractedChannels;

        float getHapticScaleGamma() const {
        // Need to keep consistent with the value in VibratorService.
        switch (mHapticIntensity) {
        case HAPTIC_SCALE_VERY_LOW:
            return 2.0f;
        case HAPTIC_SCALE_LOW:
            return 1.5f;
        case HAPTIC_SCALE_HIGH:
            return 0.5f;
        case HAPTIC_SCALE_VERY_HIGH:
            return 0.25f;
        default:
            return 1.0f;
        }
        }

        float getHapticMaxAmplitudeRatio() const {
        // Need to keep consistent with the value in VibratorService.
        switch (mHapticIntensity) {
        case HAPTIC_SCALE_VERY_LOW:
            return HAPTIC_SCALE_VERY_LOW_RATIO;
        case HAPTIC_SCALE_LOW:
            return HAPTIC_SCALE_LOW_RATIO;
        case HAPTIC_SCALE_NONE:
        case HAPTIC_SCALE_HIGH:
        case HAPTIC_SCALE_VERY_HIGH:
            return 1.0f;
        default:
            return 0.0f;
        }
        }
    };

    inline std::shared_ptr<Track> getTrack(int name) {
+2 −0
Original line number Diff line number Diff line
@@ -36,8 +36,10 @@ cc_library_shared {

    shared_libs: [
        "libaudioutils",
        "libbinder",
        "liblog",
        "libutils",
        "libvibrator",
    ],

    relative_install_path: "soundfx",
+40 −7
Original line number Diff line number Diff line
@@ -96,7 +96,10 @@ int HapticGenerator_Init(struct HapticGeneratorContext *context) {
    context->config.outputCfg.bufferProvider.cookie = nullptr;
    context->config.outputCfg.mask = EFFECT_CONFIG_ALL;

    memset(&context->param, 0, sizeof(struct HapticGeneratorParam));
    memset(context->param.hapticChannelSource, 0, sizeof(context->param.hapticChannelSource));
    context->param.hapticChannelCount = 0;
    context->param.audioChannelCount = 0;
    context->param.maxHapticIntensity = os::HapticScale::MUTE;

    context->state = HAPTICGENERATOR_STATE_INITIALIZED;
    return 0;
@@ -236,12 +239,36 @@ int HapticGenerator_Reset(struct HapticGeneratorContext *context) {
    return 0;
}

int HapticGenerator_SetParameter(struct HapticGeneratorContext *context __unused,
                                 int32_t param __unused,
                                 uint32_t size __unused,
                                 void *value __unused) {
    ALOGW("Setparameter is not implemented in HapticGenerator");
    return -ENOSYS;
int HapticGenerator_SetParameter(struct HapticGeneratorContext *context,
                                 int32_t param,
                                 uint32_t size,
                                 void *value) {
    switch (param) {
    case HG_PARAM_HAPTIC_INTENSITY: {
        if (value == nullptr || size != (uint32_t) (2 * sizeof(int))) {
            return -EINVAL;
        }
        int id = *(int *) value;
        os::HapticScale hapticIntensity = static_cast<os::HapticScale>(*((int *) value + 1));
        if (hapticIntensity == os::HapticScale::MUTE) {
            context->param.id2Intensity.erase(id);
        } else {
            context->param.id2Intensity.emplace(id, hapticIntensity);
        }
        context->param.maxHapticIntensity = hapticIntensity;
        for (const auto&[id, intensity] : context->param.id2Intensity) {
            context->param.maxHapticIntensity = std::max(
                    context->param.maxHapticIntensity, intensity);
        }
        break;
    }

    default:
        ALOGW("Unknown param: %d", param);
        return -EINVAL;
    }

    return 0;
}

/**
@@ -346,6 +373,11 @@ int32_t HapticGenerator_Process(effect_handle_t self,
        return -ENODATA;
    }

    if (context->param.maxHapticIntensity == os::HapticScale::MUTE) {
        // Haptic channels are muted, not need to generate haptic data.
        return 0;
    }

    // Resize buffer if the haptic sample count is greater than buffer size.
    size_t hapticSampleCount = inBuffer->frameCount * context->param.hapticChannelCount;
    if (hapticSampleCount > context->inputBuffer.size()) {
@@ -367,6 +399,7 @@ int32_t HapticGenerator_Process(effect_handle_t self,
    float* hapticOutBuffer = HapticGenerator_runProcessingChain(
            context->processingChain, context->inputBuffer.data(),
            context->outputBuffer.data(), inBuffer->frameCount);
    os::scaleHapticData(hapticOutBuffer, hapticSampleCount, context->param.maxHapticIntensity);

    // For haptic data, the haptic playback thread will copy the data from effect input buffer,
    // which contains haptic data at the end of the buffer, directly to sink buffer.
+6 −0
Original line number Diff line number Diff line
@@ -19,9 +19,11 @@

#include <functional>
#include <vector>
#include <map>

#include <hardware/audio_effect.h>
#include <system/audio_effect.h>
#include <vibrator/ExternalVibrationUtils.h>

#include "Processors.h"

@@ -45,6 +47,10 @@ struct HapticGeneratorParam {
                                     // The value will be offset of audio channel
    uint32_t audioChannelCount;
    uint32_t hapticChannelCount;

    // A map from track id to haptic intensity.
    std::map<int, os::HapticScale> id2Intensity;
    os::HapticScale maxHapticIntensity; // max intensity will be used to scale haptic data.
};

// A structure to keep all shared pointers for all processors in HapticGenerator.
Loading