当前位置: 首页 > news >正文

Linux Pulseaudio深度解析之pa_mainloop_dispatch调用流程与实战(七十三)

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

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

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

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


🍉🍉🍉文章目录🍉🍉🍉

  • 🌻1. 前言
      • 要点概括
  • 🌻2. 应用场景与用法
    • 函数原型
    • 参数说明
    • 返回值
  • 应用场景
  • 🌻3. 调用流程剖析
    • 🌻3.1 核心步骤
      • 1. 应用层进入 mainloop
      • 2. dispatch 接收已经就绪的事件
      • 3. 检查 mainloop 状态
      • 4. 选择待分发事件
      • 5. 执行对应 callback
      • 6. 更新事件状态
      • 7. 返回分发结果
      • 8. 驱动异步链路继续向前
    • 🌻3.2 调用流程图
    • 🌻3.3 mainloop dispatch 生命周期图
  • 🌻4. 实战应用案例
  • 🌻5. 一句话总结

🌻1. 前言

本篇目的:

Linux PulseAudio 深度解析之pa_mainloop_dispatch调用流程与实战。

要点概括

  • 核心功能:分发 mainloop 中已经就绪的事件,并执行对应回调函数。
  • 工作机制pa_mainloop_prepare()负责准备监听事件,pa_mainloop_poll()负责等待事件发生,pa_mainloop_dispatch()负责把已经发生的事件分发给对应 callback。
  • 典型用途:理解 PulseAudio 异步回调机制、分析 socket 事件触发、分析 defer/time/io 事件调度、手动拆解 mainloop 运行过程。

🌻2. 应用场景与用法

pa_mainloop_dispatch()是 PulseAudio mainloop 事件循环中的核心分发接口。

在 PulseAudio 中,Context 连接完成、Stream 状态变化、Socket 可读可写、定时器触发、defer 事件触发,最终都需要通过 mainloop 的事件分发机制执行对应回调。

而该接口用于:

将已经就绪的 mainloop 事件分发出去,并调用对应的回调函数。


函数原型

intpa_mainloop_dispatch(pa_mainloop*m);

参数说明

m:目标 pa_mainloop 对象

返回值

返回int类型结果

用于表示本轮事件分发是否成功,以及 mainloop 当前是否还能继续运行。


应用场景

pa_mainloop_dispatch()常见应用场景主要有三类。

第一类是理解 PulseAudio 异步回调机制。应用调用pa_context_connect()后,并不会立刻进入PA_CONTEXT_READY,而是要等 mainloop 后续运行。当 socket 连接完成、服务端返回协议包、状态变化事件就绪后,pa_mainloop_dispatch()才会把这些事件分发出去,最终触发context_cb()stream_cb()write_cb()等回调。

第二类是手动拆解 mainloop 执行流程。平时应用通常直接调用pa_mainloop_run(),它内部会循环执行 prepare、poll、dispatch。为了调试和学习,可以手动调用pa_mainloop_prepare()pa_mainloop_poll()pa_mainloop_dispatch(),这样可以清楚看到事件循环每一步分别负责什么。

第三类是调试 IO、Time、Defer 事件。在分析 PulseAudio 连接流程、socket 事件、延迟回调、定时器回调时,pa_mainloop_dispatch()是关键入口。它不是负责等待事件,而是负责“事件已经发生之后,应该调用哪个 callback”。


🌻3. 调用流程剖析

🌻3.1 核心步骤

1. 应用层进入 mainloop

通常应用不会直接频繁调用pa_mainloop_dispatch(),而是调用:

pa_mainloop_run(mainloop,NULL);

如果手动拆解,可以写成:

pa_mainloop_prepare(mainloop,-1);pa_mainloop_poll(mainloop);pa_mainloop_dispatch(mainloop);

2. dispatch 接收已经就绪的事件

pa_mainloop_dispatch()不负责阻塞等待事件。

它处理的是:

pa_mainloop_poll() 已经发现的事件

也就是说:

poll 阶段负责等事件 dispatch 阶段负责执行事件

3. 检查 mainloop 状态

进入 dispatch 后,会检查 mainloop 当前状态是否允许继续分发。

如果 mainloop 已经退出、终止或状态异常,本轮 dispatch 就不会继续执行正常事件分发。


4. 选择待分发事件

mainloop 内部维护多类事件:

defer_events io_events time_events pollfds

dispatch 阶段会根据当前事件状态,选择可以执行的事件。


5. 执行对应 callback

如果是 defer 事件,就执行 defer callback;如果是 IO 事件,就根据 fd 的读写状态执行 IO callback;如果是 time 事件,就执行 timer callback。

这些 callback 可能是:

连接完成回调 socket 可读回调 stream 写回调 context 状态回调 timer 回调 defer 回调

6. 更新事件状态

callback 执行完成后,mainloop 会根据事件类型更新内部状态。

例如:

一次性 defer 事件可能被释放 IO 事件继续保留等待下一次 fd 就绪 time 事件可能重新设置下一次触发时间

7. 返回分发结果

本轮事件处理完成后,pa_mainloop_dispatch()返回。

如果外层是pa_mainloop_run(),则继续进入下一轮:

prepare → poll → dispatch

8. 驱动异步链路继续向前

对于 PulseAudio 客户端来说,pa_mainloop_dispatch()的核心价值是:

