Android-Erweiterungen

OpenSL ES für Android erweitert die OpenSL ES-Referenzspezifikation um die Kompatibilität mit Android und die Nutzung der Leistungsfähigkeit und Flexibilität der Android-Plattform.

Die Definition der API für die Android-Erweiterungen findest du in OpenSLES_Android.h und den darin enthaltenen Headerdateien. Weitere Informationen zu diesen Erweiterungen finden Sie unter OpenSLES_Android.h. Diese Datei befindet sich im Installationsstammverzeichnis im Verzeichnis sysroot/usr/include/SLES. Sofern nicht anders angegeben, sind alle Schnittstellen explizit.

Diese Erweiterungen schränken die Portabilität Ihrer Anwendung auf andere OpenSL ES-Implementierungen ein, da sie Android-spezifisch sind. Sie können dieses Problem umgehen, indem Sie die Verwendung der Erweiterungen vermeiden oder sie mit #ifdef bei der Kompilierung ausschließen.

Die folgende Tabelle zeigt die Android-spezifischen Schnittstellen und Data Locators, die Android OpenSL ES für jeden Objekttyp unterstützt. Die Yes-Werte in den Zellen geben die Schnittstellen und Datenfinder an, die für jeden Objekttyp verfügbar sind.

Funktion Audio player Audiorekorder Modul Ausgabemix
Android-Zwischenspeicher Ja: Quelle (decodieren) Nein Nein Nein
Android-Konfiguration Ja Ja Nein Nein
Android-Effekt Ja Nein Nein Ja
Android-Effektfunktionen Nein Nein Ja Nein
Android-Effekt senden Ja Nein Nein Nein
Android: Einfache Zwischenspeicherwarteschlange Ja: Quelle (Wiedergabe) oder Senke (Decodierung) Ja Nein Nein
Android-Zwischenspeicher für Datensuche Ja: Quelle (decodieren) Nein Nein Nein
Android-Dateideskriptor-Datensuche Ja: Quelle Nein Nein Nein
Android – einfacher Zwischenspeicher für Datensuche Ja: Quelle (Wiedergabe) oder Senke (Decodierung) Ja: Spülbecken Nein Nein

Android-Konfigurationsoberfläche

Die Android-Konfigurationsoberfläche bietet eine Möglichkeit, plattformspezifische Parameter für Objekte festzulegen. Diese Schnittstelle unterscheidet sich von anderen OpenSL ES 1.0.1-Schnittstellen dadurch, dass Ihre Anwendung sie vor der Instanziierung des entsprechenden Objekts verwenden kann. Daher können Sie das Objekt vor der Instanziierung konfigurieren. In der Headerdatei OpenSLES_AndroidConfiguration.h, die sich unter /sysroot/usr/include/SLES befindet, sind die folgenden verfügbaren Konfigurationsschlüssel und Werte dokumentiert:

  • Streamtyp für Audioplayer (Standardwert: SL_ANDROID_STREAM_MEDIA)
  • Profil für Audiorekorder aufnehmen (Standardeinstellung: SL_ANDROID_RECORDING_PRESET_GENERIC).

Das folgende Code-Snippet zeigt ein Beispiel dafür, wie der Android-Audiostreamtyp in einem Audioplayer festgelegt wird:

// CreateAudioPlayer and specify SL_IID_ANDROIDCONFIGURATION
// in the required interface ID array. Do not realize player yet.
// ...
SLAndroidConfigurationItf playerConfig;
result = (*playerObject)->GetInterface(playerObject,
    SL_IID_ANDROIDCONFIGURATION, &playerConfig);
assert(SL_RESULT_SUCCESS == result);
SLint32 streamType = SL_ANDROID_STREAM_ALARM;
result = (*playerConfig)->SetConfiguration(playerConfig,
    SL_ANDROID_KEY_STREAM_TYPE, &streamType, sizeof(SLint32));
assert(SL_RESULT_SUCCESS == result);
// ...
// Now realize the player here.

Mit ähnlichem Code können Sie die Voreinstellung für einen Audiorekorder konfigurieren:

// ... obtain the configuration interface as the first four lines above, then:
SLuint32 presetValue = SL_ANDROID_RECORDING_PRESET_VOICE_RECOGNITION;
result = (*playerConfig)->SetConfiguration(playerConfig,
    RECORDING_PRESET, &presetValue, sizeof(SLuint32));

Benutzeroberflächen für Android-Effekte

Die Android-Schnittstellen für Effekte, Senden von Effekten und Effektfunktionen bieten einen generischen Mechanismus, über den Apps gerätespezifische Audioeffekte abfragen und verwenden können. Gerätehersteller sollten alle verfügbaren gerätespezifischen Audioeffekte dokumentieren.

Portable Anwendungen sollten für Audioeffekte die OpenSL ES 1.0.1 APIs anstelle der Android-Effekterweiterungen verwenden.

Android-Dateideskriptor-Datensuche

Mit der Android-Dateideskriptor-Datensuche können Sie die Quelle für einen Audioplayer als offenen Dateideskriptor mit Lesezugriff angeben. Das Datenformat muss MIME sein.

Diese Erweiterung ist besonders nützlich in Verbindung mit dem nativen Asset-Manager, da die App Assets über einen Dateideskriptor aus dem APK liest.

Einfache Android-Benutzeroberfläche für die Datensuche für Zwischenspeicher

In der Referenzspezifikation von OpenSL ES 1.0.1 können Pufferwarteschlangen nur für Audioplayer verwendet werden und sind mit PCM und anderen Datenformaten kompatibel. Die Android-Spezifikationen für die einfache Zwischenspeicherwarteschlangen-Datensuche und -Schnittstellen sind mit der Referenzspezifikation bis auf zwei Ausnahmen identisch:

  • Sie können in Android einfache Pufferwarteschlangen mit Audiorekordern und Audioplayern verwenden.
  • Für diese Warteschlangen können Sie nur das PCM-Datenformat verwenden.

Zum Aufzeichnen sollte Ihre Anwendung leere Zwischenspeicher in die Warteschlange stellen. Wenn ein registrierter Callback eine Benachrichtigung sendet, dass das System das Schreiben von Daten in einen Zwischenspeicher abgeschlossen hat, kann die App Daten aus diesem Zwischenspeicher lesen.

Die Wiedergabe funktioniert auf die gleiche Weise. Aus Gründen der zukünftigen Kompatibilität mit Quellcode empfehlen wir jedoch, für Anwendungen einfache Pufferwarteschlangen für Android anstelle von Zwischenspeicherwarteschlangen in OpenSL ES 1.0.1 zu verwenden.

Verhalten der Pufferwarteschlange

Die Android-Implementierung beinhaltet nicht die Anforderung der Referenzspezifikation, dass der Wiedergabe-Cursor zum Anfang des aktuell wiedergegebenen Zwischenspeichers zurückkehren muss, wenn die Wiedergabe in den SL_PLAYSTATE_STOPPED-Status übergeht. Diese Implementierung kann diesem Verhalten entsprechen oder die Position des Wiedergabe-Cursors unverändert lassen. Daher kann Ihre App nicht davon ausgehen, dass eines der beiden Verhaltensweisen eintritt. Daher sollten Sie nach einem Übergang zu SL_PLAYSTATE_STOPPED die Methode BufferQueue::Clear() explizit aufrufen. Dadurch wird die Zwischenspeicherwarteschlange auf einen bekannten Zustand gesetzt.

Ebenso gibt es keine Spezifikation, die festlegt, ob der Trigger für einen Pufferwarteschlangenrückruf ein Übergang zu SL_PLAYSTATE_STOPPED oder eine Ausführung von BufferQueue::Clear() sein muss. Daher empfehlen wir, keine Abhängigkeit von einem der beiden zu erstellen. Stattdessen sollte Ihre Anwendung beide verarbeiten können.

Dynamische Schnittstellen bei der Objekterstellung

