Используя AudioTrack для воспроизведения, мне иногда нужно перепрограммировать звук, который не соответствует частоте выборки, поддерживаемой AudioTrack. При этом мне нужно определить максимальную частоту дискретизации, поддерживаемую AudioTrack под текущим устройством, в соответствии с текущей конфигурацией звука.
Из-за допустимого уровня дискретизации для AudioTrack, который плохо документирован, я решил обмануть исходный код AudioTrack
и нашел эту ошеломляющую строку:
private static final int SAMPLE_RATE_HZ_MAX = 96000;
казалось бы, что экземпляр AudioTrack
применяет жесткий предел 96 кГц независимо от фактических возможностей воспроизведения устройства.
Более запутанным является класс AudioFormat
, в который я перехожу к конструктору (API 21) AudioTrack
, который содержит эту строку:
if ((sampleRate <= 0) || (sampleRate > 192000)) {
в нем setSampleRate()
. Теперь, когда жесткий предел 192 кГц. Таким образом, передачa > 192 кГц в AudioFormat (или его построитель) приведет к IllegalArgumentException
от AudioFormat
и передаче сконфигурированной 192 кГц < x < Частота дискретизации 96 кГц AudioFormat в AudioTrack также выдает IllegalArgumentException
.
То, что я обнаружил, наиболее запутанным, это метод getNativeOutputSampleRate()
в AudioTrack, который действительно возвращает правильную частоту дискретизации вывода (ну, не удивительно, учитывая, что она запускается непосредственно из собственного уровня, но так непоследовательно).
И только для этого, метод setPlaybackRate()
, который утверждает:
Действительный диапазон частоты дискретизации составляет от 1 Гц до дважды значения, возвращаемого 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 кГц, код печатает:
Скорость родного потока: 48000 Гц
Трек создан успешно (прямой)
но когда я подключаю внешний ЦАП с возможностями воспроизведения до 192 кГц, я получаю:
Скорость родного потока: 192000 Гц
Не удалось создать AudioTrack по собственному тарифу!
Трек создан успешно (косвенно)
Что с этими несоответствиями? И есть, setPlaybackRate()
идентичный частоте дискретизации, переданной в конструктор?