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

Commit 7ffab293 authored by Glenn Kasten's avatar Glenn Kasten Committed by Android (Google) Code Review
Browse files

Merge "Integrate improved coefficient sinc resampler: VHQ" into jb-mr1-dev

parents f66cc52c ac602050
Loading
Loading
Loading
Loading
+1 −2
Original line number Diff line number Diff line
@@ -321,8 +321,7 @@ void VideoEditorSRC::checkAndSetResampler() {
        mResampler = AudioResampler::create(
                        16 /* bit depth */,
                        mChannelCnt,
                        mOutputSampleRate,
                        AudioResampler::DEFAULT);
                        mOutputSampleRate);
        CHECK(mResampler);
        mResampler->setSampleRate(mSampleRate);
        mResampler->setVolume(kUnityGain, kUnityGain);
+1 −1
Original line number Diff line number Diff line
@@ -80,7 +80,7 @@ M4OSA_Context LVAudioResamplerCreate(M4OSA_Int32 bitDepth, M4OSA_Int32 inChanne

    VideoEditorResampler *context = new VideoEditorResampler();
    context->mResampler = AudioResampler::create(
        bitDepth, inChannelCount, sampleRate, AudioResampler::DEFAULT);
        bitDepth, inChannelCount, sampleRate);
    if (context->mResampler == NULL) {
        return NULL;
    }
+3 −1
Original line number Diff line number Diff line
@@ -20,7 +20,9 @@ LOCAL_SRC_FILES:= \
    AudioPolicyService.cpp      \
    ServiceUtilities.cpp        \
    AudioResamplerSinc.cpp.arm
#   AudioResamplerCubic.cpp.arm

# uncomment to enable AudioResampler::MED_QUALITY
# LOCAL_SRC_FILES += AudioResamplerCubic.cpp.arm

LOCAL_SRC_FILES += StateQueue.cpp

+13 −1
Original line number Diff line number Diff line
@@ -539,11 +539,23 @@ bool AudioMixer::track_t::setResampler(uint32_t value, uint32_t devSampleRate)
        if (sampleRate != value) {
            sampleRate = value;
            if (resampler == NULL) {
                ALOGV("creating resampler from track %d Hz to device %d Hz", value, devSampleRate);
                AudioResampler::src_quality quality;
                // force lowest quality level resampler if use case isn't music or video
                // FIXME this is flawed for dynamic sample rates, as we choose the resampler
                // quality level based on the initial ratio, but that could change later.
                // Should have a way to distinguish tracks with static ratios vs. dynamic ratios.
                if (!((value == 44100 && devSampleRate == 48000) ||
                      (value == 48000 && devSampleRate == 44100))) {
                    quality = AudioResampler::LOW_QUALITY;
                } else {
                    quality = AudioResampler::DEFAULT_QUALITY;
                }
                resampler = AudioResampler::create(
                        format,
                        // the resampler sees the number of channels after the downmixer, if any
                        downmixerBufferProvider != NULL ? MAX_NUM_CHANNELS : channelCount,
                        devSampleRate);
                        devSampleRate, quality);
                resampler->setLocalTimeFreq(localTimeFreq);
            }
            return true;
+118 −16
Original line number Diff line number Diff line
@@ -24,9 +24,7 @@
#include <cutils/properties.h>
#include "AudioResampler.h"
#include "AudioResamplerSinc.h"
#if 0
#include "AudioResamplerCubic.h"
#endif