Der Einfachheit halber erlaubt die Android-Implementierung von OpenSL ES 1.0.1 deiner App, bei der Instanziierung eines Objekts dynamische Schnittstellen anzugeben. Dies ist eine Alternative zur Verwendung von DynamicInterfaceManagement::AddInterface(), um diese Schnittstellen nach der Instanziierung hinzuzufügen.

Berichte zu Erweiterungen

Es gibt drei Methoden, um herauszufinden, ob die Plattform Android-Erweiterungen unterstützt. Diese Methoden sind:

  • Engine::QueryNumSupportedExtensions()
  • Engine::QuerySupportedExtension()
  • Engine::IsExtensionSupported()

Jede dieser Methoden gibt ANDROID_SDK_LEVEL_<API-level> zurück, wobei API-level das API-Level der Plattform ist, z. B. ANDROID_SDK_LEVEL_23. Ein Plattform-API-Level von 9 oder höher bedeutet, dass die Plattform die Erweiterungen unterstützt.

Audio in PCM decodieren

In diesem Abschnitt wird eine eingestellte Android-spezifische Erweiterung für OpenSL ES 1.0.1 beschrieben, mit der ein codierter Stream ohne sofortige Wiedergabe in PCM decodiert werden kann. Die folgende Tabelle enthält Empfehlungen für die Verwendung dieser Erweiterung und Alternativen.

API-Ebene Alternativen
Bis einschließlich 15 Jahre Ein Open-Source-Codec mit einer geeigneten Lizenz
16 bis 20 Die MediaCodec-Klasse oder einen Open-Source-Codec mit einer geeigneten Lizenz
21 und älter NDK MediaCodec in den <media/NdkMedia*.h>-Headerdateien, der Klasse MediaCodec oder einem Open-Source-Codec mit einer geeigneten Lizenz

Hinweis: Für die NDK-Version der MediaCodec API ist derzeit keine Dokumentation verfügbar. Sie können sich jedoch den Beispielcode für native-codec ansehen.

In einem Standard-Audioplayer werden die Daten auf einem Audiogerät wiedergegeben, wobei der Ausgabemix als Datensenke angegeben wird. Die Android-Erweiterung unterscheidet sich dadurch, dass ein Audioplayer stattdessen als Decoder agiert, wenn die App die Datenquelle entweder als URI oder als Android-Dateideskriptor-Data-Locator, der im MIME-Datenformat beschrieben wird, angegeben hat. In einem solchen Fall ist die Datensenke eine einfache Android-Pufferwarteschlangen-Datensuche, die das PCM-Datenformat verwendet.

Diese Funktion ist in erster Linie für Spiele gedacht, bei denen Audio-Assets vorab geladen werden, wenn zu einem neuen Level gewechselt wird. Sie ähnelt der Funktionalität der SoundPool-Klasse.

Die Anwendung sollte zuerst eine Reihe leerer Zwischenspeicher in die einfache Android-Zwischenspeicherwarteschlange stellen. Danach füllt die App die Puffer mit PCM-Daten. Der Callback für die einfache Pufferwarteschlange von Android wird ausgelöst, wenn jeder Puffer gefüllt ist. Der Callback-Handler verarbeitet die PCM-Daten, stellt den jetzt leeren Zwischenspeicher wieder in die Warteschlange und kehrt dann zurück. Die Anwendung ist für die Überwachung decodierter Zwischenspeicher verantwortlich. Die Liste der Callback-Parameter enthält nicht genügend Informationen, um den Puffer, der Daten enthält, oder den Zwischenspeicher anzugeben, der als Nächstes in die Warteschlange eingereiht werden soll.

Die Datenquelle meldet implizit das Ende des Streams (EOS), indem ein SL_PLAYEVENT_HEADATEND-Ereignis am Ende des Streams gesendet wird. Nachdem die App alle empfangenen Daten decodiert hat, führt sie keine weiteren Aufrufe an den Android-Callback für die einfache Zwischenspeicherwarteschlange aus.

Das PCM-Datenformat der Senke entspricht in der Regel dem der codierten Datenquelle hinsichtlich Abtastrate, Kanalanzahl und Bittiefe. Sie können jedoch in eine andere Abtastrate, Kanalanzahl oder Bittiefe decodieren. Informationen zu einer Bereitstellung zur Erkennung des tatsächlichen PCM-Formats finden Sie unter Format decodierter PCM-Daten über Metadaten bestimmen.

