getMinBufferSizeJava接口
getMinBufferSize是AudioRecord和AudioTrack的static 接口, AudioRecord/AudioTrack中的实现是不同的,先分析AudioRecord的getMinBufferSize.
AudioRecord::getMinBufferSize
frameworks/base/media/java/android/media/AudioRecord.java
public class AudioRecord implements AudioRouting, MicrophoneDirection,
AudioRecordingMonitor, AudioRecordingMonitorClient
{
static public int getMinBufferSize(int sampleRateInHz, int channelConfig, int audioFormat) {
int channelCount = 0;
switch (channelConfig) {
case AudioFormat.CHANNEL_IN_DEFAULT: // AudioFormat.CHANNEL_CONFIGURATION_DEFAULT
case AudioFormat.CHANNEL_IN_MONO:
case AudioFormat.CHANNEL_CONFIGURATION_MONO:
channelCount = 1;
break;
case AudioFormat.CHANNEL_IN_STEREO:
case AudioFormat.CHANNEL_CONFIGURATION_STEREO:
case (AudioFormat.CHANNEL_IN_FRONT | AudioFormat.CHANNEL_IN_BACK):
channelCount = 2;
break;
case AudioFormat.CHANNEL_IN_5POINT1:
channelCount = 6;
break;
case AudioFormat.CHANNEL_INVALID:
default:
loge("getMinBufferSize(): Invalid channel configuration.");
return ERROR_BAD_VALUE;
}
int size = native_get_min_buff_size(sampleRateInHz, channelCount, audioFormat);
if (size == 0) {
return ERROR_BAD_VALUE;
}
else if (size == -1) {
return ERROR;
}
else {
return size;
}
}
}
AudioTrack::getMinBufferSize
public class AudioTrack extends PlayerBase
implements AudioRouting
, VolumeAutomation
{
static public int getMinBufferSize(int sampleRateInHz, int channelConfig, int audioFormat) {
int channelCount = 0;
switch(channelConfig) {
case AudioFormat.CHANNEL_OUT_MONO:
case AudioFormat.CHANNEL_CONFIGURATION_MONO:
channelCount = 1;
break;
case AudioFormat.CHANNEL_OUT_STEREO:
case AudioFormat.CHANNEL_CONFIGURATION_STEREO:
channelCount = 2;
break;
default:
if (!isMultichannelConfigSupported(channelConfig)) {
loge("getMinBufferSize(): Invalid channel configuration.");
return ERROR_BAD_VALUE;
} else {
channelCount = AudioFormat.channelCountFromOutChannelMask(channelConfig);
}
}
if (!AudioFormat.isPublicEncoding(audioFormat)) {
loge("getMinBufferSize(): Invalid audio format.");
return ERROR_BAD_VALUE;
}
// sample rate, note these values are subject to change
// Note: AudioFormat.SAMPLE_RATE_UNSPECIFIED is not allowed
if ( (sampleRateInHz < AudioFormat.SAMPLE_RATE_HZ_MIN) ||
(sampleRateInHz > AudioFormat.SAMPLE_RATE_HZ_MAX) ) {
loge("getMinBufferSize(): " + sampleRateInHz + " Hz is not a supported sample rate.");
return ERROR_BAD_VALUE;
}
int size = native_get_min_buff_size(sampleRateInHz, channelCount, audioFormat);
if (size <= 0) {
loge("getMinBufferSize(): error querying hardware");
return ERROR;
}
else {
return size;
}
}
}
native_get_min_buffer_size
frameworks/base/core/jni/android_media_AudioRecord.cpp
{"native_get_min_buff_size",
"(III)I", (void *)android_media_AudioRecord_get_min_buff_size},
frameworks/base/core/jni/android_media_AudioTrack.cpp
{"native_get_min_buff_size",
"(III)I", (void *)android_media_AudioTrack_get_min_buff_size},
AudioRecord::getMinBufferSize代码流程
java app code:
AudioRecord.getMinBufferSize(16000,
AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT);
JNI
frameworks/base/core/jni/android_media_AudioRecord.cpp
static jint android_media_AudioRecord_get_min_buff_size(JNIEnv *env, jobject thiz,
jint sampleRateInHertz, jint channelCount, jint audioFormat) {
ALOGV(">> android_media_AudioRecord_get_min_buff_size(%d, %d, %d)",
sampleRateInHertz, channelCount, audioFormat);
size_t frameCount = 0;
audio_format_t format = audioFormatToNative(audioFormat);
status_t result = AudioRecord::getMinFrameCount(&frameCount,
sampleRateInHertz,
format,
audio_channel_in_mask_from_count(channelCount));
return frameCount * channelCount * audio_bytes_per_sample(format);
}
// 把java层的 AudioFormat.ENCODING_PCM_xxx 转换成 native 层的 AUDIO_FORMAT_PCM_xxx
static inline audio_format_t audioFormatToNative(int audioFormat)
{
switch (audioFormat) {
case ENCODING_PCM_24BIT:
return AUDIO_FORMAT_PCM_24_BIT_PACKED;
case ENCODING_PCM_16BIT:
return AUDIO_FORMAT_PCM_16_BIT;
case ENCODING_PCM_8BIT:
return AUDIO_FORMAT_PCM_8_BIT;
}
// 获得 channel mask
static inline audio_channel_mask_t audio_channel_in_mask_from_count(uint32_t channel_count)
{
uint32_t bits;
switch (channel_count) {
case 0:
return AUDIO_CHANNEL_NONE;
case 1:
bits = AUDIO_CHANNEL_IN_MONO;
break;
case 2:
bits = AUDIO_CHANNEL_IN_STEREO;
break;
case 3:
case 4:
case 5:
case 6:
case 7:
case 8:
// FIXME FCC_8
return audio_channel_mask_for_index_assignment_from_count(channel_count);
default:
return AUDIO_CHANNEL_INVALID;
}
return audio_channel_mask_from_representation_and_bits(
AUDIO_CHANNEL_REPRESENTATION_POSITION, bits);
}
Native lib
libaudioclient/AudioRecord.cpp
frameworks/av/media/libaudioclient/AudioRecord.cpp
status_t AudioRecord::getMinFrameCount(
size_t* frameCount,
uint32_t sampleRate,
audio_format_t format,
audio_channel_mask_t channelMask)
{
if (frameCount == NULL) {
return BAD_VALUE;
}
size_t size;
status_t status = AudioSystem::getInputBufferSize(sampleRate, format, channelMask, &size);
if (status != NO_ERROR) {
ALOGE("%s(): AudioSystem could not query the input buffer size for"
" sampleRate %u, format %#x, channelMask %#x; status %d",
__func__, sampleRate, format, channelMask, status);
return status;
}
// We double the size of input buffer for ping pong use of record buffer.
// Assumes audio_is_linear_pcm(format)
if ((*frameCount = (size * 2) / (audio_channel_count_from_in_mask(channelMask) *
audio_bytes_per_sample(format))) == 0) {
ALOGE("%s(): Unsupported configuration: sampleRate %u, format %#x, channelMask %#x",
__func__, sampleRate, format, channelMask);
return BAD_VALUE;
}
return NO_ERROR;
}
AudioSystem::getInputBufferSize
status_t AudioSystem::getInputBufferSize(uint32_t sampleRate, audio_format_t format,
audio_channel_mask_t channelMask, size_t* buffSize)
{
const sp<AudioFlingerClient> afc = getAudioFlingerClient();
if (afc == 0) {
return NO_INIT;
}
return afc->getInputBufferSize(sampleRate, format, channelMask, buffSize);
}
const sp<AudioSystem::AudioFlingerClient> AudioSystem::getAudioFlingerClient()
{
// calling get_audio_flinger() will initialize gAudioFlingerClient if needed
const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
if (af == 0) return 0;
Mutex::Autolock _l(gLock);
return gAudioFlingerClient;
}
// establish binder interface to AudioFlinger service
const sp<IAudioFlinger> AudioSystem::get_audio_flinger()
{
sp<IAudioFlinger> af;
sp<AudioFlingerClient> afc;
bool reportNoError = false;
{
Mutex::Autolock _l(gLock);
if (gAudioFlinger == 0) {
sp<IServiceManager> sm = defaultServiceManager();
sp<IBinder> binder;
do {
binder = sm->getService(String16("media.audio_flinger"));
if (binder != 0)
break;
ALOGW("AudioFlinger not published, waiting...");
usleep(500000); // 0.5 s
} while (true);
if (gAudioFlingerClient == NULL) {
gAudioFlingerClient = new AudioFlingerClient();
} else {
reportNoError = true;
}
binder->linkToDeath(gAudioFlingerClient);
gAudioFlinger = interface_cast<IAudioFlinger>(binder);
LOG_ALWAYS_FATAL_IF(gAudioFlinger == 0);
afc = gAudioFlingerClient;
// Make sure callbacks can be received by gAudioFlingerClient
ProcessState::self()->startThreadPool();
}
af = gAudioFlinger;
}
if (afc != 0) {
int64_t token = IPCThreadState::self()->clearCallingIdentity();
af->registerClient(afc);
IPCThreadState::self()->restoreCallingIdentity(token);
}
if (reportNoError) reportError(NO_ERROR);
return af;
}
class AudioSystem内部类 AudioFlingerClient
class AudioFlingerClient: public IBinder::DeathRecipient, public BnAudioFlingerClient
{
public:
AudioFlingerClient() :
mInBuffSize(0), mInSamplingRate(0),
mInFormat(AUDIO_FORMAT_DEFAULT), mInChannelMask(AUDIO_CHANNEL_NONE) {
}
AudioFlingerClient::getInputBufferSize
status_t AudioSystem::AudioFlingerClient::getInputBufferSize(
uint32_t sampleRate, audio_format_t format,
audio_channel_mask_t channelMask, size_t* buffSize)
{
const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
if (af == 0) {
return PERMISSION_DENIED;
}
Mutex::Autolock _l(mLock);
// Do we have a stale mInBuffSize or are we requesting the input buffer size for new values
if ((mInBuffSize == 0) || (sampleRate != mInSamplingRate) || (format != mInFormat)
|| (channelMask != mInChannelMask)) {
size_t inBuffSize = af->getInputBufferSize(sampleRate, format, channelMask);
if (inBuffSize == 0) {
ALOGE("AudioSystem::getInputBufferSize failed sampleRate %d format %#x channelMask %#x",
sampleRate, format, channelMask);
return BAD_VALUE;
}
// A benign race is possible here: we could overwrite a fresher cache entry
// save the request params
mInSamplingRate = sampleRate;
mInFormat = format;
mInChannelMask = channelMask;
mInBuffSize = inBuffSize;
}
*buffSize = mInBuffSize;
return NO_ERROR;
}
frameworks/av/media/libaudioclient/IAudioFlinger.cpp
virtual size_t getInputBufferSize(uint32_t sampleRate, audio_format_t format,
audio_channel_mask_t channelMask) const
{
Parcel data, reply;
data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
data.writeInt32(sampleRate);
data.writeInt32(format);
data.writeInt32(channelMask);
remote()->transact(GET_INPUTBUFFERSIZE, data, &reply);
return reply.readInt64();
}
AudioFlinger service binder接口实现
有点不解的是 GET_INPUTBUFFERSIZE的实现也是在文件 IAudioFlinger.cpp 中
case GET_INPUTBUFFERSIZE: {
CHECK_INTERFACE(IAudioFlinger, data, reply);
uint32_t sampleRate = data.readInt32();
audio_format_t format = (audio_format_t) data.readInt32();
audio_channel_mask_t channelMask = data.readInt32();
reply->writeInt64( getInputBufferSize(sampleRate, format, channelMask) );
return NO_ERROR;
} break;
AudioFlinger service 实现
frameworks/av/services/audioflinger/AudioFlinger.cpp
size_t AudioFlinger::getInputBufferSize(uint32_t sampleRate, audio_format_t format,
audio_channel_mask_t channelMask) const
{
status_t ret = initCheck();
if (ret != NO_ERROR) {
return 0;
}
if ((sampleRate == 0) ||
!audio_is_valid_format(format) || !audio_has_proportional_frames(format) ||
!audio_is_input_channel(channelMask)) {
return 0;
}
AutoMutex lock(mHardwareLock);
if (mPrimaryHardwareDev == nullptr) {
return 0;
}
mHardwareStatus = AUDIO_HW_GET_INPUT_BUFFER_SIZE;
sp<DeviceHalInterface> dev = mPrimaryHardwareDev->hwDevice();
std::vector<audio_channel_mask_t> channelMasks = {channelMask};
if (channelMask != AUDIO_CHANNEL_IN_MONO)
channelMasks.push_back(AUDIO_CHANNEL_IN_MONO);
if (channelMask != AUDIO_CHANNEL_IN_STEREO)
channelMasks.push_back(AUDIO_CHANNEL_IN_STEREO);
std::vector<audio_format_t> formats = {format};
if (format != AUDIO_FORMAT_PCM_16_BIT)
formats.push_back(AUDIO_FORMAT_PCM_16_BIT);
std::vector<uint32_t> sampleRates = {sampleRate};
static const uint32_t SR_44100 = 44100;
static const uint32_t SR_48000 = 48000;
if (sampleRate != SR_48000)
sampleRates.push_back(SR_48000);
if (sampleRate != SR_44100)
sampleRates.push_back(SR_44100);
mHardwareStatus = AUDIO_HW_IDLE;
// Change parameters of the configuration each iteration until we find a
// configuration that the device will support.
audio_config_t config = AUDIO_CONFIG_INITIALIZER;
for (auto testChannelMask : channelMasks) {
config.channel_mask = testChannelMask;
for (auto testFormat : formats) {
config.format = testFormat;
for (auto testSampleRate : sampleRates) {
config.sample_rate = testSampleRate;
size_t bytes = 0;
status_t result = dev->getInputBufferSize(&config, &bytes);
if (result != OK || bytes == 0) {
continue;
}
if (config.sample_rate != sampleRate || config.channel_mask != channelMask ||
config.format != format) {
uint32_t dstChannelCount = audio_channel_count_from_in_mask(channelMask);
uint32_t srcChannelCount =
audio_channel_count_from_in_mask(config.channel_mask);
size_t srcFrames =
bytes / audio_bytes_per_frame(srcChannelCount, config.format);
size_t dstFrames = destinationFramesPossible(
srcFrames, config.sample_rate, sampleRate);
bytes = dstFrames * audio_bytes_per_frame(dstChannelCount, format);
}
return bytes;
}
}
}
ALOGW("getInputBufferSize failed with minimum buffer size sampleRate %u, "
"format %#x, channelMask %#x",sampleRate, format, channelMask);
return 0;
}
DeviceHalInterface: AudioFlinger service 调用HalService
frameworks/av/media/libaudiohal/include/media/audiohal/DeviceHalInterface.h
// Returns audio input buffer size according to parameters passed.
virtual status_t getInputBufferSize(const struct audio_config *config,
size_t *size) = 0;
frameworks/av/media/libaudiohal/impl/DeviceHalHidl.cpp
status_t DeviceHalHidl::getInputBufferSize(
const struct audio_config *config, size_t *size) {
if (mDevice == 0) return NO_INIT;
AudioConfig hidlConfig;
HidlUtils::audioConfigFromHal(*config, &hidlConfig);
Result retval;
Return<void> ret = mDevice->getInputBufferSize(
hidlConfig,
[&](Result r, uint64_t bufferSize) {
retval = r;
if (retval == Result::OK) {
*size = static_cast<size_t>(bufferSize);
}
});
return processReturn("getInputBufferSize", ret, retval);
}
hardware/interfaces/audio/6.0/IDevice.hal
/**
* Returns audio input buffer size according to parameters passed or
* INVALID_ARGUMENTS if one of the parameters is not supported.
*
* @param config audio configuration.
* @return retval operation completion status.
* @return bufferSize input buffer size in bytes.
*/
getInputBufferSize(AudioConfig config)
generates (Result retval, uint64_t bufferSize);
audio hal service实现
hardware/interfaces/audio/core/all-versions/default/PrimaryDevice.cpp
Return<void> PrimaryDevice::getInputBufferSize(const AudioConfig& config,
getInputBufferSize_cb _hidl_cb) {
return mDevice->getInputBufferSize(config, _hidl_cb);
}
Return<void> Device::getInputBufferSize(const AudioConfig& config, getInputBufferSize_cb _hidl_cb) {
audio_config_t halConfig;
HidlUtils::audioConfigToHal(config, &halConfig);
size_t halBufferSize = mDevice->get_input_buffer_size(mDevice, &halConfig);
Result retval(Result::INVALID_ARGUMENTS);
uint64_t bufferSize = 0;
if (halBufferSize != 0) {
retval = Result::OK;
bufferSize = halBufferSize;
}
_hidl_cb(retval, bufferSize);
return Void();
}
audioHalService 加载hal so库
vendor/qcom/opensource/audio-hal/primary-hal/hal/audio_hw.c
static size_t get_input_buffer_size(uint32_t sample_rate,
audio_format_t format,
int channel_count,
bool is_low_latency)
{
/* Don't know if USB HIFI in this context so use true to be conservative */
if (check_input_parameters(sample_rate, format, channel_count,
true /*is_usb_hifi */) != 0)
return 0;
return get_stream_buffer_size(AUDIO_CAPTURE_PERIOD_DURATION_MSEC,
sample_rate,
format,
channel_count,
is_low_latency);
}
static size_t get_stream_buffer_size(size_t duration_ms,
uint32_t sample_rate,
audio_format_t format,
int channel_count,
bool is_low_latency)
{
size_t size = 0;
uint32_t bytes_per_period_sample = 0;
size = (sample_rate * duration_ms) / 1000;
if (is_low_latency)
size = configured_low_latency_capture_period_size;
bytes_per_period_sample = audio_bytes_per_sample(format) * channel_count;
size *= audio_bytes_per_sample(format) * channel_count;
/* make sure the size is multiple of 32 bytes and additionally multiple of
* the frame_size (required for 24bit samples and non-power-of-2 channel counts)
* At 48 kHz mono 16-bit PCM:
* 5.000 ms = 240 frames = 15*16*1*2 = 480, a whole multiple of 32 (15)
* 3.333 ms = 160 frames = 10*16*1*2 = 320, a whole multiple of 32 (10)
* Also, make sure the size is multiple of bytes per period sample
*/
size = nearest_multiple(size, lcm(32, bytes_per_period_sample));
return size;
}
简言之
client AudioRecord 通过AudioSystem 获得AudioFlinger的代理调用AudioFlinger Service, 而AudioFlinger service 又使用IDevice的代理 调用hardware.audio.service的服务,而hardware.audio.service的实现是通过加载 硬件相关的hal.so 实现的。对getMinBuffer这个相对简单的实现而言并没有设计audiopolicy 和stream等。