Audio

AAudio to nowy interfejs API na Androida C wprowadzony w wersji Androida O. Został zaprojektowany z myślą o zaawansowanych aplikacjach audio, które wymagają małych opóźnień. Aplikacje komunikują się z AAudio, odczytując i zapisując dane w strumieniach.

Interfejs AAudio API jest z założenia dopracowany tak, nie wykonuje tych funkcji:

  • Wyliczenie urządzeń audio
  • Automatyczne kierowanie między punktami końcowymi audio
  • I/O pliku
  • Dekodowanie skompresowanego dźwięku
  • Automatyczna prezentacja wszystkich danych wejściowych/strumieni w pojedynczym wywołaniu zwrotnym.

Pierwsze kroki

Możesz zadzwonić do AAudio, używając kodu w C++. Aby dodać zestaw funkcji AAudio do aplikacji, dołącz plik nagłówka AAudio.h:

#include <aaudio/AAudio.h>

Strumienie audio

AAudio przenosi dane audio między aplikacją a wejściami i wyjściami audio w urządzeniu z Androidem. Aplikacja przekazuje dane do i z powrotem, odczytując i zapisując dane do strumieni audio. Reprezentuje je struktura AAudioStream. Wywołania odczytu/zapisu mogą być blokowane lub nieblokujące.

Strumień jest definiowany przez:

  • Urządzenie audio, które jest źródłem lub ujściem danych w strumieniu.
  • Tryb udostępniania, który określa, czy transmisja ma wyłączny dostęp do urządzenia audio, które w innym przypadku można było dzielić między wieloma transmisjami.
  • Format danych dźwiękowych w strumieniu.

Urządzenie audio

Każdy strumień jest podłączony do jednego urządzenia audio.

Urządzenie audio to interfejs sprzętowy lub wirtualny punkt końcowy, który pełni funkcję źródła bądź ujścia ciągłego strumienia cyfrowych danych dźwiękowych. Nie myl urządzenia audio. (wbudowany mikrofon lub zestaw słuchawkowy Bluetooth) z urządzeniem z Androidem (telefonem lub zegarkiem), na którym działa Twoja aplikacja.

Możesz użyć metody getDevices() AudioManager, aby wykryć urządzenia audio, które są dostępne na Twoim urządzeniu z Androidem. Metoda zwraca informacje o type każdego urządzenia.

Każde urządzenie audio ma swój unikalny identyfikator na urządzeniu z Androidem. Za pomocą tego identyfikatora możesz powiązać strumień audio z konkretnym urządzeniem audio. W większości przypadków możesz jednak pozwolić AAudio wybrać domyślne urządzenie główne, zamiast podawać je samodzielnie.

Urządzenie audio podłączone do strumienia określa, czy jest to strumień wejściowy, czy wyjściowy. Strumień może przenosić dane tylko w jednym kierunku. Definiując strumień, określasz również jego kierunek. Po otwarciu strumienia Android sprawdza, czy urządzenie audio i kierunek transmisji są zgodne.

Tryb udostępniania

Strumień ma tryb udostępniania:

  • AAUDIO_SHARING_MODE_EXCLUSIVE oznacza, że transmisja ma wyłączny dostęp do urządzenia audio. innego strumienia audio nie może używać tego urządzenia. Jeśli urządzenie audio jest już używane, to może nie mieć możliwości uzyskania wyłącznego dostępu do transmisji. Transmisje na wyłączność zwykle mają niższe opóźnienie, ale jest też większe prawdopodobieństwo, że zostaną przerwane. Transmisje tylko na żywo powinny być zamykane, gdy nie są już potrzebne, aby inne aplikacje miały dostęp do urządzenia. Transmisje na wyłączność zapewniają najniższe możliwe opóźnienia.
  • AAUDIO_SHARING_MODE_SHARED umożliwia AAudio miksowanie dźwięku. AAudio łączy wszystkie współdzielone transmisje przypisane do tego samego urządzenia.

Tryb udostępniania możesz ustawić bezpośrednio podczas tworzenia transmisji. Domyślnie tryb udostępniania to SHARED.

Format dźwięku

Dane przekazywane przez strumień mają standardowe atrybuty dźwięku cyfrowego. Są to:

  • Przykładowy format danych
  • Liczba kanałów (liczba próbek na klatkę)
  • Częstotliwość próbkowania

AAudio zezwala na te przykładowe formaty:

format_audio Typ danych C Uwagi
AAUDIO_FORMAT_PCM_I16 int16_t, typowe próbki 16-bitowe, format Q0.15
AAUDIO_FORMAT_PCM_FLOAT (AAUDIO_FORMAT_PCM_FLOAT) liczba zmiennoprzecinkowa Od –1,0 do +1,0
AAUDIO_FORMAT_PCM_I24_SPACKED uint8_t w grupach po 3 spakowane 24-bitowe próbki w formacie Q0.23
AAUDIO_FORMAT_PCM_I32 int32_t, typowe próbki 32-bitowe, format Q0.31
AAUDIO_FORMAT_IEC61937 uint8_t Skompresowany dźwięk opakowany zgodnie z normą IEC61937 na potrzeby przekazywania HDMI lub S/PDIF

Jeśli zażądasz konkretnego formatu przykładowego, strumień użyje go, nawet jeśli format nie jest optymalny dla danego urządzenia. Jeśli nie określisz formatu próbki, AAudio wybierze optymalny format. Po otwarciu strumienia utwórz zapytanie dotyczące przykładowego formatu danych, a następnie w razie potrzeby konwertować dane, tak jak w tym przykładzie:

aaudio_format_t dataFormat = AAudioStream_getDataFormat(stream);
//... later
if (dataFormat == AAUDIO_FORMAT_PCM_I16) {
     convertFloatToPcm16(...)
}

Tworzenie strumienia audio

Biblioteka AAudio jest zgodna z wzorcem projektu kreatora i udostępnia komponent AAudioStreamBuilder.

  1. Utwórz obiekt AAudioStreamBuilder:

    AAudioStreamBuilder *builder;
    aaudio_result_t result = AAudio_createStreamBuilder(&builder);
    

  2. Ustaw konfigurację strumienia audio w kreatorze, używając funkcji odpowiadających jego parametrom. Dostępne są te opcjonalne funkcje:

    AAudioStreamBuilder_setDeviceId(builder, deviceId);
    AAudioStreamBuilder_setDirection(builder, direction);
    AAudioStreamBuilder_setSharingMode(builder, mode);
    AAudioStreamBuilder_setSampleRate(builder, sampleRate);
    AAudioStreamBuilder_setChannelCount(builder, channelCount);
    AAudioStreamBuilder_setFormat(builder, format);
    AAudioStreamBuilder_setBufferCapacityInFrames(builder, frames);
    

    Pamiętaj, że te metody nie zgłaszają błędów, takich jak niezdefiniowana stała czy wartość spoza zakresu.

    Jeśli nie określisz identyfikatora deviceId, domyślną wartością będzie główne urządzenie wyjściowe. Jeśli nie określisz kierunku strumienia, domyślnie zostanie wybrany strumień wyjściowy. W przypadku pozostałych parametrów możesz ustawić wartość bezpośrednio lub pozwolić, by system przypisać wartość optymalną, nie określając w ogóle parametru ani ustawiając go do AAUDIO_UNSPECIFIED.

    Na wszelki wypadek po utworzeniu strumienia audio sprawdź jego stan zgodnie z opisem w kroku 4 poniżej.

  3. Gdy skonfigurujesz strumień AAudioStreamBuilder, użyj go do utworzenia strumienia:

    AAudioStream *stream;
    result = AAudioStreamBuilder_openStream(builder, &stream);
    

  4. Po utworzeniu strumienia sprawdź jego konfigurację. Jeśli podasz format próbki, częstotliwość próbkowania ani liczbę próbek na klatkę. Jeśli określisz tryb udostępniania lub pojemność bufora, te ustawienia mogą ulec zmianie w zależności od możliwości urządzenia audio obsługującego transmisję urządzenie z Androidem, na którym działa. W kwestiach obrony programowanie, sprawdź konfigurację transmisji przed jej użyciem. Dostępne są funkcje pobierania ustawień strumienia, które odpowiadają poszczególnym ustawienia kreatora:

    AAudioStreamBuilder_setDeviceId() AAudioStream_getDeviceId()
    AAudioStreamBuilder_setDirection() AAudioStream_getDirection()
    AAudioStreamBuilder_setSharingMode() AAudioStream_getSharingMode()
    AAudioStreamBuilder_setSampleRate() AAudioStream_getSampleRate()
    AAudioStreamBuilder_setChannelCount() AAudioStream_getChannelCount()
    AAudioStreamBuilder_setFormat() AAudioStream_getFormat()
    AAudioStreamBuilder_setBufferCapacityInFrames() AAudioStream_getBufferCapacityInFrames()

  5. Możesz zapisać kreator i użyć go w przyszłości, żeby utworzyć więcej transmisji. Jeśli jednak nie zamierzasz już z niej korzystać, usuń ją.

    AAudioStreamBuilder_delete(builder);
    

