OpenSL ES für Android

WARNUNG: OpenSL ES wurde eingestellt. Entwickler sollten die Open-Source-Oboe-Bibliothek verwenden, die auf GitHub verfügbar ist. Oboe ist ein C++-Wrapper, der eine API bietet, die AAudio sehr ähnelt. Oboe ruft AAudio auf, wenn AAudio verfügbar ist, und wechselt zu OpenSL ES, wenn AAudio nicht verfügbar ist.

Auf dieser Seite erfahren Sie, inwiefern sich die NDK-Implementierung von OpenSL ES™ von der Referenzspezifikation für OpenSL ES 1.0.1 unterscheidet. Wenn Sie Beispielcode aus der Spezifikation verwenden, müssen Sie ihn möglicherweise so ändern, dass er auf Android-Geräten funktioniert.

Sofern nicht anders angegeben, sind alle Funktionen ab Android 2.3 (API-Level 9) verfügbar. Einige Funktionen sind nur für Android 4.0 (API-Level 14) verfügbar. Diese sind entsprechend gekennzeichnet.

Hinweis : Im Android Compatibility Definition Document (CDD) werden die Hardware- und Softwareanforderungen eines kompatiblen Android-Geräts aufgeführt. Weitere Informationen zum allgemeinen Kompatibilitätsprogramm finden Sie unter Android-Kompatibilität und das eigentliche CDD-Dokument unter CDD.

OpenSL ES bietet eine C-Programmierschnittstelle, auf die auch mit C++ zugegriffen werden kann. Sie bietet ähnliche Audiobereiche wie diese Android Java APIs:

Wie bei allen Elementen des Android Native Development Kit (NDK) besteht der Hauptzweck von OpenSL ES für Android darin, die Implementierung gemeinsam genutzter Bibliotheken zu erleichtern, die über die Java Native Interface (JNI ) aufgerufen werden. Das NDK ist nicht für das Schreiben reiner C/C++-Anwendungen gedacht. OpenSL ES ist jedoch eine API mit umfassender Funktionalität und wir gehen davon aus, dass Sie die meisten Ihrer Audioanforderungen nur mit dieser API erfüllen können, ohne Upcalls zu Code ausführen zu müssen, der in der Android-Laufzeit ausgeführt wird.

Hinweis : Die native Audio-API (High-Performance Audio) von Android basiert zwar auf OpenSL ES, ist aber keine konforme Implementierung eines OpenSL ES 1.0.1-Profils (Spiel, Musik oder Smartphone). Das liegt daran, dass Android nicht alle Funktionen implementiert, die für eines der Profile erforderlich sind. Alle bekannten Fälle, in denen sich Android von der Spezifikation unterscheidet, werden auf der Seite Android-Erweiterungen beschrieben.

Aus der Referenzspezifikation übernommene Features

Die Android NDK-Implementierung von OpenSL ES übernimmt einen Großteil des Feature-Sets aus der Referenzspezifikation mit bestimmten Einschränkungen.

Globale Einstiegspunkte

OpenSL ES für Android unterstützt alle globalen Einstiegspunkte in der Android-Spezifikation. Zu diesen Einstiegspunkten gehören:

  • slCreateEngine
  • slQueryNumSupportedEngineInterfaces
  • slQuerySupportedEngineInterfaces

Objekte und Oberflächen

In der folgenden Tabelle sind die Objekte und Schnittstellen aufgeführt, die von der Android NDK-Implementierung von OpenSL ES unterstützt werden. Wenn in der Zelle Ja angezeigt wird, ist die Funktion in dieser Implementierung verfügbar.

Android NDK-Unterstützung für Objekte und Schnittstellen

Funktion Audio player Audiorekorder Motor Ausgabemix
Bassverstärkung Ja Nein Nein Ja
Pufferwarteschlange Ja Nein Nein Nein
Datensuche für Pufferwarteschlangen Ja: Quelle Nein Nein Nein
Dynamische Benutzeroberflächenverwaltung Ja Ja Ja Ja
Effekt gesendet Ja Nein Nein Nein
Motor Nein Nein Ja Nein
Umgebungshall Nein Nein Nein Ja
Equalizer Ja Nein Nein Ja
Daten-Locator für E/A-Geräte Nein Ja: Quelle Nein Nein
Metadaten extrahieren Ja: In PCM decodieren Nein Nein Nein
Solo stummschalten Ja Nein Nein Nein
Objekt Ja Ja Ja Ja
Output-Mix-Locator Ja: Spülbecken Nein Nein Nein
Wiedergeben Ja Nein Nein Nein
Wiedergabegeschwindigkeit Ja Nein Nein Nein
Prefetch-Status Ja Nein Nein Nein
Voreingestellter Hall Nein Nein Nein Ja
Aufnehmen Nein Ja Nein Nein
Suche Ja Nein Nein Nein
URI-Daten-Locator Ja: Quelle Nein Nein Nein
Virtualizer Ja Nein Nein Ja
Lautstärke Ja Nein Nein Nein

