AudioFlinger 加载硬件模块和打开输入输出设备
前面我们看到,AudioPolicyService
的 AudioPolicyManager
最终请求 AudioFlinger
加载音频硬件模块。AudioFlinger
加载音频硬件模块的操作定义 (位于 frameworks/av/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp) 如下:
audio_module_handle_t AudioFlinger::loadHwModule(const char *name)
{
if (name == NULL) {
return AUDIO_MODULE_HANDLE_NONE;
}
if (!settingsAllowed()) {
return AUDIO_MODULE_HANDLE_NONE;
}
Mutex::Autolock _l(mLock);
AutoMutex lock(mHardwareLock);
return loadHwModule_l(name);
}
// loadHwModule_l() must be called with AudioFlinger::mLock and AudioFlinger::mHardwareLock held
audio_module_handle_t AudioFlinger::loadHwModule_l(const char *name)
{
for (size_t i = 0; i < mAudioHwDevs.size(); i++) {
if (strncmp(mAudioHwDevs.valueAt(i)->moduleName(), name, strlen(name)) == 0) {
ALOGW("loadHwModule() module %s already loaded", name);
return mAudioHwDevs.keyAt(i);
}
}
sp<DeviceHalInterface> dev;
int rc = mDevicesFactoryHal->openDevice(name, &dev);
if (rc) {
ALOGE("loadHwModule() error %d loading module %s", rc, name);
return AUDIO_MODULE_HANDLE_NONE;
}
mHardwareStatus = AUDIO_HW_INIT;
rc = dev->initCheck();
mHardwareStatus = AUDIO_HW_IDLE;
if (rc) {
ALOGE("loadHwModule() init check error %d for module %s", rc, name);
return AUDIO_MODULE_HANDLE_NONE;
}
// Check and cache this HAL's level of support for master mute and master
// volume. If this is the first HAL opened, and it supports the get
// methods, use the initial values provided by the HAL as the current
// master mute and volume settings.
AudioHwDevice::Flags flags = static_cast<AudioHwDevice::Flags>(0);
if (0 == mAudioHwDevs.size()) {
mHardwareStatus = AUDIO_HW_GET_MASTER_VOLUME;
float mv;
if (OK == dev->getMasterVolume(&mv)) {
mMasterVolume = mv;
}
mHardwareStatus = AUDIO_HW_GET_MASTER_MUTE;
bool mm;
if (OK == dev->getMasterMute(&mm)) {
mMasterMute = mm;
}
}
mHardwareStatus = AUDIO_HW_SET_MASTER_VOLUME;
if (OK == dev->setMasterVolume(mMasterVolume)) {
flags = static_cast<AudioHwDevice::Flags>(flags |
AudioHwDevice::AHWD_CAN_SET_MASTER_VOLUME);
}
mHardwareStatus = AUDIO_HW_SET_MASTER_MUTE;
if (OK == dev->setMasterMute(mMasterMute)) {
flags = static_cast<AudioHwDevice::Flags>(flags |
AudioHwDevice::AHWD_CAN_SET_MASTER_MUTE);
}
mHardwareStatus = AUDIO_HW_IDLE;
if (strcmp(name, AUDIO_HARDWARE_MODULE_ID_MSD) == 0) {
// An MSD module is inserted before hardware modules in order to mix encoded streams.
flags = static_cast<AudioHwDevice::Flags>(flags | AudioHwDevice::AHWD_IS_INSERT);
}
audio_module_handle_t handle = (audio_module_handle_t) nextUniqueId(AUDIO_UNIQUE_ID_USE_MODULE);
AudioHwDevice *audioDevice = new AudioHwDevice(handle, name, dev, flags);
if (strcmp(name, AUDIO_HARDWARE_MODULE_ID_PRIMARY) == 0) {
mPrimaryHardwareDev = audioDevice;
mHardwareStatus = AUDIO_HW_SET_MODE;
mPrimaryHardwareDev->hwDevice()->setMode(mMode);
mHardwareStatus = AUDIO_HW_IDLE;
}
mAudioHwDevs.add(handle, audioDevice);
ALOGI("loadHwModule() Loaded %s audio interface, handle %d", name, handle);
return handle;
}
这个操作的执行过程如下:
- 检查要打开的音频硬件模块是否已经打开,如果已经打开,则直接返回模块句柄,否则继续执行;
- 请求 Audio HAL 服务,打开音频硬件模块,获得设备 HAL 接口对象,关于 Audio HAL 更详细的内容,可以参考 Android Audio HAL 服务;
- 初始化设备 HAL 接口对象;
- 如果打开的音频硬件模块是第一个,则初始化主音量
mMasterVolume
和主静音mMasterMute
; - 为打开的设备 HAL 接口对象设置主音量和主静音;
- 基于设备 HAL 接口对象为要打开的音频硬件模块创建
AudioHwDevice
对象,在AudioFlinger
中,AudioHwDevice
对象用来描述打开的音频硬件模块; - 如果要打开的音频硬件模块名称为
AUDIO_HARDWARE_MODULE_ID_PRIMARY
,即 primary,则初始化主硬件设备等; - 保存为音频硬件模块创建的
AudioHwDevice
对象,并返回模块句柄。
相同的实体在不同模块中的抽象不同,在不同模块间的概念不统一,AudioPolicyService
中的音频硬件模块在 AudioFlinger
中被称为设备 Device,AudioPolicyService
中的音频设备,在 AudioFlinger
中则被称为流 Stream。
音频输出描述符 SwAudioOutputDescriptor
在 open()
操作中请求 AudioFlinger
打开音频输出设备,打开音频输出设备的 AudioFlinger::openOutput()
函数定义 (位于 frameworks/av/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp) 如下:
sp<AudioFlinger::ThreadBase> AudioFlinger::openOutput_l(audio_module_handle_t module,
audio_io_handle_t *output,
audio_config_t *halConfig,
audio_config_base_t *mixerConfig __unused,
audio_devices_t deviceType,
const String8& address,
audio_output_flags_t flags)
{
AudioHwDevice *outHwDev = findSuitableHwDev_l(module, deviceType);
if (outHwDev == NULL) {
return 0;
}
if (*output == AUDIO_IO_HANDLE_NONE) {
*output = nextUniqueId(AUDIO_UNIQUE_ID_USE_OUTPUT);
} else {
// Audio Policy does not currently request a specific output handle.
// If this is ever needed, see openInput_l() for example code.
ALOGE("openOutput_l requested output handle %d is not AUDIO_IO_HANDLE_NONE", *output);
return 0;
}
mHardwareStatus = AUDIO_HW_OUTPUT_OPEN;
// FOR TESTING ONLY:
// This if statement allows overriding the audio policy settings
// and forcing a specific format or channel mask to the HAL/Sink device for testing.
if (!(flags & (AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD | AUDIO_OUTPUT_FLAG_DIRECT))) {
// Check only for Normal Mixing mode
if (kEnableExtendedPrecision) {
// Specify format (uncomment one below to choose)
//halConfig->format = AUDIO_FORMAT_PCM_FLOAT;
//halConfig->format = AUDIO_FORMAT_PCM_24_BIT_PACKED;
//halConfig->format = AUDIO_FORMAT_PCM_32_BIT;
//halConfig->format = AUDIO_FORMAT_PCM_8_24_BIT;
// ALOGV("openOutput_l() upgrading format to %#08x", halConfig->format);
}
if (kEnableExtendedChannels) {
// Specify channel mask (uncomment one below to choose)
//halConfig->channel_mask = audio_channel_out_mask_from_count(4); // for USB 4ch
//halConfig->channel_mask = audio_channel_mask_from_representation_and_bits(
// AUDIO_CHANNEL_REPRESENTATION_INDEX, (1 << 4) - 1); // another 4ch example
}
}
AudioStreamOut *outputStream = NULL;
status_t status = outHwDev->openOutputStream(
&outputStream,
*output,
deviceType,
flags,
halConfig,
address.string());
mHardwareStatus = AUDIO_HW_IDLE;
if (status == NO_ERROR) {
if (flags & AUDIO_OUTPUT_FLAG_MMAP_NOIRQ) {
sp<MmapPlaybackThread> thread =
new MmapPlaybackThread(this, *output, outHwDev, outputStream, mSystemReady);
mMmapThreads.add(*output, thread);
ALOGV("openOutput_l() created mmap playback thread: ID %d thread %p",
*output, thread.get());
return thread;
} else {
sp<PlaybackThread> thread;
//TODO: b/193496180 use spatializer flag at audio HAL when available
if (flags == (audio_output_flags_t)(AUDIO_OUTPUT_FLAG_FAST
| AUDIO_OUTPUT_FLAG_DEEP_BUFFER)) {
#ifdef MULTICHANNEL_EFFECT_CHAIN
thread = new SpatializerThread(this, outputStream, *output,
mSystemReady, mixerConfig);
ALOGD("openOutput_l() created spatializer output: ID %d thread %p",
*output, thread.get());
#else
ALOGE("openOutput_l() cannot create spatializer thread "
"without #define MULTICHANNEL_EFFECT_CHAIN");
#endif
} else if (flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
thread = new OffloadThread(this, outputStream, *output, mSystemReady);
ALOGV("openOutput_l() created offload output: ID %d thread %p",
*output, thread.get());
} else if ((flags & AUDIO_OUTPUT_FLAG_DIRECT)
|| !isValidPcmSinkFormat(halConfig->format)
|| !isValidPcmSinkChannelMask(halConfig->channel_mask)) {
thread = new DirectOutputThread(this, outputStream, *output, mSystemReady);
ALOGV("openOutput_l() created direct output: ID %d thread %p",
*output, thread.get());
} else {
thread = new MixerThread(this, outputStream, *output, mSystemReady);
ALOGV("openOutput_l() created mixer output: ID %d thread %p",
*output, thread.get());
}
mPlaybackThreads.add(*output, thread);
struct audio_patch patch;
mPatchPanel.notifyStreamOpened(outHwDev, *output, &patch);
if (thread->isMsdDevice()) {
thread->setDownStreamPatch(&patch);
}
return thread;
}
}
return 0;
}
status_t AudioFlinger::openOutput(const media::OpenOutputRequest& request,
media::OpenOutputResponse* response)
{
audio_module_handle_t module = VALUE_OR_RETURN_STATUS(
aidl2legacy_int32_t_audio_module_handle_t(request.module));
audio_config_t halConfig = VALUE_OR_RETURN_STATUS(
aidl2legacy_AudioConfig_audio_config_t(request.halConfig));
audio_config_base_t mixerConfig = VALUE_OR_RETURN_STATUS(
aidl2legacy_AudioConfigBase_audio_config_base_t(request.mixerConfig));
sp<DeviceDescriptorBase> device = VALUE_OR_RETURN_STATUS(
aidl2legacy_DeviceDescriptorBase(request.device));
audio_output_flags_t flags = VALUE_OR_RETURN_STATUS(
aidl2legacy_int32_t_audio_output_flags_t_mask(request.flags));
audio_io_handle_t output;
uint32_t latencyMs;
ALOGI("openOutput() this %p, module %d Device %s, SamplingRate %d, Format %#08x, "
"Channels %#x, flags %#x",
this, module,
device->toString().c_str(),
halConfig.sample_rate,
halConfig.format,
halConfig.channel_mask,
flags);
audio_devices_t deviceType = device->type();
const String8 address = String8(device->address().c_str());
if (deviceType == AUDIO_DEVICE_NONE) {
return BAD_VALUE;
}
Mutex::Autolock _l(mLock);
sp<ThreadBase> thread = openOutput_l(module, &output, &halConfig,
&mixerConfig, deviceType, address, flags);
if (thread != 0) {
if ((flags & AUDIO_OUTPUT_FLAG_MMAP_NOIRQ) == 0) {
PlaybackThread *playbackThread = (PlaybackThread *)thread.get();
latencyMs = playbackThread->latency();
// notify client processes of the new output creation
playbackThread->ioConfigChanged(AUDIO_OUTPUT_OPENED);
// the first primary output opened designates the primary hw device if no HW module
// named "primary" was already loaded.
AutoMutex lock(mHardwareLock);
if ((mPrimaryHardwareDev == nullptr) && (flags & AUDIO_OUTPUT_FLAG_PRIMARY)) {
ALOGI("Using module %d as the primary audio interface", module);
mPrimaryHardwareDev = playbackThread->getOutput()->audioHwDev;
mHardwareStatus = AUDIO_HW_SET_MODE;
mPrimaryHardwareDev->hwDevice()->setMode(mMode);
mHardwareStatus = AUDIO_HW_IDLE;
}
} else {
MmapThread *mmapThread = (MmapThread *)thread.get();
mmapThread->ioConfigChanged(AUDIO_OUTPUT_OPENED);
}
response->output = VALUE_OR_RETURN_STATUS(legacy2aidl_audio_io_handle_t_int32_t(output));
response->config =
VALUE_OR_RETURN_STATUS(legacy2aidl_audio_config_t_AudioConfig(halConfig));
response->latencyMs = VALUE_OR_RETURN_STATUS(convertIntegral<int32_t>(latencyMs));
response->flags = VALUE_OR_RETURN_STATUS(
legacy2aidl_audio_output_flags_t_int32_t_mask(flags));
return NO_ERROR;
}
return NO_INIT;
}
这个操作的执行过程如下:
- 根据音频硬件模块句柄和设备类型查找适当的音频硬件模块;
- 构造音频输出设备 ID;
- 请求音频硬件模块打开音频输出流,
AudioFlinger
中的流等价于AudioPolicyService
中的设备; - 根据音频硬件设备的标记配置创建不同的 Thread,这些标记主要来自于音频策略 XML 配置文件。
根据音频硬件模块句柄和设备类型查找适当的音频硬件模块的 findSuitableHwDev_l()
函数定义 (位于 frameworks/av/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp) 如下:
static const char * const audio_interfaces[] = {
AUDIO_HARDWARE_MODULE_ID_PRIMARY,
AUDIO_HARDWARE_MODULE_ID_A2DP,
AUDIO_HARDWARE_MODULE_ID_USB,
};
AudioHwDevice* AudioFlinger::findSuitableHwDev_l(
audio_module_handle_t module,
audio_devices_t deviceType)
{
// if module is 0, the request comes from an old policy manager and we should load
// well known modules
AutoMutex lock(mHardwareLock);
if (module == 0) {
ALOGW("findSuitableHwDev_l() loading well know audio hw modules");
for (size_t i = 0; i < arraysize(audio_interfaces); i++) {
loadHwModule_l(audio_interfaces[i]);
}
// then try to find a module supporting the requested device.
for (size_t i = 0; i < mAudioHwDevs.size(); i++) {
AudioHwDevice *audioHwDevice = mAudioHwDevs.valueAt(i);
sp<DeviceHalInterface> dev = audioHwDevice->hwDevice();
uint32_t supportedDevices;
if (dev->getSupportedDevices(&supportedDevices) == OK &&
(supportedDevices & deviceType) == deviceType) {
return audioHwDevice;
}
}
} else {
// check a match for the requested module handle
AudioHwDevice *audioHwDevice = mAudioHwDevs.valueFor(module);
if (audioHwDevice != NULL) {
return audioHwDevice;
}
}
return NULL;
}
在这个函数中,如果音频硬件模块句柄为 0,则会先加载几个音频硬件模块,然后找到第一个支持请求的音频设备类型的音频硬件模块,并返回;如果音频硬件模块句柄不为 0,则根据句柄查找并返回。
加载音频硬件模块不只会在 AudioPolicyService
中发起,当向 AudioFlinger
请求打开输入输出音频设备,查找音频硬件模块时也可能发起。
在音频硬件模块 AudioHwDevice
中打开音频输出流的操作定义 (位于 frameworks/av/services/audioflinger/AudioHwDevice.cpp) 如下:
status_t AudioHwDevice::openOutputStream(
AudioStreamOut **ppStreamOut,
audio_io_handle_t handle,
audio_devices_t deviceType,
audio_output_flags_t flags,
struct audio_config *config,
const char *address)
{
struct audio_config originalConfig = *config;
AudioStreamOut *outputStream = new AudioStreamOut(this, flags);
// Try to open the HAL first using the current format.
ALOGV("openOutputStream(), try "
" sampleRate %d, Format %#x, "
"channelMask %#x",
config->sample_rate,
config->format,
config->channel_mask);
status_t status = outputStream->open(handle, deviceType, config, address);
if (status != NO_ERROR) {
delete outputStream;
outputStream = NULL;
// FIXME Look at any modification to the config.
// The HAL might modify the config to suggest a wrapped format.
// Log this so we can see what the HALs are doing.
ALOGI("openOutputStream(), HAL returned"
" sampleRate %d, Format %#x, "
"channelMask %#x, status %d",
config->sample_rate,
config->format,
config->channel_mask,
status);
// If the data is encoded then try again using wrapped PCM.
bool wrapperNeeded = !audio_has_proportional_frames(originalConfig.format)
&& ((flags & AUDIO_OUTPUT_FLAG_DIRECT) != 0)
&& ((flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) == 0);
if (wrapperNeeded) {
if (SPDIFEncoder::isFormatSupported(originalConfig.format)) {
outputStream = new SpdifStreamOut(this, flags, originalConfig.format);
status = outputStream->open(handle, deviceType, &originalConfig, address);
if (status != NO_ERROR) {
ALOGE("ERROR - openOutputStream(), SPDIF open returned %d",
status);
delete outputStream;
outputStream = NULL;
}
} else {
ALOGE("ERROR - openOutputStream(), SPDIFEncoder does not support format 0x%08x",
originalConfig.format);
}
}
}
*ppStreamOut = outputStream;
return status;
}
这里创建 AudioStreamOut
对象并执行其 open()
操作。当 open()
执行失败时,则可能会根据配置的音频数据格式,尝试创建 SpdifStreamOut
对象并执行其 open()
操作。
AudioStreamOut
的 open()
操作定义 (位于 frameworks/av/services/audioflinger/AudioStreamOut.cpp) 如下:
status_t AudioStreamOut::open(
audio_io_handle_t handle,
audio_devices_t deviceType,
struct audio_config *config,
const char *address)
{
sp<StreamOutHalInterface> outStream;
audio_output_flags_t customFlags = (config->format == AUDIO_FORMAT_IEC61937)
? (audio_output_flags_t)(flags | AUDIO_OUTPUT_FLAG_IEC958_NONAUDIO)
: flags;
int status = hwDev()->openOutputStream(
handle,
deviceType,
customFlags,
config,
address,
&outStream);
ALOGD("AudioStreamOut::open(), HAL returned "
" stream %p, sampleRate %d, Format %#x, "
"channelMask %#x, status %d",
outStream.get(),
config->sample_rate,
config->format,
config->channel_mask,
status);
// Some HALs may not recognize AUDIO_FORMAT_IEC61937. But if we declare
// it as PCM then it will probably work.
if (status != NO_ERROR && config->format == AUDIO_FORMAT_IEC61937) {
struct audio_config customConfig = *config;
customConfig.format = AUDIO_FORMAT_PCM_16_BIT;
status = hwDev()->openOutputStream(
handle,
deviceType,
customFlags,
&customConfig,
address,
&outStream);
ALOGV("AudioStreamOut::open(), treat IEC61937 as PCM, status = %d", status);
}
if (status == NO_ERROR) {
stream = outStream;
mHalFormatHasProportionalFrames = audio_has_proportional_frames(config->format);
status = stream->getFrameSize(&mHalFrameSize);
LOG_ALWAYS_FATAL_IF(status != OK, "Error retrieving frame size from HAL: %d", status);
LOG_ALWAYS_FATAL_IF(mHalFrameSize <= 0, "Error frame size was %zu but must be greater than"
" zero", mHalFrameSize);
}
return status;
}
这里请求 Audio HAL 服务打开音频输出流,当失败时,根据配置的音频数据格式,则可能会尝试换一种音频数据格式再打开一次。
AudioFlinger
在打开音频输入输出设备时,创建的各种 Thread 具有如下这样的继承层次结构:
![](https://img.haomeiwen.com/i1315506/1c8cd0a5579c6ee7.png)
音频输入描述符 AudioInputDescriptor
在 open()
操作中请求 AudioFlinger
打开音频输入设备,打开音频输入设备的 AudioFlinger::openInput()
函数定义 (位于 frameworks/av/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp) 如下:
status_t AudioFlinger::openInput(const media::OpenInputRequest& request,
media::OpenInputResponse* response)
{
Mutex::Autolock _l(mLock);
if (request.device.type == AUDIO_DEVICE_NONE) {
return BAD_VALUE;
}
audio_io_handle_t input = VALUE_OR_RETURN_STATUS(
aidl2legacy_int32_t_audio_io_handle_t(request.input));
audio_config_t config = VALUE_OR_RETURN_STATUS(
aidl2legacy_AudioConfig_audio_config_t(request.config));
AudioDeviceTypeAddr device = VALUE_OR_RETURN_STATUS(
aidl2legacy_AudioDeviceTypeAddress(request.device));
sp<ThreadBase> thread = openInput_l(
VALUE_OR_RETURN_STATUS(aidl2legacy_int32_t_audio_module_handle_t(request.module)),
&input,
&config,
device.mType,
device.address().c_str(),
VALUE_OR_RETURN_STATUS(aidl2legacy_AudioSourceType_audio_source_t(request.source)),
VALUE_OR_RETURN_STATUS(aidl2legacy_int32_t_audio_input_flags_t_mask(request.flags)),
AUDIO_DEVICE_NONE,
String8{});
response->input = VALUE_OR_RETURN_STATUS(legacy2aidl_audio_io_handle_t_int32_t(input));
response->config = VALUE_OR_RETURN_STATUS(legacy2aidl_audio_config_t_AudioConfig(config));
response->device = request.device;
if (thread != 0) {
// notify client processes of the new input creation
thread->ioConfigChanged(AUDIO_INPUT_OPENED);
return NO_ERROR;
}
return NO_INIT;
}
sp<AudioFlinger::ThreadBase> AudioFlinger::openInput_l(audio_module_handle_t module,
audio_io_handle_t *input,
audio_config_t *config,
audio_devices_t devices,
const char* address,
audio_source_t source,
audio_input_flags_t flags,
audio_devices_t outputDevice,
const String8& outputDeviceAddress)
{
AudioHwDevice *inHwDev = findSuitableHwDev_l(module, devices);
if (inHwDev == NULL) {
*input = AUDIO_IO_HANDLE_NONE;
return 0;
}
// Audio Policy can request a specific handle for hardware hotword.
// The goal here is not to re-open an already opened input.
// It is to use a pre-assigned I/O handle.
if (*input == AUDIO_IO_HANDLE_NONE) {
*input = nextUniqueId(AUDIO_UNIQUE_ID_USE_INPUT);
} else if (audio_unique_id_get_use(*input) != AUDIO_UNIQUE_ID_USE_INPUT) {
ALOGE("openInput_l() requested input handle %d is invalid", *input);
return 0;
} else if (mRecordThreads.indexOfKey(*input) >= 0) {
// This should not happen in a transient state with current design.
ALOGE("openInput_l() requested input handle %d is already assigned", *input);
return 0;
}
audio_config_t halconfig = *config;
sp<DeviceHalInterface> inHwHal = inHwDev->hwDevice();
sp<StreamInHalInterface> inStream;
status_t status = inHwHal->openInputStream(
*input, devices, &halconfig, flags, address, source,
outputDevice, outputDeviceAddress, &inStream);
ALOGV("openInput_l() openInputStream returned input %p, devices %#x, SamplingRate %d"
", Format %#x, Channels %#x, flags %#x, status %d addr %s",
inStream.get(),
devices,
halconfig.sample_rate,
halconfig.format,
halconfig.channel_mask,
flags,
status, address);
// If the input could not be opened with the requested parameters and we can handle the
// conversion internally, try to open again with the proposed parameters.
if (status == BAD_VALUE &&
audio_is_linear_pcm(config->format) &&
audio_is_linear_pcm(halconfig.format) &&
(halconfig.sample_rate <= AUDIO_RESAMPLER_DOWN_RATIO_MAX * config->sample_rate) &&
(audio_channel_count_from_in_mask(halconfig.channel_mask) <= FCC_LIMIT) &&
(audio_channel_count_from_in_mask(config->channel_mask) <= FCC_LIMIT)) {
// FIXME describe the change proposed by HAL (save old values so we can log them here)
ALOGV("openInput_l() reopening with proposed sampling rate and channel mask");
inStream.clear();
status = inHwHal->openInputStream(
*input, devices, &halconfig, flags, address, source,
outputDevice, outputDeviceAddress, &inStream);
// FIXME log this new status; HAL should not propose any further changes
}
if (status == NO_ERROR && inStream != 0) {
AudioStreamIn *inputStream = new AudioStreamIn(inHwDev, inStream, flags);
if ((flags & AUDIO_INPUT_FLAG_MMAP_NOIRQ) != 0) {
sp<MmapCaptureThread> thread =
new MmapCaptureThread(this, *input, inHwDev, inputStream, mSystemReady);
mMmapThreads.add(*input, thread);
ALOGV("openInput_l() created mmap capture thread: ID %d thread %p", *input,
thread.get());
return thread;
} else {
// Start record thread
// RecordThread requires both input and output device indication to forward to audio
// pre processing modules
sp<RecordThread> thread = new RecordThread(this, inputStream, *input, mSystemReady);
mRecordThreads.add(*input, thread);
ALOGV("openInput_l() created record thread: ID %d thread %p", *input, thread.get());
return thread;
}
}
*input = AUDIO_IO_HANDLE_NONE;
return 0;
}
这个操作的执行过程如下:
- 根据音频硬件模块句柄和设备类型查找适当的音频硬件模块;
- 构造音频输入设备 ID;
- 直接请求设备 HAL 接口对象打开音频输入流;
- 上一步中以请求的参数打开音频输入流失败时,还会处理内部转换,并尝试再次以适当的参数打开;
- 为音频输入流创建
AudioStreamIn
对象; - 根据音频硬件设备的标记配置创建不同的 Thread,这些标记主要来自于音频策略 XML 配置文件。
网友评论