Ta strona zawiera szczegółowe informacje o tym, czym implementacja OpenSL EST za pomocą NDK różni się od specyfikacji referencyjnej OpenSL ES 1.0.1. Jeśli używasz przykładowego kodu ze specyfikacji, być może trzeba będzie go zmodyfikować pod kątem działania na Androidzie.
O ile nie wskazano inaczej, wszystkie funkcje są dostępne na urządzeniach z Androidem 2.3 (poziom interfejsu API 9) i nowszym. Niektóre funkcje są dostępne tylko na Androidzie 4.0 (poziom interfejsu API 14). Są to wymienione poniżej funkcje.
Uwaga: dokument CDD (Android Compatibility Definition Document) zawiera listę wymagań dotyczących sprzętu i oprogramowania zgodnego urządzenia z Androidem. Więcej informacji na temat ogólnego programu zgodności znajdziesz w artykule na temat zgodności z Androidem, a dokumentu dotyczącego dokumentu CDD znajdziesz na stronie CDD.
OpenSL ES udostępnia interfejs w języku C, z którego można też korzystać w C++. Udostępnia funkcje podobne do części audio tych interfejsów API w języku Java na Androida:
Tak jak w przypadku całego pakietu Android Native Development Kit (NDK), głównym celem OpenSL ES na Androida jest ułatwienie implementacji bibliotek udostępnionych, które można wywoływać za pomocą natywnego interfejsu Java (JNI ). Pakiet NDK nie służy do tworzenia aplikacji w języku C/C++. OpenSL ES to jednak interfejs API o pełnym zakresie funkcji i spodziewamy się, że będziesz w stanie zaspokoić większość swoich potrzeb związanych z dźwiękiem, używając tylko tego interfejsu API, bez konieczności ponownego wywoływania kodu w środowisku wykonawczym Androida.
Uwaga: chociaż oparty na OpenSL ES, natywny interfejs API Androida do odtwarzania dźwięku (wydajna ścieżka dźwiękowa) nie jest zgodną implementacją żadnego profilu OpenSL ES 1.0.1 (gry, muzyki lub telefonu). Dzieje się tak, ponieważ Android nie oferuje wszystkich funkcji wymaganych przez którykolwiek z profili. Znane przypadki, w których Android działa inaczej niż specyfikacja, opisujemy na stronie Rozszerzenia na Androida.
Funkcje dziedziczone ze specyfikacji referencyjnej
Implementacja OpenSL ES na Androida z pakietu Android NDK dziedziczy znaczną część zestawu funkcji ze specyfikacji referencyjnej, z pewnymi ograniczeniami.
Globalne punkty wejścia
OpenSL ES na Androida obsługuje wszystkie globalne punkty wejścia wymienione w specyfikacji Androida. Są to między innymi:
slCreateEngine
slQueryNumSupportedEngineInterfaces
slQuerySupportedEngineInterfaces
Obiekty i interfejsy
W tabeli poniżej znajdziesz obiekty i interfejsy obsługiwane przez implementację pakietu Android NDK na OpenSL ES. Jeśli w komórce znajduje się wartość Tak, oznacza to, że funkcja jest dostępna w tej implementacji.
Cecha | Odtwarzacz dźwięku | Rejestratory dźwięku | Mechanizm | Składanka wyjściowa |
---|---|---|---|---|
Wzmocnienie basów | Tak | Nie | Nie | Tak |
Kolejka bufora | Tak | Nie | Nie | Nie |
Lokalizator danych kolejki bufora | Tak: źródło | Nie | Nie | Nie |
Dynamiczne zarządzanie interfejsem | Tak | Tak | Tak | Tak |
Wysłano efekt | Tak | Nie | Nie | Nie |
Mechanizm | Nie | Nie | Tak | Nie |
Pogłos środowiskowy | Nie | Nie | Nie | Tak |
Korektor | Tak | Nie | Nie | Tak |
Lokalizator danych urządzenia I/O | Nie | Tak: źródło | Nie | Nie |
Wyodrębnianie metadanych | Tak: dekoduj do PCM | Nie | Nie | Nie |
Wycisz solo | Tak | Nie | Nie | Nie |
Obiekt | Tak | Tak | Tak | Tak |
Lokalizator miksu wyjściowego | Tak: ujście | Nie | Nie | Nie |
Odtwórz | Tak | Nie | Nie | Nie |
Prędkość odtwarzania | Tak | Nie | Nie | Nie |
Stan wstępnego pobierania | 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 opisano ograniczenia niektórych z tych funkcji.
Ograniczenia
Funkcje opisane w tabeli 1 podlegają pewnym ograniczeniom. Te ograniczenia oznaczają różnice w stosunku do specyfikacji referencyjnej. W pozostałej części tej sekcji dowiesz się więcej na temat tych różnic.
Dynamiczne zarządzanie interfejsem
OpenSL ES na Androida nie obsługuje RemoveInterface
ani ResumeInterface
.
Kombinacje efektów: pogłos otoczenia i gotowy pogłos
Nie możesz używać pogłosu środowiska i gotowego pogłosu na tym samym wyjściu.
Platforma może zignorować żądania efektu, jeśli oszacuje, że obciążenie procesora byłoby zbyt duże.
Wysłano efekt
SetSendLevel()
obsługuje 1 poziom wysyłania na odtwarzacz audio.
Pogłos środowiskowy
Pogłos środowiskowy nie obsługuje pól reflectionsDelay
, reflectionsLevel
ani reverbDelay
elementu SLEnvironmentalReverbSettings
struct.
Format danych MIME
Formatu danych MIME można używać tylko z lokalizatorem danych URI i tylko w przypadku odtwarzacza audio. Nie można użyć tego formatu danych w przypadku dyktafonu.
Implementacja OpenSL ES na Androida wymaga zainicjowania mimeType
jako NULL
lub prawidłowego ciągu znaków UTF-8. Musisz też zainicjować containerType
prawidłową wartość.
W przypadku braku innych kwestii, takich jak możliwość przenoszenia do innych implementacji lub formatów treści, których aplikacja nie może zidentyfikować za pomocą nagłówka, zalecamy ustawienie mimeType
na NULL
i containerType
na SL_CONTAINERTYPE_UNSPECIFIED
.
OpenSL ES na Androida obsługuje te formaty audio, o ile platforma Android również je obsługuje:
- WAV PCM.
- WAV (alaw)
- WAV ulaw.
- MP3 Ogg Vorbis.
- AAC LC.
- HE-AACv1 (AAC+).
- HE-AACv2 (ulepszone AAC+).
- AMR.
- FLAC
Uwaga: listę formatów dźwięku obsługiwanych przez Androida znajdziesz w artykule Obsługiwane formaty multimediów.
W ramach tej implementacji OpenSL ES obowiązują następujące ograniczenia:
- Formaty AAC muszą znajdować się w kontenerze MP4 lub ADTS.
- OpenSL ES na Androida nie obsługuje MIDI.
- WMA nie jest częścią systemu AOSP i nie zweryfikowaliśmy jego zgodności z OpenSL ES na Androida.
- Implementacja OpenSL ES w Androidzie NDK nie pozwala na bezpośrednie odtwarzanie DRM ani treści zaszyfrowanych. Aby odtworzyć chronione treści audio, musisz odszyfrować je w aplikacji, zanim zacznie się odtwarzanie. Aplikacja musi egzekwować 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 bufora. Obsługiwane konfiguracje odtwarzania PCM mają te cechy:
- 8-bitowy bez podpisu lub 16-bitowy.
- Mono lub stereo.
- Odpowiednia kolejność bajtów w formacie Little-endian.
- Przykładowe częstotliwości:
- 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 obsługiwane przez OpenSL ES na potrzeby nagrywania zależą od urządzenia. Zazwyczaj dostępne jest podpisywanie 16 000 Hz mono/16-bitowe niezależnie od urządzenia.
Wartość w polu samplesPerSec
jest wyrażona w miliHz, mimo że nazwa wprowadza w błąd. Aby uniknąć przypadkowego użycia niewłaściwej wartości, zalecamy zainicjowanie tego pola przy użyciu jednej ze stałych symboli zdefiniowanych do tego celu, np. SL_SAMPLINGRATE_44_1
.
Android 5.0 (poziom interfejsu API 21) i nowsze obsługują dane zmiennoprzecinkowe.
Prędkość odtwarzania
Współczynnik odtwarzania OpenSL ES wskazuje szybkość, z jaką obiekt przedstawia dane, wyrażoną w tysięcznych normalnej szybkości, czyli na tysiąc kilometrów. Na przykład szybkość odtwarzania 1000 na kilometr to 1000/1000, czyli normalna prędkość. Zakres szybkości to zamknięty przedział czasu, w którym określono 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 platformy i implementacji. Aplikacja może określać te możliwości w czasie działania, 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 przesyłania dla źródła danych w formacie PCM i zakres szybkości jednostkowej od 1000 do 1000 na tysiąc dla innych formatów. Oznacza to, że zakres szybkości jednostkowej jest efektywnie jedną wartością.
Nagraj
OpenSL ES na Androida nie obsługuje zdarzeń SL_RECORDEVENT_HEADATLIMIT
ani SL_RECORDEVENT_HEADMOVING
.
Szukaj
Metoda SetLoop()
umożliwia zapętlenie całego pliku. Aby włączyć zapętlenie, ustaw parametr startPos
na 0, a parametr endPos
na SL_TIME_UNKNOWN
.
Lokalizator danych kolejki bufora
Odtwarzacz audio lub rejestrator z lokalizatorem danych dla kolejki bufora obsługuje tylko format danych PCM.
Lokalizator danych urządzenia I/O
OpenSL ES na Androida obsługuje używanie lokalizatora danych urządzenia wejścia-wyjścia tylko wtedy, gdy jako źródło danych dla aplikacji Engine::CreateAudioRecorder()
określisz lokalizator.
Zainicjuj lokalizator danych urządzenia, używając wartości podanych 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 przypadku odtwarzacza audio. W rejestratorze dźwięku nie można użyć lokalizatora danych URI. W identyfikatorze URI można używać tylko schematów http:
i file:
. Inne schematy, takie jak https:
, ftp:
lub content:
, są niedozwolone.
Nie zweryfikowaliśmy jeszcze obsługi funkcji rtsp:
z dźwiękiem na platformie Androida.
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
Oprogramowanie OpenSL ES na Androida obsługuje aplikacje wielowątkowe i jest bezpieczne w wątkach. Obsługuje jeden silnik na aplikację i do 32 obiektów na silnik. Dostępna pamięć urządzenia i procesor mogą jeszcze bardziej ograniczać liczbę używanych obiektów.
Te opcje wyszukiwarek są rozpoznawane, ale są ignorowane przez slCreateEngine
:
SL_ENGINEOPTION_THREADSAFE
SL_ENGINEOPTION_LOSSOFCONTROL
Standardów OpenMAX AL i OpenSL ES można używać jednocześnie w tej samej aplikacji. W tym przypadku istnieje wewnętrznie jeden udostępniony obiekt wyszukiwarki, a limit 32 obiektów jest dzielony między OpenMAX AL i OpenSL ES. Aplikacja powinna utworzyć oba silniki, używać obu, a na koniec zniszczyć oba. Implementacja przechowuje liczbę odwołań we współdzielonym mechanizmie, aby została poprawnie zniszczona podczas drugiej operacji zniszczenia.
Uwagi dotyczące programowania
Uwagi dotyczące programowania OpenSL ES zawierają dodatkowe informacje, które pomogą Ci prawidłowo wdrożyć OpenSL ES.
Uwaga: dla ułatwienia załączamy kopię specyfikacji OpenSL ES 1.0.1 z pakietem NDK w usłudze docs/opensles/OpenSL_ES_Specification_1.0.1.pdf
.
Problemy z platformą
W tej sekcji opisano znane problemy we wstępnej wersji platformy, która obsługuje te interfejsy API.
Dynamiczne zarządzanie interfejsem
DynamicInterfaceManagement::AddInterface
nie działa. Zamiast tego określ interfejs w tablicy, która jest przekazywana do Create()
, jak w przykładowym kodzie pogłosu środowiskowego.
Zaplanuj przyszłe wersje OpenSL ES
Interfejsy API audio o wysokiej wydajności na Androida opierają się na Khronos Group OpenSL ES 1.0.1. Firma Khronos opublikowała poprawioną wersję 1.1 tego standardu. Zawiera ona nowe funkcje, objaśnienia, poprawki literówek i pewne niezgodności. Większość spodziewanych niezgodności jest stosunkowo niewielka lub dotyczy obszarów OpenSL ES, które nie są obsługiwane przez Androida.
Aplikacja opracowana w tej wersji powinna działać w przyszłych wersjach platformy Androida, o ile będziesz przestrzegać wytycznych podanych w sekcji Planowanie zgodności plików binarnych poniżej.
Uwaga: zgodność źródeł w przyszłości nie jest celem. Oznacza to, że po uaktualnieniu do nowszej wersji NDK może być konieczne zmodyfikowanie kodu źródłowego aplikacji w celu dostosowania do nowego interfejsu API. Spodziewamy się, że większość z tych zmian będzie nieznaczna. Szczegóły znajdziesz poniżej.
Zapewnij zgodność z plikami binarnymi
Aby w przyszłości zapewnić zgodność aplikacji z plikami binarnymi, zalecamy stosowanie się do tych wytycznych:
- Korzystaj tylko z udokumentowanego zestawu funkcji obsługiwanych przez Androida z OpenSL ES 1.0.1.
- Nie zależą od konkretnego kodu wyniku w przypadku nieudanej operacji. Przygotuj się na użycie innego kodu wyniku.
- Moduły obsługi wywołań zwrotnych aplikacji zwykle działają w kontekście ograniczonym. Trzeba ich napisać tak, aby szybko wykonywały swoją pracę i jak najszybciej powracały do niej. Nie uruchamiaj złożonych operacji w obrębie modułu obsługi wywołania zwrotnego. Na przykład w ramach wywołania zwrotnego ukończenia kolejki bufora możesz dodać do kolejki kolejny bufor, ale nie możesz utworzyć odtwarzacza dźwięku.
- Moduły obsługi wywołań zwrotnych powinny być przygotowane do częstszego lub rzadszego wywoływania, aby otrzymywać dodatkowe typy zdarzeń i ignorować typy zdarzeń, których nie rozpoznają. Wywołania zwrotne skonfigurowane z maską zdarzenia utworzoną z włączonych typów zdarzeń powinny być przygotowane do wywoływania z wieloma ustawionymi bitami typów zdarzeń jednocześnie. Użyj znaku „&”, aby przetestować każdy bit zdarzenia, a nie przypadek przełącznika.
- Używaj stanu pobierania z wyprzedzeniem i wywołań zwrotnych jako ogólnych wskaźników postępu, ale nie zależą od konkretnych, zakodowanych na stałe poziomów wypełnienia ani sekwencji wywołań zwrotnych. Znaczenie poziomu wypełnienia stanu pobierania z wyprzedzeniem i działanie błędów wykrytych podczas pobierania z wyprzedzeniem mogą ulec zmianie.
Uwaga: więcej informacji znajdziesz w sekcji Działanie kolejki bufora poniżej.
Zaplanuj zgodność źródła
Jak już wspomnieliśmy, w następnej wersji OpenSL ES firmy Khronos Group należy spodziewać się niezgodności kodu źródłowego. Prawdopodobne obszary zmian:
- Prawdopodobnie nastąpią istotne zmiany w interfejsie kolejki bufora, zwłaszcza w obszarach
BufferQueue::Enqueue
, listy parametrówslBufferQueueCallback
i nazwie polaSLBufferQueueState.playIndex
. Zalecamy, aby w kodzie aplikacji używać prostych kolejek bufora na Androidzie. Z tego powodu w przykładowym kodzie dołączonym do pakietu NDK użyliśmy prostych kolejek bufora na Androidzie do odtwarzania. (Używamy też prostej kolejki bufora na Androidzie do nagrywania i dekodowania plików w PCM, ale jest to spowodowane tym, że standardowy OpenSL ES 1.0.1 nie obsługuje nagrywania ani dekodowania do ujścia danych kolejki bufora). - Do parametrów wejściowych przekazywanych przez odwołanie zostanie dodane pole
const
oraz do pól strukturySLchar *
używanych jako wartości wejściowe. Nie powinno to wymagać żadnych zmian w kodzie. - Niektóre parametry, które są obecnie podpisane, zostaną zastąpione przez typy niepodpisane.
Może być konieczna zmiana typu parametru z
SLint32
naSLuint32
lub podobna. Możesz też dodać rzutowanie. Equalizer::GetPresetName
kopiuje ciąg znaków do pamięci aplikacji, zamiast zwracać wskaźnik do pamięci implementacji. Będzie to znacząca zmiana, dlatego zalecamy unikanie wywoływania tej metody lub odizolowanie jej stosowania.- W typach struct będą dodatkowe pola. W przypadku parametrów wyjściowych możesz je ignorować, ale w przypadku parametrów wejściowych należy zainicjować nowe pola. Na szczęście wszystkie te pola znajdują się na obszarach, które nie są obsługiwane przez Androida.
- Identyfikatory GUID interfejsu ulegną zmianie. Aby uniknąć zależności, używaj nazwy symbolicznej, a nie identyfikatora GUID, by używać interfejsów.
SLchar
zmieni się zunsigned char
nachar
. Dotyczy to głównie lokalizatora danych URI i formatu danych MIME.- Nazwa usługi
SLDataFormat_MIME.mimeType
zostanie zmieniona napMimeType
, a nazwaSLDataLocator_URI.URI
– napURI
. Aby odizolować kod od tej zmiany, zalecamy zainicjowanie struktur danychSLDataFormat_MIME
iSLDataLocator_URI
za pomocą listy wartości rozdzielonych przecinkami, a nie nazwy pola. Ta technika jest używana w przykładowym kodzie. - Funkcja
SL_DATAFORMAT_PCM
nie zezwala aplikacji na określanie reprezentacji danych w postaci liczby całkowitej, nieoznaczonej liczby całkowitej lub liczby zmiennoprzecinkowej. Implementacja na Androida zakłada, że 8-bitowe dane to nieoznaczona liczba całkowita, a 16-bitowa liczba całkowita ze znakiem. Ponadto polesamplesPerSec
jest błędne, ponieważ rzeczywiste jednostki podane są w miliHz. Spodziewamy się, że te problemy zostaną rozwiązane w kolejnej wersji OpenSL ES, która będzie zawierać nowy rozszerzony format danych PCM, który umożliwi aplikacji wyraźne określenie reprezentacji i poprawienie nazwy pola. Będzie to nowy format danych, a obecny format danych PCM będzie nadal dostępny (chociaż jest wycofany), więc nie musisz wprowadzać żadnych natychmiastowych zmian w kodzie.