开始
包含以下两个头文件:
#include <SLES/OpenSLES.h>
#include <SLES/OpenSLES_Android.h>
OpenSLES_Android.h是Android对OpenSL ES的扩展,包含了以下两个头文件:
#include <SLES/OpenSLES_AndroidConfiguration.h>
#include <SLES/OpenSLES_AndroidMetadata.h>
PCM data format
PCM is the only data format you can use with buffer queues.
PCM是唯一支持缓冲队列的音频格式。
支持以下参数播放PCM:
- 8位或16位
- 单通道或双通道
- 小端模式字节序
- 采样率:
- 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
支持以下参数采集PCM:
- 16位
- 单通道
- 16,000 Hz
Android simple buffer queue
For future source code compatibility, however, we suggest that applications use Android simple buffer queues instead of OpenSL ES 1.0.1 buffer queues.
为了代码的兼容性,我们建议App使用Android simple buffer queues代替OpenSL ES 1.0.1 buffer queues。
使用要点:
- 音频播放和采集都可以使用Android simple buffer queues
- Android simple buffer queues只接受PCM格式数据
注意:
- 播放停止,设置SL_PLAYSTATE_STOPPED状态后,要调用
BufferQueue的Clear方法才能保证播放游标在缓存队列的起始位置。 - 录音停止,设置SL_RECORDSTATE_STOPPED状态后,要调用BufferQueue的Clear方法才能保证录音游标在缓存队列的起始位置。
Decode audio to PCM
- Android API 15及以下,使用开源的第三方解码库
- Android API 16-20,使用MediaCodec或者开源的第三方解码库
- Android API 21及以上,使用NDK层的MediaCodec,在 <media/NdkMedia*.h>头文件中,或者使用MediaCodec或者开源的第三方解码库
Audio Latency
快速输出混音的接口:
- SL_IID_ANDROIDSIMPLEBUFFERQUEUE
- SL_IID_VOLUME
- SL_IID_MUTESOLO
涉及声音信号处理的接口:
- SL_IID_BASSBOOST
- SL_IID_EFFECTSEND
- SL_IID_ENVIRONMENTALREVERB
- SL_IID_EQUALIZER
- SL_IID_PLAYBACKRATE
- SL_IID_PRESETREVERB
- SL_IID_VIRTUALIZER
- SL_IID_ANDROIDEFFECT
- SL_IID_ANDROIDEFFECTSEND
所以当创建播放器的时候,确保只添加快速接口(上面3个),比如:
const SLInterfaceID interface_ids[2] = { SL_IID_ANDROIDSIMPLEBUFFERQUEUE, SL_IID_VOLUME };
示例代码:
The following code snippet shows an example of how to set the Android audio stream type on an audio player:
// 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.
You can use similar code to configure the preset for an audio recorder:
// ... 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));
An app running on Android 5.0 (API level 21) and higher can supply data to an AudioPlayer in single-precision, floating-point format.
In following example code, the Engine::CreateAudioPlayer() method creates an audio player that uses floating-point data:
#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;
The criteria for reporting these flags is defined in the CDD in sections 5.6 Audio Latency and 5.10 Professional Audio.
Here’s how to check for these features in Java:
boolean hasLowLatencyFeature =
getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUDIO_LOW_LATENCY);
boolean hasProFeature =
getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUDIO_PRO);
In Java, you can obtain the optimal sample rate from AudioManager as shown in the following code example:
AudioManager am = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
String sampleRateStr = am.getProperty(AudioManager.PROPERTY_OUTPUT_SAMPLE_RATE);
int sampleRate = Integer.parseInt(sampleRateStr);
if (sampleRate == 0) sampleRate = 44100; // Use a default value if property not found
Once you know the optimal sample rate, you can supply it when creating your player using OpenSL ES:
// create buffer queue audio player
void Java_com_example_audio_generatetone_MainActivity_createBufferQueueAudioPlayer
(JNIEnv* env, jclass clazz, jint sampleRate, jint framesPerBuffer)
{
...
// specify the audio source format
SLDataFormat_PCM format_pcm;
format_pcm.numChannels = 2;
format_pcm.samplesPerSec = (SLuint32) sampleRate * 1000;
...
}
You can obtain the optimal buffer size in a similar way to the optimal sample rate, using the AudioManager API:
AudioManager am = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
String framesPerBuffer = am.getProperty(AudioManager.PROPERTY_OUTPUT_FRAMES_PER_BUFFER);
int framesPerBufferInt = Integer.parseInt(framesPerBuffer);
if (framesPerBufferInt == 0) framesPerBufferInt = 256; // Use default
When you create your player, make sure you only add fast interfaces, as shown in the following example:
const SLInterfaceID interface_ids[2] = { SL_IID_ANDROIDSIMPLEBUFFERQUEUE, SL_IID_VOLUME };
To avoid this warmup latency, you can enqueue buffers of audio data containing silence, as shown in the following code example:
#define CHANNELS 1
static short* silenceBuffer;
int numSamples = frames * CHANNELS;
silenceBuffer = malloc(sizeof(*silenceBuffer) * numSamples);
for (i = 0; i < numSamples; i++) {
silenceBuffer[i] = 0;
}