Estensioni per Android

OpenSL ES per Android estende la specifica di riferimento OpenSL ES per renderla compatibile con Android e per sfruttare la potenza e la flessibilità della piattaforma Android.

La definizione dell'API per le estensioni Android si trova in OpenSLES_Android.h e nei file di intestazione che include. Consulta OpenSLES_Android.h per i dettagli su queste estensioni. Questo file si trova nella directory principale di installazione, nella directory sysroot/usr/include/SLES. Se non diversamente indicato, tutte le interfacce sono esplicite.

Queste estensioni limitano la portabilità dell'applicazione in altre implementazioni OpenSL ES perché sono specifiche per Android. Puoi mitigare questo problema evitando di utilizzare le estensioni o utilizzando #ifdef per escluderle al momento della compilazione.

La seguente tabella mostra le interfacce e i localizzatori di dati specifici per Android supportati da Android OpenSL ES per ciascun tipo di oggetto. I valori nelle celle indicano le interfacce e i localizzatori di dati disponibili per ciascun tipo di oggetto.

Feature Lettore audio Registratore audio Motore Mix di output
Coda del buffer Android Sì: sorgente (decodifica) No No No
Configurazione di Android No No
Effetto Android No No
Funzionalità degli effetti Android No No No
Invio effetto Android No No No
Coda di buffer semplice Android Sì: origine (riproduzione) o sink (decodifica) No No
Localizzatore dati della coda di buffer Android Sì: sorgente (decodifica) No No No
Localizzatore dati descrittore di file Android Sì: origine No No No
Localizzatore Android semplice dei dati della coda di buffer Sì: origine (riproduzione) o sink (decodifica) Sì: sink No No

Interfaccia di configurazione Android

L'interfaccia di configurazione di Android consente di impostare parametri specifici della piattaforma per gli oggetti. Questa interfaccia è diversa dalle altre interfacce OpenSL ES 1.0.1 in quanto la tua app può utilizzarla prima di creare un'istanza dell'oggetto corrispondente; pertanto, puoi configurare l'oggetto prima di crearlo. Il file delle intestazioni OpenSLES_AndroidConfiguration.h, che si trova all'indirizzo /sysroot/usr/include/SLES, documenta le seguenti chiavi e valori di configurazione disponibili:

  • Tipo di stream per i lettori audio (valore predefinito: SL_ANDROID_STREAM_MEDIA).
  • Profilo di registrazione per registratori audio (valore predefinito: SL_ANDROID_RECORDING_PRESET_GENERIC).

Il seguente snippet di codice mostra un esempio di come impostare il tipo di stream audio Android su un lettore audio:

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

Puoi utilizzare un codice simile per configurare la preimpostazione per un registratore audio:

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

Interfacce di effetti Android

Le interfacce Android per le funzionalità di effetto, invio di effetti ed effetti offrono un meccanismo generico che consente a un'applicazione di eseguire query e utilizzare effetti audio specifici del dispositivo. I produttori di dispositivi devono documentare tutti gli effetti audio specifici disponibili per il dispositivo.

Le applicazioni portatili dovrebbero utilizzare le API OpenSL ES 1.0.1 per gli effetti audio anziché le estensioni per gli effetti Android.

Localizzatore dati descrittore di file Android

Il localizzatore di dati del descrittore di file Android consente di specificare l'origine di un lettore audio come descrittore di file aperto con accesso in lettura. Il formato dei dati deve essere MIME.

Questa estensione è particolarmente utile in combinazione con il gestore di asset nativo, perché l'app legge gli asset dall'APK tramite un descrittore di file.

Interfaccia e localizzazione dei dati della coda di buffer semplice Android

Nella specifica di riferimento OpenSL ES 1.0.1, le code di buffer possono essere utilizzate solo per i lettori audio e sono compatibili con PCM e altri formati di dati. Le specifiche dell'interfaccia e del localizzatore di dati della coda di buffer semplice di Android sono identiche alla specifica di riferimento, con due eccezioni:

  • Puoi utilizzare code di buffer semplici Android con registratori audio e lettori audio.
  • Con queste code puoi utilizzare solo il formato dei dati PCM.

Per la registrazione, l'app deve accodare i buffer vuoti. Quando un callback registrato invia una notifica che informa che il sistema ha terminato di scrivere dati in un buffer, l'app può leggere dal buffer.

La riproduzione funziona allo stesso modo. Per la compatibilità con i codici sorgente futuri, tuttavia, consigliamo che le applicazioni utilizzino code di buffer Android semplici anziché code di buffer OpenSL ES 1.0.1.

Comportamento della coda di buffer

L'implementazione di Android non include il requisito della specifica di riferimento secondo cui il cursore di riproduzione ritorna all'inizio del buffer attualmente in riproduzione quando la riproduzione entra nello stato SL_PLAYSTATE_STOPPED. Questa implementazione può essere conforme a tale comportamento o può lasciare invariata la posizione del cursore di riproduzione. Di conseguenza, la tua app non può presupporre che si verifichi uno dei due comportamenti. Pertanto, devi chiamare esplicitamente il metodo BufferQueue::Clear() dopo una transizione a SL_PLAYSTATE_STOPPED. In questo modo la coda del buffer viene impostata su uno stato noto.

