简介: CSDN博客专家、《Android系统多媒体进阶实战》作者

博主新书推荐:《Android系统多媒体进阶实战》🚀
Android Audio工程师专栏地址: Audio工程师进阶系列原创干货持续更新中……】🚀
Android多媒体专栏地址: 多媒体系统工程师系列原创干货持续更新中……】🚀
专题一 二:AAOS车载系统+AOSP14系统攻城狮入门视频实战课 🚀
专题三:Android14 Binder之HIDL与AIDL通信实战课 🚀
专题四:Android15快速自定义与集成音效实战课 🚀
专题五:Android15音频策略实战课 🚀
专题六:Android15音频性能实战课(无声/杂音/断音/爆音实战案例) 🚀

人生格言: 人生从来没有捷径,只有行动才是治疗恐惧和懒惰的唯一良药.

更多原创,欢迎关注:Android系统攻城狮

欢迎关注Android系统攻城狮

🌻1. 前言

本篇目的:Linux PulseAudio 深度解析之 pa_context_get_sink_info_list 调用流程与实战。

要点概括

  • 核心功能:获取 PulseAudio Server 当前所有 Sink(输出设备)信息。
  • 工作机制:通过 Native Protocol 向 PulseAudio Daemon 发送查询请求,由服务端遍历全部 Sink 后逐个回调返回。

🌻2. 用法与应用场景

pa_context_get_sink_info_list
是 PulseAudio 设备管理体系中最常用的查询接口之一。

在 PulseAudio 中:

  • 声卡
  • HDMI
  • USB Audio
  • 蓝牙耳机

最终都会抽象为:

Sink(音频输出设备)

而该接口用于:

获取系统当前全部 Sink 列表。

函数原型

pa_operation* pa_context_get_sink_info_list(
        pa_context *c,
        pa_sink_info_cb_t cb,
        void *userdata);

参数说明

c:
PulseAudio Context

cb:
Sink 信息回调函数

userdata:
用户私有数据

回调函数原型

typedef void (*pa_sink_info_cb_t)(
        pa_context *c,
        const pa_sink_info *i,
        int eol,
        void *userdata);

返回值

返回 pa_operation 对象

用于:

  • 查询执行状态
  • 生命周期管理
  • 等待查询结束

应用场景

1. 获取系统全部播放设备

pa_context_get_sink_info_list(...)

返回:

  • Speaker
  • Headphone
  • HDMI
  • Bluetooth

等全部输出设备。


2. 构建设备选择界面

例如:

1. 内置扬声器
2. HDMI 显示器
3. 蓝牙耳机

很多播放器:

  • VLC
  • Chromium
  • PipeWire-Pulse

都会依赖类似逻辑。


3. 自动选择输出设备

例如:

  • 蓝牙耳机插入
  • HDMI 接入
  • USB 声卡接入

需要先获得:

所有 Sink 列表

再进行设备切换。


🌻3. 调用流程剖析

🌻3.1 核心步骤

1. 应用层发起查询
pa_context_get_sink_info_list(
        context,
        sink_info_cb,
        userdata);

2. libpulse 创建 operation

内部创建:

pa_operation

用于管理此次异步查询。


3. 发送协议命令

通过 Native Protocol 发送:

PA_COMMAND_GET_SINK_INFO_LIST

到 PulseAudio Daemon。


4. 服务端遍历全部 Sink

Daemon 内部:

core->sinks

通常保存:

  • alsa_output
  • hdmi_output
  • bluez_output

等设备对象。

服务端开始遍历:

全部 Sink

5. 逐个返回 Sink 信息

对于每个 Sink:

sink1
sink2
sink3
...

都会触发一次:

sink_info_cb(...)

6. 返回结束标记

最后一次回调:

eol = 1

表示:

所有 Sink 已全部返回。


🌻3.2 调用流程图

Application
应用程序

调用 pa_context_get_sink_info_list

创建 pa_operation

发送 GET_SINK_INFO_LIST

PulseAudio Server

遍历全部 Sink

Sink #1

Sink #2

Sink #N

触发回调

应用层接收设备信息

eol=1

🌻3.3 Sink 信息查询生命周期图

Application

pa_context_get_sink_info_list

创建 operation

发送查询请求

Daemon 遍历 Sink

返回 Sink #1

回调 sink_info_cb

返回 Sink #2

再次回调

返回 Sink #N

eol=1

查询结束

🌻4. 实战应用案例

#include <pulse/pulseaudio.h>
#include <stdio.h>

static void sink_info_cb(
        pa_context *c,
        const pa_sink_info *i,
        int eol,
        void *userdata) {

    if (eol > 0) {

        printf("Sink 列表查询结束\n");
        return;
    }

    printf("Sink Name  : %s\n",
           i->name);

    printf("Description: %s\n",
           i->description);

    printf("Index      : %u\n",
           i->index);

    printf("-----------------\n");
}

void list_all_sinks(
        pa_context *context) {

    pa_operation *op;

    op = pa_context_get_sink_info_list(
            context,
            sink_info_cb,
            NULL);

    if (!op) {

        printf("query sink failed\n");
        return;
    }

    pa_operation_unref(op);
}

int main() {

    pa_context *context;

    /*
     * 假设 context 已连接成功
     */

    list_all_sinks(context);

    return 0;
}

🌻5. 源码层核心原理

pa_context_get_sink_info_list
属于:

PulseAudio 异步设备枚举接口。

内部核心流程:

pa_context_get_sink_info_list()pa_pstream_send_tagstruct()
    ↓
发送 GET_SINK_INFO_LIST
    ↓
Daemon 遍历 core->sinks
    ↓
逐个回调返回
    ↓
eol=1

服务端核心对象:

pa_core

内部保存:

core->sinks

其类型为:

pa_idxset

查询过程实际上就是:

遍历 core->sinks
逐个返回 pa_sink_info

因此:

pa_context_get_sink_info_list

本质属于:

“全量设备枚举接口”。

🌻6. 一句话总结

pa_context_get_sink_info_list
本质上是:

“向 PulseAudio Server 查询当前所有输出设备”。

它负责:

  • 获取全部 Sink
  • 构建设备列表
  • 支撑设备切换
  • 支撑蓝牙/HDMI 管理

是 PulseAudio 设备发现体系中的核心基础接口之一。

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