AudioTrack采样率不一致

ini*_*mfs 30 java android sample-rate audiotrack

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

由于AudioTrack的允许采样率很难记录,我决定窥探源代码AudioTrack并发现这个惊人的界限:

private static final int SAMPLE_RATE_HZ_MAX = 96000;
Run Code Online (Sandbox Code Playgroud)

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

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

if ((sampleRate <= 0) || (sampleRate > 192000)) {
Run Code Online (Sandbox Code Playgroud)

在它的setSampleRate()方法.现在这是192 KHz的硬限制.所以,传递> 192千赫到的AudioFormat(或它的助洗剂)将导致IllegalArgumentExceptionAudioFormat与传递一个配置192千赫<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");
    }
}
Run Code Online (Sandbox Code Playgroud)

在程序流程之后,当本机采样率<96 KHz时,代码打印出来:

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

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

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

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

And*_*sch 2

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

最好避免指定非本机采样率。它将在软件中重新采样,往好了说是浪费资源,往坏了说是造成延迟的原因。

或者听听 Google 工程师的说法