A-Audio

AAudio ist eine neue Android C API, die mit dem Release von Android O eingeführt wird. Es wurde für leistungsstarke Audioanwendungen entwickelt, die eine niedrige Latenz erfordern. Apps kommunizieren mit AAudio, indem sie Daten in Streams lesen und schreiben.

Die AAudio API ist grundsätzlich minimal, keine der folgenden Funktionen ausführt:

  • Liste der Audiogeräte
  • Automatisches Routing zwischen Audioendpunkten
  • Datei-E/A
  • Decodierung komprimierter Audiodateien
  • Automatische Darstellung aller Eingaben/Streams in einem einzigen Callback.

Erste Schritte

Du kannst AAudio über C++-Code aufrufen. Fügen Sie die AAudio.h-Headerdatei hinzu, um Ihrer App die AAudio-Funktion hinzuzufügen:

#include <aaudio/AAudio.h>

Audiostreams

AAudio überträgt Audiodaten zwischen Ihrer App und den Audioein- und -ausgängen auf Ihrem Android-Gerät. Ihre App leitet Daten ein und aus, indem sie aus Audiostreams liest und schreibt. Diese werden durch die Struktur „AAudioStream“ dargestellt. Die Lese-/Schreibaufrufe können blockieren oder nicht blockieren.

Ein Stream wird so definiert:

  • Das Audio gerät, das die Quelle oder Senke für die Daten im Stream ist.
  • Der Freigabemodus, der bestimmt, ob ein Stream exklusiven Zugriff auf ein Audiogerät hat, der andernfalls von mehreren Streams gemeinsam genutzt werden könnte.
  • Das Format der Audiodaten im Stream.

Audiogerät

Jeder Stream ist mit einem einzelnen Audiogerät verbunden.

Ein Audiogerät ist eine Hardwareschnittstelle oder ein virtueller Endpunkt, die als Quelle oder Senke für einen kontinuierlichen Stream digitaler Audiodaten fungiert. Verwechseln Sie kein Audiogerät. (integriertes Mikrofon oder Bluetooth-Headset) mit dem Android-Gerät (Smartphone oder Smartwatch), auf dem Ihre App läuft.

Du kannst die AudioManager-Methode getDevices() verwenden, um die auf deinem Android-Gerät verfügbaren Audiogeräte zu finden. Die Methode gibt Informationen zum type jedes Geräts zurück.

Jedes Audiogerät hat auf dem Android-Gerät eine eindeutige ID. Mithilfe der ID können Sie einen Audiostream an ein bestimmtes Audiogerät binden. In den meisten Fällen können Sie jedoch festlegen, dass AAudio das primäre Standardgerät auswählen soll, anstatt selbst ein Gerät anzugeben.

Das an einen Stream angeschlossene Audiogerät bestimmt, ob der Stream für die Ein- oder Ausgabe bestimmt ist. Ein Stream kann Daten nur in eine Richtung verschieben. Wenn Sie einen Stream definieren, legen Sie auch seine Richtung fest. Wenn Sie einen Stream öffnen, prüft Android, ob Audiogerät und Streamrichtung übereinstimmen.

Freigabemodus

Ein Stream hat einen Freigabemodus:

  • AAUDIO_SHARING_MODE_EXCLUSIVE bedeutet, dass der Stream exklusiven Zugriff auf sein Audiogerät hat. Das Gerät kann von keinem anderen Audiostream verwendet werden. Wenn das Audiogerät bereits verwendet wird, hat der Stream möglicherweise keinen exklusiven Zugriff. Exklusive Streams haben wahrscheinlich eine geringere Latenz, können aber auch mit höherer Wahrscheinlichkeit getrennt werden. Du solltest exklusive Streams schließen, sobald du sie nicht mehr benötigst, damit andere Apps auf das Gerät zugreifen können. Exklusive Streams bieten die geringstmögliche Latenz.
  • AAUDIO_SHARING_MODE_SHARED ermöglicht das Mischen von Audio über AAudio. AAudio kombiniert alle geteilten Streams, die demselben Gerät zugewiesen sind.