Im nächsten Abschnitt werden die Einschränkungen für einige dieser Funktionen erläutert.

Beschränkungen

Für die Funktionen in Tabelle 1 gelten bestimmte Einschränkungen. Diese Einschränkungen stellen Unterschiede zur Referenzspezifikation dar. Im Rest dieses Abschnitts finden Sie Informationen zu diesen Unterschieden.

Dynamische Benutzeroberflächenverwaltung

OpenSL ES für Android unterstützt weder RemoveInterface noch ResumeInterface.

Effektkombinationen: Raumhall und voreingestellter Hall

Für denselben Ausgabemix können nicht gleichzeitig Raumhall und vordefinierter Hall verwendet werden.

Die Plattform ignoriert möglicherweise Effektanfragen, wenn die CPU-Auslastung voraussichtlich zu hoch ist.

Effekt gesendet

SetSendLevel() unterstützt eine einzelne Sendeebene pro Audioplayer.

Umgebungshall

Der Raumhall unterstützt die Felder reflectionsDelay, reflectionsLevel und reverbDelay des SLEnvironmentalReverbSettings-Structs nicht.

MIME-Datenformat

Sie können das MIME-Datenformat nur mit dem URI-Datensucher und nur für einen Audioplayer verwenden. Dieses Datenformat kann nicht für einen Audiorekorder verwendet werden.

Für die Android-Implementierung von OpenSL ES musst du mimeType entweder mit NULL oder einem gültigen UTF-8-String initialisieren. Außerdem müssen Sie containerType mit einem gültigen Wert initialisieren. Wenn keine anderen Aspekte zu berücksichtigen sind, z. B. die Portabilität zu anderen Implementierungen oder Inhaltsformate, die eine App nicht anhand des Headers identifizieren kann, empfehlen wir, mimeType auf NULL und containerType auf SL_CONTAINERTYPE_UNSPECIFIED festzulegen.

OpenSL ES für Android unterstützt die folgenden Audioformate, sofern sie auch von der Android-Plattform unterstützt werden:

  • WAV PCM.
  • WAV alaw.
  • WAV ulaw.
  • MP3 Ogg Vorbis.
  • AAC LC.
  • HE-AACv1 (AAC+).
  • HE-AACv2 (erweitertes AAC+).
  • AMR.
  • FLAC.

Hinweis : Eine Liste der von Android unterstützten Audioformate findest du unter Unterstützte Medienformate.

Für die Verarbeitung dieses und anderer Formate in dieser OpenSL ES-Implementierung gelten die folgenden Einschränkungen:

  • AAC-Formate müssen sich in einem MP4- oder ADTS-Container befinden.
  • OpenSL ES für Android unterstützt kein MIDI.
  • WMA ist nicht Teil von AOSP und wir haben die Kompatibilität mit OpenSL ES für Android nicht überprüft.
  • Die Android NDK-Implementierung von OpenSL ES unterstützt keine direkte Wiedergabe von DRM- oder verschlüsselten Inhalten. Wenn Sie geschützte Audioinhalte abspielen möchten, müssen Sie sie vor der Wiedergabe in Ihrer App entschlüsseln. Dabei müssen alle DRM-Einschränkungen durch Ihre App erzwungen werden.

OpenSL ES für Android unterstützt die folgenden Methoden zur Manipulation von Objekten nicht:

  • Resume()
  • RegisterCallback()
  • AbortAsyncOperation()
  • SetPriority()
  • GetPriority()
  • SetLossOfControlInterfaces()

PCM-Datenformat

PCM ist das einzige Datenformat, das du mit Pufferwarteschlangen verwenden kannst. Unterstützte PCM-Wiedergabekonfigurationen haben die folgenden Eigenschaften:

  • 8-Bit-vorzeichenlos oder 16-Bit-mit Vorzeichen.
  • Mono oder Stereo.
  • Little-Endian-Bytereihenfolge.
  • Abtastraten:
    • 8.000 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