Allo stesso modo, non esistono specifiche che regolano se l'attivatore per un callback della coda del buffer debba essere una transizione a SL_PLAYSTATE_STOPPED o un'esecuzione di BufferQueue::Clear(). Pertanto, ti consigliamo di non creare dipendenze da una parte o dall'altra; la tua app dovrebbe invece essere in grado di gestirle entrambe.

Interfacce dinamiche durante la creazione degli oggetti

Per praticità, l'implementazione Android di OpenSL ES 1.0.1 consente alla tua app di specificare interfacce dinamiche quando crea un'istanza di un oggetto. Questa è un'alternativa all'utilizzo di DynamicInterfaceManagement::AddInterface() per aggiungere queste interfacce dopo la creazione di un'istanza.

Report sulle estensioni

Esistono tre metodi per stabilire se la piattaforma supporta le estensioni Android. Questi metodi sono:

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

Ciascuno di questi metodi restituisce ANDROID_SDK_LEVEL_<API-level>, dove API-level è il livello API della piattaforma; ad esempio, ANDROID_SDK_LEVEL_23. Un livello API della piattaforma pari a 9 o superiore indica che la piattaforma supporta le estensioni.

Decodifica l'audio in PCM

Questa sezione descrive un'estensione deprecata specifica per Android a OpenSL ES 1.0.1 per la decodifica di uno stream codificato in PCM senza riproduzione immediata. La tabella seguente fornisce consigli per l'utilizzo di questa estensione e delle alternative.

Livello API Alternative
Fino a 15 anni Un codec open source con una licenza adeguata
Da 16 a 20 La classe MediaCodec o un codec open source con una licenza adeguata
Da 21 in su NDK MediaCodec nei file di intestazione <media/NdkMedia*.h>, nella classe MediaCodec o in un codec open source con una licenza adatta

Nota: al momento non esiste alcuna documentazione per la versione NDK dell'API MediaCodec. Tuttavia, puoi fare riferimento al codice campione native-codec per un esempio.

Un lettore audio standard esegue la riproduzione su un dispositivo audio, specificando il mix di output come sink di dati. L'estensione di Android differisce per il fatto che un lettore audio agisce invece da decodificatore se l'app ha specificato l'origine dati come URI o come localizzatore di dati descrittore di file Android descritto usando il formato dei dati MIME. In questo caso, il data sink è un semplice localizzatore Android di dati della coda di buffer che utilizza il formato dei dati PCM.

Questa funzionalità è pensata principalmente per consentire ai giochi di precaricare i relativi asset audio quando si passa a un nuovo livello di gioco, che è simile alla funzionalità fornita dalla classe SoundPool.

L'applicazione dovrebbe inizialmente accodare un insieme di buffer vuoti nella coda di buffer semplice di Android. Dopodiché, l'app riempie i buffer con i dati PCM. Il callback semplice della coda di buffer Android si attiva dopo che ogni buffer è stato riempito. Il gestore di callback elabora i dati PCM, accoda di nuovo il buffer ora vuoto e poi restituisce. L'applicazione è responsabile di tenere traccia dei buffer decodificati; l'elenco dei parametri di callback non include informazioni sufficienti per indicare il buffer che contiene i dati o il buffer che deve essere accodato successivamente.

L'origine dati segnala implicitamente la fine del flusso (EOS) pubblicando un evento SL_PLAYEVENT_HEADATEND alla fine del flusso. Dopo aver decodificato tutti i dati ricevuti, l'app non effettua ulteriori chiamate al callback della coda di buffer semplice di Android.

Il formato dei dati PCM del sink in genere corrisponde a quello dell'origine dati codificata per quanto riguarda frequenza di campionamento, conteggio dei canali e profondità di bit. Tuttavia, puoi decodificare con una frequenza di campionamento, un conteggio di canali o una profondità di bit diversi. Per informazioni su un provisioning per rilevare l'effettivo formato PCM, consulta Determinare il formato dei dati PCM decodificati tramite i metadati.

La funzionalità di decodifica PCM di OpenSL ES per Android supporta la messa in pausa e la ricerca iniziale; non supporta il controllo del volume, gli effetti, il loop o la velocità di riproduzione.

A seconda dell'implementazione della piattaforma, la decodifica può richiedere risorse che non possono essere lasciate inattive. Pertanto, ti consigliamo di assicurarti di fornire un numero sufficiente di buffer PCM vuoti, altrimenti il decoder non muore mai. Questo può accadere, ad esempio, se la tua app restituisce il callback semplice della coda di buffer di Android senza accodare un altro buffer vuoto. Il risultato della mancanza di decoder non è specificato, ma può includere l'eliminazione dei dati PCM decodificati, la messa in pausa del processo di decodifica o la chiusura definitiva del decoder.

Nota: per decodificare uno stream codificato in PCM ma non riprodurlo immediatamente, per le app eseguite su Android 4.x (livelli API 16-20), consigliamo di utilizzare la classe MediaCodec. Per le nuove applicazioni eseguite su Android 5.0 (livello API 21) o versioni successive, consigliamo di utilizzare l'equivalente NDK <NdkMedia*.h>. Questi file di intestazione si trovano nella directory media/ sotto la directory principale di installazione.