Du kannst den Freigabemodus auch explizit festlegen, wenn du einen Stream erstellst. Standardmäßig ist der Freigabemodus SHARED.

Audioformat

Die durch einen Stream übergebenen Daten haben die üblichen digitalen Audioattribute. Dazu gehören:

  • Beispieldatenformat
  • Kanalanzahl (Beispiele pro Frame)
  • Abtastrate

AAudio unterstützt die folgenden Beispielformate:

aaudio_format_t Datentyp C Hinweise
AAUDIOFORMAT_PCM_I16 int16_t Gängige 16-Bit-Samples, Format Q0.15
AAUDIOFORMAT_PCM_FLOAT schweben -1,0 bis +1,0
AAUDIO_FORMAT_PCM_I24_PAKET uint8_t in Dreiergruppen gepackte 24-Bit-Samples, Format Q0.23
AAUDIOFORMAT_PCM_I32 int32_t Gängige 32-Bit-Beispiele, Q0.31-Format
AAUDIOFORMAT_IEC61937 Uint8_t Komprimiertes Audio, das gemäß IEC61937 für HDMI oder S/PDIF-Passthrough verarbeitet wird

Wenn Sie ein bestimmtes Beispielformat anfordern, wird dieses Format auch wenn das Format für das Gerät nicht optimal ist. Wenn du kein Beispielformat angibst, wird von AAudio das optimale Format ausgewählt. Nach dem Öffnen des Streams müssen Sie das Beispieldatenformat abfragen und dann Daten bei Bedarf konvertieren, wie in diesem Beispiel:

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

Audiostream erstellen

Die AAudio-Bibliothek folgt einem Builder-Designmuster und bietet AAudioStreamBuilder.

  1. Erstellen Sie einen AAudioStreamBuilder:

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

  2. Legen Sie die Konfiguration des Audiostreams im Builder mithilfe der Builder-Funktionen fest, die den Streamparametern entsprechen. Folgende optionale Set-Funktionen sind verfügbar:

    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);
    

    Beachten Sie, dass diese Methoden keine Fehler wie eine nicht definierte Konstante oder einen Wert melden, der außerhalb des zulässigen Bereichs liegt.

    Wenn Sie keine „deviceId“ angeben, wird standardmäßig das primäre Ausgabegerät verwendet. Wenn Sie keine Streamrichtung angeben, ist die Standardeinstellung ein Ausgabestream. Für alle anderen Parameter können Sie explizit einen Wert festlegen oder das System Weisen Sie den optimalen Wert zu, indem Sie den Parameter überhaupt nicht angeben oder es an AAUDIO_UNSPECIFIED.

    Sicherheitshalber sollten Sie den Status des Audiostreams nach dem Erstellen überprüfen. Dies wird in Schritt 4 unten beschrieben.

  3. Wenn AAudioStreamBuilder konfiguriert ist, verwenden Sie ihn, um einen Stream zu erstellen:

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

  4. Prüfen Sie nach dem Erstellen des Streams seine Konfiguration. Wenn Sie Stichprobenformat, Abtastrate und Samples pro Frame ändern. Wenn Sie den Freigabemodus oder die Pufferkapazität angegeben haben, können diese sich ändern. von den Funktionen des Audiogeräts des Streams und der Android-Gerät, auf dem sie ausgeführt wird. Aus Gründen der guten Defensive sollten Sie die Konfiguration des Streams überprüfen, bevor Sie ihn verwenden. Es gibt Funktionen zum Abrufen der Stream-Einstellung, Builder-Einstellung:

    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. Sie können den Builder speichern und später wiederverwenden, um weitere Streams zu erstellen. Wenn Sie sie jedoch nicht mehr verwenden möchten, sollten Sie sie löschen.

    AAudioStreamBuilder_delete(builder);
    

Audiostream verwenden

Statusübergänge