Korzystanie ze strumienia audio

Przejścia stanu

Strumień AAudio ma zazwyczaj jeden z 5 stabilnych stanów (stan błędu „Odłączono” został omówiony na końcu tej sekcji):

  • Otwórz
  • Rozpoczęto
  • Wstrzymano
  • Rumieniec
  • Zatrzymano

Dane przepływają przez strumień tylko wtedy, gdy jest on w stanie rozpoczęcia. Do do przenoszenia strumienia między stanami, użyj jednej z funkcji żądających stanu przejście:

aaudio_result_t result;
result = AAudioStream_requestStart(stream);
result = AAudioStream_requestStop(stream);
result = AAudioStream_requestPause(stream);
result = AAudioStream_requestFlush(stream);

Pamiętaj, że żądanie wstrzymania lub usunięcia jest możliwe tylko w przypadku strumienia wyjściowego:

Te funkcje są asynchroniczne, a stan nie ulega zmianie. natychmiast. Gdy poprosisz o zmianę stanu, strumień zostanie przeniesiony odpowiednie stany przejściowe:

  • Uruchamiam
  • Wstrzymuję
  • Rumień
  • Zatrzymuję
  • Zamykanie

Na diagramie poniżej widać stany stabilne w postaci zaokrąglonych prostokątów, a stany tymczasowe w postaci prostokątów z kropkami. Chociaż nie jest widoczna, możesz dzwonić pod numer close() z dowolnego stanu

Cykl życia AAudio

AAudio nie obsługuje wywołań zwrotnych, które ostrzegałyby o zmianach stanu. Jedna oferta specjalna funkcji, W polu AAudioStream_waitForStateChange(stream, inputState, nextState, timeout) można czekać na zmianę stanu.

Funkcja samodzielnie nie wykrywa zmiany stanu i nie czeka na konkretnego stanu. Czeka, aż uzyska aktualny stan jest inna niż inputState, którą określasz.

Na przykład po przesłaniu prośby o wstrzymanie strumień powinien od razu zacząć może zostać tymczasowo wstrzymany, a później do stanu wstrzymania – chociaż nie ma gwarancji, że tak się stanie. Ponieważ nie możesz poczekać na stan wstrzymania, naciśnij waitForStateChange(), aby poczekać na dowolny stan inne niż wstrzymanie. Aby to zrobić:

aaudio_stream_state_t inputState = AAUDIO_STREAM_STATE_PAUSING;
aaudio_stream_state_t nextState = AAUDIO_STREAM_STATE_UNINITIALIZED;
int64_t timeoutNanos = 100 * AAUDIO_NANOS_PER_MILLISECOND;
result = AAudioStream_requestPause(stream);
result = AAudioStream_waitForStateChange(stream, inputState, &nextState, timeoutNanos);

Jeśli stan strumienia nie jest wstrzymywany (inputState, który zakładamy, że był bieżącego stanu w momencie wywołania), funkcja zwraca się natychmiast. W przeciwnym razie zostaną zablokowane, dopóki stan nie przestanie być wstrzymywany lub nie wygaśnie. Gdy zwracany jest parametr nextState, który pokazuje bieżący stan funkcji .

