OSTRZEŻENIE: standard OpenSL ES został wycofany. Deweloperzy powinni używać biblioteki Oboe typu open source, która jest dostępna na GitHubie. Oboe to kod w języku C++ zapewniający interfejs API podobny do AAudio. Oboe wywołuje AAudio, gdy jest ono dostępne, a gdy nie jest, używa OpenSL ES.
Ta strona zawiera szczegółowe informacje o tym, jak implementacja OpenSL ES™ w NDK różni się od specyfikacji referencyjnej OpenSL ES 1.0.1. Jeśli używasz przykładowego kodu ze specyfikacji, może być konieczne jego zmodyfikowanie, aby działał na Androidzie.
O ile nie zaznaczono inaczej, wszystkie funkcje są dostępne w wersji Androida 2.3 (interfejs API na poziomie 9) i wyższych. Niektóre funkcje są dostępne tylko w Androidzie 4.0 (poziom interfejsu API 14).
Uwaga: dokument z definicją zgodności z Androidem (CDD) zawiera wymagania sprzętowe i oprogramowania zgodnego urządzenia z Androidem. Więcej informacji o ogólnym programie zgodności znajdziesz w dokumentacji na temat zgodności z Androidem, a w dokumentacji CDD – o samym dokumencie CDD.
OpenSL ES udostępnia interfejs w języku C, który jest też dostępny w języku C++. Zawiera funkcje podobne do tych, które są dostępne w częściach interfejsów API na Androida w języku Java:
Podobnie jak w przypadku wszystkich pakietów NDK (NDK – Native Development Kit) głównym celem OpenSL ES na Androida jest ułatwienie implementacji współdzielonych bibliotek, które mają być wywoływane za pomocą natywnej interfejsu Java (JNI ). Pakiet NDK nie jest przeznaczony do pisania czystych aplikacji C/C++. OpenSL ES to jednak interfejs API o pełnej funkcjonalności, który powinien umożliwić Ci realizację większości potrzeb związanych z dźwiękiem przy użyciu tylko tego interfejsu API, bez wywołań kodu działającego w czasie wykonywania Androida.
Uwaga: interfejs API natywnego dźwięku na Androidzie (wysoko wydajny dźwięk) jest oparty na OpenSL ES, ale nie jest zgodną implementacją żadnego profilu OpenSL ES 1.0.1 (gra, muzyka lub telefon). Dzieje się tak, ponieważ Android nie obsługuje wszystkich funkcji wymaganych przez żaden z tych profili. Wszystkie znane przypadki, w których Android działa inaczej niż określono w specyfikacji, opisano na stronie Rozszerzenia na Androida.
Funkcje dziedziczone ze specyfikacji referencyjnej
Implementacja OpenSL ES na Androidzie w wersji NDK dziedziczy większość funkcji ze specyfikacji referencyjnej, z pewnymi ograniczeniami.
Globalne punkty wejścia
OpenSL ES na Androida obsługuje wszystkie globalne punkty wejścia w specyfikacji Androida. Te punkty wejścia to:
slCreateEngine
slQueryNumSupportedEngineInterfaces
slQuerySupportedEngineInterfaces
Obiekty i interfejsy
W tabeli poniżej znajdziesz obiekty i interfejsy obsługiwane przez implementację OpenSL ES w Androidzie NDK. Jeśli w komórce pojawi się opcja Tak, funkcja jest dostępna w tej implementacji.
Funkcja | Odtwarzacz audio | Rejestratory dźwięku | Silnik | Zestaw wyjściowy |
---|---|---|---|---|
Wzmocnienie basów | Tak | Nie | Nie | Tak |
Kolejka buforowania | Tak | Nie | Nie | Nie |
lokalizator danych kolejki bufora | Tak: źródło | Nie | Nie | Nie |
Dynamiczne zarządzanie interfejsem | Tak | Tak | Tak | Tak |
Wysyłanie efektów | Tak | Nie | Nie | Nie |
Silnik | Nie | Nie | Tak | Nie |
pogłos środowiska, | Nie | Nie | Nie | Tak |
Korektor | Tak | Nie | Nie | Tak |
Lokalizator danych urządzeń wejścia-wyjścia | Nie | Tak: źródło | Nie | Nie |
Wyodrębnianie metadanych | Tak: dekoduj do formatu PCM | Nie | Nie | Nie |
Wycisz solo | Tak | Nie | Nie | Nie |
Obiekt | Tak | Tak | Tak | Tak |
Lokalizator wyjściowego miksu | Tak: zlew | Nie | Nie | Nie |
Odtwórz | Tak | Nie | Nie | Nie |
Szybkość odtwarzania | Tak | Nie | Nie | Nie |
Stan pobierania z wyprzedzeniem | Tak | Nie | Nie | Nie |
Gotowy pogłos | Nie | Nie | Nie | Tak |
Nagraj | Nie | Tak | Nie | Nie |
Szukaj | Tak | Nie | Nie | Nie |
lokalizator danych URI | Tak: źródło | Nie | Nie | Nie |
Wirtualizator | Tak | Nie | Nie | Tak |
Głośność | Tak | Nie | Nie | Nie |
W następnej sekcji opisujemy ograniczenia dotyczące niektórych z tych funkcji.
Ograniczenia
W przypadku funkcji wymienionych w tabeli 1 obowiązują pewne ograniczenia. Te ograniczenia stanowią różnice w stosunku do specyfikacji referencyjnej. Pozostała część tej sekcji zawiera informacje o tych różnicach.
Dynamiczne zarządzanie interfejsem
OpenSL ES na Androida nie obsługuje funkcji RemoveInterface
ani ResumeInterface
.
Kombinacje efektów: pogłos środowiska i gotowy pogłos
Nie można użyć jednocześnie pogłosu środowiskowego i gotowego pogłosu w tym samym miksie wyjściowym.
Platforma może zignorować żądania efektów, jeśli uzna, że obciążenie procesora będzie zbyt duże.
Efekt wysłano
SetSendLevel()
obsługuje 1 poziom wysyłania na odtwarzacz audio.
Pogłos środowiska
Pogłos środowiska nie obsługuje pól reflectionsDelay
, reflectionsLevel
ani reverbDelay
struktury SLEnvironmentalReverbSettings
.
Format danych MIME
Formatu danych MIME możesz używać tylko w przypadku lokalizatora danych URI i tylko w przypadku odtwarzacza audio. Nie możesz używać tego formatu danych do rejestratora dźwięku.
Implementacja OpenSL ES na Androidzie wymaga zainicjowania mimeType
do NULL
lub prawidłowego ciągu UTF-8. Musisz też zainicjować containerType
prawidłową wartością.
Jeśli nie ma innych przesłanek, np. przenośności na inne implementacje lub formaty treści, których aplikacja nie może zidentyfikować na podstawie nagłówka, zalecamy ustawienie wartości mimeType
na NULL
, a wartości containerType
na SL_CONTAINERTYPE_UNSPECIFIED
.
OpenSL ES na Androida obsługuje te formaty audio, o ile są one obsługiwane przez platformę Android:
- WAV PCM.
- WAV alaw.
- WAV ulaw.
- MP3 Ogg Vorbis.
- AAC LC.
- HE-AACv1 (AAC+).
- HE-AACv2 (ulepszona wersja AAC+).
- AMR.
- FLAC.
Uwaga: listę formatów audio obsługiwanych przez Androida znajdziesz w artykule Obsługiwane formaty multimediów.
W ramach tej implementacji OpenSL ES obowiązują następujące ograniczenia dotyczące obsługi tych i innych formatów:
- Formaty AAC muszą znajdować się w kontenerze MP4 lub ADTS.
- OpenSL ES na Androida nie obsługuje MIDI.
- WMA nie jest częścią AOSP, a my nie weryfikujemy jego zgodności z OpenSL ES na Androida.
- Implementacja OpenSL ES w Android NDK nie obsługuje bezpośredniego odtwarzania treści chronionych DRM lub zaszyfrowanych. Aby odtworzyć chronione treści audio, musisz je odszyfrować w aplikacji przed odtworzeniem, a aplikacja musi egzekwować wszelkie ograniczenia DRM.
Metody związane z obiektami
OpenSL ES na Androida nie obsługuje tych metod manipulowania obiektami:
Resume()
RegisterCallback()
AbortAsyncOperation()
SetPriority()
GetPriority()
SetLossOfControlInterfaces()
Format danych PCM
PCM to jedyny format danych, którego możesz używać z kolejkami buforów. Obsługiwane konfiguracje odtwarzania PCM:
- 8-bitowa bez znaku lub 16-bitowa ze znakiem.
- mono lub stereo.
- bajty w porządku little-endian,
- Częstotliwości próbkowania:
- 8000 Hz.
- 11 025 Hz.
- 12 000 Hz.
- 16 000 Hz.
- 22 050 Hz.
- 24 000 Hz.
- 32 000 Hz.
- 44 100 Hz.
- 48 000 Hz.
Konfiguracje, które OpenSL ES na Androida obsługują nagrywanie,zależą od urządzenia. Zwykle dźwięk mono/16-bitowy z podpisem 16 000 Hz jest dostępny niezależnie od urządzenia.
Wartość pola samplesPerSec
jest podawana w milihercach Hz, mimo że nazwa może być myląca. Aby uniknąć przypadkowego użycia nieprawidłowej wartości, zalecamy zainicjowanie tego pola za pomocą jednej z konstant symbolicznych zdefiniowanych w tym celu, np. SL_SAMPLINGRATE_44_1
.
Android 5.0 (poziom interfejsu API 21) i nowsze wersje obsługują dane zmiennoprzecinkowe.
Szybkość odtwarzania
Prędkość odtwarzania OpenSL ES wskazuje szybkość, z jaką obiekt przedstawia dane, wyrażoną w tysięcznych częściach normalnej szybkości lub na mille. Na przykład szybkość odtwarzania 1000 na tysiąc to 1000/1000, czyli normalna szybkość. Zakres szybkości to zamknięty przedział, który wyraża zakres możliwych szybkości odtwarzania.
Obsługa zakresów szybkości odtwarzania i innych funkcji może się różnić w zależności od wersji i implementacji platformy. Aplikacja może określić te możliwości w czasie wykonywania, wysyłając zapytanie do urządzenia za pomocą funkcji PlaybackRate::GetRateRange()
lub PlaybackRate::GetCapabilitiesOfRate()
.
Urządzenie zwykle obsługuje ten sam zakres szybkości dla źródła danych w formacie PCM oraz jednolitą szybkość w zakresie 1000 do 1000 w przypadku innych formatów. Oznacza to, że jednolita szybkość jest w istocie jedną wartością.
Nagraj
OpenSL ES na Androida nie obsługuje zdarzeń SL_RECORDEVENT_HEADATLIMIT
ani SL_RECORDEVENT_HEADMOVING
.
Szukaj
Metoda SetLoop()
umożliwia odtwarzanie całego pliku w pętli. Aby włączyć zapętlenie, ustaw parametr startPos
na 0, a parametr endPos
na SL_TIME_UNKNOWN
.
lokalizator danych kolejki bufora
Odtwarzacz audio lub dyktafon z lokalizatorem danych do obsługi kolejki bufora obsługuje tylko format danych PCM.
lokalizator danych urządzenia wejścia/wyjścia
OpenSL ES na Androida obsługuje lokalizator danych urządzenia wejścia/wyjścia tylko wtedy, gdy użyjesz go jako źródła danych dla Engine::CreateAudioRecorder()
.
Inicjuj lokalizator danych urządzenia, używając wartości zawartych w tym fragmencie kodu:
SLDataLocator_IODevice loc_dev = {SL_DATALOCATOR_IODEVICE, SL_IODEVICE_AUDIOINPUT, SL_DEFAULTDEVICEID_AUDIOINPUT, NULL};
Lokalizator danych URI
OpenSL ES na Androida może używać lokalizatora danych URI tylko w formacie danych MIME i tylko w odtwarzaczu audio. Nie możesz używać identyfikatora URI w przypadku rejestratora dźwięku. Identyfikator URI może używać tylko schematów http:
i file:
. Inne schematy, takie jak https:
,
ftp:
lub
content:
, są niedozwolone.
Nie zweryfikowaliśmy obsługi rtsp:
z dźwiękiem na platformie Android.
Struktury danych
Android obsługuje te struktury danych OpenSL ES 1.0.1:
SLDataFormat_MIME
SLDataFormat_PCM
SLDataLocator_BufferQueue
SLDataLocator_IODevice
SLDataLocator_OutputMix
SLDataLocator_URI
SLDataSink
SLDataSource
SLEngineOption
SLEnvironmentalReverbSettings
SLInterfaceID
Konfiguracja platformy
OpenSL ES na Androida jest przeznaczony do aplikacji wielowątkowych i jest bezpieczny pod względem wątków. Obsługuje 1 wyszukiwarkę na aplikację i maksymalnie 32 obiekty na wyszukiwarkę. Dostępna pamięć urządzenia i procesor mogą dodatkowo ograniczać liczbę obiektów, które można wykorzystać.
Te opcje silnika są rozpoznawane, ale są ignorowane przez slCreateEngine
:
SL_ENGINEOPTION_THREADSAFE
SL_ENGINEOPTION_LOSSOFCONTROL
OpenMAX AL i OpenSL ES mogą być używane razem w tej samej aplikacji. W tym przypadku wewnętrznie jest jeden udostępniony obiekt silnika, a limit 32 obiektów jest wspólny dla OpenMAX AL i OpenSL ES. Aplikacja powinna utworzyć oba silniki, użyć obu silników i na koniec je zniszczyć. Implementacja utrzymuje liczbę odwołań do udostępnionego mechanizmu, aby można było go prawidłowo zniszczyć podczas drugiej operacji usuwania.
Informacje o programowaniu
Uwagi dotyczące programowania OpenSL ES zawierają dodatkowe informacje, które zapewniają prawidłowe wdrożenie OpenSL ES.
Uwaga:
dla Twojej wygody dołączyliśmy kopię specyfikacji OpenSL ES 1.0.1 wraz z NDK w języku: docs/opensles/OpenSL_ES_Specification_1.0.1.pdf
.
Problemy z platformą
Ta sekcja opisuje znane problemy w pierwszej wersji platformy obsługującej te interfejsy API.
Dynamiczne zarządzanie interfejsem
DynamicInterfaceManagement::AddInterface
nie działa. Zamiast tego określ interfejs w tablicy przekazywanej do funkcji Create()
, jak pokazano w przykładowym kodzie dla pogłosu środowiskowego.
Planowanie przyszłych wersji OpenSL ES
Interfejsy API do obsługi wydajnego dźwięku na Androidzie są oparte na OpenSL ES 1.0.1 grupy Khronos Group. Khronos opublikował poprawioną wersję 1.1 standardu. Zmieniona wersja zawiera nowe funkcje, wyjaśnienia, poprawki błędów typograficznych oraz niektóre niespójności. Większość oczekiwanych niezgodności jest stosunkowo nieznaczna lub występują w obszarach OpenSL ES, które nie są obsługiwane przez Androida.
Aplikacja opracowana w tej wersji powinna działać w przyszłych wersjach platformy Android, o ile przestrzegasz wskazówek podanych w sekcji Plan zgodności binarnej poniżej.
Uwaga: przyszła zgodność źródeł nie jest celem. Oznacza to, że jeśli uaktualnisz NDK do nowszej wersji, może być konieczne zmodyfikowanie kodu źródłowego aplikacji, aby był zgodny z nowym interfejsem API. Spodziewamy się, że większość takich zmian będzie niewielka. Szczegóły znajdziesz poniżej.
Planowanie zgodności binarnej
Aby poprawić zgodność binarną w przyszłości, zalecamy, aby aplikacja przestrzegała tych wytycznych:
- Używaj tylko udokumentowanego podzbioru funkcji obsługiwanych przez Androida w OpenSL ES 1.0.1.
- Nie polegaj na konkretnym kodzie wyniku operacji, która się nie udała. Bądź przygotowany na inny kod wyniku.
- Moduły obsługi wywołań zwrotnych aplikacji zwykle działają w kontekście ograniczonym. Powinny być napisane w taki sposób, aby można było szybko je wykonać, a potem jak najszybciej wrócić. Nie wykonuj operacji złożonych w ramach modułu obsługi wywołania zwrotnego. Na przykład w ramach wywołania zwrotnego ukończenia kolejki bufora możesz umieścić w kolejce kolejny bufor, ale nie utworzysz odtwarzacza dźwięku.
- Moduły obsługi wywołań zwrotnych powinny być przygotowane do częstszego lub rzadszego wywoływania, aby mogły otrzymywać dodatkowe typy zdarzeń, i powinny ignorować typy zdarzeń, których nie rozpoznają. Wywołania zwrotne skonfigurowane z maską zdarzeń z włączonych typów zdarzeń powinny być przygotowane do wywołania z wieloma ustawionymi jednocześnie wieloma bitami typu zdarzenia. Użyj operatora „&”, aby przetestować każdy bit zdarzenia zamiast instrukcji warunkowej switch.
- Używaj stanu wstępnego pobierania i wyzwań zwrotnych jako ogólnych wskaźników postępu, ale nie polegaj na konkretnych, zakodowanych na stałe poziomach wypełnienia ani sekwencjach wywołań zwrotnych. Znaczenie poziomu wypełniania stanu wstępnego i zachowanie w przypadku błędów wykrytych podczas wstępnego pobierania mogą ulec zmianie.
Uwaga: więcej informacji znajdziesz w sekcji Oczekujące bufory.
Planowanie pod kątem zgodności źródła
Jak już wspomnieliśmy, w następnej wersji OpenSL ES z grupy Khronos Group spodziewamy się niezgodności kodu źródłowego. Możliwe obszary zmian:
- Interfejs kolejki bufora prawdopodobnie ulegnie znacznym zmianom, zwłaszcza w obszarach
BufferQueue::Enqueue
, liście parametrówslBufferQueueCallback
i nazwie polaSLBufferQueueState.playIndex
. Zalecamy, aby kod aplikacji używał kolejek prostych buforów Androida. W przykładowym kodzie dostarczonym z NDK użyliśmy prostych kolejek buforów Androida do odtwarzania. (do nagrywania i dekodowania do formatu PCM używamy też prostej kolejki buforów Androida, ale jest to spowodowane tym, że standard OpenSL ES 1.0.1 nie obsługuje zapisywania ani dekodowania do odbiornika danych kolejki buforów). - Do parametrów wejściowych przekazywanych przez odniesienie i do pól struktury
SLchar *
używanych jako wartości wejściowe zostanie dodany parametrconst
. Nie powinno to wymagać żadnych zmian w kodzie. - Niektóre obecnie podpisane parametry zostaną zastąpione typami niepodpisanymi.
Może być konieczne zmodyfikowanie typu parametru z
SLint32
naSLuint32
lub podobny albo dodanie operatora przypisania. Equalizer::GetPresetName
kopiuje ciąg znaków do pamięci aplikacji zamiast zwracać wskaźnika do pamięci implementacji. To znacząca zmiana, dlatego zalecamy unikanie wywoływania tej metody lub odizolowanie jej używania.- W typach strukturalnych pojawią się dodatkowe pola. W przypadku parametrów wyjściowych te nowe pola można zignorować, ale w przypadku parametrów wejściowych nowe pola trzeba zainicjować. Na szczęście wszystkie te pola znajdują się w obszarach, które nie są obsługiwane przez Androida.
- Zmienią się identyfikatory GUID interfejsu. Aby uniknąć zależności, odwołuj się do interfejsów za pomocą nazwy symbolicznej zamiast identyfikatora GUID.
SLchar
zmieni się zunsigned char
nachar
. Ma to wpływ głównie na lokalizator danych URI i format danych MIME.- Nazwa
SLDataFormat_MIME.mimeType
zostanie zmieniona napMimeType
, a nazwaSLDataLocator_URI.URI
zostanie zmieniona napURI
. Zalecamy inicjowanie struktur danychSLDataFormat_MIME
iSLDataLocator_URI
za pomocą listy wartości oddzielonych przecinkami w nawiasach klamrowych zamiast nazwy pola, aby odizolować kod od tej zmiany. Ta technika jest używana w przykładowym kodzie. SL_DATAFORMAT_PCM
nie zezwala aplikacji na określenie reprezentacji danych jako liczby całkowitej ze znakiem, liczby całkowitej bez znaku lub liczby zmiennoprzecinkowej. Implementacja na Androidzie zakłada, że 8-bitowe dane są liczbą całkowitą bez znaku, a 16-bitowe – liczbą całkowitą ze znakiem. Dodatkowo polesamplesPerSec
jest nieprawidłowe, ponieważ rzeczywiste jednostki to milisekundy. Te problemy powinny zostać rozwiązane w kolejnych wersjach OpenSL ES, które wprowadzą nowy format rozszerzonych danych PCM, który pozwoli aplikacji wyraźnie określić reprezentację i poprawi nazwę pola. Będzie to nowy format danych, ale obecny format danych PCM nadal będzie dostępny (choć przestarzały), więc nie powinno to wymagać wprowadzania żadnych zmian w kodzie.