2015-05-01 28 views
29

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?

+6

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!/ –

+1

@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

Odpowiedz

1

Obecnie większość telefonów z Androidem dostępnych na rynku obsługuje tylko jedną częstotliwość próbkowania. Uważam, że niektóre odtwarzacze Samsung grają z częstotliwością 48 kHz, a prawie wszystkie inne grają z częstotliwością 44,1 kHz. Wartości te są podyktowane przez sprzęt i chociaż istnieje możliwość zmiany szybkości natywnej, jego funkcją jest na drugim miejscu dowód przyszłości, ale przede wszystkim 2. ponowne próbkowanie WSZYSTKIEGO dźwięku w czasie wykonywania w OPROGRAMOWANIU. Jest to kosztowne zadanie, a także nieco destrukcyjne. Powodem, dla którego istnieje twardy limit na poziomie 192 kHz (= 2 * 96 kHz) jest prawdopodobne, ponieważ wysyłanie ponad dwukrotnie wyższej częstotliwości (96 kHz) jest ogromnym marnowaniem zasobów, ponieważ równie dobrze można po prostu wyrzucić co drugą próbkę, aby skutecznie zmniejszyć próbkę przez współczynnik 2, aż znajdziesz się w tym zakresie.

Najlepiej unikać określania nienatywnej częstotliwości próbkowania. Zostanie ponownie pobrana w oprogramowaniu i będzie w najlepszym przypadku marnowaniem zasobów, aw najgorszym - źródłem opóźnień.

Or hear it from a Google engineer

+0

Doceń link, wkrótce go obejrzę. Jednak, jak już wspomniałem, urządzenia z Androidem są w stanie wyświetlać dźwięk na zewnętrznym źródle, takim jak zewnętrzny przetwornik cyfrowo-analogowy USB. Posiadam taki DAC i kiedy go podłączam, Android negocjuje ** natywną ** stawkę 192 KHz (jako wskaźnik w dziennikach systemowych, a także wskaźnik częstości próbkowania w moim DACu). Wysiłek polegający na określeniu stopy natywnej jest taki, aby ** zminimalizować ** koszt wydajności ponownego próbkowania, gdy nie jest to konieczne. Pliki źródłowe w częstotliwości 96 KHz + powinny pozostać nietknięte (tzn. Prosto, bez ponownego próbkowania), jeśli to możliwe, aby zmaksymalizować żywotność baterii. – initramfs

+0

Ach, pomyślałem, że mogłem coś przeoczyć, kiedy rozmawiałeś o USB. https://gitlab.com/SaberMod/pa-android-frameworks-base/commit/70b395e8c1d06ca9288afd418b9e889df4060eab Haha, limit 48kHz był „stałe” w ubiegłym roku, przymocowane do 96kHz Przypuszczam komentarz Aladin Q jest poprawna odpowiedź! Dlatego: 'if (sampleRateInHz SAMPLE_RATE_HZ_MAX) { rzut nowy IllegalArgumentException (sampleRateInHz + "Hz nie jest obsługiwany próbkowania."); } ' – Andy