Die PCM-Decodierungsfunktion von OpenSL ES für Android unterstützt die Pausen- und die anfängliche Suche. Sie unterstützt keine Lautstärkeregelung, Effekte, Schleifen und Wiedergaberaten.

Je nach Plattformimplementierung können für die Decodierung Ressourcen erforderlich sein, die nicht inaktiv bleiben können. Daher empfehlen wir Ihnen, eine ausreichende Anzahl leerer PCM-Zwischenspeicher bereitzustellen, da der Decoder sonst nicht mehr benötigt. Das kann beispielsweise vorkommen, wenn deine App vom Android-Callback für die einfache Zwischenspeicherwarteschlange zurückkehrt, ohne einen weiteren leeren Zwischenspeicher einzufügen. Das Ergebnis eines Decodierermangels ist nicht angegeben, kann jedoch Folgendes umfassen: Löschen der decodierten PCM-Daten, Anhalten des Decodierungsvorgangs oder Beenden des Decoders.

Hinweis : Wenn Sie einen codierten Stream in PCM decodieren, aber nicht sofort wiedergeben möchten, empfehlen wir für Apps, die unter Android 4.x (API-Level 16–20) ausgeführt werden, die Klasse MediaCodec. Für neue Anwendungen unter Android 5.0 (API-Level 21) oder höher empfehlen wir die Verwendung des NDK-Äquivalents <NdkMedia*.h>. Diese Headerdateien befinden sich im Verzeichnis media/ unter Ihrem Installationsstammverzeichnis.

Streaming von ADTS AAC zu PCM decodieren

Ein Audioplayer fungiert als Streaming-Decoder, wenn die Datenquelle eine Android-Pufferwarteschlangen-Datensuche ist, die das MIME-Datenformat verwendet, und die Datensenke eine einfache Android-Pufferwarteschlangen-Datensuche ist, die das PCM-Datenformat verwendet. Konfigurieren Sie das MIME-Datenformat wie folgt:

  • Container: SL_CONTAINERTYPE_RAW
  • MIME-Typ-String: SL_ANDROID_MIME_AACADTS

Diese Funktion ist in erster Linie für Streaming-Media-Anwendungen gedacht, die sich mit AAC-Audio beschäftigen, aber vor der Wiedergabe eine benutzerdefinierte Audioverarbeitung durchführen müssen. Die meisten Anwendungen, die Audio in PCM decodieren müssen, sollten die unter Audio in PCM decodieren beschriebene Methode verwenden, da diese einfacher ist und mehr Audioformate verarbeitet. Das hier beschriebene Verfahren ist ein spezialisierterer Ansatz und sollte nur angewendet werden, wenn diese beiden Bedingungen zutreffen:

  • Die komprimierte Audioquelle ist ein Stream von AAC-Frames in ADTS-Headern.
  • Dieser Stream wird über die Anwendung verwaltet. Die Daten befinden sich nicht in einer Netzwerkressource, deren ID ein URI ist, oder in einer lokalen Datei, deren ID ein Dateideskriptor ist.

Die Anwendung sollte zunächst eine Reihe gefüllter Puffer in die Android-Pufferwarteschlange einreihen. Jeder Puffer enthält einen oder mehrere vollständige ADTS AAC-Frames. Der Android-Pufferwarteschlangenrückruf wird ausgelöst, nachdem jeder Puffer geleert wurde. Der Callback-Handler sollte den Puffer auffüllen, neu in die Warteschlange stellen und anschließend zurückkehren. Die Anwendung muss codierte Puffer nicht im Auge behalten. Die Liste der Callback-Parameter enthält ausreichende Informationen, um den Puffer anzugeben, der als Nächstes in die Warteschlange eingereiht werden soll. Das Ende des Streams wird explizit durch ein EOS-Element in die Warteschlange markiert. Nach EOS sind keine Warteschlangen mehr zulässig.

