https://blog.csdn.net/xuesen_lin/article/details/8805076?utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromMachineLearnPai2%7Edefault-3.control&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromMachineLearnPai2%7Edefault-3.control
AudioFlinger加载不同的 audio.primary.so或者audio.primary.default.so 、audio.a2dp.so或者audio.a2dp.default.so 、audio.usb.so或者audio.usb.default.so
指定的audiointerface,比如“primary”、“a2dp”或者“usb”。函数load_audio_interface用来加载设备所需的库文件,然后打开设备并创建一个audio_hw_device_t实例。音频接口设备所对应的库文件名称是有一定格式的,比如a2dp的模块名可能是audio.a2dp.so或者audio.a2dp.default.so
————————————————
版权声明:本文为CSDN博主「林学森」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/xuesen_lin/article/details/8805076
每种音频设备接口由一个对应的so库提供支持。那么AudioFlinger怎么会知道当前设备中支持上述的哪些接口,每种接口又支持哪些具体的音频设备呢?这是AudioPolicyService的责任之一,即根据用户配置来指导AudioFlinger加载设备接口
目前Audio系统中支持的音频设备接口(Audio Interface)分为三大类,即:
/*frameworks/av/services/audioflinger/AudioFlinger.cpp*/
static const char * const audio_interfaces[] = {
AUDIO_HARDWARE_MODULE_ID_PRIMARY, //主音频设备,必须存在
AUDIO_HARDWARE_MODULE_ID_A2DP, //蓝牙A2DP音频
AUDIO_HARDWARE_MODULE_ID_USB, //USB音频,早期的版本不支持
};
————————————————
版权声明:本文为CSDN博主「林学森」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/xuesen_lin/article/details/8805076
每种音频设备接口由一个对应的so库提供支持。那么AudioFlinger怎么会知道当前设备中支持上述的哪些接口,每种接口又支持哪些具体的音频设备呢?这是AudioPolicyService的责任之一,即根据用户配置来指导AudioFlinger加载设备接口。
当AudioPolicyManagerBase(AudioPolicyService中持有的Policy管理者,后面小节有详细介绍)构造时,它会读取厂商关于音频设备的描述文件(audio_policy.conf),然后据此来打开以上三类音频接口(如果存在的话)。这一过程最终会调用loadHwModule@AudioFlinger,如下所示:
————————————————
版权声明:本文为CSDN博主「林学森」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/xuesen_lin/article/details/8805076
/*frameworks/av/services/audioflinger*/
audio_module_handle_t AudioFlinger::loadHwModule(const char *name)/*name就是前面audio_interfaces 数组成员中的字符串*/
{
if (!settingsAllowed()) {
return 0;
}
Mutex::Autolock _l(mLock);
returnloadHwModule_l(name);
}
loadHwModule_l的函数分析
/Step 1. 是否已经添加了这个interface?/
/Step 2. 加载audio interface/
int rc = mDevicesFactoryHal->openDevice(name, &dev);
调用
status_t DevicesFactoryHalLocal::openDevice(const char *name, sp<DeviceHalInterface> *device) {
audio_hw_device_t *dev;
status_t rc = load_audio_interface(name, &dev);
if (rc == OK) {
*device = new DeviceHalLocal(dev);
}
return rc;
}
load_audio_interface调用
DevicesFactoryHalLocal.cpp
static status_t load_audio_interface(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 = BAD_VALUE;
audio_hw_device_close(*dev);
goto out;
}
return OK;
out:
*dev = NULL;
return rc;
}
hw_get_module_by_class调用
int hw_get_module_by_class(const char *class_id, const char *inst,
const struct hw_module_t **module)
{
int i = 0;
char prop[PATH_MAX] = {0};
char path[PATH_MAX] = {0};
char name[PATH_MAX] = {0};
char prop_name[PATH_MAX] = {0};
if (inst)
snprintf(name, PATH_MAX, "%s.%s", class_id, inst);
else
strlcpy(name, class_id, PATH_MAX);
/*
* Here we rely on the fact that calling dlopen multiple times on
* the same .so will simply increment a refcount (and not load
* a new copy of the library).
* We also assume that dlopen() is thread-safe.
*/
/* First try a property specific to the class and possibly instance */
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);
}
**hardware.c load调用 dlopen加载库文件**
static int load(const char *id,
const char *path,
const struct hw_module_t **pHmi)
{
int status = -EINVAL;
void *handle = NULL;
struct hw_module_t *hmi = NULL;
#ifdef __ANDROID_VNDK__
const bool try_system = false;
#else
const bool try_system = true;
#endif
/*
* load the symbols resolving undefined symbols before
* dlopen returns. Since RTLD_GLOBAL is not or'd in with
* RTLD_NOW the external symbols will not be global
*/
if (try_system &&
strncmp(path, HAL_LIBRARY_PATH1, strlen(HAL_LIBRARY_PATH1)) == 0) {
/* If the library is in system partition, no need to check
* sphal namespace. Open it with dlopen.
*/
handle = dlopen(path, RTLD_NOW);
} else {
handle = android_load_sphal_library(path, RTLD_NOW);
}
if (handle == NULL) {
char const *err_str = dlerror();
ALOGE("load: module=%s\n%s", path, err_str?err_str:"unknown");
status = -EINVAL;
goto done;
}
Android系统支持的音频设备(输出)
Device Name
Description
AUDIO_DEVICE_OUT_EARPIECE
听筒
AUDIO_DEVICE_OUT_SPEAKER
喇叭
AUDIO_DEVICE_OUT_WIRED_HEADSET
带话筒的耳机
AUDIO_DEVICE_OUT_WIRED_HEADPHONE
耳机
AUDIO_DEVICE_OUT_BLUETOOTH_SCO
SCO 蓝牙
AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET
SCO 蓝牙耳机
AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT
SCO 车载套件
AUDIO_DEVICE_OUT_BLUETOOTH_A2DP
A2DP 蓝牙
AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES
A2DP 蓝牙耳机
AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER
A2DP 蓝牙喇叭
AUDIO_DEVICE_OUT_AUX_DIGITAL
AUX IN
AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET
模拟dock headset
AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET
数字dock headset
AUDIO_DEVICE_OUT_USB_ACCESSORY
USB配件
AUDIO_DEVICE_OUT_USB_DEVICE
USB设备
AUDIO_DEVICE_OUT_DEFAULT
默认设备
AUDIO_DEVICE_OUT_ALL
上述每种设备只占int值一个bit位,这里是指上述设备的集合
AUDIO_DEVICE_OUT_ALL_A2DP
上述设备中与A2DP蓝牙相关的设备集合
AUDIO_DEVICE_OUT_ALL_SCO
上述设备中与SCO蓝牙相关的设备集合
AUDIO_DEVICE_OUT_ALL_USB
上述设备中与USB相关的设备集合
打开音频输出通道(output)在AF中对应的接口是openOutput()
audio_io_handle_t AudioFlinger::openOutput(audio_module_handle_tmodule, audio_devices_t *pDevices,
uint32_t *pSamplingRate,audio_format_t *pFormat,
audio_channel_mask_t *pChannelMask,
uint32_t *pLatencyMs, audio_output_flags_t flags)
{
/*入参中的module是由前面的loadHwModule 获得的,它是一个audiointerface的id号,可以通过此id在mAudioHwDevs中查找到对应的AudioHwDevice对象*/
status_t status;
PlaybackThread *thread =NULL;
…
audio_stream_out_t *outStream = NULL;
audio_hw_device_t*outHwDev;
…
/*Step 1. 查找相应的audio interface
outHwDev = findSuitableHwDev_l(module, *pDevices);
…
/*Step 2. 为设备打开一个输出流*/
mHardwareStatus =AUDIO_HW_OUTPUT_OPEN;
status = outHwDev->open_output_stream(outHwDev, id, *pDevices,(audio_output_flags_t)flags,
&config, &outStream);
mHardwareStatus =AUDIO_HW_IDLE;
…
if (status == NO_ERROR &&outStream != NULL) {
/*Step 3.生成AudioStreamOut*/
AudioStreamOut *output = newAudioStreamOut(outHwDev, outStream);
/*Step 4.创建PlaybackThread*/
if ((flags & AUDIO_OUTPUT_FLAG_DIRECT) ||(config.format != AUDIO_FORMAT_PCM_16_BIT) ||
(config.channel_mask != AUDIO_CHANNEL_OUT_STEREO)) {
thread = new DirectOutputThread(this, output, id, *pDevices);
} else {
thread = new MixerThread(this, output, id, *pDevices);
}
mPlaybackThreads.add(id,thread); //添加播放线程
…
/*Step 5.Primary output情况下的处理*/
if ((mPrimaryHardwareDev== NULL) &&flags & AUDIO_OUTPUT_FLAG_PRIMARY)) {
ALOGI("Usingmodule %d has the primary audio interface", module);
mPrimaryHardwareDev = outHwDev;
AutoMutexlock(mHardwareLock);
mHardwareStatus =AUDIO_HW_SET_MODE;
outHwDev->set_mode(outHwDev, mMode);
…
float initialVolume = 1.0;
mMasterVolumeSupportLvl = MVS_NONE;
mHardwareStatus = AUDIO_HW_GET_MASTER_VOLUME; //测试设备是否支持主音量获取
if ((NULL !=outHwDev->get_master_volume) &&
(NO_ERROR ==outHwDev->get_master_volume (outHwDev, &initialVolume))) {
mMasterVolumeSupportLvl = MVS_FULL;
} else {
mMasterVolumeSupportLvl = MVS_SETONLY;
initialVolume= 1.0;
}
mHardwareStatus = AUDIO_HW_SET_MASTER_VOLUME;//测试是否支持主音量设置
if ((NULL ==outHwDev->set_master_volume) ||
(NO_ERROR !=outHwDev->set_master_volume (outHwDev, initialVolume))) {
mMasterVolumeSupportLvl = MVS_NONE;
}
for (size_t i = 0; i <mAudioHwDevs.size(); i++) {
audio_hw_device_t *dev = mAudioHwDevs.valueAt(i)->hwDevice();
if ((dev !=mPrimaryHardwareDev) &&
(NULL !=dev->set_master_volume)) {
dev->set_master_volume(dev,initialVolume);
}
}
mHardwareStatus =AUDIO_HW_IDLE;
mMasterVolumeSW =(MVS_NONE == mMasterVolumeSupportLvl)? initialVolume: 1.0;
mMasterVolume = initialVolume;
}
return id;
}
return 0;
}
————————————————
版权声明:本文为CSDN博主「林学森」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/xuesen_lin/article/details/8805076
上面这段代码中,颜色加深的部分是我们接下来分析的重点,主要还是围绕outHwDev这个变量所做的一系列操作,即:
· 查找合适的音频接口设备(findSuitableHwDev_l)
· 创建音频输出流(通过open_output_stream获得一个audio_stream_out_t)
· 利用AudioStreamOut来封装audio_stream_out_t与audio_hw_device_t
· 创建播放线程(PlaybackThread)
· 如果当前设备是主设备,则还需要进行相应的设置,包括模式、主音量等等
显然,outHwDev用于记录一个打开的音频接口设备,它的数据类型是audio_hw_device_t,是由HAL规定的一个音频接口设备所应具有的属性集合,如下所示:
struct audio_hw_device {
struct hw_device_t common;
…
int (*set_master_volume)(struct audio_hw_device *dev, float volume);
int (*set_mode)(struct audio_hw_device *dev, audio_mode_t mode);
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);
…}
https://blog.csdn.net/xuesen_lin/article/details/8805076?utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromMachineLearnPai2%7Edefault-3.control&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromMachineLearnPai2%7Edefault-3.control