Ein AAudio-Stream befindet sich normalerweise in einem von fünf stabilen Status (der Fehlerstatus "Nicht verbunden" wird am Ende dieses Abschnitts beschrieben):

  • Öffnen
  • Gestartet
  • Pausiert
  • Errötet
  • Gestoppt

Daten fließen nur durch einen Stream, wenn er sich im Status „Gestartet“ befindet. Bis Stream zwischen Zuständen verschieben, nutzen Sie eine der Funktionen, die einen Status anfordern Übergang:

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

Beachten Sie, dass Sie nur für einen Ausgabestream eine Pause oder ein Leeren anfordern können:

Diese Funktionen sind asynchron und die Statusänderung erfolgt nicht sofort. Wenn Sie eine Statusänderung anfordern, verschiebt der Stream einen der entsprechenden Übergangsstatus:

  • Wird gestartet
  • Wird pausiert
  • Spülen
  • Wird beendet
  • Closing

Das folgende Zustandsdiagramm zeigt die stabilen Zustände als abgerundete Rechtecke und die vorübergehenden Zustände als gepunktete Rechtecke. close() wird zwar nicht angezeigt, du kannst aber von jedem Bundesstaat aus anrufen

AAudio-Lebenszyklus

AAudio bietet keine Callbacks, die dich auf Statusänderungen aufmerksam machen. Ein besonderes . Mit AAudioStream_waitForStateChange(stream, inputState, nextState, timeout) kann auf eine Statusänderung gewartet werden.

Die Funktion erkennt keine Statusänderung selbst und wartet nicht auf eine Bundesstaats. Es wird gewartet, bis der aktuelle Status unterscheidet sich von der von Ihnen angegebenen inputState.

Nach einer Anfrage zum Pausieren sollte ein Stream z. B. sofort und erreichen später den Status "Pausiert". Es gibt jedoch keine Garantie dafür, dass dies der Fall ist. Da Sie nicht auf den Status „Pausiert“ warten können, verwenden Sie waitForStateChange(), um auf einen beliebigen Status zu warten. außer „Pausieren“. Das geht so:

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);

Wenn der Status des Streams nicht „Pausiert“ lautet (der inputState, von dem wir angenommen haben, aktuellen Status zum Zeitpunkt des Aufrufs), wird die Funktion sofort zurückgegeben. Andernfalls werden sie wird blockiert, bis der Status nicht mehr pausiert wird oder das Zeitlimit abläuft. Wenn der Parameter gibt der Parameter nextState den aktuellen Status der .

Sie können diese Technik auch nach dem Aufruf von „Start“, „Stopp“ oder „Flush“ unter Verwendung des entsprechenden vorübergehenden Status als „inputState“. Nicht anrufen waitForStateChange() nach dem Aufruf von AAudioStream_close() seit dem Stream wird gelöscht, sobald er geschlossen wird. Und AAudioStream_close() nicht anrufen während waitForStateChange() in einem anderen Thread ausgeführt wird.

Lesen und Schreiben in einem Audiostream

Es gibt zwei Möglichkeiten, die Daten in einem Stream zu verarbeiten, nachdem er gestartet wurde:

Für einen blockierenden Lese- oder Schreibvorgang, bei dem die angegebene Anzahl von Frames übertragen wird, legen Sie für "timeNanos" einen Wert größer als null fest. Legen Sie für einen Anruf, der nicht zu einer Blockierung führt, „timeNanos“ auf null fest. In diesem Fall ist das Ergebnis die tatsächliche Anzahl der übertragenen Frames.

Achten Sie beim Lesen der Eingabe darauf, Frames gelesen wurden. Andernfalls enthält der Zwischenspeicher möglicherweise unbekannte Daten, die eine Audiofehler. Sie können den Puffer mit Nullen auffüllen, um Lautes Dropout:

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);
}

Sie können den Zwischenspeicher des Streams vor dem Start des Streams vorbereiten, indem Sie Daten in den Zwischenspeicher schreiben oder den Zwischenspeicher verwenden. Dies muss in einem nicht blockierenden Anruf erfolgen und für das ZeitlimitNanos muss der Wert null festgelegt sein.