Tej samej techniki możesz używać po wywołaniu żądania start, stop lub flush, z odpowiednim stanem przejściowym jako parametrinputState. Nie dzwoń waitForStateChange() po wywołaniu AAudioStream_close() od momentu rozpoczęcia transmisji zostaną usunięte zaraz po jej zamknięciu. I nie dzwoń do: AAudioStream_close() gdy funkcja waitForStateChange() jest uruchomiona w innym wątku.

Odczytywanie i zapisywanie w strumieniu audio

Dane ze strumienia po jego uruchomieniu można przetworzyć na 2 sposoby:

W przypadku blokującego odczytu lub zapisu, który powoduje przesłanie określonej liczby klatek, ustaw limit czasu oczekiwaniaNanos większy niż zero. W przypadku wywołania nieblokującego ustaw limit timeNanos na zero. W tym przypadku wynikiem jest rzeczywista liczba przesłanych klatek.

Odczytując dane wejściowe, sprawdź prawidłową liczbę Liczba odczytanych klatek: . W przeciwnym razie bufor może zawierać nieznane dane, które powodują Zakłócenie dźwięku. Możesz wypełnić bufor zerami, aby utworzyć ciche porzucenie:

aaudio_result_t result =
    AAudioStream_read(stream, audioData, numFrames, timeout);
if (result < 0) {
  // Error!
}
if (result != numFrames) {
  // pad the buffer with zeros
  memset(static_cast<sample_type*>(audioData) + result * samplesPerFrame, 0,
      sizeof(sample_type) * (numFrames - result) * samplesPerFrame);
}

Możesz najpierw przygotować bufor strumienia, zapisując dane lub wyciszając go. Należy to zrobić w nieblokującym wywołaniu z limitem czasu oczekiwaniaNanos ustawionym na zero.

Dane w buforze muszą być w formacie danych zwracanym przez funkcję AAudioStream_getDataFormat().

Zamykanie strumienia audio

Gdy skończysz korzystać ze strumienia, zamknij go:

AAudioStream_close(stream);

Po zamknięciu strumienia nie będzie można używać go z żadną funkcją opartą na strumieniu AAudio.

Odłączony strumień audio

Strumień audio może zostać odłączony w dowolnym momencie, jeśli wystąpi jedno z tych zdarzeń:

  • Powiązane urządzenie audio nie jest już połączone (np. gdy słuchawki są odłączone).
  • Wystąpił błąd wewnętrzny.
  • Urządzenie audio nie jest już głównym urządzeniem audio.

Jeśli strumień jest odłączony, ma stan „Odłączony”. a każda próba wykonania funkcji AAudioStream_write() lub innej spowoduje zwrócenie błędu. Zawsze musisz zatrzymać i zamknąć odłączony strumień niezależnie od kodu błędu.

Jeśli używasz wywołania zwrotnego danych (zamiast jednej z bezpośrednich metod odczytu/zapisu) nie otrzymasz kodu zwrotnego, jeśli transmisja zostanie odłączona. Aby otrzymać powiadomienie, gdy tak się stanie, wpisz AAudioStream_errorCallback i zarejestruj ją za pomocą AAudioStreamBuilder_setErrorCallback()

Jeśli otrzymasz powiadomienie o rozłączeniu w wątku wywołań zwrotnych o błędzie, zatrzymanie i zamknięcie usługi strumienia musi zostać wykonane w innym wątku. W przeciwnym razie może wystąpić zakleszczenie.

Pamiętaj, że gdy otworzysz nową transmisję, mogą one mieć inne ustawienia z pierwotnego strumienia (np. framePerBurst):

void errorCallback(AAudioStream *stream,
                   void *userData,
                   aaudio_result_t error) {
    // Launch a new thread to handle the disconnect.
    std::thread myThread(my_error_thread_proc, stream, userData);
    myThread.detach(); // Don't wait for the thread to finish.
}

Optymalizowanie skuteczności

