Cette page explique en quoi l'implémentation du NDK OpenSL ES™ diffère de la spécification de référence d'OpenSL ES 1.0.1. Si vous utilisez l'exemple de code fourni par la spécification, vous devrez peut-être le modifier pour qu'il fonctionne sur Android.
Sauf indication contraire, toutes les fonctionnalités sont disponibles à partir d'Android 2.3 (niveau d'API 9) ou version ultérieure. Les fonctionnalités qui ne sont disponibles que pour Android 4.0 (niveau d'API 14) sont indiquées.
Remarque : Le document de définition de compatibilité Android (CDD) indique la configuration matérielle et logicielle requise pour un appareil Android compatible. Pour plus d'informations sur le programme de compatibilité global, consultez Compatibilité Android. Vous pouvez également consulter le CDD lui-même.
OpenSL ES fournit une interface en langage C également accessible en C++. Elle propose des fonctionnalités semblables aux portions audio de ces API Java Android :
Comme pour tous les kits de développement natifs (NDK) Android, l'objectif principal d'OpenSL ES pour Android est de faciliter l'implémentation de bibliothèques partagées appelées à l'aide de l'interface native Java (JNI). Ce NDK n'est pas destiné à l'écriture d'applications en C/C++ pur. Cependant, OpenSL ES est une API complète, et nous pensons qu'elle devrait vous aider à répondre à la plupart de vos besoins audio, sans avoir à faire appel à du code en cours d'exécution dans l'environnement d'exécution Android.
Remarque : Bien que basée sur OpenSL ES, l'API audio native (audio hautes performances) Android n'est pas une implémentation conforme d'un profil OpenSL ES 1.0.1 (jeu, musique, ou téléphone). En effet, Android n'implémente pas toutes les fonctionnalités requises par les profils. Tous les cas connus où Android se comporte différemment de la spécification sont décrits sur la page Extensions Android.
Fonctionnalités héritées de la spécification de référence
L'implémentation du NDK Android OpenSL ES hérite d'une grande partie des caractéristiques liées à la spécification de référence, avec certaines limitations.
Points d'entrée mondiaux
OpenSL ES pour Android est compatible avec tous les points d'entrée mondiaux de la spécification Android. Ces points d'entrée sont les suivants :
slCreateEngine
slQueryNumSupportedEngineInterfaces
slQuerySupportedEngineInterfaces
Objets et interfaces
Le tableau suivant présente les objets et les interfaces compatibles avec l'implémentation du NDK Android OpenSL ES. Si un oui apparaît dans la cellule, la fonctionnalité est disponible dans cette implémentation.
Fonctionnalité | Lecteur audio | Enregistreur audio | Moteur | Mixage de sortie |
---|---|---|---|---|
Amplification des basses | Oui | Non | Non | Oui |
File d'attente de tampon | Oui | Non | Non | Non |
Localisateur de données de la file d'attente de tampon | Oui : source | Non | Non | Non |
Gestion dynamique des interfaces | Oui | Oui | Oui | Oui |
Envoi d'effet | Oui | Non | Non | Non |
Moteur | Non | Non | Oui | Non |
Réverbération environnementale | Non | Non | Non | Oui |
Égaliseur | Oui | Non | Non | Oui |
Localisateur de données d'appareil d'E/S | Non | Oui : source | Non | Non |
Extraction des métadonnées | Oui : décodage en PCM | Non | Non | Non |
Couper le son | Oui | Non | Non | Non |
Objet | Oui | Oui | Oui | Oui |
Localisateur de mixage de sortie | Oui : récepteur | Non | Non | Non |
Lecture | Oui | Non | Non | Non |
Vitesse de lecture | Oui | Non | Non | Non |
État de préchargement | Oui | Non | Non | Non |
Réverbération prédéfinie | Non | Non | Non | Oui |
Enregistrement | Non | Oui | Non | Non |
Recherche | Oui | Non | Non | Non |
Localisateur de données URI | Oui : source | Non | Non | Non |
Virtualiseur | Oui | Non | Non | Oui |
Volume | Oui | Non | Non | Non |
La section suivante explique les limites de certaines de ces fonctionnalités.
Limites
Certaines limites s'appliquent aux fonctionnalités du tableau 1. Ces limites représentent des différences par rapport à la spécification de référence. Le reste de cette section fournit des informations sur ces différences.
Gestion dynamique des interfaces
OpenSL ES pour Android n'est pas compatible avec RemoveInterface
ni ResumeInterface
.
Combinaisons d'effets : réverbération environnementale et réverbération prédéfinie
Vous ne pouvez pas utiliser à la fois la réverbération environnementale et la réverbération prédéfinie sur le même mixage de sortie.
La plate-forme peut ignorer les demandes d'effets si elle estime que la charge du processeur serait trop élevée.
Envoi d'effet
SetSendLevel()
accepte un seul niveau d'envoi par lecteur audio.
Réverbération environnementale
La réverbération environnementale n'est pas compatible avec les champs reflectionsDelay
, reflectionsLevel
ou reverbDelay
de la structure SLEnvironmentalReverbSettings
.
Format de données MIME
Vous ne pouvez utiliser le format de données MIME qu'avec le localisateur de données URI et uniquement pour un lecteur audio. Vous ne pouvez pas utiliser ce format pour un enregistreur audio.
L'implémentation Android d'OpenSL ES nécessite l'initialisation de mimeType
sur NULL
ou une chaîne UTF-8 valide. Vous devez également initialiser containerType
sur une valeur valide.
En l'absence d'autres considérations, telles que la portabilité vers d'autres implémentations ou formats de contenu qu'une application ne peut pas identifier par son en-tête, nous vous recommandons de définir mimeType
sur NULL
et containerType
sur SL_CONTAINERTYPE_UNSPECIFIED
.
OpenSL ES pour Android accepte les formats audio suivants, à condition que la plate-forme Android les accepte également :
- WAV PCM
- WAV alaw
- WAV ulaw
- MP3 Ogg Vorbis
- AAC LC
- HE-AACv1 (AAC+)
- HE-AACv2 (AAC+ amélioré)
- AMR
- FLAC
Remarque : Pour obtenir la liste des formats audio compatibles avec Android, consultez la section Formats multimédias acceptés.
Les limites suivantes s'appliquent à la gestion de ces formats et d'autres dans cette implémentation d'OpenSL ES :
- Les formats AAC doivent se trouver dans un conteneur MP4 ou ADTS.
- OpenSL ES pour Android n'est pas compatible avec MIDI.
- WMA ne fait pas partie d'AOSP, et nous n'avons pas vérifié sa compatibilité avec OpenSL ES pour Android.
- L'implémentation du NDK Android OpenSL ES n'est pas compatible avec la lecture directe de DRM ou de contenu chiffré. Pour lire du contenu audio protégé, vous devez d'abord le déchiffrer dans votre application, laquelle doit appliquer les éventuelles restrictions DRM.
Méthodes liées aux objets
OpenSL ES pour Android n'accepte pas les méthodes suivantes pour manipuler les objets :
Resume()
RegisterCallback()
AbortAsyncOperation()
SetPriority()
GetPriority()
SetLossOfControlInterfaces()
Format de données PCM
PCM est le seul format de données que vous pouvez utiliser avec les files d'attente de tampon. Les configurations de lecture PCM compatibles présentent les caractéristiques suivantes :
- 8 bits non signé ou 16 bits signé
- Mono ou stéréo
- Ordre des octets Little Endian
- Taux d'échantillonnage de :
- 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
Les configurations compatibles avec OpenSL ES pour Android dépendent de l'appareil. Généralement, les options 16 000 Hz mono/16 bits signé sont disponibles quel que soit l'appareil.
La valeur du champ samplesPerSec
est exprimée en milliHz, malgré le nom qui prête à condition. Pour éviter d'utiliser accidentellement des valeurs incorrectes, nous vous recommandons d'initialiser ce champ à l'aide de l'une des constantes symboliques définies à cette fin, telles que SL_SAMPLINGRATE_44_1
.
Android 5.0 (niveau d'API 21) ou version ultérieure est compatible avec les données à virgule flottante.
Vitesse de lecture
La vitesse de lecture OpenSL ES indique la vitesse à laquelle un objet présente des données, exprimée en millièmes de la vitesse normale, ou pour mille. Par exemple, une vitesse de lecture de 1 000 pour mille correspond à 1 000/1 000 ou à la vitesse normale. Une plage de fréquences est un intervalle fermé qui exprime une plage de vitesses de lecture possibles.
La compatibilité des plages de vitesses de lecture et d'autres capacités peut varier selon la version de la plate-forme et son implémentation. Votre application peut déterminer ces capacités au moment de l'exécution en utilisant PlaybackRate::GetRateRange()
ou PlaybackRate::GetCapabilitiesOfRate()
pour interroger l'appareil.
Un appareil accepte généralement la même plage de vitesses pour une source de données au format PCM, et une plage de vitesses unitaires de 1 000 pour mille à 1 000 pour mille pour les autres formats. Autrement dit, la plage de vitesses unitaires est en réalité une valeur unique.
Enregistrement
OpenSL ES pour Android n'est pas compatible avec les événements SL_RECORDEVENT_HEADATLIMIT
ou SL_RECORDEVENT_HEADMOVING
.
Recherche
La méthode SetLoop()
active la lecture en boucle de tout le fichier. Pour activer la lecture en boucle, définissez le paramètre startPos
sur 0 et le paramètre endPos
sur SL_TIME_UNKNOWN
.
Localisateur de données de la file d'attente de tampon
Un lecteur ou enregistreur audio avec un localisateur de données pour une file d'attente de tampon n'est compatible qu'avec le format de données PCM.
Localisateur de données d'appareil d'E/S
OpenSL ES pour Android ne permet d'utiliser un localisateur de données d'appareil d'E/S que si vous avez spécifié le localisateur comme source de données pour Engine::CreateAudioRecorder()
.
Initialisez le localisateur de données d'appareil à l'aide des valeurs indiquées dans l'extrait de code suivant :
SLDataLocator_IODevice loc_dev = {SL_DATALOCATOR_IODEVICE, SL_IODEVICE_AUDIOINPUT, SL_DEFAULTDEVICEID_AUDIOINPUT, NULL};
Localisateur de données URI
OpenSL ES pour Android ne peut utiliser le localisateur de données URI qu'avec le format de données MIME, et uniquement pour un lecteur audio. Vous ne pouvez pas utiliser un localisateur de données URI pour un enregistreur audio. L'URI ne peut utiliser que les schémas http:
et file:
. Les autres schémas, tels que https:
, ftp:
ou content:
, ne sont pas autorisés.
Nous n'avons pas validé la compatibilité de rtsp:
avec le son sur la plate-forme Android.
Structures de données
Android est compatible avec les structures de données OpenSL ES 1.0.1 suivantes :
SLDataFormat_MIME
SLDataFormat_PCM
SLDataLocator_BufferQueue
SLDataLocator_IODevice
SLDataLocator_OutputMix
SLDataLocator_URI
SLDataSink
SLDataSource
SLEngineOption
SLEnvironmentalReverbSettings
SLInterfaceID
Configuration de la plate-forme
L'API OpenSL ES pour Android est conçue pour les applications multithread et est thread-safe. Elle accepte un seul moteur par application et jusqu'à 32 objets par moteur. La mémoire d'appareil et le processeur disponibles peuvent restreindre davantage le nombre d'objets utilisables.
Ces options de moteur sont reconnues, mais sont ignorées par slCreateEngine
:
SL_ENGINEOPTION_THREADSAFE
SL_ENGINEOPTION_LOSSOFCONTROL
OpenMAX AL et OpenSL ES peuvent être utilisés ensemble dans la même application. Dans ce cas, il n'existe qu'un seul objet de moteur partagé en interne, et la limite de 32 objets est partagée entre OpenMAX AL et OpenSL ES. L'application doit créer les deux moteurs, les utiliser tous les deux, puis les détruire. L'implémentation conserve un nombre de référence sur le moteur partagé afin que la destruction ait lieu de manière appropriée lors de la deuxième opération de destruction.
Notes de programmation
Les notes de programmation OpenSL ES fournissent des informations supplémentaires pour garantir une implémentation correcte d'OpenSL ES.
Remarque : Pour vous aider, nous avons inclus une copie de la spécification OpenSL ES 1.0.1 avec le NDK dans docs/opensles/OpenSL_ES_Specification_1.0.1.pdf
.
Problèmes de plate-forme
Cette section décrit les problèmes connus dans la version initiale de la plate-forme qui accepte ces API.
Gestion dynamique des interfaces
DynamicInterfaceManagement::AddInterface
ne fonctionne pas. Spécifiez plutôt l'interface dans le tableau transmis à Create()
, comme indiqué dans l'exemple de code pour la réverbération environnementale.
Planifier les futures versions d'OpenSL ES
Les API audio hautes performances d'Android sont basées sur la version OpenSL ES 1.0.1 de Khronos Group. Khronos a publié une version révisée 1.1 du standard. La version révisée comprend de nouvelles fonctionnalités, des précisions, des corrections d'erreurs typographiques et quelques incompatibilités. La plupart des incompatibilités attendues sont relativement mineures ou concernent des aspects d'OpenSL ES qui ne sont pas compatibles avec Android.
Une application développée avec cette version devrait fonctionner sur les futures versions de la plate-forme Android, à condition de suivre les consignes décrites dans la section Planifier la compatibilité binaire ci-dessous.
Remarque : La compatibilité des sources futures n'est pas un objectif en soi. Autrement dit, si vous passez à une version plus récente du NDK, vous devrez peut-être modifier le code source de votre application pour qu'il soit conforme à la nouvelle API. Nous pensons que la plupart de ces modifications seront mineures. Consultez les détails ci-dessous.
Planifier la compatibilité binaire
Nous recommandons à votre application de suivre ces consignes pour améliorer la compatibilité binaire future :
- Utilisez uniquement le sous-ensemble de fonctionnalités Android compatibles d'OpenSL ES 1.0.1.
- Ne vous basez pas sur un code de résultat particulier pour une opération ayant échoué. Soyez prêt à gérer un autre code de résultat.
- Les gestionnaires de rappel d'applications s'exécutent généralement dans un contexte limité. Ils doivent être écrits pour effectuer leurs tâches rapidement, puis revenir le plus rapidement possible. N'exécutez pas d'opérations complexes dans un gestionnaire de rappel. Par exemple, dans un rappel de fin de file d'attente de tampon, vous pouvez mettre en file d'attente un autre tampon, mais ne créez pas de lecteur audio.
- Les gestionnaires de rappel doivent être préparés pour être appelés plus ou moins fréquemment, pour recevoir des types d'événements supplémentaires, et ils doivent ignorer les types d'événements qu'ils ne reconnaissent pas. Les rappels configurés avec un masque d'événement composé de types d'événements activés doivent être préparés pour être appelés avec plusieurs bits de type d'événement définis simultanément. Utilisez "&" pour tester chaque bit d'événement plutôt qu'un cas de contacteur.
- Utilisez l'état de préchargement et les rappels comme indications générales de la progression, mais ne dépendez pas des niveaux de remplissage ni des séquences de rappel codés en dur. La signification du niveau de remplissage de l'état de préchargement et le comportement en cas d'erreurs détectées lors du préchargement peuvent changer.
Remarque : Consultez la section Comportement de la file d'attente de tampon ci-dessous pour en savoir plus.
Planifier la compatibilité des sources
Comme indiqué précédemment, des incompatibilités de code source sont attendues dans la prochaine version d'OpenSL ES de Khronos Group. Voici les éléments susceptibles d'être concernés par des modifications :
- L'interface de la file d'attente de tampon devrait avoir des modifications importantes, notamment dans les zones de
BufferQueue::Enqueue
, de la liste des paramètres deslBufferQueueCallback
et du nom du champSLBufferQueueState.playIndex
. Nous vous recommandons d'utiliser plutôt les files d'attente de tampon simples Android. Dans l'exemple de code fourni avec le NDK, nous avons utilisé des files d'attente de tampon simples Android pour la lecture pour cette raison. Notez que nous utilisons également une file d'attente de tampon simple Android pour l'enregistrement et le décodage vers PCM, mais cela est dû au fait que la version OpenSL ES 1.0.1 standard n'est pas compatible avec l'enregistrement ni le décodage dans le récepteur de données d'une file d'attente de tampon. const
sera ajouté aux paramètres d'entrée transmis par référence et aux champs de structureSLchar *
utilisés comme valeurs d'entrée. Cela ne devrait pas nécessiter de modification du code.- Certains types de paramètres actuellement non signés seront remplacés par des types signés.
Vous devrez peut-être remplacer le type de paramètre
SLint32
parSLuint32
ou par un type de paramètre similaire, ou ajouter une conversion. Equalizer::GetPresetName
copie la chaîne dans la mémoire de l'application au lieu de renvoyer un pointeur vers la mémoire d'implémentation. Il s'agit d'un changement significatif. Nous vous recommandons donc d'éviter d'appeler cette méthode. Dans le cas contraire, isolez votre utilisation.- Il existe des champs supplémentaires dans les types de structure. Pour les paramètres de sortie, ces nouveaux champs peuvent être ignorés, mais pour les paramètres d'entrée, les nouveaux champs devront être initialisés. Heureusement, tous ces champs devraient se trouver dans des zones non compatibles avec Android.
- Les GUID de l'interface seront modifiés. Pour éviter toute dépendance, reportez-vous aux interfaces en fonction de leur nom symbolique plutôt que qu'en fonction du GUID.
SLchar
passera deunsigned char
àchar
. Cela concerne principalement le localisateur de données d'URI et le format de données MIME.SLDataFormat_MIME.mimeType
sera renommépMimeType
, etSLDataLocator_URI.URI
sera renommépURI
. Nous vous recommandons d'initialiser les structures de donnéesSLDataFormat_MIME
etSLDataLocator_URI
à l'aide d'une liste de valeurs séparées par des virgules et des accolades, plutôt que par le nom de champ, afin d'isoler votre code de cette modification. Cette technique est utilisée dans l'exemple de code.SL_DATAFORMAT_PCM
n'autorise pas l'application à spécifier la représentation des données sous forme d'entier signé, d'entier non signé ou de virgule flottante. L'implémentation Android suppose que les données 8 bits sont des entiers non signés et que les données 16 bits sont des entiers signés. De plus, le champsamplesPerSec
prête à confusion, car les unités réelles sont en milliHz. Ces problèmes devraient être résolus dans la prochaine version d'OpenSL ES, qui inclura un nouveau format de données PCM étendues permettant à l'application de spécifier explicitement la représentation et de corriger le nom du champ. Comme il s'agit d'un nouveau format de données et que le format de données PCM actuel sera toujours disponible (bien qu'obsolète), aucune modification immédiate de votre code ne devrait être nécessaire.