Decodifica di streaming da ADTS AAC a PCM

Un lettore audio funge da decodificatore di flussi di dati se l'origine dati è un localizzatore di dati di code di buffer Android che utilizza il formato dei dati MIME e il data sink è un localizzatore di dati di coda di buffer Android semplice che utilizza il formato dei dati PCM. Configura il formato dei dati MIME come segue:

  • Contenitore: SL_CONTAINERTYPE_RAW
  • Stringa di tipo MIME: SL_ANDROID_MIME_AACADTS

Questa funzionalità è pensata principalmente per le applicazioni di streaming multimediale che gestiscono l'audio AAC, ma che devono eseguire un'elaborazione audio personalizzata prima della riproduzione. La maggior parte delle applicazioni che devono decodificare l'audio in PCM dovrebbe utilizzare il metodo descritto Decodifica dell'audio in PCM, poiché è più semplice e gestisce più formati audio. La tecnica descritta qui è un approccio più specializzato, da utilizzare solo se si applicano entrambe le condizioni:

  • La sorgente audio compressa è un flusso di frame AAC contenuti nelle intestazioni ADTS.
  • L'applicazione gestisce questo flusso. I dati non si trovano all'interno di una risorsa di rete il cui identificatore è un URI o in un file locale il cui identificatore è un descrittore di file.

Inizialmente l'applicazione dovrebbe accodare un insieme di buffer riempiti nella coda del buffer Android. Ogni buffer contiene uno o più frame ADTS AAC completi. Il callback della coda del buffer Android viene attivato dopo che ogni buffer è stato svuotato. Il gestore di callback deve riempire e accodare di nuovo il buffer, quindi tornare indietro. L'applicazione non deve tenere traccia dei buffer codificati; l'elenco dei parametri di callback include informazioni sufficienti per indicare il buffer che deve essere accodato successivamente. La fine dello stream è contrassegnata esplicitamente accodando un elemento EOS. Dopo la fine del ciclo di vita, non sono più consentite accode.

Ti consigliamo di assicurarti di fornire buffer ADTS AAC completi per evitare di esaurire il decoder. Questo può accadere, ad esempio, se la tua app restituisce dal callback della coda del buffer Android senza accodare un altro buffer completo. Il risultato della mancanza di decoder è imprecisato.

Sotto tutti gli aspetti, ad eccezione dell'origine dati, il metodo di decodifica in streaming è lo stesso descritto in Decode audio to PCM (Decodifica l'audio in PCM).

Nonostante la somiglianza nei nomi, una coda di buffer Android non è uguale a una coda di buffer Android semplice. Il decoder di flussi di dati utilizza entrambi i tipi di code di buffer: una coda di buffer Android per l'origine dati ADTS AAC e una coda di buffer semplice Android per il sink di dati PCM. Per ulteriori informazioni sull'API Simple buffer Queue di Android, consulta l'articolo sull'interfaccia e sul localizzatore di dati semplici della coda di buffer di Android. Per ulteriori informazioni sull'API Android buffer Queue, consulta il file index.html nella directory docs/Additional_library_docs/openmaxal/ sotto la directory principale di installazione.

Determinare il formato dei dati PCM decodificati tramite i metadati

L'interfaccia SLMetadataExtractionItf fa parte della specifica di riferimento. Tuttavia, le chiavi dei metadati che indicano il formato effettivo dei dati PCM decodificati sono specifiche di Android. Il file di intestazione OpenSLES_AndroidMetadata.h definisce queste chiavi dei metadati. Il file di intestazione si trova nella directory principale dell'installazione, nella directory /sysroot/usr/include/SLES.

Gli indici chiave dei metadati sono disponibili subito dopo il termine dell'esecuzione del metodo Object::Realize(). Tuttavia, i valori associati sono disponibili solo dopo che l'app ha decodificato i primi dati codificati. È buona norma eseguire una query per gli indici chiave nel thread principale dopo aver chiamato il metodo Object::Realize e leggere i valori dei metadati in formato PCM nel gestore di callback della coda di buffer semplice Android quando lo chiami per la prima volta. Consulta l'esempio di codice nel pacchetto NDK per alcuni esempi di utilizzo di questa interfaccia.

I nomi delle chiavi dei metadati sono stabili, ma gli indici delle chiavi non sono documentati e sono soggetti a modifiche. Un'applicazione non deve presupporre che gli indici siano persistenti in diverse esecuzioni di esecuzione e non deve presupporre che più istanze di oggetti condividano indici nella stessa esecuzione.

Dati in virgola mobile

Un'app eseguita su Android 5.0 (livello API 21) e versioni successive può fornire dati a un AudioPlayer in formato a precisione singola e in virgola mobile.

Nel codice di esempio riportato di seguito, il metodo Engine::CreateAudioPlayer() crea un lettore audio che utilizza dati in virgola mobile:

#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;
Leggi ulteriori informazioni sull'audio con rappresentazione in virgola mobile nella pagina Campionamento audio.