Wydajność aplikacji audio możesz zoptymalizować, dostosowując jej wewnętrzne bufory i używając specjalnych wątków o wysokim priorytecie.

Dostrajam bufory w celu zminimalizowania opóźnienia

AAudio przekazuje dane do i z utrzymywanych wewnętrznych buforów, po jednym dla każdego urządzenia audio.

Pojemność bufora to łączna ilość danych, jakie może on zawierać. Możesz zadzwonić do nas, AAudioStreamBuilder_setBufferCapacityInFrames() aby ustawić pojemność. Metoda ogranicza pojemność, którą można przydzielić do maksymalnej wartości, na jaką pozwala urządzenie. Używaj AAudioStream_getBufferCapacityInFrames() aby sprawdzić rzeczywistą pojemność bufora.

Aplikacja nie musi wykorzystywać całego bufora. AAudio wypełnia bufor do wartości rozmiaru, który możesz ustawić. Rozmiar bufora nie może być większy od jego pojemności, a często jest mniejszy. Kontrolując rozmiar bufora, określasz liczbę serii potrzebnych do wypełnienia go, a tym samym kontrolujesz czas oczekiwania. Korzystanie z metod AAudioStreamBuilder_setBufferSizeInFrames() oraz AAudioStreamBuilder_getBufferSizeInFrames() dostosować rozmiar bufora.

Gdy aplikacja odtwarza dźwięk, zapisuje go w buforze i blokuje do momentu zakończenia zapisu. AAudio odczytuje z bufora w postaci dyskretnych seriach. Każda seria zawiera wiele klatek audio i jest zwykle mniejsza niż rozmiar odczytywanego bufora. System kontroluje rozmiar i szybkość serii. Właściwości te są zwykle określane przez obwód urządzenia audio. Chociaż nie możesz zmienić rozmiaru serii ani szybkości serii, możesz ustawić rozmiar wewnętrznego bufora zgodnie z liczbą zawartych w nim serii. Najniższe opóźnienie osiąga zazwyczaj, jeśli rozmiar bufora AAudioStream jest wielokrotnością zgłoszonego rozmiaru serii.

      Buforowanie AAudio

Jednym ze sposobów na zoptymalizowanie rozmiaru bufora jest uruchomienie go od dużego bufora i stopniowe zmniejszanie go aż do momentu, gdy zacznie go zmniejszać, a następnie cofając go do góry. Możesz też zacząć od małego bufora, a jeśli powoduje to zbyt małe uruchomienia, zwiększ go do momentu, aż dane wyjściowe będą płynnie się wyświetlać.

Ten proces może potrwać bardzo szybko, prawdopodobnie zanim użytkownik odtworzy pierwszy dźwięk. Warto najpierw skonfigurować rozmiar bufora przy użyciu ciszy, by użytkownik nie słyszał o zakłóceniach dźwięku. Wydajność systemu może się zmieniać z upływem czasu (na przykład użytkownik może wyłączyć tryb samolotowy). Dostrajanie buforów wymaga niewielkiego nakładu pracy, dlatego i może to robić w sposób ciągły, podczas gdy aplikacja odczytuje lub zapisuje dane w strumieniu.

Oto przykład pętli optymalizacji bufora:

int32_t previousUnderrunCount = 0;
int32_t framesPerBurst = AAudioStream_getFramesPerBurst(stream);
int32_t bufferSize = AAudioStream_getBufferSizeInFrames(stream);

int32_t bufferCapacity = AAudioStream_getBufferCapacityInFrames(stream);

while (go) {
    result = writeSomeData();
    if (result < 0) break;

    // Are we getting underruns?
    if (bufferSize < bufferCapacity) {
        int32_t underrunCount = AAudioStream_getXRunCount(stream);
        if (underrunCount > previousUnderrunCount) {
            previousUnderrunCount = underrunCount;
            // Try increasing the buffer size by one burst
            bufferSize += framesPerBurst;
            bufferSize = AAudioStream_setBufferSize(stream, bufferSize);
        }
    }
}

