跳转至

pa_alsa_profile_set_probe

void pa_alsa_profile_set_probe(
        pa_alsa_profile_set *ps,               // ALSA 音频配置集合
        const char *dev_id,                    // 设备标识符
        const pa_sample_spec *ss,               // 采样规格
        unsigned default_n_fragments,           // 默认分片数
        unsigned default_fragment_size_msec) {  // 默认分片大小(毫秒)

    bool found_output = false, found_input = false;  // 是否找到输出和输入配置

    pa_alsa_profile *p, *last = NULL;      // 当前配置和上一个配置
    pa_alsa_profile **pp, **probe_order;   // 配置探测顺序数组
    pa_alsa_mapping *m;                     // ALSA 映射
    pa_hashmap *broken_inputs, *broken_outputs, *used_paths;  // 存储损坏输入、损坏输出和已使用路径的哈希映射
    pa_alsa_mapping *selected_fallback_input = NULL, *selected_fallback_output = NULL;  // 选定的回退输入和输出映射

    pa_assert(ps);           // 断言配置集合存在
    pa_assert(dev_id);       // 断言设备标识符存在
    pa_assert(ss);           // 断言采样规格存在

    // 创建哈希映射来存储损坏的输入、输出和已使用的路径
    broken_inputs = pa_hashmap_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
    broken_outputs = pa_hashmap_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
    used_paths = pa_hashmap_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);

    // 创建用于指示探测顺序的 probe_order 数组
    pp = probe_order = pa_xnew0(pa_alsa_profile *, pa_hashmap_size(ps->profiles) + 1);

    // 将配置按一定的优先级顺序添加到探测顺序中
    pp += add_profiles_to_probe(pp, ps->profiles, false, false);
    pp += add_profiles_to_probe(pp, ps->profiles, false, true);
    pp += add_profiles_to_probe(pp, ps->profiles, true, false);
    pp += add_profiles_to_probe(pp, ps->profiles, true, true);

    // 遍历探测顺序中的配置
    for (pp = probe_order; *pp; pp++) {
        uint32_t idx;
        p = *pp;

        // 跳过已经找到的回退配置,但仍然探测已选的回退配置
        if (found_input && p->fallback_input)
            if (selected_fallback_input == NULL || pa_idxset_get_by_index(p->input_mappings, 0) != selected_fallback_input)
                continue;
        if (found_output && p->fallback_output)
            if (selected_fallback_output == NULL || pa_idxset_get_by_index(p->output_mappings, 0) != selected_fallback_output)
                continue;

        // 跳过已经标记为支持的配置
        if (!p->supported) {
            // 最终化配置探测
            profile_finalize_probing(last, p);
            p->supported = true;

            // 检查输出映射是否能够打开
            if (p->output_mappings) {
                PA_IDXSET_FOREACH(m, p->output_mappings, idx) {
                    if (pa_hashmap_get(broken_outputs, m) == m) {
                        // 标记为不支持的配置
                        pa_log_debug("Skipping profile %s - will not be able to open output:%s", p->name, m->name);
                        p->supported = false;
                        break;
                    }
                }
            }

            // 检查输入映射是否能够打开
            if (p->input_mappings && p->supported) {
                PA_IDXSET_FOREACH(m, p->input_mappings, idx) {
                    if (pa_hashmap_get(broken_inputs, m) == m) {
                        // 标记为不支持的配置
                        pa_log_debug("Skipping profile %s - will not be able to open input:%s", p->name, m->name);
                        p->supported = false;
                        break;
                    }
                }
            }

            if (p->supported)
                pa_log_debug("Looking at profile %s", p->name);

            // 检查是否可以打开所有新的映射
            if (p->output_mappings && p->supported)
                PA_IDXSET_FOREACH(m, p->output_mappings, idx) {
                    // 检查是否已经打开
                    if (m->output_pcm)
                        continue;

                    // 尝试打开 PCM 设备
                    pa_log_debug("Checking for playback on %s (%s)", m->description, m->name);
                    if (!(m->output_pcm = mapping_open_pcm(m, ss, dev_id, m->exact_channels,
                                                           SND_PCM_STREAM_PLAYBACK,
                                                           default_n_fragments,
                                                           default_fragment_size_msec))) {
                        // 标记为不支持的配置
                        p->supported = false;
                        if (pa_idxset_size(p->output_mappings) == 1 &&
                            ((!p->input_mappings) || pa_idxset_size(p->input_mappings) == 0)) {
                            pa_log_debug("Caching failure to open output:%s", m->name);
                            pa_hashmap_put(broken_outputs, m, m);
                        }
                        break;
                    }

                    if (m->hw_device_index < 0)
                        mapping_query_hw_device(m, m->output_pcm);
                }

            // 检查输入映射是否能够打开
            if (p->input_mappings && p->supported)
                PA_IDXSET_FOREACH(m, p->input_mappings, idx) {
                    // 检查是否已经打开
                    if (m->input_pcm)
                        continue;

                    // 尝试打开 PCM 设备
                    pa_log_debug("Checking for recording on %s (%s)", m->description, m->name);
                    if (!(m->input_pcm = mapping_open_pcm(m, ss, dev_id, m->exact_channels,
                                                          SND_PCM_STREAM_CAPTURE,
                                                          default_n_fragments,
                                                          default_fragment_size_msec))) {
                        // 标记为不支持的配置
                        p->supported = false;
                        if (pa_idxset_size(p->input_mappings) == 1 &&
                            ((!p->output_mappings) || pa_idxset_size(p->output_mappings) == 0)) {
                            pa_log_debug("Caching failure to open input:%s", m->name);
                            pa_hashmap_put(broken_inputs, m, m);
                        }
                        break;
                    }

                    if (m->hw_device_index < 0)
                        mapping_query_hw_device(m, m->input_pcm);
                }

            last = p;

            if (!p->supported)
                continue;
        }

        pa_log_debug("Profile %s supported.", p->name);

        // 标记已找到输出和输入配置
        if (p->output_mappings)
            PA_IDXSET_FOREACH(m, p->output_mappings, idx)
                if (m->output_pcm) {
                    found_output = true;
                    if (p->fallback_output && selected_fallback_output == NULL) {
                        selected_fallback_output = m;
                    }
                    mapping_paths_probe(m, p, PA_ALSA_DIRECTION_OUTPUT, used_paths);
                }

        if (p->input_mappings)
            PA_IDXSET_FOREACH(m, p->input_mappings, idx)
                if (m->input_pcm) {
                    found_input = true;
                    if (p->fallback_input && selected_fallback_input == NULL) {
                        selected_fallback_input = m;
                    }
                    mapping_paths_probe(m, p, PA_ALSA_DIRECTION_INPUT, used_paths);
                }
    }

    // 最终化配置探测,清理资源
    profile_finalize_probing(last, NULL);

    // 丢弃不支持的配置
    pa_alsa_profile_set_drop_unsupported(ps);

    // 丢弃未使用的路径
    paths_drop_unused(ps->input_paths, used_paths);
    paths_drop_unused(ps->output_paths, used_paths);

    // 释放资源
    pa_hashmap_free(broken_inputs);
    pa_hashmap_free(broken_outputs);
    pa_hashmap_free(used_paths);
    pa_xfree(probe_order);

    ps->probed = true; // 标记为已完成探测
}

💬 评论