Die von OpenSL ES für Android unterstützten Konfigurationen für die Aufzeichnung sind geräteabhängig. Normalerweise ist unabhängig vom Gerät 16.000 Hz Mono/16-Bit signiert verfügbar.

Der Wert des Felds samplesPerSec wird trotz des irreführenden Namens in Millihertz angegeben. Um versehentlich den falschen Wert zu verwenden, empfehlen wir, dieses Feld mit einer der zu diesem Zweck definierten symbolischen Konstanten zu initialisieren, z. B. SL_SAMPLINGRATE_44_1.

Android 5.0 (API-Level 21) und höher unterstützen Gleitkommadaten.

Wiedergabegeschwindigkeit

Eine OpenSL ES-Wiedergaberate gibt die Geschwindigkeit an, mit der ein Objekt Daten darstellt, ausgedrückt in Tausendstel der normalen Geschwindigkeit oder Pro Mille. Eine Wiedergaberate von 1.000 pro Mille entspricht beispielsweise 1.000/1.000, also der normalen Geschwindigkeit. Ein Taktfrequenzbereich ist ein geschlossenes Intervall, das einen Bereich möglicher Wiedergaberaten angibt.

Die Unterstützung für Wiedergabegeschwindigkeitsbereiche und andere Funktionen kann je nach Plattformversion und Implementierung variieren. Ihre App kann diese Funktionen zur Laufzeit ermitteln. Dazu wird das Gerät mit PlaybackRate::GetRateRange() oder PlaybackRate::GetCapabilitiesOfRate() abgefragt.

Ein Gerät unterstützt in der Regel denselben Ratenbereich für eine Datenquelle im PCM-Format und einen Einheitsratebereich von 1.000 promille bis 1.000 promille für andere Formate. Das bedeutet, dass der Einheitsratebereich effektiv ein einzelner Wert ist.

Aufnehmen

OpenSL ES für Android unterstützt die Ereignisse SL_RECORDEVENT_HEADATLIMIT und SL_RECORDEVENT_HEADMOVING nicht.

Suche

Mit der SetLoop()-Methode kann die gesamte Datei wiederholt werden. Wenn du das Looping aktivieren möchtest, setze den Parameter startPos auf 0 und den Parameter endPos auf SL_TIME_UNKNOWN.

Daten-Locator für Buffer-Warteschlange

Ein Audioplayer oder -rekorder mit einem Datenlocator für eine Pufferwarteschlange unterstützt nur das PCM-Datenformat.

Daten-Locator für E/A-Geräte

OpenSL ES für Android unterstützt die Verwendung eines Datenlocators für E/A-Geräte nur, wenn Sie den Locator als Datenquelle für Engine::CreateAudioRecorder() angegeben haben. Initialisieren Sie den Gerätedaten-Locator mit den Werten im folgenden Code-Snippet:

SLDataLocator_IODevice loc_dev =
  {SL_DATALOCATOR_IODEVICE, SL_IODEVICE_AUDIOINPUT,
  SL_DEFAULTDEVICEID_AUDIOINPUT, NULL};

URI-Daten-Locator

OpenSL ES für Android kann den URI-Daten-Locator nur mit dem MIME-Datenformat und nur für einen Audioplayer verwenden. Sie können für einen Audiorekorder keinen URI-Datenfinder verwenden. Der URI kann nur die Schemas http: und file: verwenden. Andere Schemas wie https:, ftp: oder content: sind nicht zulässig.

Wir haben die Unterstützung von rtsp: mit Audio auf der Android-Plattform nicht überprüft.

Datenstrukturen

Android unterstützt die folgenden OpenSL ES 1.0.1-Datenstrukturen:

  • SLDataFormat_MIME
  • SLDataFormat_PCM
  • SLDataLocator_BufferQueue
  • SLDataLocator_IODevice
  • SLDataLocator_OutputMix
  • SLDataLocator_URI
  • SLDataSink
  • SLDataSource
  • SLEngineOption
  • SLEnvironmentalReverbSettings
  • SLInterfaceID

Plattformkonfiguration

OpenSL ES für Android ist für mehrstufige Anwendungen konzipiert und threadsicher. Es unterstützt eine einzelne Engine pro Anwendung und bis zu 32 Objekte pro Engine. Der verfügbare Arbeitsspeicher und die verfügbare CPU des Geräts können die verwendbare Anzahl von Objekten weiter einschränken.