Die Daten im Zwischenspeicher müssen dem von AAudioStream_getDataFormat() zurückgegebenen Datenformat entsprechen.

Audiostream schließen

Wenn Sie einen Stream nicht mehr benötigen, schließen Sie ihn:

AAudioStream_close(stream);

Nachdem du einen Stream geschlossen hast, kann er nicht mehr mit einer streambasierten AAudio-Funktion verwendet werden.

Audiostream getrennt

Die Verbindung eines Audiostreams kann jederzeit getrennt werden, wenn eines der folgenden Ereignisse eintritt:

  • Das zugehörige Audiogerät ist nicht mehr verbunden, z. B. wenn Kopfhörer ausgesteckt sind.
  • Intern tritt ein Fehler auf.
  • Ein Audiogerät ist nicht mehr das primäre Audiogerät.

Wenn die Verbindung zu einem Stream getrennt wurde, hat er den Status „Nicht verbunden“. Alle Versuche, AAudioStream_write() oder andere Funktionen auszuführen, geben einen Fehler zurück. Unabhängig vom Fehlercode muss ein getrennter Stream immer beendet und geschlossen werden.

Wenn Sie einen Daten-Callback verwenden (im Gegensatz zu einer der direkten Lese-/Schreibmethoden) erhältst du keinen Rückgabe-Code, wenn die Verbindung zum Stream getrennt wird. Schreibe einen AAudioStream_errorCallback, um informiert zu werden. und registrieren sie mit AAudioStreamBuilder_setErrorCallback() sein.

Wenn Sie in einem Fehler-Callback-Thread über die Verbindung informiert werden, des Streams muss über einen anderen Thread erfolgen. Andernfalls kann es zu einem Deadlock kommen.

Hinweis: Wenn du einen neuen Stream öffnest, werden möglicherweise andere Einstellungen angezeigt. aus dem ursprünglichen Stream (z. B. "framesPerBurst"):

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.
}

Leistungsoptimierung

Sie können die Leistung einer Audioanwendung optimieren, indem Sie deren interne Zwischenspeicher anpassen und spezielle Threads mit hoher Priorität verwenden.

Zwischenspeicher abstimmen, um die Latenz zu minimieren

AAudio übergibt Daten in und aus internen Zwischenspeichern, die von AAudio verwaltet werden, einen für jedes Audiogerät.

Die Kapazität des Zwischenspeichers entspricht der Gesamtmenge der Daten, die in einem Zwischenspeicher enthalten sein können. Sie können AAudioStreamBuilder_setBufferCapacityInFrames() um die Kapazität festzulegen. Die Methode begrenzt die Kapazität, die Sie zuweisen können, auf den Maximalwert, der vom Gerät zugelassen wird. Verwenden Sie AAudioStream_getBufferCapacityInFrames() um die tatsächliche Kapazität des Zwischenspeichers zu überprüfen.

Eine Anwendung muss nicht die gesamte Kapazität eines Zwischenspeichers nutzen. AAudio füllt einen Puffer bis zu einer von Ihnen festgelegten Größe aus. Die Größe eines Zwischenspeichers darf nicht größer als seine Kapazität sein und ist häufig kleiner. Durch das Steuern der Puffergröße bestimmen Sie die Anzahl der Bursts, die zum Füllen des Speichers erforderlich sind, und steuern somit die Latenz. Verwenden Sie die Methoden AAudioStreamBuilder_setBufferSizeInFrames(). und AAudioStreamBuilder_getBufferSizeInFrames() um mit der Puffergröße zu arbeiten.