#ifdef __arm__
#include <machine/cpu-features.h>
@@ -42,7 +40,7 @@ namespace android {
class AudioResamplerOrder1 : public AudioResampler {
public:
    AudioResamplerOrder1(int bitDepth, int inChannelCount, int32_t sampleRate) :
        AudioResampler(bitDepth, inChannelCount, sampleRate), mX0L(0), mX0R(0) {
        AudioResampler(bitDepth, inChannelCount, sampleRate, LOW_QUALITY), mX0L(0), mX0R(0) {
    }
    virtual void resample(int32_t* out, size_t outFrameCount,
            AudioBufferProvider* provider);
@@ -79,29 +77,120 @@ private:
    int mX0R;
};

bool AudioResampler::qualityIsSupported(src_quality quality)
{
    switch (quality) {
    case DEFAULT_QUALITY:
    case LOW_QUALITY:
#if 0   // these have not been qualified recently so are not supported unless explicitly requested
    case MED_QUALITY:
    case HIGH_QUALITY:
#endif
    case VERY_HIGH_QUALITY:
        return true;
    default:
        return false;
    }
}

// ----------------------------------------------------------------------------
AudioResampler* AudioResampler::create(int bitDepth, int inChannelCount,
        int32_t sampleRate, int quality) {

    // can only create low quality resample now
    AudioResampler* resampler;
static pthread_once_t once_control = PTHREAD_ONCE_INIT;
static AudioResampler::src_quality defaultQuality = AudioResampler::DEFAULT_QUALITY;

void AudioResampler::init_routine()
{
    char value[PROPERTY_VALUE_MAX];
    if (property_get("af.resampler.quality", value, 0)) {
        quality = atoi(value);
        ALOGD("forcing AudioResampler quality to %d", quality);
    if (property_get("af.resampler.quality", value, NULL) > 0) {
        char *endptr;
        unsigned long l = strtoul(value, &endptr, 0);
        if (*endptr == '\0') {
            defaultQuality = (src_quality) l;
            ALOGD("forcing AudioResampler quality to %d", defaultQuality);
            if (defaultQuality < DEFAULT_QUALITY || defaultQuality > VERY_HIGH_QUALITY) {
                defaultQuality = DEFAULT_QUALITY;
            }
        }
    }
}

    if (quality == DEFAULT)
uint32_t AudioResampler::qualityMHz(src_quality quality)
{
    switch (quality) {
    default:
    case DEFAULT_QUALITY:
    case LOW_QUALITY:
        return 3;
    case MED_QUALITY:
        return 6;
    case HIGH_QUALITY:
        return 20;
    case VERY_HIGH_QUALITY:
        return 34;
    }
}

static const uint32_t maxMHz = 75;  // an arbitrary number that permits 2 VHQ, should be tunable
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
static uint32_t currentMHz = 0;

AudioResampler* AudioResampler::create(int bitDepth, int inChannelCount,
        int32_t sampleRate, src_quality quality) {

    bool atFinalQuality;
    if (quality == DEFAULT_QUALITY) {
        // read the resampler default quality property the first time it is needed
        int ok = pthread_once(&once_control, init_routine);
        if (ok != 0) {
            ALOGE("%s pthread_once failed: %d", __func__, ok);
        }
        quality = defaultQuality;
        atFinalQuality = false;
    } else {
        atFinalQuality = true;
    }

    // naive implementation of CPU load throttling doesn't account for whether resampler is active
    pthread_mutex_lock(&mutex);
    for (;;) {
        uint32_t deltaMHz = qualityMHz(quality);
        uint32_t newMHz = currentMHz + deltaMHz;
        if ((qualityIsSupported(quality) && newMHz <= maxMHz) || atFinalQuality) {
            ALOGV("resampler load %u -> %u MHz due to delta +%u MHz from quality %d",
                    currentMHz, newMHz, deltaMHz, quality);
            currentMHz = newMHz;
            break;
        }
        // not enough CPU available for proposed quality level, so try next lowest level
        switch (quality) {
        default:
        case DEFAULT_QUALITY:
        case LOW_QUALITY:
            atFinalQuality = true;
            break;
        case MED_QUALITY:
            quality = LOW_QUALITY;
            break;
        case HIGH_QUALITY:
            quality = MED_QUALITY;
            break;
        case VERY_HIGH_QUALITY:
            quality = HIGH_QUALITY;
            break;
        }
    }
    pthread_mutex_unlock(&mutex);

    AudioResampler* resampler;

    switch (quality) {
    default:
    case DEFAULT_QUALITY:
    case LOW_QUALITY:
        ALOGV("Create linear Resampler");
        resampler = new AudioResamplerOrder1(bitDepth, inChannelCount, sampleRate);
        break;
#if 0
#if 0   // disabled because it has not been qualified recently, if requested will use default:
    case MED_QUALITY:
        ALOGV("Create cubic Resampler");
        resampler = new AudioResamplerCubic(bitDepth, inChannelCount, sampleRate);
@@ -110,6 +199,7 @@ AudioResampler* AudioResampler::create(int bitDepth, int inChannelCount,
    case HIGH_QUALITY:
        ALOGV("Create HIGH_QUALITY sinc Resampler");
        resampler = new AudioResamplerSinc(bitDepth, inChannelCount, sampleRate);
        break;
    case VERY_HIGH_QUALITY:
        ALOGV("Create VERY_HIGH_QUALITY sinc Resampler = %d", quality);
        resampler = new AudioResamplerSinc(bitDepth, inChannelCount, sampleRate, quality);
@@ -122,17 +212,20 @@ AudioResampler* AudioResampler::create(int bitDepth, int inChannelCount,
}

AudioResampler::AudioResampler(int bitDepth, int inChannelCount,
        int32_t sampleRate) :
        int32_t sampleRate, src_quality quality) :
    mBitDepth(bitDepth), mChannelCount(inChannelCount),
            mSampleRate(sampleRate), mInSampleRate(sampleRate), mInputIndex(0),
            mPhaseFraction(0), mLocalTimeFreq(0),
            mPTS(AudioBufferProvider::kInvalidPTS) {
            mPTS(AudioBufferProvider::kInvalidPTS), mQuality(quality) {
    // sanity check on format
    if ((bitDepth != 16) ||(inChannelCount < 1) || (inChannelCount > 2)) {
        ALOGE("Unsupported sample format, %d bits, %d channels", bitDepth,
                inChannelCount);
        // ALOG_ASSERT(0);
    }
    if (sampleRate <= 0) {
        ALOGE("Unsupported sample rate %d Hz", sampleRate);
    }

    // initialize common members
    mVolume[0] = mVolume[1] = 0;
@@ -141,6 +234,15 @@ AudioResampler::AudioResampler(int bitDepth, int inChannelCount,
}

AudioResampler::~AudioResampler() {
    pthread_mutex_lock(&mutex);
    src_quality quality = getQuality();
    uint32_t deltaMHz = qualityMHz(quality);
    int32_t newMHz = currentMHz - deltaMHz;
    ALOGV("resampler load %u -> %d MHz due to delta -%u MHz from quality %d",
            currentMHz, newMHz, deltaMHz, quality);
    LOG_ALWAYS_FATAL_IF(newMHz < 0, "negative resampler load %d MHz", newMHz);
    currentMHz = newMHz;
    pthread_mutex_unlock(&mutex);
}

void AudioResampler::setSampleRate(int32_t inSampleRate) {
Loading