Diese Engine-Optionen werden erkannt, aber von slCreateEngine ignoriert:

  • SL_ENGINEOPTION_THREADSAFE
  • SL_ENGINEOPTION_LOSSOFCONTROL

OpenMAX AL und OpenSL ES können in derselben Anwendung zusammen verwendet werden. In diesem Fall gibt es intern ein einziges gemeinsames Engine-Objekt und das Limit von 32 Objekten wird zwischen OpenMAX AL und OpenSL ES aufgeteilt. Die Anwendung sollte beide Engines erstellen, beide Engines verwenden und schließlich beide löschen. Die Implementierung führt eine Referenzzählung für die freigegebene Engine, damit sie beim zweiten Löschvorgang korrekt gelöscht wird.

Programmhinweise

Die OpenSL ES-Programmierhinweise enthalten zusätzliche Informationen, die für eine ordnungsgemäße Implementierung von OpenSL ES erforderlich sind.

Hinweis : Wir haben eine Kopie der Spezifikation von OpenSL ES 1.0.1 mit dem NDK in docs/opensles/OpenSL_ES_Specification_1.0.1.pdf beigefügt.

Plattformprobleme

In diesem Abschnitt werden bekannte Probleme in der ersten Plattformversion beschrieben, die diese APIs unterstützt.

Dynamische Benutzeroberflächenverwaltung

DynamicInterfaceManagement::AddInterface funktioniert nicht. Geben Sie die Benutzeroberfläche stattdessen im Array an, das an Create() übergeben wird, wie im Beispielcode für den Umgebungsreverb gezeigt.

Für zukünftige Versionen von OpenSL ES planen

Die leistungsstarken Audio-APIs von Android basieren auf Khronos Group OpenSL ES 1.0.1. Khronos hat eine überarbeitete Version 1.1 des Standards veröffentlicht. Die überarbeitete Version enthält neue Funktionen, Klarstellungen, Korrekturen von Tippfehlern und einige Inkompatibilitäten. Die meisten der erwarteten Inkompatibilitäten sind relativ geringfügig oder betreffen Bereiche von OpenSL ES, die von Android nicht unterstützt werden.

Eine mit dieser Version entwickelte Anwendung sollte auf zukünftigen Versionen der Android-Plattform funktionieren, sofern Sie die im Abschnitt Binäre Kompatibilität planen beschriebenen Richtlinien einhalten.

Hinweis : Die zukünftige Kompatibilität von Quellen wird nicht angestrebt. Wenn Sie also auf eine neuere Version des NDK umstellen, müssen Sie möglicherweise den Quellcode Ihrer Anwendung so ändern, dass er der neuen API entspricht. Wir gehen davon aus, dass die meisten dieser Änderungen geringfügig sind. Weitere Informationen finden Sie unten.

Binärkompatibilität planen

Wir empfehlen, dass Ihre Anwendung diesen Richtlinien entspricht, um die zukünftige Binärkompatibilität zu verbessern:

  • Verwenden Sie nur die dokumentierte Teilmenge der von Android unterstützten Funktionen aus OpenSL ES 1.0.1.
  • Verlasse dich nicht auf einen bestimmten Ergebniscode für einen fehlgeschlagenen Vorgang. Sei darauf vorbereitet, mit einem anderen Ergebniscode umzugehen.
  • Callback-Handler von Anwendungen werden in der Regel in einem eingeschränkten Kontext ausgeführt. Sie sollten so geschrieben sein, dass sie ihre Arbeit schnell erledigen und dann so schnell wie möglich zurückkehren können. Führen Sie keine komplexen Vorgänge innerhalb eines Callback-Handlers aus. Sie können beispielsweise in einem Callback für den Abschluss der Zwischenspeicherwarteschlange einen weiteren Zwischenspeicher in die Warteschlange stellen, aber keinen Audioplayer erstellen.
  • Callback-Handler sollten darauf vorbereitet sein, häufiger oder seltener aufgerufen zu werden, um zusätzliche Ereignistypen zu empfangen, und sollten Ereignistypen ignorieren, die sie nicht erkennen. Callbacks, die mit einer Ereignismaske aus aktivierten Ereignistypen konfiguriert sind, sollten so vorbereitet sein, dass sie mit mehreren gleichzeitig festgelegten Ereignistyp-Bits aufgerufen werden können. Verwenden Sie „&“, um für jedes Ereignisbit anstelle eines Switch-Case-Vorgangs zu testen.
  • Verwende den prefetch-Status und Callbacks als allgemeine Hinweise auf den Fortschritt, aber verlasse dich nicht auf bestimmte hartcodierte Füllstände oder Callback-Sequenzen. Die Bedeutung des Füllstands des prefetch-Status und das Verhalten bei Fehlern, die während des Prefetch erkannt werden, können sich ändern.