Wenn eine Anwendung Audio ausgibt, schreibt sie in einen Zwischenspeicher und wird blockiert, bis der Schreibvorgang abgeschlossen ist. AAudio liest den Zwischenspeicher in diskreten Bursts. Jede Burst enthält mehrere Audioframes und ist normalerweise kleiner als die Größe des gelesenen Zwischenspeichers. Das System steuert die Burst-Größe und -Rate. Diese Eigenschaften werden in der Regel vom Schaltkreis des Audiogeräts bestimmt. Obwohl Sie die Größe eines Bursts oder die Burst-Rate nicht ändern können, können Sie die Größe des internen Zwischenspeichers anhand der Anzahl der enthaltenen Bursts festlegen. Im Allgemeinen erhalten Sie die niedrigste Latenz, wenn die Puffergröße Ihres AAudioStream ein Vielfaches der gemeldeten Burst-Größe ist.

      AAudio-Pufferung

Eine Möglichkeit zur Optimierung der Puffergröße besteht darin, mit einem großen Puffer zu beginnen, ihn schrittweise zu senken, bis Unterläufe beginnen, und ihn dann wieder nach oben zu bewegen. Alternativ können Sie mit einer kleinen Puffergröße beginnen. Wenn dies zu Unterläufen führt, erhöhen Sie die Puffergröße, bis die Ausgabe wieder sauber verläuft.

Dieser Vorgang kann sehr schnell stattfinden, möglicherweise noch bevor der Nutzer den ersten Ton abspielt. Es empfiehlt sich, zuerst die anfängliche Größe der Pufferung unter Verwendung von Stille anzupassen, damit der Nutzer keine Audiostörungen hört. Die Systemleistung kann sich im Laufe der Zeit ändern (z. B. wenn der Nutzer den Flugmodus deaktiviert). Da die Pufferabstimmung nur wenig Aufwand verursacht, während die App Daten in einen Stream liest oder in einen Stream schreibt.

Hier ist ein Beispiel für eine Pufferoptimierungsschleife:

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);
        }
    }
}

Die Verwendung dieser Technik zur Optimierung der Puffergröße für einen Eingabestream hat keinen Vorteil. Eingabestreams werden so schnell wie möglich ausgeführt, zwischengespeicherter Daten auf ein Minimum reduzieren, bis die App vorzeitig beendet wird.

Callback mit hoher Priorität verwenden

Wenn Ihre App Audiodaten aus einem gewöhnlichen Thread liest oder schreibt, kann dieser vorzeitig beendet werden oder es kommt zu Zeitjitter. Dies kann zu Audiofehlern führen. Größere Puffer können vor solchen Störungen schützen, aber ein großer Puffer führt auch zu einer längeren Audiolatenz. Bei Anwendungen, die eine niedrige Latenz erfordern, kann ein Audiostream eine asynchrone Callback-Funktion verwenden, um Daten zu und von Ihrer App zu übertragen. AAudio führt den Callback in einem Thread mit höherer Priorität aus, der eine bessere Leistung aufweist.

Die Callback-Funktion hat diesen Prototyp:

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

Verwenden Sie die Streamerstellung, um den Callback zu registrieren:

AAudioStreamBuilder_setDataCallback(builder, myCallback, myUserData);

Im einfachsten Fall führt der Stream regelmäßig die Callback-Funktion aus, um um die Daten für den nächsten Burst zu erhalten.

Die Callback-Funktion sollte keinen Lese- oder Schreibvorgang für den Stream ausführen, aufgerufen. Wenn der Callback zu einem Eingabestream gehört, sollte Ihr Code die im audioData-Zwischenspeicher bereitgestellten Daten (angegeben als dritte -Argument). Wenn der Callback zu einem Ausgabestream gehört, sollte Ihr Code Daten in den Puffer.

Sie können beispielsweise einen Callback verwenden, um kontinuierlich eine Sinuswellenausgabe zu generieren. wie hier:

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;
}

Es ist möglich, mehr als einen Stream mit AAudio zu verarbeiten. Sie können einen Stream als Master verwenden und Verweise auf andere Streams in den Nutzerdaten übergeben. Registrieren Sie einen Callback für den Master-Stream. Verwende dann die nicht blockierende E/A für die anderen Streams. Hier ist ein Beispiel für einen Round-Trip-Callback, der einen Eingabestream an einen Ausgabestream übergibt. Der aufrufende Masterstream ist der Ausgabestream. Der Eingabestream ist in den Nutzerdaten enthalten.