把底层事件变成上层 callback

例如:

socket 可读 ↓ dispatch 执行协议处理回调 ↓ context 状态变化 ↓ 触发 context_cb()

🌻3.2 调用流程图


🌻3.3 mainloop dispatch 生命周期图


🌻4. 实战应用案例

#include<pulse/pulseaudio.h>#include<stdio.h>staticvoidcontext_state_cb(pa_context*c,void*userdata){pa_context_state_tstate;state=pa_context_get_state(c);if(state==PA_CONTEXT_READY){printf("context ready\n");}elseif(state==PA_CONTEXT_FAILED){printf("context failed\n");}elseif(state==PA_CONTEXT_TERMINATED){printf("context terminated\n");}}voidmanual_mainloop_once(pa_mainloop*mainloop){intret;/* * 1. 准备本轮需要监听的事件 */ret=pa_mainloop_prepare(mainloop,-1);if(ret<0){printf("mainloop prepare failed\n");return;}/* * 2. 等待 fd、timer、defer 等事件发生 */ret=pa_mainloop_poll(mainloop);if(ret<0){printf("mainloop poll failed\n");return;}/* * 3. 分发已经发生的事件,并执行对应 callback */ret=pa_mainloop_dispatch(mainloop);if(ret<0){printf("mainloop dispatch failed\n");return;}}intmain(){pa_mainloop*mainloop;pa_context*context;mainloop=pa_mainloop_new();context=pa_context_new(pa_mainloop_get_api(mainloop),"mainloop_dispatch_demo");pa_context_set_state_callback(context,context_state_cb,NULL);pa_context_connect(context,NULL,0,NULL);/* * 为了演示 dispatch,这里手动跑几轮 mainloop。 * 实际项目中通常直接使用 pa_mainloop_run()。 */for(;;){manual_mainloop_once(mainloop);if(pa_context_get_state(context)==PA_CONTEXT_READY)break;if(pa_context_get_state(context)==PA_CONTEXT_FAILED)break;if(pa_context_get_state(context)==PA_CONTEXT_TERMINATED)break;}pa_context_disconnect(context);pa_context_unref(context);pa_mainloop_free(mainloop);return0;}

🌻5. 一句话总结

pa_mainloop_dispatch()本质上是:

“把 mainloop 中已经就绪的事件分发给对应 callback”。

它不负责创建事件,也不负责等待事件,而是负责在poll返回之后,把 IO、Time、Defer 等事件转换成真正的回调执行,是 PulseAudio 异步连接、状态变化、读写通知和 Stream 回调能够运转起来的关键分发入口。

http://www.jsqmd.com/news/1072817/

相关文章:

  • 5个Grafika图形处理核心问题解析:Android高性能渲染的实战指南
  • Anthropic Agent最佳实践系列一: Agent 架构入门
  • linux笔记6(软链接)
  • 城市NOA深度复盘|全网实车测评 端到端分支架构迭代、车企智驾方案对标、第三方供应链拆解、全路况落地适配、全域闭环端到端量产代码、助力城区复杂人车混行路况降接管
  • PyTorch字符级RNN实战指南
  • 车联网蓝牙测试:经典蓝牙数据抓包.(SSP配对模式)
  • OpencvSharp 算子学习教案之 - Cv2.Circle 重载2
  • 数字化赋能传统离散制造:智能化技术在高端石材工程领域的落地与深度优化
  • 【LangChain核心组件】文档加载器
  • 2018Y408
  • Sqlserver数据库日志文件过大(收缩/裁剪处理)
  • CSDN 高质量 DHCP 实验博文
  • 花5万买串口屏,总结出的7条血泪教训做储能设备的千万别再踩坑
  • CircleCI自动化_circleci-automation
  • 程序员跨境收支必备:查外汇网实战指南
  • 《Effective Python》读书笔记14: 附录 - 90条建议完整列表
  • 鸿蒙PC中使用ohos-sdk完成Rust适配,自动签名编译安装第三方库walkdir是 Rust 递归遍历目录的专用库
  • 第34章:自动化代码评审Agent——自动审查PR并给出建议
  • AI调试助手EAP谱试,连接周期从2天到3小时
  • 一篇文章带你入门漏洞靶场:从 0 到 1 玩转 bWAPP(附完整安装教程)
  • ChatGPT 转 pdf 怎么压缩但清晰,AI 导出鸭平衡体积与清晰度,告别文档臃肿问题
  • Codex CLI-03-AGENTS.md 编写指南:让 AI 理解你的项目
  • 屏幕截图文字识别工具帮你屏幕截图取字
  • 论文分享➲ arXiv2026 | H2HMem: A Multimodal Memory Benchmark for Agents in Human-Human Interactions
  • 鸿蒙PC适配llvm-gcc-compat编译安装第三方库convert_case,打造Rust 第三方字符串命名风格互相转换
  • 5分钟搞定OpenCode Go套餐无缝接入Claude Code,性价比直接起飞!
  • 鸿蒙 PC使用ohos-pip-autosign激活自动签名工具,安装第三方库arrow实现Python人性化时间处理库
  • 嵌入式linux学习记录十四、术语
  • 第二章 基本数据类型及其操作4
  • SoK: Taxonomy and Evaluation of Prompt Security in Large Language Models