Sie sollten vollständige AAC-Puffer von ADTS bereitstellen, damit der Decoder nicht zu lange benötigt. Dies kann beispielsweise der Fall sein, wenn Ihre App vom Android-Callback für die Zwischenspeicherwarteschlange zurückgibt, ohne einen weiteren vollständigen Puffer einzureihen. Das Ergebnis des Decodermangels ist nicht angegeben.

Mit Ausnahme der Datenquelle entspricht die Streaming-Decodierungsmethode der Methode, die unter Audio in PCM decodieren beschrieben wird.

Trotz der ähnlichen Namen ist eine Zwischenspeicherwarteschlange in Android nicht dasselbe wie eine einfache Zwischenspeicherwarteschlange in Android. Der Streaming-Decoder verwendet beide Arten von Pufferwarteschlangen: eine Android-Pufferwarteschlange für die ADTS AAC-Datenquelle und eine einfache Android-Pufferwarteschlange für die PCM-Datensenke. Weitere Informationen zur Android Simple buffer Queue API finden Sie unter Android: Simple buffer Queue API. Weitere Informationen zur Android buffer Queue API finden Sie in der Datei index.html im Verzeichnis docs/Additional_library_docs/openmaxal/ unter dem Installationsstammverzeichnis.

Das Format decodierter PCM-Daten über Metadaten bestimmen

Die Schnittstelle SLMetadataExtractionItf ist Teil der Referenzspezifikation. Die Metadatenschlüssel, die das tatsächliche Format der decodierten PCM-Daten angeben, sind jedoch Android-spezifisch. Diese Metadatenschlüssel sind in der OpenSLES_AndroidMetadata.h-Headerdatei definiert. Diese Headerdatei befindet sich im Installationsstammverzeichnis im Verzeichnis /sysroot/usr/include/SLES.

Die Metadaten-Schlüsselindexe sind sofort verfügbar, nachdem die Methode Object::Realize() ausgeführt wurde. Die zugehörigen Werte sind jedoch erst verfügbar, nachdem die Anwendung die ersten codierten Daten decodiert hat. Es empfiehlt sich, nach dem Aufrufen der Object::Realize-Methode die Schlüsselindexe im Hauptthread abzufragen und die Metadatenwerte des PCM-Formats im Callback-Handler der einfachen Android-Zwischenspeicherwarteschlange zu lesen, wenn der Thread zum ersten Mal aufgerufen wird. Beispiele für die Arbeit mit dieser Schnittstelle finden Sie im Beispielcode im NDK-Paket.

Die Namen der Metadatenschlüssel sind stabil. Die Schlüsselindexe sind jedoch nicht dokumentiert und können sich ändern. Eine Anwendung sollte nicht davon ausgehen, dass Indexe über verschiedene Ausführungsläufe hinweg persistent sind, und nicht davon ausgehen, dass mehrere Objektinstanzen Indizes innerhalb desselben Durchlaufs teilen.

Gleitkommadaten

Eine App unter Android 5.0 (API-Level 21) und höher kann einem AudioPlayer Daten im Gleitkommaformat mit einfacher Genauigkeit bereitstellen.

Im folgenden Beispielcode erstellt die Methode Engine::CreateAudioPlayer() einen Audioplayer, der Gleitkommadaten verwendet:

#include <SLES/OpenSLES_Android.h>
...
SLAndroidDataFormat_PCM_EX pcm;
pcm.formatType = SL_ANDROID_DATAFORMAT_PCM_EX;
pcm.numChannels = 2;
pcm.sampleRate = SL_SAMPLINGRATE_44_1;
pcm.bitsPerSample = 32;
pcm.containerSize = 32;
pcm.channelMask = SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT;
pcm.endianness = SL_BYTEORDER_LITTLEENDIAN;
pcm.representation = SL_ANDROID_PCM_REPRESENTATION_FLOAT;
...
SLDataSource audiosrc;
audiosrc.pLocator = ...
audiosrc.pFormat = &pcm;
Weitere Informationen zu Gleitkomma-Audio finden Sie auf der Seite "Audio wiedergeben".