Hinweis : Weitere Informationen finden Sie unten im Abschnitt Verhalten von Pufferwarteschlangen.

Quellkompatibilität planen

Wie bereits erwähnt, sind in der nächsten Version von OpenSL ES von der Khronos Group Inkompatibilitäten mit dem Quellcode zu erwarten. Zu den wahrscheinlichen Änderungsbereichen gehören:

  • An der Schnittstelle der Zwischenspeicherwarteschlange sind erhebliche Änderungen zu erwarten, insbesondere in Bezug auf BufferQueue::Enqueue, die Parameterliste für slBufferQueueCallback und den Namen des Felds SLBufferQueueState.playIndex. Wir empfehlen, im Anwendungscode stattdessen einfache Android-Pufferwarteschlangen zu verwenden. Im Beispielcode, der mit dem NDK geliefert wird, haben wir aus diesem Grund einfache Android-Pufferwarteschlangen für die Wiedergabe verwendet. Wir verwenden auch die einfache Pufferwarteschlange von Android zum Aufzeichnen und Decodieren in PCM, da OpenSL ES 1.0.1 das Aufzeichnen oder Decodieren in eine Pufferwarteschlange nicht unterstützt.
  • Den per Verweis übergebenen Eingabeparametern und den SLchar *-Strukturfeldern, die als Eingabewerte verwendet werden, wird const hinzugefügt. Dies sollte keine Änderungen an Ihrem Code erfordern.
  • Einige Parameter, die derzeit signiert sind, werden durch signaturlose Typen ersetzt. Möglicherweise müssen Sie einen Parametertyp von SLint32 in SLuint32 oder ähnlich ändern oder eine Umwandlung hinzufügen.
  • Equalizer::GetPresetName kopiert den String in den Anwendungsspeicher, anstatt einen Zeiger in den Implementierungsspeicher zurückzugeben. Dies ist eine erhebliche Änderung. Wir empfehlen Ihnen daher, diese Methode entweder nicht aufzurufen oder ihre Verwendung einzuschränken.
  • Die Strukturtypen enthalten zusätzliche Felder. Bei Ausgabeparametern können diese neuen Felder ignoriert werden. Bei Eingabeparametern müssen sie jedoch initialisiert werden. Glücklicherweise befinden sich alle diese Felder voraussichtlich in Bereichen, die von Android nicht unterstützt werden.
  • Die GUIDs der Benutzeroberfläche ändern sich. Verweise auf Schnittstellen anhand des symbolischen Namens anstelle der GUID, um Abhängigkeiten zu vermeiden.
  • Der Preis für SLchar ändert sich von unsigned char in char. Dies betrifft hauptsächlich den URI-Datenlocator und das MIME-Datenformat.
  • SLDataFormat_MIME.mimeType wird in pMimeType umbenannt und SLDataLocator_URI.URI wird in pURI umbenannt. Wir empfehlen, die Datenstrukturen SLDataFormat_MIME und SLDataLocator_URI mit einer in Klammern gesetzten, durch Kommas getrennten Liste von Werten anstatt nach Feldnamen zu initialisieren, um Ihren Code von dieser Änderung zu isolieren. Diese Technik wird im Beispielcode verwendet.
  • SL_DATAFORMAT_PCM erlaubt es der Anwendung nicht, die Darstellung der Daten als signierte Ganzzahl, als ungesignierte Ganzzahl oder als Gleitkommazahl anzugeben. Bei der Android-Implementierung wird davon ausgegangen, dass 8-Bit-Daten vorzeichenlose Ganzzahlen und 16-Bit-Daten vorzeichenbehaftete Ganzzahlen sind. Außerdem ist das Feld samplesPerSec falsch, da die tatsächlichen Einheiten in MilliHz angegeben werden. Diese Probleme werden voraussichtlich in der nächsten OpenSL ES-Version behoben, die ein neues erweitertes PCM-Datenformat einführt, mit dem die Anwendung die Darstellung explizit angeben und den Feldnamen korrigieren kann. Da es sich um ein neues Datenformat handelt und das aktuelle PCM-Datenformat weiterhin verfügbar (wenn auch nicht mehr empfohlen) sein wird, sollten keine sofortigen Änderungen an deinem Code erforderlich sein.