AAudio ist eine neue Android-C-API, die mit Android O eingeführt wurde. Er wurde für leistungsstarke Audioanwendungen entwickelt, die eine geringe Latenz erfordern. Apps kommunizieren mit AAudio, indem sie Daten in Streams lesen und schreiben.
Die AAudio API ist von Natur aus minimalistisch und führt keine der folgenden Funktionen aus:
- Aufzählung von Audiogeräten
- Automatisches Routing zwischen Audioendpunkten
- Datei-E/A
- Dekodierung komprimierter Audiodaten
- Automatische Darstellung aller Eingaben/Streams in einem einzigen Rückruf.
Erste Schritte
Sie können AAudio aus C++-Code aufrufen. Wenn Sie Ihrer App die AAudio-Funktionen hinzufügen möchten, schließen Sie die Kopfzeilendatei „AAudio.h“ ein:
#include <aaudio/AAudio.h>
Audiostreams
AAudio überträgt Audiodaten zwischen Ihrer App und den Audioinputs und ‑outputs auf Ihrem Android-Gerät. Ihre App gibt Daten ein und aus, indem sie aus Audiostreams liest und in diese schreibt. Diese werden durch die Struktur „AAudioStream“ dargestellt. Die Lese-/Schreibaufrufe können blockierend oder nicht blockierend sein.
Ein Stream wird durch Folgendes definiert:
- Das Audiogerät, das die Quelle oder das Ziel für die Daten im Stream ist.
- Der Freigabemodus, der festlegt, ob ein Stream exklusiven Zugriff auf ein Audiogerät hat, das andernfalls von mehreren Streams gemeinsam genutzt werden könnte.
- Das Format der Audiodaten im Stream.
Audiogerät
Jeder Stream ist einem einzelnen Audiogerät zugeordnet.
Ein Audiogerät ist eine Hardwareschnittstelle oder ein virtueller Endpunkt, der als Quelle oder Senke für einen kontinuierlichen Stream digitaler Audiodaten dient. Verwechseln Sie ein Audiogerät (ein integriertes Mikrofon oder Bluetooth-Headset) nicht mit dem Android-Gerät (Smartphone oder Smartwatch), auf dem Ihre App ausgeführt wird.
Mit der AudioManager
-Methode getDevices()
kannst du die Audiogeräte finden, die auf deinem Android-Gerät verfügbar sind. Die Methode gibt Informationen zum type
jedes Geräts zurück.
Jedes Audiogerät hat eine eindeutige ID auf dem Android-Gerät. Sie können die ID verwenden, um einen Audiostream an ein bestimmtes Audiogerät zu binden. In den meisten Fällen können Sie jedoch AAudio das Standardprimärgerät auswählen lassen, anstatt es selbst anzugeben.
Das an einen Stream angeschlossene Audiogerät bestimmt, ob der Stream für die Eingabe oder Ausgabe bestimmt ist. Ein Stream kann Daten nur in eine Richtung übertragen. 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 das Audiogerät hat. Das Gerät kann von keinem anderen Audiostream verwendet werden. Wenn das Audiogerät bereits verwendet wird, kann der Stream möglicherweise keinen exklusiven Zugriff erhalten. Bei exklusiven Streams ist die Latenz wahrscheinlich niedriger, aber die Verbindung wird auch häufiger getrennt. Schließen Sie exklusive Streams, sobald Sie sie nicht mehr benötigen, damit andere Apps auf das Gerät zugreifen können. Exklusive Streams bieten die niedrigste mögliche Latenz.- Mit
AAUDIO_SHARING_MODE_SHARED
kann AAudio Audio mischen. AAudio mischt alle freigegebenen Streams, die demselben Gerät zugewiesen sind.
Sie können den Freigabemodus beim Erstellen eines Streams explizit festlegen. Standardmäßig ist der Freigabemodus SHARED
.
Audioformat
Die Daten, die über einen Stream übergeben werden, haben die üblichen digitalen Audioattribute. Das sind:
- Beispiel für ein Datenformat
- Kanalanzahl (Stichproben pro Frame)
- Abtastrate
AAudio unterstützt die folgenden Sample-Formate:
aaudio_format_t | C-Datentyp | Hinweise |
---|---|---|
AAUDIO_FORMAT_PCM_I16 | int16_t | gängige 16-Bit-Samples, Q0.15-Format |
AAUDIO_FORMAT_PCM_FLOAT | float | −1,0 bis +1,0 |
AAUDIO_FORMAT_PCM_I24_PACKED | uint8_t in Gruppen von 3 | komprimierte 24-Bit-Samples, Q0.23-Format |
AAUDIO_FORMAT_PCM_I32 | int32_t | Gängige 32-Bit-Samples, Q0.31-Format |
AAUDIO_FORMAT_IEC61937 | uint8_t | Komprimiertes Audio, das in IEC61937 für HDMI- oder S/PDIF-Passthrough verpackt ist |
Wenn du ein bestimmtes Sample-Format anforderst, wird dieses Format für den Stream verwendet, auch wenn es nicht optimal für das Gerät ist. Wenn Sie kein Sample-Format angeben, wählt AAudio ein optimales Format aus. Nachdem der Stream geöffnet wurde, müssen Sie das Beispieldatenformat abfragen und die 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.
- AAudioStreamBuilder erstellen:
AAudioStreamBuilder *builder; aaudio_result_t result = AAudio_createStreamBuilder(&builder);
- Lege die Audiostreamkonfiguration im Builder mithilfe der Builderfunktionen fest, die den Streamparametern entsprechen. Die folgenden optionalen 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 melden, z. B. eine nicht definierte Konstante oder einen Wert außerhalb des zulässigen Bereichs.
Wenn Sie die deviceId nicht angeben, wird standardmäßig das primäre Ausgabegerät verwendet. Wenn Sie die Streamrichtung nicht angeben, ist standardmäßig ein Ausgabestream festgelegt. Für alle anderen Parameter können Sie einen Wert explizit festlegen oder das System den optimalen Wert zuweisen lassen, indem Sie den Parameter gar nicht angeben oder auf
AAUDIO_UNSPECIFIED
setzen.Prüfen Sie zur Sicherheit nach dem Erstellen den Status des Audiostreams, wie in Schritt 4 unten beschrieben.
- Wenn der AAudioStreamBuilder konfiguriert ist, können Sie damit einen Stream erstellen:
AAudioStream *stream; result = AAudioStreamBuilder_openStream(builder, &stream);
- Prüfen Sie nach dem Erstellen des Streams die Konfiguration. Wenn Sie ein Sample-Format, eine Sample-Rate oder Samples pro Frame angegeben haben, werden diese nicht geändert. Wenn Sie den Freigabemodus oder die Pufferkapazität angegeben haben, können diese sich je nach den Funktionen des Audiogeräts des Streams und des Android-Geräts, auf dem er ausgeführt wird, ändern. Aus Sicherheitsgründen sollten Sie die Konfiguration des Streams prüfen, bevor Sie ihn verwenden. Es gibt Funktionen, mit denen die Streameinstellung abgerufen werden kann, die der jeweiligen Builder-Einstellung entspricht:
- Du kannst den Builder speichern und in Zukunft wiederverwenden, um weitere Streams zu erstellen. Wenn Sie es jedoch nicht mehr verwenden möchten, sollten Sie es löschen.
AAudioStreamBuilder_delete(builder);
Audiostream verwenden
Statusübergänge
Ein AAudio-Stream befindet sich normalerweise in einem der fünf stabilen Status. Der Fehlerstatus „Disconnected“ (Nicht verbunden) wird am Ende dieses Abschnitts beschrieben:
- Öffnen
- Gestartet
- Pausiert
- Errötet
- Gestoppt
Daten fließen nur durch einen Stream, wenn er den Status „Gestartet“ hat. Wenn Sie einen Stream zwischen Status wechseln möchten, verwenden Sie eine der Funktionen, die einen Statusübergang anfordern:
aaudio_result_t result;
result = AAudioStream_requestStart(stream);
result = AAudioStream_requestStop(stream);
result = AAudioStream_requestPause(stream);
result = AAudioStream_requestFlush(stream);
Du kannst die Pausierung oder das Leeren nur für einen Ausgabestream anfordern:
Diese Funktionen sind asynchron und die Statusänderung erfolgt nicht sofort. Wenn Sie einen Statuswechsel anfordern, wechselt der Stream in einen der entsprechenden inaktiven Status:
- Wird gestartet
- Pausieren
- Spülen
- Wird beendet
- Closing
Im folgenden Zustandsdiagramm sind die stabilen Zustände als abgerundete Rechtecke und die vorübergehenden Zustände als gepunktete Rechtecke dargestellt.
Auch wenn es nicht angezeigt wird, können Sie close()
von jedem US-Bundesstaat aus anrufen.
AAudio bietet keine Rückrufe, um Sie über Statusänderungen zu informieren. Mit der speziellen Funktion AAudioStream_waitForStateChange(stream, inputState, nextState, timeout)
können Sie auf eine Statusänderung warten.
Die Funktion erkennt keine Statusänderung von selbst und wartet nicht auf einen bestimmten Status. Es wird gewartet, bis der aktuelle Status von inputState
abweicht.
Nach dem Pausieren sollte ein Stream beispielsweise sofort den Status „Pausiert“ erreichen. Es gibt jedoch keine Garantie dafür.
Da Sie nicht auf den Status „Pausiert“ warten können, verwenden Sie waitForStateChange()
, um auf einen anderen Status als „Pausiert“ zu warten. So gehts:
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 „Pausieren“ (inputState
, der angenommene aktuelle Status zum Zeitpunkt des Aufrufs) ist, wird die Funktion sofort zurückgegeben. Andernfalls wird der Vorgang blockiert, bis der Status nicht mehr „Pausiert“ ist oder die Zeitüberschreitung abgelaufen ist. Wenn die Funktion zurückgegeben wird, zeigt der Parameter nextState
den aktuellen Status des Streams an.
Du kannst diese Methode auch nach dem Aufrufen von „request start“, „stop“ oder „flush“ verwenden und dabei den entsprechenden sitzungsspezifischen Status als „inputState“ verwenden. Rufe waitForStateChange()
nicht nach AAudioStream_close()
auf, da der Stream gelöscht wird, sobald er geschlossen wird. Außerdem darf AAudioStream_close()
nicht aufgerufen werden, während waitForStateChange()
in einem anderen Thread ausgeführt wird.
Lesen und Schreiben in einen Audiostream
Es gibt zwei Möglichkeiten, die Daten in einem Stream nach dem Start zu verarbeiten:
- Verwenden Sie einen Callback mit hoher Priorität.
- Verwenden Sie die Funktionen
AAudioStream_read(stream, buffer, numFrames, timeoutNanos)
undAAudioStream_write(stream, buffer, numFrames, timeoutNanos)
. um den Stream zu lesen oder zu schreiben.
Legen Sie für ein blockierendes Lesen oder Schreiben, bei dem die angegebene Anzahl von Frames übertragen wird, einen Wert für „timeoutNanos“ fest, der größer als null ist. Für einen nicht blockierenden Aufruf muss timeoutNanos auf null gesetzt werden. In diesem Fall ist das Ergebnis die tatsächlich übertragene Anzahl von Frames.
Wenn Sie Eingaben lesen, sollten Sie prüfen, ob die richtige Anzahl von Frames gelesen wurde. Andernfalls enthält der Puffer möglicherweise unbekannte Daten, die zu Audiostörungen führen können. Du kannst den Puffer mit Nullen auffüllen, um einen stummen Aussetzer zu erstellen:
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);
}
Du kannst den Puffer des Streams vor dem Starten des Streams mit Daten oder Stille füllen. Dies muss in einem nicht blockierenden Aufruf erfolgen, bei dem „timeoutNanos“ auf null gesetzt ist.
Die Daten im Puffer müssen mit dem Datenformat übereinstimmen, das von AAudioStream_getDataFormat()
zurückgegeben wird.
Audiostream schließen
Wenn Sie einen Stream nicht mehr verwenden, schließen Sie ihn:
AAudioStream_close(stream);
Nachdem Sie einen Stream geschlossen haben, können Sie den Stream-Zeiger nicht mehr mit einer streambasierten AAudio-Funktion verwenden.
Das Schließen eines Streams ist nicht threadsicher. Versuche NICHT, einen Stream in einem Thread zu schließen, während du ihn in einem anderen Thread verwendest. Wenn Sie mehrere Threads verwenden, müssen diese sorgfältig synchronisiert werden. Sie können den gesamten Code zur Streamverwaltung in einem einzigen Thread platzieren und ihm dann Befehle über eine atomare Warteschlange senden.
Unterbrochener Audiostream
Die Verbindung zu einem Audiostream kann jederzeit getrennt werden, wenn eines der folgenden Ereignisse eintritt:
- Das zugehörige Audiogerät ist nicht mehr verbunden (z. B. wenn Kopfhörer nicht angeschlossen sind).
- Ein interner Fehler ist aufgetreten.
- Ein Audiogerät ist nicht mehr das primäre Audiogerät.
Wenn die Verbindung zu einem Stream getrennt ist, hat er den Status „Disconnected“ (Getrennt). Alle Versuche, AAudioStream_write() oder andere Funktionen auszuführen, schlagen fehl. Sie müssen einen getrennten Stream unabhängig vom Fehlercode immer beenden und schließen.
Wenn Sie einen Daten-Callback verwenden (im Gegensatz zu einer der direkten Lese-/Schreibmethoden), erhalten Sie keinen Rückgabecode, wenn die Verbindung zum Stream getrennt wird. Wenn Sie benachrichtigt werden möchten, wenn dies der Fall ist, schreiben Sie eine Funktion vom Typ AAudioStream_errorCallback und registrieren Sie sie mit AAudioStreamBuilder_setErrorCallback().
Wenn du über einen Fehler-Callback-Thread über die Unterbrechung informiert wirst, muss der Stream in einem anderen Thread angehalten und geschlossen werden. Andernfalls kann es zu einer Deadlock-Situation kommen.
Wenn du einen neuen Stream öffnest, hat dieser möglicherweise andere Einstellungen als der ursprüngliche 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.
}
Leistung optimieren
Sie können die Leistung einer Audioanwendung optimieren, indem Sie die internen Puffer anpassen und spezielle Threads mit hoher Priorität verwenden.
Puffer optimieren, um die Latenz zu minimieren
AAudio gibt Daten in interne Puffer ein und aus, die von ihm verwaltet werden, jeweils einen für jedes Audiogerät.
Die Kapazität des Puffers ist die Gesamtmenge an Daten, die ein Puffer aufnehmen kann. Sie können AAudioStreamBuilder_setBufferCapacityInFrames()
aufrufen, um die Kapazität festzulegen. Die Methode begrenzt die Kapazität, die Sie zuweisen können, auf den maximal zulässigen Wert des Geräts. Verwenden Sie AAudioStream_getBufferCapacityInFrames()
, um die tatsächliche Kapazität des Buffers zu prüfen.
Eine App muss nicht die gesamte Kapazität eines Buffers nutzen. AAudio füllt einen Puffer bis zu einer Größe, die Sie festlegen können. Die Größe eines Puffers darf nicht größer als seine Kapazität sein und ist oft kleiner. Mit der Puffergröße legen Sie die Anzahl der Bursts fest, die zum Füllen des Puffers erforderlich sind, und steuern so die Latenz. Verwenden Sie die Methoden AAudioStreamBuilder_setBufferSizeInFrames()
und AAudioStreamBuilder_getBufferSizeInFrames()
, um mit der Puffergröße zu arbeiten.
Wenn eine Anwendung Audio wiedergibt, wird sie in einen Puffer geschrieben und blockiert, bis der Schreibvorgang abgeschlossen ist. AAudio liest in diskreten Bursts aus dem Puffer. Jeder Burst enthält mehrere Audioframes und ist in der Regel kleiner als die Größe des zu lesenden Buffers. Das System steuert die Burst-Größe und -Rate. Diese Eigenschaften werden in der Regel von der Schaltung des Audiogeräts bestimmt. Sie können zwar weder die Größe eines Bursts noch die Burstrate ändern, aber die Größe des internen Puffers entsprechend der Anzahl der enthaltenen Bursts festlegen. Im Allgemeinen ist die Latenz am niedrigsten, wenn die Puffergröße Ihres AAudioStreams ein Vielfaches der gemeldeten Burst-Größe ist.
Eine Möglichkeit, die Puffergröße zu optimieren, besteht darin, mit einem großen Puffer zu beginnen und ihn nach und nach zu verkleinern, bis Unterbrechungen auftreten, und ihn dann wieder zu erhöhen. Alternativ können Sie mit einer kleinen Puffergröße beginnen und die Puffergröße erhöhen, wenn es zu Unterbrechungen kommt, bis die Ausgabe wieder reibungslos funktioniert.
Dieser Vorgang kann sehr schnell erfolgen, möglicherweise noch bevor der Nutzer den ersten Ton abspielt. Du solltest die anfängliche Puffergröße zuerst mit Stille ausführen, 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 Pufferoptimierung nur sehr wenig Overhead verursacht, kann Ihre App sie kontinuierlich ausführen, während sie Daten in einen Stream liest oder schreibt.
Hier ein Beispiel für eine Schleife zur Pufferoptimierung:
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 Methode zur Optimierung der Puffergröße für einen Eingabestream bietet keinen Vorteil. Eingabestreams werden so schnell wie möglich ausgeführt, um die Menge der zwischengespeicherten Daten auf ein Minimum zu beschränken. Sie werden dann aufgefüllt, wenn die App unterbrochen wird.
Callback mit hoher Priorität verwenden
Wenn Ihre App Audiodaten aus einem gewöhnlichen Thread liest oder schreibt, kann es zu Vorwegnahme oder Zeitjitter kommen. Das kann zu Audiostörungen führen. Größere Puffer können zwar vor solchen Störungen schützen, aber ein großer Puffer führt auch zu einer längeren Audiolatenz. Bei Anwendungen mit niedriger Latenz kann ein Audiostream eine asynchrone Rückruffunktion verwenden, um Daten von und zu Ihrer App zu übertragen. AAudio führt den Rückruf in einem Thread mit höherer Priorität aus, der eine bessere Leistung hat.
Die Callback-Funktion hat diesen Prototyp:
typedef aaudio_data_callback_result_t (*AAudioStream_dataCallback)(
AAudioStream *stream,
void *userData,
void *audioData,
int32_t numFrames);
Registriere den Callback über die Stream-Erstellung:
AAudioStreamBuilder_setDataCallback(builder, myCallback, myUserData);
Im einfachsten Fall führt der Stream die Rückruffunktion regelmäßig aus, um die Daten für den nächsten Burst abzurufen.
Die Callback-Funktion darf keine Lese- oder Schreibvorgänge auf dem Stream ausführen, der sie aufgerufen hat. Wenn der Rückruf zu einem Eingabestream gehört, sollte Ihr Code die Daten verarbeiten, die im AudioData-Puffer (als drittes Argument angegeben) bereitgestellt werden. Wenn der Rückruf zu einem Ausgabestream gehört, sollte Ihr Code Daten in den Puffer legen.
So könnten Sie beispielsweise einen Rückruf verwenden, um kontinuierlich eine Sinuswellenausgabe zu generieren:
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;
}
Mit AAudio ist es möglich, mehrere Streams zu verarbeiten. Sie können einen Stream als Master verwenden und Verweise auf andere Streams in den Nutzerdaten übergeben. Registriere einen Callback für den Masterstream. Verwenden Sie 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 weitergibt. Der Master-Aufrufstream ist der Ausgabestream. Der Eingabestream ist in den Nutzerdaten enthalten.
Der Rückruf führt ein nicht blockierendes Lesen aus dem Eingabestream durch und legt die Daten in den Puffer des Ausgabestreams ab:
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;
}
In diesem Beispiel wird davon ausgegangen, dass die Eingabe- und Ausgabestreams dieselbe Anzahl von Kanälen, dasselbe Format und dieselbe Abtastrate haben. Das Format der Streams kann nicht übereinstimmen, solange der Code die Übersetzungen richtig verarbeitet.
Leistungsmodus festlegen
Jeder AAudioStream hat einen Leistungsmodus, der sich stark auf das Verhalten Ihrer App auswirkt. Es gibt drei Modi:
AAUDIO_PERFORMANCE_MODE_NONE
ist der Standardmodus. Dabei wird ein Basisstream verwendet, der Latenz und Energieeinsparungen in Einklang bringt.AAUDIO_PERFORMANCE_MODE_LOW_LATENCY
verwendet kleinere Puffer und einen optimierten Datenpfad, um die Latenz zu verringern.AAUDIO_PERFORMANCE_MODE_POWER_SAVING
verwendet größere interne Puffer und einen Datenpfad, bei dem die Latenz gegen eine geringere Leistung getauscht wird.
Sie können den Leistungsmodus durch Aufrufen von setPerformanceMode() auswählen und den aktuellen Modus durch Aufrufen von getPerformanceMode() ermitteln.
Wenn eine geringe Latenz in Ihrer Anwendung wichtiger ist als Energieeinsparungen, verwenden Sie AAUDIO_PERFORMANCE_MODE_LOW_LATENCY
.
Das ist nützlich für Apps, die sehr interaktiv sind, z. B. Spiele oder Tastatursynthesizer.
Wenn in Ihrer Anwendung der Energiesparmodus wichtiger ist als eine niedrige Latenz, verwenden Sie AAUDIO_PERFORMANCE_MODE_POWER_SAVING
.
Dies ist typisch für Apps, die zuvor generierte Musik abspielen, z. B. Streaming-Audio oder MIDI-Dateiplayer.
In der aktuellen Version von AAudio müssen Sie den AAUDIO_PERFORMANCE_MODE_LOW_LATENCY
-Leistungsmodus zusammen mit einem Rückruf mit hoher Priorität verwenden, um die niedrigstmögliche Latenz zu erreichen. 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 der AAudio-Funktionen können nicht gleichzeitig von mehreren Threads aufgerufen werden. Das liegt daran, dass AAudio die Verwendung von Mutexes vermeidet, die zu Thread-Vorbevorkündungen und Störungen führen können.
Rufen Sie AAudioStream_waitForStateChange()
nicht auf und lesen oder schreiben Sie nicht in denselben Stream aus zwei verschiedenen Threads. Schließen Sie einen Stream in einem Thread auch nicht, während Sie in einem anderen Thread darauf lesen oder schreiben.
Aufrufe, die Streameinstellungen wie AAudioStream_getSampleRate()
und AAudioStream_getChannelCount()
zurückgeben, sind threadsicher.
Diese Aufrufe sind ebenfalls threadsicher:
AAudio_convert*ToText()
AAudio_createStreamBuilder()
AAudioStream_get*()
außerAAudioStream_getTimestamp()
Bekannte Probleme
- Die Audiolatenz ist bei blockierendem write() hoch, da in der Android O-DP2-Version kein FAST-Track verwendet wird. Verwenden Sie einen Callback, um die Latenz zu verringern.
Weitere Informationen
Weitere Informationen finden Sie in den folgenden Ressourcen: