Podczas odtwarzania z funkcji AudioTrack muszę czasami zmienić jakość dźwięku, który nie jest zgodny z częstotliwością próbkowania obsługiwaną przez funkcję AudioTrack. W tym celu muszę określić maksymalną częstotliwość próbkowania obsługiwaną przez funkcję AudioTrack, pod bieżącym urządzeniem, w bieżącej konfiguracji audio.Niepoprawność próbkowania AudioTrack
Ze względu na dopuszczalne częstości próbkowania dla AudioTrack są słabo udokumentowane, postanowiłem snoop wokół kodu źródłowego AudioTrack
i znalazłem to zdumiewające wiersz:
private static final int SAMPLE_RATE_HZ_MAX = 96000;
Wydawałoby się, że instancja AudioTrack
ubiega twardy limit 96 kHz, niezależnie od rzeczywistych możliwości odtwarzania urządzenia.
bardziej skomplikowane w klasie AudioFormat
, w którym do konstruktora (API 21) AudioTrack
, która zawiera linię:
if ((sampleRate <= 0) || (sampleRate > 192000)) {
w to setSampleRate()
metodą. Teraz jest to twardy limit 192 KHz. Przekazanie> 192 KHz do AudioFormat (lub jego konstruktora) spowoduje, że IllegalArgumentException
z AudioFormat
i przekazanie skonfigurowanej częstotliwości 192 KHz < x < częstotliwości 96 KHz AudioFormat do ścieżki AudioTrack spowoduje również wygenerowanie IllegalArgumentException
.
Co znalazłem, jak dotąd, najbardziej kłopotliwe jest metoda getNativeOutputSampleRate()
w AudioTrack który faktycznie nie zwróci poprawną częstotliwość próbkowania wyjścia (dobrze, ponieważ nie wiele niespodzianka to biegł bezpośrednio od rodzimej warstwy, ale tak niespójny).
I tak na dodatek, przy czym sposób setPlaybackRate()
które Zastrzeżenia patentowe
Prawidłowy zakres częstotliwości próbkowania wynosi od 1 Hz do dwukrotnej wartości powrotu getNativeOutputSampleRate (int).
I rzeczywiście, spróbowałem i działa? Rozważmy następujący fragment:
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");
}
}
po przebiegu programu, gdy rodzimy częstotliwość próbkowania jest < 96 KHz, kod wypisuje:
Native szybkość strumienia: 48000 Hz
Utwór stworzony z powodzeniem (bezpośrednio)
, ale po podłączeniu zewnętrznego DAC z możliwością odtwarzania do 192 KHz, otrzymuję:
Native szybkość strumienia: 192000 Hz
udało się utworzyć AudioTrack w natywnej szybkości!
Ścieżka utworzona pomyślnie (pośrednia)
Co z tymi niekonsekwencjami?I jest, setPlaybackRate()
identyczny z częstotliwością próbkowania przekazywaną do konstruktora?
Można rozważyć złożenie sprawy do https://code.google.com/p/android/issues/list o tych niespójności (co mogę potwierdzić, są również obecne w źródle API 22). Odnośnie 'setPlaybackRate()', wyraźnie pomija (niespójne) kontrole, o których wspomniałeś i bezpośrednio ustawia odtwarzanie po stronie natywnej. Warto również przyjrzeć się historii [core/jni/android_media_AudioTrack.cpp] [1] [1]: https://android.googlesource.com/platform/frameworks/base/+/ 88e209d% 5E!/ –
@AladinQ Dziękuję za link do źródła, nie wiedziałem, że zawierają źródła warstwy natywnej, które powinny pomóc w debugowaniu problemu. Będę wstrzymywał wymienianie go jako problemu, biorąc pod uwagę, że nie może być nic złego (po prostu błędy dokumentacji lub nieudokumentowane zachowanie). Stało się to wcześniej ... Zobaczę, co mogę czerpać z natywnego źródła. – initramfs