Der Callback führt einen nicht blockierenden Lesevorgang aus dem Eingabestream aus, wobei die Daten im Zwischenspeicher des Ausgabestreams platziert werden:

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;
}

Beachten Sie, dass in diesem Beispiel davon ausgegangen wird, dass die Ein- und Ausgabestreams die gleiche Anzahl von Kanälen, das gleiche Format und die gleiche Abtastrate haben. Das Format der Streams kann abweichen, solange der Code die Übersetzungen korrekt verarbeitet.

Leistungsmodus festlegen

Jeder AAudioStream verfügt über einen Leistungsmodus, der großen Einfluss auf das Verhalten deiner App hat. Es gibt drei Modi:

  • AAUDIO_PERFORMANCE_MODE_NONE ist der Standardmodus. Dabei wird ein einfacher Stream verwendet, der Latenz und Energieeinsparungen ausgleicht.
  • AAUDIO_PERFORMANCE_MODE_LOW_LATENCY verwendet kleinere Zwischenspeicher und einen optimierten Datenpfad für reduzierte Latenz.
  • AAUDIO_PERFORMANCE_MODE_POWER_SAVING verwendet größere interne Zwischenspeicher und einen Datenpfad, bei dem die Latenz verringert wird, um weniger Energie zu verbrauchen.

Durch Aufrufen von setPerformanceMode() können Sie den Leistungsmodus auswählen. und ermitteln Sie den aktuellen Modus durch Aufrufen von getPerformanceMode().

Wenn eine niedrige Latenz in Ihrer Anwendung wichtiger als Energieeinsparungen ist, verwenden Sie AAUDIO_PERFORMANCE_MODE_LOW_LATENCY. Dies ist nützlich für Apps, die sehr interaktiv sind, z. B. Spiele oder Tastatur-Synthesizer.

Wenn das Einsparen von Energie in Ihrer Anwendung wichtiger ist als eine niedrige Latenz, verwenden Sie AAUDIO_PERFORMANCE_MODE_POWER_SAVING. Das ist typisch für Apps, die zuvor generierte Musik wiedergeben, z. B. Audiostreams oder MIDI-Dateiplayer.

In der aktuellen Version von AAudio musst du den AAUDIO_PERFORMANCE_MODE_LOW_LATENCY-Leistungsmodus zusammen mit einem Callback mit hoher Priorität verwenden, um die geringstmögliche Latenz zu erzielen. Orientieren Sie sich an diesem Beispiel:

// 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);

Threadsicherheit

Die AAudio API ist nicht vollständig threadsicher. Einige AAudio-Funktionen können nicht gleichzeitig von mehr als einem Thread aufgerufen werden. Das liegt daran, dass AAudio keine Mutexe verwendet, die zu einem vorzeitigen Beenden von Threads und zu Störungen führen können.

Sicherheitshalber solltest du AAudioStream_waitForStateChange() nicht aufrufen und nicht aus zwei verschiedenen Threads in denselben Stream lesen oder schreiben. Ebenso sollten Sie einen Stream in einem Thread nicht schließen, während Sie ihn in einem anderen Thread lesen oder schreiben.

Aufrufe, die Stream-Einstellungen wie AAudioStream_getSampleRate() und AAudioStream_getChannelCount() zurückgeben, sind threadsicher.

Diese Aufrufe sind auch threadsicher:

  • AAudio_convert*ToText()
  • AAudio_createStreamBuilder()
  • AAudioStream_get*() mit Ausnahme von AAudioStream_getTimestamp()

Bekannte Probleme

  • Die Audiolatenz ist hoch für die Blockierung von „write()“, da der Android O DP2-Release keinen FAST-Track verwendet. Verwenden Sie einen Callback, um die Latenz zu verringern.

Weitere Informationen

Weitere Informationen finden Sie in den folgenden Ressourcen:

API-Referenz

Codelabs

Videos