接着上一篇Android AudioFlinger(一)——初识AndroidAudio Flinger,我们继续分析AndroidAudio,看看AndroidAudio Flinger 是如何实现设备管理的。
继续分析
按照职责来划分的画,audioflinger只是策略的执行者,策略的制定者其实是audiopolicyservice。比如某种stream类型对应什么设备、何时打开接口等等,都由它来决定。
目前Android音频系统中支持的音频设备接口主要有三种:
static const char * const audio_interfaces[] = {
AUDIO_HARDWARE_MODULE_ID_PRIMARY, //主要音频设备
AUDIO_HARDWARE_MODULE_ID_A2DP, //蓝牙音频设备
AUDIO_HARDWARE_MODULE_ID_USB, //USB音频设备
};
这三种音频设备对应的就是三个so库,那如何知道我需要加载哪一个库呢,下面我们就跟随代码来看一看。
AudioHwDevice* AudioFlinger::findSuitableHwDev_l(
audio_module_handle_t module,
audio_devices_t devices)
{
// if module is 0, the request comes from an old policy manager and we should load
// well known modules
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]);
}
...
return NULL;
}
这里可以看到将audio_interface传入了loadHwModule_l函数中,循环遍历了三种音频设备都会调用一遍。
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);
....
audio_module_handle_t handle = (audio_module_handle_t) nextUniqueId(AUDIO_UNIQUE_ID_USE_MODULE);
mAudioHwDevs.add(handle, new AudioHwDevice(handle, name, dev, flags));
ALOGI("loadHwModule() Loaded %s audio interface, handle %d", name, handle);
return handle;
}
这个函数我们主要看两个地方,openDevice打开了一个音频设备,而且是根据我们for循环穿下来的name打开的。之后调用的mAudioHwDevs.add将设备添加到vector容器中,很明显我们需要先看下如何打开的这设备。
// /frameworks/av/media/libaudiohal/DevicesFactoryHalInterface.cpp
sp<DevicesFactoryHalInterface> DevicesFactoryHalInterface::create() {
if (hardware::audio::V4_0::IDevicesFactory::getService() != nullptr) {
return new V4_0::DevicesFactoryHalHybrid();
}
if (hardware::audio::V2_0::IDevicesFactory::getService() != nullptr) {
return new DevicesFactoryHalHybrid();
}
return nullptr;
}
这段代码表示的是mDevicesFactoryHal的创建过程,很明显,mDevicesFactoryHal就等于DevicesFactoryHalHybrid()。
status_t DevicesFactoryHalHybrid::openDevice(const char *name, sp<DeviceHalInterface> *device) {
if (mHidlFactory != 0 && strcmp(AUDIO_HARDWARE_MODULE_ID_A2DP, name) != 0 &&
strcmp(AUDIO_HARDWARE_MODULE_ID_HEARING_AID, name) != 0) {
return mHidlFactory->openDevice(name, device);
}
return mLocalFactory->openDevice(name, device);
}
这里会做一个判断,如果不是蓝牙也不是hearing就会调用mHidlFactory,我们就走这里看下,不是蓝牙的情况,也就是说primary和usb都会走这里获取。
///frameworks/av/media/libaudiohal/4.0/DevicesFactoryHalHidl.cpp
status_t DevicesFactoryHalHidl::openDevice(const char *name, sp<DeviceHalInterface> *device) {
if (mDevicesFactory == 0) return NO_INIT;
Result retval = Result::NOT_INITIALIZED;
Return<void> ret = mDevicesFactory->openDevice(
name,
[&](Result r, const sp<IDevice>& result) {
retval = r;
if (retval == Result::OK) {
*device = new DeviceHalHidl(result);
}
});
...
return FAILED_TRANSACTION;
}
这里也没做什么只是继续调用了mDevicesFactory->openDevice并传入了name和一个回调函数,采用了lamda表达式,可以进一步了解下这个写法。
///hardware/interfaces/audio/core/all-versions/default/include/core/all-versions/default/DevicesFactory.impl.h
Return<void> DevicesFactory::openDevice(const hidl_string& moduleName, openDevice_cb _hidl_cb) {
if (moduleName == AUDIO_HARDWARE_MODULE_ID_PRIMARY) {
return openDevice<PrimaryDevice>(moduleName.c_str(), _hidl_cb);
}
return openDevice(moduleName.c_str(), _hidl_cb);
}
Return<void> DevicesFactory::openPrimaryDevice(openPrimaryDevice_cb _hidl_cb) {
return openDevice<PrimaryDevice>(AUDIO_HARDWARE_MODULE_ID_PRIMARY, _hidl_cb);
}
Return<void> DevicesFactory::openDevice(const char* moduleName, openDevice_cb _hidl_cb) {
return openDevice<implementation::Device>(moduleName, _hidl_cb);
}
template <class DeviceShim, class Callback>
Return<void> DevicesFactory::openDevice(const char* moduleName, Callback _hidl_cb) {
audio_hw_device_t* halDevice;
Result retval(Result::INVALID_ARGUMENTS);
sp<DeviceShim> result;
int halStatus = loadAudioInterface(moduleName, &halDevice);
if (halStatus == OK) {
result = new DeviceShim(halDevice);
retval = Result::OK;
} else if (halStatus == -EINVAL) {
retval = Result::NOT_INITIALIZED;
}
_hidl_cb(retval, result);
return Void();
}
// static
int DevicesFactory::loadAudioInterface(const char* if_name, audio_hw_device_t** dev) {
const hw_module_t* mod;
int rc;
rc = hw_get_module_by_class(AUDIO_HARDWARE_MODULE_ID, if_name, &mod);
if (rc) {
ALOGE("%s couldn't load audio hw module %s.%s (%s)", __func__, AUDIO_HARDWARE_MODULE_ID,
if_name, strerror(-rc));
goto out;
}
rc = audio_hw_device_open(mod, dev);
if (rc) {
ALOGE("%s couldn't open audio hw device in %s.%s (%s)", __func__, AUDIO_HARDWARE_MODULE_ID,
if_name, strerror(-rc));
goto out;
}
if ((*dev)->common.version < AUDIO_DEVICE_API_VERSION_MIN) {
ALOGE("%s wrong audio hw device version %04x", __func__, (*dev)->common.version);
rc = -EINVAL;
audio_hw_device_close(*dev);
goto out;
}
return OK;
out:
*dev = NULL;
return rc;
}
这块代码相对简单就没有什么一次往下追就可以看到最终调用了hw_get_module_by_class,并且传入了name,AUDIO_HARDWARE_MODULE_ID就是hal层会设置的ID,相互匹配上。
// /hardware/libhardware/hardware.c
#if defined(__LP64__)
#define HAL_LIBRARY_PATH1 "/system/lib64/hw"
#define HAL_LIBRARY_PATH2 "/vendor/lib64/hw"
#define HAL_LIBRARY_PATH3 "/odm/lib64/hw"
#else
#define HAL_LIBRARY_PATH1 "/system/lib/hw"
#define HAL_LIBRARY_PATH2 "/vendor/lib/hw"
#define HAL_LIBRARY_PATH3 "/odm/lib/hw"
#endif
static const char *variant_keys[] = {
"ro.hardware", /* This goes first so that it can pick up a different
file on the emulator. */
"ro.product.board",
"ro.board.platform",
"ro.arch"
};
int hw_get_module_by_class(const char *class_id, const char *inst,
const struct hw_module_t **module)
{
if (inst)
snprintf(name, PATH_MAX, "%s.%s", class_id, inst);
else
strlcpy(name, class_id, PATH_MAX);
...
snprintf(prop_name, sizeof(prop_name), "ro.hardware.%s", name);
if (property_get(prop_name, prop, NULL) > 0) {
if (hw_module_exists(path, sizeof(path), name, prop) == 0) {
goto found;
}
}
/* Loop through the configuration variants looking for a module */
for (i=0 ; i<HAL_VARIANT_KEYS_COUNT; i++) {
if (property_get(variant_keys[i], prop, NULL) == 0) {
continue;
}
if (hw_module_exists(path, sizeof(path), name, prop) == 0) {
goto found;
}
}
/* Nothing found, try the default */
if (hw_module_exists(path, sizeof(path), name, "default") == 0) {
goto found;
}
return -ENOENT;
found:
/* load the module, if this fails, we're doomed, and we should not try
* to load a different variant. */
return load(class_id, path, module);
}
到这里就会去获取你得项目代号,通过prop获取,可以看到variant_keys里面有四个属性,一次判断,有其中之一匹配上即可,如果匹配不上就会使用默认的primary,库就在对应的vendor、system、odm下搜索。到这里我们设备so库的查找就结束了,只要我们配置好项目属性值,与so库对应即可查询使用。
回到我们一开始说的地方,loadHwModule_l函数中还做了一件是,就是将获取的设备添加到mAudioHwDevs键值对中,其中key值由(audio_module_handle_t)
nextUniqueId(AUDIO_UNIQUE_ID_USE_MODULE);获取,这样可以保证这个值全局唯一。
现在我们完成audio interface的加载,但是每一个interface里面包含的设备又有非常多个,目前Android支持的就如下代码所示。
enum { AUDIO_DEVICE_NONE = 0x0, /* reserved bits */ AUDIO_DEVICE_BIT_IN = 0x80000000, AUDIO_DEVICE_BIT_DEFAULT = 0x40000000, /* output devices */这些是输出声音的设备,就是我们听声音的设备 AUDIO_DEVICE_OUT_EARPIECE = 0x1, // 听筒 AUDIO_DEVICE_OUT_SPEAKER = 0x2, // 扬声器 AUDIO_DEVICE_OUT_WIRED_HEADSET = 0x4, // 线控耳机,可以通过耳机控制远端播放、暂停、音量调节等功能的耳机 AUDIO_DEVICE_OUT_WIRED_HEADPHONE = 0x8, // 普通耳机,只能听,不能操控播放 AUDIO_DEVICE_OUT_BLUETOOTH_SCO = 0x10, // 单声道蓝牙耳机,十进制16 AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET = 0x20, // 车载免提蓝牙设备,十进制32 AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT = 0x40, // 立体声蓝牙耳机,十进制64 AUDIO_DEVICE_OUT_BLUETOOTH_A2DP = 0x80, // 蓝牙耳机 AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES = 0x100, // 十进制256 AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER = 0x200, // 十进制512 AUDIO_DEVICE_OUT_AUX_DIGITAL = 0x400, // HDMI输出 AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET = 0x800, // 十进制2048 AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET = 0x1000, // 十进制4096 AUDIO_DEVICE_OUT_USB_ACCESSORY = 0x2000, AUDIO_DEVICE_OUT_USB_DEVICE = 0x4000, //USB设备 AUDIO_DEVICE_OUT_REMOTE_SUBMIX = 0x8000, AUDIO_DEVICE_OUT_DEFAULT = AUDIO_DEVICE_BIT_DEFAULT, /* input devices */ (这里主要是接收声音的设备就是我们对着说话的设备) AUDIO_DEVICE_IN_COMMUNICATION = AUDIO_DEVICE_BIT_IN | 0x1, AUDIO_DEVICE_IN_AMBIENT = AUDIO_DEVICE_BIT_IN | 0x2, AUDIO_DEVICE_IN_BUILTIN_MIC = AUDIO_DEVICE_BIT_IN | 0x4, //手机自带MIC AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET = AUDIO_DEVICE_BIT_IN | 0x8, //蓝牙耳机 AUDIO_DEVICE_IN_WIRED_HEADSET = AUDIO_DEVICE_BIT_IN | 0x10, //3.5MM线性耳机 AUDIO_DEVICE_IN_AUX_DIGITAL = AUDIO_DEVICE_BIT_IN | 0x20, AUDIO_DEVICE_IN_VOICE_CALL = AUDIO_DEVICE_BIT_IN | 0x40, AUDIO_DEVICE_IN_BACK_MIC = AUDIO_DEVICE_BIT_IN | 0x80, AUDIO_DEVICE_IN_REMOTE_SUBMIX = AUDIO_DEVICE_BIT_IN | 0x100, AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET = AUDIO_DEVICE_BIT_IN | 0x200, AUDIO_DEVICE_IN_DGTL_DOCK_HEADSET = AUDIO_DEVICE_BIT_IN | 0x400, AUDIO_DEVICE_IN_USB_ACCESSORY = AUDIO_DEVICE_BIT_IN | 0x800, AUDIO_DEVICE_IN_USB_DEVICE = AUDIO_DEVICE_BIT_IN | 0x1000, //USB耳机 AUDIO_DEVICE_IN_DEFAULT = AUDIO_DEVICE_BIT_IN | AUDIO_DEVICE_BIT_DEFAULT,};
下面我们来继续分析,audioflinger是如何打开一个output通道的。打开output通道在audioflinger内的函数是openOutput:
sp<AudioFlinger::ThreadBase> AudioFlinger::openOutput_l(audio_module_handle_t module,
audio_io_handle_t *output,
audio_config_t *config,
audio_devices_t devices,
const String8& address,
audio_output_flags_t flags)
{
AudioHwDevice *outHwDev = findSuitableHwDev_l(module, devices);
if (outHwDev == NULL) {
return 0;
}
if (*output == AUDIO_IO_HANDLE_NONE) {
*output = nextUniqueId(AUDIO_UNIQUE_ID_USE_OUTPUT);
}
mHardwareStatus = AUDIO_HW_OUTPUT_OPEN;
AudioStreamOut *outputStream = NULL;
status_t status = outHwDev->openOutputStream(
&outputStream,
*output,
devices,
flags,
config,
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,
devices, AUDIO_DEVICE_NONE, mSystemReady);
mMmapThreads.add(*output, thread);
return thread;
} else {
sp<PlaybackThread> thread;
if (flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
thread = new OffloadThread(this, outputStream, *output, devices, mSystemReady);
} else if ((flags & AUDIO_OUTPUT_FLAG_DIRECT)
|| !isValidPcmSinkFormat(config->format)
|| !isValidPcmSinkChannelMask(config->channel_mask)) {
thread = new DirectOutputThread(this, outputStream, *output, devices, mSystemReady);
} else {
thread = new MixerThread(this, outputStream, *output, devices, mSystemReady);
}
mPlaybackThreads.add(*output, thread);
return thread;
}
}
return 0;
}
上面代码的主要做了以下操作:
查找合适的音频接口设备(findSuitableHwDev_l),这里最后调用的就是我们一开始讲道理的loadHwModule_l函数。
创建音频流,通过openOutputStream获得了一个AudioStreamOut。
创建播放线程PlaybackThread
outHwDev用于记录了一个打开的音频接口设备,数据类型是audioHwDevice,就是通过刚刚分析的键值对mAudioHwDevs中获取到,对应的就是HAL的audio_hw_device,里面实现了HAL的共有属性,setMasterMute、setMasterVolume、open_output_stream等。
struct audio_module {
struct hw_module_t common;
};
struct audio_hw_device {
struct hw_device_t common;
int (*set_master_volume)(struct audio_hw_device *dev, float volume);
int (*set_parameters)(struct audio_hw_device *dev, const char *kv_pairs);
int (*open_output_stream)(struct audio_hw_device *dev,
audio_io_handle_t handle,
audio_devices_t devices,
audio_output_flags_t flags,
struct audio_config *config,
struct audio_stream_out **stream_out,
const char *address);
int (*set_master_mute)(struct audio_hw_device *dev, bool mute);
};
下面我们来分别讲一下每一步都是如何实现的
如何实现
1. 第一步:findSuitableHwDev_l
当module为0的时候,加载所有的音频设备interface,然后遍历查找符合我们要求的device。
当module不为0的时候直接通过module索引查找对应的device,就从我们一开始就提到过的mAudioHwDevs容器中获取。
AudioHwDevice* AudioFlinger::findSuitableHwDev_l(
audio_module_handle_t module,
audio_devices_t devices)
{
// if module is 0, the request comes from an old policy manager and we should load
// well known modules
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 & devices) == devices) {
return audioHwDevice;
}
}
} else {
// check a match for the requested module handle
AudioHwDevice *audioHwDevice = mAudioHwDevs.valueFor(module);
if (audioHwDevice != NULL) {
return audioHwDevice;
}
}
return NULL;
}
2. 第二步:outHwDev->openOutputStream
这块比较抽象,我这里拿MTK平台的代码举例看一下,可以看到这里首先就是申请了一块内存给legacy_stream_out,这里也包含了audio_stream_out ,然后给其中的函数指针赋值,比如set_parameters 我们会经常用到,最终实现就是out_set_parameters,再往下我们就不分析了,过于底层,后面会有专门的篇章讲解hal层的实现。
struct legacy_stream_out {
struct audio_stream_out stream;
AudioMTKStreamOutInterface *legacy_out;
};
static int adev_open_output_stream(struct audio_hw_device *dev,
audio_io_handle_t handle,
audio_devices_t devices,
audio_output_flags_t flags,
struct audio_config *config,
struct audio_stream_out **stream_out,
const char *address __unused) {
...
struct legacy_stream_out *out;
out = (struct legacy_stream_out *)calloc(1, sizeof(*out));
if (!out) {
return -ENOMEM;
}
...
out->stream.common.get_sample_rate = out_get_sample_rate;
out->stream.common.set_sample_rate = out_set_sample_rate;
out->stream.common.get_buffer_size = out_get_buffer_size;
out->stream.common.get_channels = out_get_channels;
out->stream.common.get_format = out_get_format;
out->stream.common.set_format = out_set_format;
out->stream.common.standby = out_standby;
out->stream.common.dump = out_dump;
out->stream.common.set_parameters = out_set_parameters;
out->stream.common.get_parameters = out_get_parameters;
out->stream.common.add_audio_effect = out_add_audio_effect;
out->stream.common.remove_audio_effect = out_remove_audio_effect;
out->stream.get_latency = out_get_latency;
out->stream.set_volume = out_set_volume;
out->stream.write = out_write;
out->stream.get_render_position = out_get_render_position;
out->stream.get_next_write_timestamp = out_get_next_write_timestamp;
out->stream.set_callback = out_set_callback;
out->stream.get_presentation_position = out_get_presentation_position;
out->stream.update_source_metadata = out_update_source_metadata;
out->stream.pause = out_pause;
out->stream.resume = out_resume;
out->stream.drain = out_drain;
out->stream.flush = out_flush;
*stream_out = &out->stream;
return 0;
err_open:
free(out);
*stream_out = NULL;
return ret;
}
3. 第三步:PlaybackThread。
现在我们打开了output通道,那么如何往里写入音频数据呢?这就是PlaybackThread的作用。
这里我们看到有多种thread,都有什么区别呢?
MmapPlaybackThread是用于高效处理音频播放的线程,借助内存映射技术降低延迟、提高性能,尤其适合需要低延迟和高吞吐量的音频应用场景。
OffloadThread 在音频框架中是一个专门处理音频卸载(offload)任务的线程,主要用于将音频处理的某些部分卸载到硬件上,以提高性能、降低 CPU 负担,并提供更低延迟的音频处理。
DirectOutputThread 的核心作用是通过减少音频数据处理的步骤和延迟,提供高效、低延迟的音频输出。它适用于那些对音频输出延迟要求较高的应用,如游戏音效、实时音频通信等,确保音频数据能够直接、迅速地送入硬件进行播放。
MixerThread 是音频框架中的一个重要线程,主要负责音频混音的处理。它的任务是将来自不同音频流(例如多个应用程序或音频源)的音频数据进行混合处理,以便最终输出到音频硬件(如扬声器、耳机等)。这个过程通常包括调节音量、应用音效(如回声消除、均衡等)以及将不同音频流合成一个单一的音频输出流。
这些都继承了PlaybackThread,audioflinger中主要使用下面两个全局变量来存储thread。
DefaultKeyedVector< audio_io_handle_t, sp<PlaybackThread> > mPlaybackThreads;
DefaultKeyedVector< audio_io_handle_t, sp<RecordThread> > mRecordThreads;
下面我们先分析下MixerThread这个线程.
首先就是创建了一个AudioMixer对象,这个就是混音处理的关键。然后检查是不是DUPLICATING,接着创建了一个AudioStreamOutSink,判断是否使用fast mixer。
// /frameworks/av/services/audioflinger/Threads.cpp
AudioFlinger::MixerThread::MixerThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output,
audio_io_handle_t id, audio_devices_t device, bool systemReady, type_t type)
: PlaybackThread(audioFlinger, output, id, device, type, systemReady),
mFastMixerFutex(0),
mMasterMono(false)
{
mAudioMixer = new AudioMixer(mNormalFrameCount, mSampleRate);
if (type == DUPLICATING) {
// The Duplicating thread uses the AudioMixer and delivers data to OutputTracks
// (downstream MixerThreads) in DuplicatingThread::threadLoop_write().
// Do not create or use mFastMixer, mOutputSink, mPipeSink, or mNormalSink.
return;
}
mOutputSink = new AudioStreamOutSink(output->stream);
if (initFastMixer) {
...
}
....
}
到这里我们的mixer就创建成功了,但是何时去运行呢,因为音频数据的传输是循环不断的存取,但是这个函数里面并没有一个loop的操作,现在我回回过头来看下mPlaybackThreads的定义,他的键是一个audio_io_handle_t变量而值是一个sp强指针类型,所以PlaybackThread一定继承自Re’fBase,那他在被第一次引用的时候就会调用onFirstRef,实现如下:
void AudioFlinger::PlaybackThread::onFirstRef()
{
run(mThreadName, ANDROID_PRIORITY_URGENT_AUDIO);
}
这里很简单就调用了一个run方法去开起了一个ThreadLoop线程
bool AudioFlinger::PlaybackThread::threadLoop()
{
...
}
到此我们的音频设备的管理就介绍完了,下一章我们进一步研究下PlaybackThread的循环主题具体做了什么。