Stosowanie tej metody do optymalizacji rozmiaru bufora dla strumienia wejściowego nie ma żadnych zalet. Strumienie wejściowe działają jak najszybciej, starając się zachować odpowiednią ilość buforowanych danych do minimum i wypełnianie, gdy aplikacja będzie wstępnie uprzedzona.

Używanie wywołania zwrotnego o wysokim priorytecie

Jeśli aplikacja odczytuje lub zapisuje dane dźwiękowe ze zwykłego wątku, może to być wstępnie wywłaszczone lub występują zakłócenia w czasie. Może to powodować zakłócenia dźwięku. Większe bufory mogą ochronić Cię przed takimi usterkami, ale duży bufor też wydłuża czas oczekiwania na dźwięk. W przypadku aplikacji wymagających małego opóźnienia strumień audio może używać asynchronicznego wywołania zwrotnego do przesyłania danych do i z aplikacji. AAudio wykonuje wywołanie zwrotne w wątku o wyższym priorytecie, który ma lepszą wydajność.

Funkcja wywołania zwrotnego ma taki prototyp:

typedef aaudio_data_callback_result_t (*AAudioStream_dataCallback)(
        AAudioStream *stream,
        void *userData,
        void *audioData,
        int32_t numFrames);

Aby zarejestrować wywołanie zwrotne, użyj budynku strumienia:

AAudioStreamBuilder_setDataCallback(builder, myCallback, myUserData);

W najprostszym przypadku strumień okresowo wykonuje funkcję wywołania zwrotnego do danych na potrzeby kolejnej serii.

Funkcja wywołania zwrotnego nie powinna wykonywać odczytu ani zapisu w strumieniu, który wywołał je. Jeśli wywołanie zwrotne należy do strumienia wejściowego, kod powinien zostać przetworzony danych umieszczanych w buforze audioData (określanego jako trzecia wartość ). Jeśli wywołanie zwrotne należy do strumienia wyjściowego, kod powinien umieścić do bufora.

Można na przykład użyć wywołania zwrotnego do ciągłego generowania fali sinusoidalnej podobny do tego:

aaudio_data_callback_result_t myCallback(
        AAudioStream *stream,
        void *userData,
        void *audioData,
        int32_t numFrames) {
    int64_t timeout = 0;

    // Write samples directly into the audioData array.
    generateSineWave(static_cast<float *>(audioData), numFrames);
    return AAUDIO_CALLABCK_RESULT_CONTINUE;
}

Przy użyciu AAudio można przetworzyć więcej niż jeden strumień. Możesz używać jednego strumienia jako głównego, i przekazywać wskaźniki do innych strumieni w danych użytkownika. Zarejestruj wywołanie zwrotne dla strumienia głównego. Następnie użyj nieblokującej operacji wejścia-wyjścia dla pozostałych strumieni. Oto przykład wywołania zwrotnego w obie strony, które przekazuje strumień wejściowy do strumienia wyjściowego. Głównym strumieniem wywołującym jest strumień wyjściowy. Strumień wejściowy jest uwzględniony w danych użytkownika.

Wywołanie zwrotne wykonuje nieblokujący odczyt ze strumienia wejściowego i umieszcza dane w buforze strumienia wyjściowego:

aaudio_data_callback_result_t myCallback(
        AAudioStream *stream,
        void *userData,
        void *audioData,
        int32_t numFrames) {
    AAudioStream *inputStream = (AAudioStream *) userData;
    int64_t timeout = 0;
    aaudio_result_t result =
        AAudioStream_read(inputStream, audioData, numFrames, timeout);

  if (result == numFrames)
      return AAUDIO_CALLABCK_RESULT_CONTINUE;
  if (result >= 0) {
      memset(static_cast<sample_type*>(audioData) + result * samplesPerFrame, 0,
          sizeof(sample_type) * (numFrames - result) * samplesPerFrame);
      return AAUDIO_CALLBACK_RESULT_CONTINUE;
  }
  return AAUDIO_CALLBACK_RESULT_STOP;
}

