本分解析android audio是如何选择device的
0 是select_devices(),函数的主干,后面小节对其中重要或难点 按层次作了解析。
参考链接:
https://blog.csdn.net/weijory/article/details/62422869
https://blog.csdn.net/edmond999/article/details/107843761
0. select_devices
# code/vendor/qcom/opensource/audio-hal/primary-hal/hal/audio_hw.c
int select_devices(struct audio_device *adev, audio_usecase_t uc_id)
{
// 1. 通过uc_id获取usecase
usecase = get_usecase_from_list(adev, uc_id);
// 2. 通过usecase,获取snd_device
// 如果是播放模式,获取输出设备 和 设备列表
if (usecase->type == PCM_PLAYBACK) {
out_snd_device = platform_get_output_snd_device(adev->platform,
usecase->stream.out,
usecase->type);
assign_devices(&usecase->device_list, &usecase->stream.out->device_list);
// 如果是录音模式,获取输入设备
} else if (usecase->type == PCM_CAPTURE) {
in_snd_device = platform_get_input_snd_device(adev->platform,
priority_in,
&out_devices,
usecase->type);
} else ...
// 3. 启用snd_device
enable_snd_device(adev, out_snd_device);
enable_snd_device(adev, in_snd_device);
// 4. 启用audio_route
enable_audio_route(adev, usecase);
}
1. enable_snd_device
int enable_snd_device(struct audio_device *adev,
snd_device_t snd_device)
{
// 1.获取设备名
platform_get_snd_device_name_extn(adev->platform, snd_device, device_name)
// 2. 根据snd_device的不同情况, 进行一系列前置操作,然后启用and更新audio_path
// 2.1 snd_device支持,并且已启用外放保护
if (platform_can_enable_spkr_prot_on_device(snd_device) &&
audio_extn_spkr_prot_is_enabled()) {
// 能否正常获取acdb_id
if (platform_get_spkr_prot_acdb_id(snd_device) < 0) {
goto err;
}
audio_extn_dev_arbi_acquire(snd_device);
// 3. 打开带保护的设备,保护算法也开始运作。应用and更新path
if (audio_extn_spkr_prot_start_processing(snd_device)) {
ALOGE("%s: spkr_start_processing failed", __func__);
audio_extn_dev_arbi_release(snd_device);
goto err;
}
// 2.2 如果设备可分割
} else if (platform_split_snd_device(adev->platform,
snd_device,
&num_devices,
new_snd_devices) == 0) {
for (i = 0; i < num_devices; i++) {
enable_snd_device(adev, new_snd_devices[i]);
}
// 3. 设置speaker_gain 。应用and更新path
platform_set_speaker_gain_in_combo(adev, snd_device, true);
// 2.3
} else {
// 2.3.1 启用island power mode
// 2.3.2
// 3. 应用and更新path
audio_route_apply_and_update_path(adev->audio_route, device_name);
}
}
1.1 audio_route_apply_and_update_path
audio_route_apply_and_update_path() 函数分为两步:
audio_route_apply_path() 和
audio_route_update_path ()
1.1.1 audio_route_apply_path
int audio_route_apply_path(struct audio_route *ar, const char *name)
{
// 根据device_name获取path
path = path_get_by_name(ar, name);
path_print(ar, path);
path_apply(ar, path);
}
1.1.2 audio_route_update_path
static int audio_route_update_path(struct audio_route *ar, const char *name, int direction)
{
// 根据不同的ctl类型
if (type == MIXER_CTL_TYPE_BYTE) {
// 1. 如果值有改变
if (ms->old_value.bytes[j] != ms->new_value.bytes[j]) {
// 2. 如果反转且激活次数 > 0
if (reverse && ms->active_count > 0) {
// 3. 复制旧值给新值
memcpy(ms->new_value.bytes, ms->old_value.bytes,
ms->num_values * value_sz);
} else {
// 3. 写ms->num_values到 ms->ctl
mixer_ctl_set_array(ms->ctl, ms->new_value.bytes, ms->num_values);
memcpy(ms->old_value.bytes, ms->new_value.bytes, ms->num_values * value_sz);
}
}
} else if (type == MIXER_CTL_TYPE_ENUM) {
...
} else if (ms->old_value.integer[j] != ms->new_value.integer[j]) {
...
}
}
static int path_apply(struct audio_route *ar, struct mixer_path *path)
{
// 1. 判断类型是否支持
...
// 2. 复制 。。。 进audio_route
memcpy(ar->mixer_state[ctl_index].new_value.ptr, path->setting[i].value.ptr,
path->setting[i].num_values * value_sz);
}
2. enable_audio_route
int enable_audio_route(struct audio_device *adev,
struct audio_usecase *usecase)
{
// 1. 根据usecase获取snd_device
if (usecase->type == PCM_CAPTURE) {
snd_device = usecase->in_snd_device;
} else if ( ... ) {
} else {
snd_device = usecase->out_snd_device;
}
// 2. 根据 snd_device 和 usecase 拼接出mixer_path
strlcpy(mixer_path, use_case_table[usecase->id], sizeof(mixer_path));
platform_add_backend_name(mixer_path, snd_device, usecase);
//
audio_route_apply_and_update_path(adev->audio_route, mixer_path);
}