30

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

由于 AudioTrack 允许的采样率没有得到很好的记录,我决定窥探源代码AudioTrack并发现这条惊人的行:

private static final int SAMPLE_RATE_HZ_MAX = 96000;

无论设备的实际播放能力如何,该实例似乎都在AudioTrack应用 96 KHz 的硬限制。

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

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

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


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

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

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

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

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()与传递给构造函数的采样率相同吗?

4

1 回答 1

2

目前市面上大部分安卓手机只支持一种采样率。我相信某些三星以 48kHz 播放,而几乎所有其他三星以 44.1kHz 播放。这些值是由硬件决定的,虽然有改变原生速率的工具,但它的功能是次要的未来证明,但主要是 2. 在运行时在软件中重新采样所有音频。这是一项昂贵的任务,而且还有些破坏性。在 192kHz (= 2 * 96kHz) 处存在硬限制的原因可能是因为发送超过两倍的最大频率 (96kHz) 会浪费大量资源,因为您不妨扔掉每秒的采样以有效地降低采样率2 倍,直到你在那个范围内。

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

或者从 Google 工程师那里听到

于 2015-07-20T18:06:41.047 回答