Zwróć uwagę, że w tym przykładzie zakładamy, że strumienie wejściowe i wyjściowe mają taką samą liczbę kanałów, format i częstotliwość próbkowania. Format strumieni może być niezgodny – musisz tylko kod prawidłowo obsługiwać tłumaczenia.

Ustawianie trybu wydajności

Każdy strumień AAudioStream ma tryb wydajności, który ma duży wpływ na działanie aplikacji. Dostępne są 3 tryby:

  • Tryb domyślny to AAUDIO_PERFORMANCE_MODE_NONE. Wykorzystuje podstawowy strumień, który równoważy opóźnienie i oszczędzanie energii.
  • AAUDIO_PERFORMANCE_MODE_LOW_LATENCY korzysta z mniejszych buforów i zoptymalizowanej ścieżki danych, aby skrócić czas oczekiwania.
  • AAUDIO_PERFORMANCE_MODE_POWER_SAVING korzysta z większych buforów wewnętrznych i ścieżki danych, co pozwala ograniczyć opóźnienia i zużywa mniej energii.

Tryb wydajności możesz wybrać, wywołując metodę setPerformanceMode(). i odkryj bieżący tryb, wywołując funkcję getPerformanceMode().

Jeśli małe opóźnienie jest ważniejsze niż oszczędność energii w aplikacji, użyj AAUDIO_PERFORMANCE_MODE_LOW_LATENCY. Przydaje się to w przypadku aplikacji, które są bardzo interaktywne, np. gier lub syntezatorów klawiaturowych.

Jeśli oszczędność energii jest dla Twojej aplikacji ważniejsze niż małe opóźnienie, użyj AAUDIO_PERFORMANCE_MODE_POWER_SAVING. Jest to typowe w aplikacjach, które odtwarzają wygenerowaną wcześniej muzykę, takich jak odtwarzacze dźwięku lub odtwarzacze plików MIDI.

W obecnej wersji AAudio aby uzyskać jak najkrótszy czas oczekiwania, należy używać trybu wydajności AAUDIO_PERFORMANCE_MODE_LOW_LATENCY wraz z wywołaniem zwrotnym o wysokim priorytecie. Skorzystaj z tego przykładu:

// Create a stream builder
AAudioStreamBuilder *streamBuilder;
AAudio_createStreamBuilder(&streamBuilder);
AAudioStreamBuilder_setDataCallback(streamBuilder, dataCallback, nullptr);
AAudioStreamBuilder_setPerformanceMode(streamBuilder, AAUDIO_PERFORMANCE_MODE_LOW_LATENCY);

// Use it to create the stream
AAudioStream *stream;
AAudioStreamBuilder_openStream(streamBuilder, &stream);

Bezpieczeństwo wątku

Interfejs AAudio API nie jest całkowicie bezpieczny dla wątków. Niektórych funkcji AAudio nie można wywoływać jednocześnie z więcej niż 1 wątku naraz. Wynika to z faktu, że w AAudio unikamy korzystania z muteksów, które mogą powodować wywłaszczanie wątków i zakłócenia.

Ze względów bezpieczeństwa nie dzwoń do AAudioStream_waitForStateChange() ani nie odczytuj ani nie zapisuj wiadomości w tym samym strumieniu z 2 różnych wątków. Podobnie nie zamykaj strumienia w jednym wątku podczas czytania lub pisania w innym.

Połączenia zwracające ustawienia transmisji, takie jak AAudioStream_getSampleRate() i AAudioStream_getChannelCount(), są bezpieczne w przypadku wątków.

Połączenia te są bezpieczne w wątkach:

  • AAudio_convert*ToText()
  • AAudio_createStreamBuilder()
  • AAudioStream_get*() oprócz AAudioStream_getTimestamp()
.

Znane problemy

  • Opóźnienie dźwięku jest duże w przypadku blokowania zapisu(), ponieważ wersja Androida O DP2 nie używa ścieżki FAST. Aby zmniejszyć opóźnienie, użyj wywołania zwrotnego.

Dodatkowe materiały

Aby dowiedzieć się więcej, skorzystaj z tych materiałów:

Jak korzystać z interfejsu API

Ćwiczenia z programowania

Filmy