背景

  • Platform: RK3399
  • OS: Android7.1.2
  • Kernel: v4.4.103

问题

Android项目产品频响测试不达标,22.05K的采样率,频响只有7.5kHz左右。

分析

这是android系统著名的src问题,当播放或者录音的采样率与底层硬件设置的采样率不一致系统就会重采样。Android系统为了统一不同的音轨,底层硬件设置的采样率一般都是固定的44.1k或是48k。
重采样的算法,特别是非整数倍SRC,会对频响有一定的影响,线性插值效果最差,而Android默认的重采样质量使用的是DYN_LOW_QUALITY,其采用的重采样算法就是线性插值,但使用sinc等高质量的算法,CPU Load就会更高。见参考[3]

AudioMixer::track_t::setResampler:

///frameworks/av/services/audioflinger/AudioMixer.c
if (trackSampleRate != devSampleRate || resampler != NULL) {
        if (sampleRate != trackSampleRate) {
            sampleRate = trackSampleRate;
            if (resampler == NULL) {
                ALOGV("Creating resampler from track %d Hz to device %d Hz",
                        trackSampleRate, 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 (isMusicRate(trackSampleRate)) {
                    quality = AudioResampler::DEFAULT_QUALITY;
                } else {
                    quality = AudioResampler::DYN_LOW_QUALITY;   //
                }

                // TODO: Remove MONO_HACK. Resampler sees #channels after the downmixer
                // but if none exists, it is the channel count (1 for mono).
                const int resamplerChannelCount = downmixerBufferProvider != NULL
                        ? mMixerChannelCount : channelCount;
                ALOGVV("Creating resampler:"
                        " format(%#x) channels(%d) devSampleRate(%u) quality(%d)\n",
                        mMixerInFormat, resamplerChannelCount, devSampleRate, quality);
                resampler = AudioResampler::create(
                        mMixerInFormat,
                        resamplerChannelCount,
                        devSampleRate, quality);
            }
            return true;
        }
    }
    return false;

重采样质量定义:
af.resampler.quality:///frameworks/av/services/audioflinger/AudioResampler.c

///frameworks/av/services/audioflinger/AudioResampler.h
 enum src_quality {
        DEFAULT_QUALITY=0,
        LOW_QUALITY=1,
        MED_QUALITY=2,
        HIGH_QUALITY=3,
        VERY_HIGH_QUALITY=4,
        DYN_LOW_QUALITY=5,
        DYN_MED_QUALITY=6,
        DYN_HIGH_QUALITY=7,
    };

解决

  1. 把android固定的重采样频率,修改成动态重采样,见参考[4]
    其原理就是动态地去修改切换底层硬件的采样率
  2. 修改重采样算法
    当framework重采样时,默认的重采样质量由DYN_LOW_QUALITY改为DYN_MED_QUALITY

扩展

  • HAL层重采样:
    用的是speex
    speex使用的是cubic插值算法
  • Framework重采样:
    这是audioflinger的工作之一,另一个就是混音。
    据不同的quality选择不同的采样算法

    LOW_QUALITY:linear Resampler
    MED_QUALITY: cubic Resampler
    HIGH_QUALITY: sinc Resampler

参考

  1. [RK3288][Android6.0] Audio中的录音重采样小结
  2. [RK3288][Android6.0] Audio中的放音重采样小结
  3. 音频开源代码中重采样算法的评估与选择
  4. 一种解决android音频src问题的方法