音频跟踪采样率不一致

2022-09-01 12:18:53

使用 AudioTrack 进行播放时,我有时需要对不符合 AudioTrack 支持的采样率的音频重新采样。在此过程中,我需要确定 AudioTrack 支持的最大采样率,在当前设备下,在当前音频配置下。

由于AudioTrack允许的采样率记录得很差,我决定窥探源代码,并发现了这一行惊人的行:AudioTrack

private static final int SAMPLE_RATE_HZ_MAX = 96000;

该实例似乎应用了96 KHz的硬限制,而不管设备的实际播放功能如何。AudioTrack

更令人困惑的是类,其中我传递给 的构造函数(API 21),其中包含以下行:AudioFormatAudioTrack

if ((sampleRate <= 0) || (sampleRate > 192000)) {

在它的方法。现在这是192 KHz的硬性限制。因此,将> 192 KHz 传递到 AudioFormat(或其构建器)将导致配置的 192 KHz < x < 96 KHz 采样率 AudioFormat 传递到 AudioTrack 中,setSampleRate()IllegalArgumentExceptionAudioFormatIllegalArgumentException


到目前为止,我发现最令人困惑的是AudioTrack中的方法,它实际上确实返回了正确的输出采样率(好吧,考虑到它是直接从本机层运行的,所以这并不奇怪,但如此不一致)。getNativeOutputSampleRate()

最重要的是,该方法声称:setPlaybackRate()

有效采样率范围为 getNativeOutputSampleRate(int) 返回值的 1 Hz 到两倍。

事实上,我确实尝试过,它有效吗?请考虑以下代码段:

int nativeRate = AudioTrack.getNativeOutputSampleRate(AudioManager.STREAM_MUSIC);

android.util.Log.i("UI", "Native stream rate: " + nativeRate + " Hz");

// Build audio attributes

AudioAttributes.Builder attribBuilder = new AudioAttributes.Builder();

attribBuilder.setContentType(AudioAttributes.CONTENT_TYPE_MUSIC);
attribBuilder.setUsage(AudioAttributes.USAGE_MEDIA);

AudioAttributes attrib = attribBuilder.build();

// Build audio format

AudioFormat.Builder afBuilder = new AudioFormat.Builder();

afBuilder.setChannelMask(AudioFormat.CHANNEL_OUT_STEREO);
afBuilder.setEncoding(AudioFormat.ENCODING_PCM_16BIT);
afBuilder.setSampleRate(nativeRate);

try{
    AudioTrack trackTest = new AudioTrack(attrib, afBuilder.build(), nativeRate, AudioTrack.MODE_STREAM, 0);

    android.util.Log.i("UI", "Track created successfully (direct)");
}catch(Exception ex){
    android.util.Log.w("UI", "Failed to create AudioTrack at native rate!");

    // Use a random supported samplerate to get pass constructor
    afBuilder.setSampleRate(48000);

    try{
        AudioTrack trackTest = new AudioTrack(attrib, afBuilder.build(), nativeRate, AudioTrack.MODE_STREAM, 0);

        trackTest.setPlaybackRate(nativeRate);

        android.util.Log.i("UI", "Track created successfully (indirect)");
    }catch(Exception e){
        android.util.Log.w("UI", "Failed to create AudioTrack at 48 KHz");
    }
}

按照程序流程,当本机采样率< 96 KHz 时,代码将打印出来:

原生流速率:48000 Hz
轨道创建成功(直接)

但是,当我连接具有高达192 KHz回放功能的外部DAC时,我得到:

原生流速率:192000 Hz
无法以原生速率创建 AudioTrack!
已成功创建的跟踪(间接)

这些不一致是什么?而且,是否与传递到构造函数中的采样率相同?setPlaybackRate()


答案 1

目前市场上大多数Android手机只支持一种采样率。我相信某些三星以48kHz的频率播放,而几乎所有其他三星则以44.1kHz的频率播放。这些值由硬件决定,尽管有一个工具可以更改本机速率,但它的功能是次要于未来证明,但主要是2。在软件中以运行时重新采样所有音频。这是一项昂贵的任务,并且还具有一定的破坏性。在192kHz(= 2 * 96kHz)处存在硬性限制的原因可能是因为发送超过最大频率(96kHz)的两倍以上是巨大的资源浪费,因为您最好扔掉每秒一个样本以有效地将采样降低2倍,直到您处于该范围内。

最好避免指定非本机采样率。它将在软件中重新采样,充其量是浪费资源,最坏的情况是滞后的根源。

或者从谷歌工程师那里听到


答案 2

推荐