Esta página fornece detalhes sobre como a implementação do OpenSL ES™ do NDK difere da especificação de referência do OpenSL ES 1.0.1. Se você usar amostras de código da especificação, poderá ser necessário modificá-las para que funcionem no Android.
A menos que indicado de outra forma, todos os recursos estão disponíveis no Android 2.3 (nível de API 9) e versões mais recentes. Alguns recursos só estão disponíveis para Android 4.0 (API de nível 14) — esses estão especificados.
Observação: o Documento de definição de compatibilidade (CDD) do Android enumera os requisitos de hardware e software de um dispositivo Android compatível. Consulte Compatibilidade do Android para saber mais sobre o programa de compatibilidade geral e CDD para informações sobre o documento correspondente.
O OpenSL ES fornece uma interface de linguagem C que também pode ser acessada usando C++. Ele apresenta recursos semelhantes às partes de áudio destas APIs Java para Android:
Assim como com o Android Native Development Kit (NDK), o objetivo principal do OpenSL ES para Android é facilitar a implementação de bibliotecas compartilhadas chamadas usando a Interface Java nativa (JNI ). O NDK não se destina à programação de aplicativos puramente em C/C++. No entanto, o OpenSL ES é uma API repleta de recursos, e esperamos que ela possa atender à maioria das suas necessidades de áudio, sem precisar chamar código em execução no tempo de execução do Android.
Observação: embora ela seja baseada no OpenSL ES, a API de áudio nativo do Android (áudio de alto desempenho) não é uma implementação que visa a conformidade com nenhum perfil do OpenSL ES 1.0.1 (jogo, música ou celular). Isso porque o Android não implementa todos os recursos exigidos por nenhum dos perfis. Todos os casos conhecidos em que o Android se comporta de maneira diferente da especificação são descritos na página Extensões do Android.
Recursos herdados da especificação de referência
A implementação do OpenSL ES do Android NDK herda grande parte do conjunto de recursos da especificação de referência, com algumas limitações.
Pontos de entrada globais
O OpenSL ES para Android é compatível com todos os pontos de entrada globais na especificação do Android. Esses pontos de entrada incluem:
slCreateEngine
slQueryNumSupportedEngineInterfaces
slQuerySupportedEngineInterfaces
Objetos e interfaces
A tabela a seguir exibe os objetos e interfaces compatíveis com a implementação do OpenSL ES no Android NDK. Se houver um Sim na célula, isso significa que o recurso está disponível nessa implementação.
Recurso | Player de áudio | Gravador de áudio | Motor | Mix de saída |
---|---|---|---|---|
Aumento de graves | Sim | Não | Não | Sim |
Fila do buffer | Sim | Não | Não | Não |
Localizador de dados de fila de buffer | Sim: origem | Não | Não | Não |
Gerenciamento dinâmico da interface | Sim | Sim | Sim | Sim |
Entrada de efeitos | Sim | Não | Não | Não |
Motor | Não | Não | Sim | Não |
Reverberação do ambiente | Não | Não | Não | Sim |
Equalizador | Sim | Não | Não | Sim |
Localizador de dados do dispositivo de E/S | Não | Sim: origem | Não | Não |
Extração de metadados | Sim: decodificar para PCM | Não | Não | Não |
Silenciar solo | Sim | Não | Não | Não |
Objeto | Sim | Sim | Sim | Sim |
Localizador do mix de saída | Sim: coletor | Não | Não | Não |
Tocar | Sim | Não | Não | Não |
Taxa de reprodução | Sim | Não | Não | Não |
Status de pré-busca | Sim | Não | Não | Não |
Reverberação da predefinição | Não | Não | Não | Sim |
Gravação | Não | Sim | Não | Não |
Busca | Sim | Não | Não | Não |
Localizador de dados de URI | Sim: origem | Não | Não | Não |
Virtualizador | Sim | Não | Não | Sim |
Volume | Sim | Não | Não | Não |
A seção a seguir explica as limitações de alguns desses recursos.
Limitações
Algumas limitações se aplicam aos recursos da Tabela 1. Essas limitações representam diferenças em relação à especificação de referência. O resto desta seção trata dessas diferenças.
Gerenciamento dinâmico da interface
O OpenSL ES para Android não é compatível com RemoveInterface
nem ResumeInterface
.
Combinações de efeito: reverberação do ambiente e reverberação da predefinição
Não é possível ter ambos os tipos de reverberação no mesmo mix de saída.
A plataforma poderá ignorar solicitações de efeito se ela estimar que a carga sobre a CPU será muito alta.
Entrada de efeitos
SetSendLevel()
permite um único nível de entrada por player de áudio.
Reverberação do ambiente
A reverberação do ambiente não aceita os campos reflectionsDelay
, reflectionsLevel
e reverbDelay
da estrutura SLEnvironmentalReverbSettings
.
Formato MIME de dados
Só é possível usar o formato MIME com o localizador de dados de URI e somente para um player de áudio. Não é possível usar esse formato de dados para um gravador de áudio.
A implementação do OpenSL ES do Android exige a inicialização de mimeType
como NULL
ou uma string UTF-8 válida. Além disso, é necessário inicializar containerType
como um valor válido.
Na ausência de outras considerações, como a portabilidade para outras implementações ou formatos de conteúdo que o app não identifica por cabeçalho, recomendamos definir mimeType
como NULL
e containerType
como SL_CONTAINERTYPE_UNSPECIFIED
.
O OpenSL ES para Android aceita os seguintes formatos de áudio, desde que a plataforma Android também os aceite:
- WAV PCM.
- WAV alaw.
- WAV ulaw.
- MP3 Ogg Vorbis.
- AAC LC.
- HE-AACv1 (AAC+).
- HE-AACv2 (AAC+ aprimorado).
- AMR.
- FLAC.
Observação: para consultar uma lista dos formatos de áudio que o Android aceita, acesse Formatos de mídia compatíveis.
As limitações a seguir se aplicam ao tratamento desses e outros formatos nessa implementação do OpenSL ES:
- Os formatos AAC (link em inglês) devem ficar dentro de um contêiner ADTS ou MP4.
- O OpenSL ES para Android não é compatível com MIDI.
- WMA não faz parte da AOSP, e não verificamos a compatibilidade desse formato com o OpenSL ES para Android.
- A implementação do OpenSL ES do Android NDK não aceita reprodução direta de DRM nem conteúdo criptografado. Para reproduzir conteúdo de áudio protegido, é necessário descriptografá-lo no aplicativo antes da reprodução, com o app aplicando todas as restrições de DRM.
Métodos relacionados a objeto
O OpenSL ES para Android não aceita os seguintes métodos para manipular objetos:
Resume()
RegisterCallback()
AbortAsyncOperation()
SetPriority()
GetPriority()
SetLossOfControlInterfaces()
Formato PCM de dados
O PCM é o único formato de dados que pode ser usado com filas de buffer. As configurações de reprodução de PCM compatíveis têm as seguintes características:
- 8 bits não assinada ou 16 bits assinada.
- Mono ou estéreo.
- Ordenação de byte little-endian.
- Taxas de amostragem 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.
As configurações que o OpenSL ES para Android aceita para gravação dependem do dispositivo. Normalmente, a configuração 16.000 Hz mono/16 bits assinada está disponível para todos os dispositivos.
O valor do campo samplesPerSec
está em unidades de mHz, apesar do nome. Para evitar aplicação acidental do valor errado, recomendamos inicializar esse campo usando
uma das constantes simbólicas definidas com esse objetivo, como SL_SAMPLINGRATE_44_1
.
O Android 5.0 (API de nível 21) e versões mais recentes aceitam dados de ponto flutuante.
Taxa de reprodução
A taxa de reprodução do OpenSL ES indica a velocidade com que um objeto apresenta dados, expressa em milésimos da velocidade normal (por mil). Por exemplo, uma taxa de reprodução de 1.000 por mil é 1.000/1.000 ou a velocidade normal. Um intervalo de taxa é um intervalo fechado que expressa a variação das possíveis taxas de reprodução.
A compatibilidade com intervalos de taxa de reprodução e outros recursos pode variar dependendo da versão da plataforma e da implementação. Seu aplicativo pode determinar esses recursos em tempo de execução usando PlaybackRate::GetRateRange()
ou PlaybackRate::GetCapabilitiesOfRate()
para consultar o dispositivo.
Normalmente, um dispositivo aceita o mesmo intervalo de taxa para uma fonte de dados no formato PCM e um intervalo de taxa unitário de 1.000 por mil a 1.000 por mil para outros formatos, ou seja, o intervalo de taxa unitário é um único valor.
Gravação
O OpenSL ES para Android não aceita os eventos SL_RECORDEVENT_HEADATLIMIT
nem SL_RECORDEVENT_HEADMOVING
.
Busca
O método SetLoop()
permite gerar loop em todo o arquivo. Para permitir o loop, defina o parâmetro startPos
como 0 e o parâmetro endPos
como SL_TIME_UNKNOWN
.
Localizador de dados de fila de buffer
Players ou gravadores de áudio com um localizador de dados para uma fila de buffer só aceitam o formato PCM.
Localizador de dados do dispositivo de E/S
O OpenSL ES para Android só aceita o uso de um localizador de dados do dispositivo de E/S quando o localizador é especificado como a fonte de dados para Engine::CreateAudioRecorder()
.
Inicialize o localizador de dados do dispositivo usando os valores no seguinte snippet de código:
SLDataLocator_IODevice loc_dev = {SL_DATALOCATOR_IODEVICE, SL_IODEVICE_AUDIOINPUT, SL_DEFAULTDEVICEID_AUDIOINPUT, NULL};
Localizador de dados de URI
O OpenSL ES para Android só pode usar o localizador de dados de URI com o formato de dados MIME e apenas para um player de áudio. Não é possível usar um localizador de dados de URI para um gravador de áudio. O URI só pode usar os esquemas http:
e file:
. Outros esquemas, como https:
, ftp:
ou content:
, não são permitidos.
Não verificamos a compatibilidade de rtsp:
com áudio na plataforma Android.
Estruturas de dados
O Android aceita as seguintes estruturas de dados do OpenSL ES 1.0.1:
SLDataFormat_MIME
SLDataFormat_PCM
SLDataLocator_BufferQueue
SLDataLocator_IODevice
SLDataLocator_OutputMix
SLDataLocator_URI
SLDataSink
SLDataSource
SLEngineOption
SLEnvironmentalReverbSettings
SLInterfaceID
Configuração da plataforma
O OpenSL ES para Android foi desenvolvido para aplicativos com várias linhas de execução e é seguro para essas linhas. Ele oferece compatibilidade com um único mecanismo por aplicativo e até 32 objetos por mecanismo. A memória e a CPU disponíveis do dispositivo podem restringir mais o número de objetos que podem ser usados.
Estas opções de mecanismo são reconhecidas, mas ignoradas pelo slCreateEngine
:
SL_ENGINEOPTION_THREADSAFE
SL_ENGINEOPTION_LOSSOFCONTROL
O OpenMAX AL e o OpenSL ES podem ser usados juntos no mesmo aplicativo. Nesse caso, haverá um único objeto de mecanismo compartilhado internamente, e o limite de 32 objetos será compartilhado entre o OpenMAX AL e o OpenSL ES. O aplicativo precisa criar, usar e destruir os dois mecanismos. A implementação mantém uma contagem de referência no mecanismo compartilhado para que ele seja corretamente destruído durante a segunda operação de destruição.
Notas de programação
As notas de programação do OpenSL ES fornecem informações complementares para garantir a implementação adequada do OpenSL ES.
Observação: por conveniência, incluímos uma cópia da especificação do OpenSL ES 1.0.1 no NDK em docs/opensles/OpenSL_ES_Specification_1.0.1.pdf
.
Problemas da plataforma
Esta seção descreve problemas conhecidos na versão inicial da plataforma que aceita estas APIs.
Gerenciamento dinâmico da interface
DynamicInterfaceManagement::AddInterface
não funciona. Em vez disso, especifique a interface na
matriz que é passada a Create()
, conforme exibido no exemplo de código de reverberação do ambiente.
Planejamento para versões futuras do OpenSL ES
As APIs de áudio de alto desempenho do Android são baseadas no OpenSL ES 1.0.1 do Khronos Group (link em inglês). A Khronos lançou a versão 1.1, uma revisão do padrão. A versão revisada inclui novos recursos, esclarecimentos, correções de erros tipográficos e algumas incompatibilidades. A maioria das compatibilidades esperadas é relativamente pequena ou está em áreas do OpenSL ES não compatíveis com o Android.
Um aplicativo desenvolvido com essa versão funcionará em versões futuras da plataforma Android, desde que as orientações definidas na seção Planejamento para compatibilidade binária abaixo sejam seguidas.
Observação: a compatibilidade com fonte futura não é um objetivo. Ou seja, se você atualizar para uma nova versão do NDK, talvez seja necessário modificar o código-fonte do aplicativo para se adequar à nova API. Esperamos que a maior parte dessas alterações seja pequena. Veja os detalhes abaixo.
Planejamento para compatibilidade binária
Recomendamos que seu aplicativo siga estas orientações para melhorar a compatibilidade binária futura:
- Use somente o subconjunto documentado de recursos do OpenSL ES 1.0.1 aceitos pelo Android.
- Não dependa de determinado código resultante para uma operação sem sucesso. Prepare-se para lidar com um código resultante diferente.
- Os gerenciadores de callback do aplicativo geralmente são executados em um contexto restrito. Eles precisam ser escritos para realizar uma função rapidamente e retornar assim que possível. Não execute operações complexas dentro de um gerenciador de callback. Por exemplo: em um callback de conclusão de fila de buffer, é possível enfileirar outro buffer, mas não crie um player de áudio.
- Os gerenciadores de callback precisam estar preparados para serem chamados com mais ou menos frequência, para receber outros tipos de evento e ignorar tipos de evento que não reconhecem. Os callbacks configurados com uma máscara de eventos feita de tipos de evento ativos precisam estar preparados para serem chamados com vários conjuntos de bits de tipo de evento simultaneamente. Use “&” para testar cada bit de evento, em vez de um caso de alternância.
- Use o status de pré-busca e callbacks como indicadores gerais de progresso, mas não dependa de níveis de preenchimento nem de sequências de callback específicas codificadas. O significado do nível de preenchimento do status de pré-busca e o comportamento em relação a erros detectados durante a pré-busca podem mudar.
Observação: consulte a seção Comportamento da fila de buffer abaixo para saber mais.
Planejamento para compatibilidade de fonte
Como mencionado, são esperadas incompatibilidades do código-fonte na próxima versão do OpenSL ES do Khronos Group. As prováveis áreas de mudança incluem:
- A interface de fila do buffer deverá trazer mudanças importantes, principalmente nas áreas de
BufferQueue::Enqueue
, na lista de parâmetros deslBufferQueueCallback
e no nome do campoSLBufferQueueState.playIndex
. Recomendamos que o código do seu aplicativo use filas de buffer simples do Android. Por esse motivo, no exemplo de código fornecido com o NDK, usamos filas de buffer simples do Android para reprodução. Além disso, usamos uma fila de buffer simples do Android para gravar e decodificar para PCM. No entanto, essa opção foi usada porque o OpenSL ES 1.0.1 padrão não aceita gravação nem decodificação para um coletor de dados de fila do buffer. - Haverá uma adição de
const
aos parâmetros de entrada passados por referência e aos campos de estruturaSLchar *
usados como valores de entrada. Isso não deve exigir nenhuma mudança no código. - Haverá uma substituição de tipos não assinados para alguns parâmetros que atualmente estão assinados.
Talvez seja necessário adicionar uma transmissão ou alterar o tipo de um parâmetro de
SLint32
paraSLuint32
ou algo parecido. Equalizer::GetPresetName
copia a string para a memória do aplicativo em vez de retornar um ponteiro para a memória de implementação. Essa será uma mudança significativa, por isso recomendamos evitar chamar esse método ou isolar o uso dele.- Haverá outros campos nos tipos de estrutura. Em relação aos parâmetros de saída, esses novos campos podem ser ignorados. No entanto, nos parâmetros de entrada, os novos campos precisarão ser inicializados. Esperamos que todos esses campos estejam em áreas não aceitas pelo Android.
- Os GUIDs de interface mudarão. Para evitar uma dependência, consulte as interfaces por nome simbólico, e não por GUID.
SLchar
mudará deunsigned char
parachar
. Isso afetará principalmente o localizador de dados de URI e o formato de dados MIME.SLDataFormat_MIME.mimeType
será renomeado parapMimeType
, eSLDataLocator_URI.URI
parapURI
. É recomendável inicializar as estruturas de dadosSLDataFormat_MIME
eSLDataLocator_URI
usando uma lista de valores separados por vírgula e fechados por chave, e não por nome de campo, para isolar seu código dessa mudança. Essa técnica é usada no exemplo de código.SL_DATAFORMAT_PCM
não permite que o aplicativo especifique a representação dos dados como número inteiro assinado, número inteiro não assinado nem ponto flutuante. A implementação do Android assume que os dados de 8 bits são números inteiros não assinados e os de 16 bits são números inteiros assinados. Além disso, o camposamplesPerSec
tem um nome incorreto, já que a unidade real é mHz. Esses problemas deverão ser resolvidos na próxima versão do OpenSL ES, que introduzirá um novo formato de dados PCM estendido, que permitirá ao aplicativo especificar explicitamente a representação e corrigir o nome do campo. Como esse será um formato de dados novo, e o formato PCM atual continuará disponível (embora obsoleto), não será necessário fazer modificações imediatas no código.