pulseaudio的相关操作(二)
这篇文章主要介绍pulseaudio playback的相关API,pulseaudio playback的具体实例可以参考[2]。如果用pulseaudio实现playback,简单地说就是创建一个playback stream,然后指定这个stream的sink,再定期的向这个stream中写数据。
mainloop相关API
pa_mainloop_new
mainloop是pulseaudio的核心,所以首先要用pa_mainloop_new创建一个mainloop实例。
pa_mainloop *pa_ml = pa_mainloop_new();
pa_mainloop_get_api
获取指向mainloop api的指针
pa_mainloop_api *pa_mlapi = pa_mainloop_get_api(pa_ml);
pa_mainloop_run
启动mainloop消息处理循环,pa_mainloop_run的定义如下,主体部分为一个while循环,此函数在最后调用。
int pa_mainloop_run(pa_mainloop *m, int *retval) {int r;while ((r = pa_mainloop_iterate(m, 1, retval)) >= 0);if (r == -2)return 1;elsereturn -1;
}
context相关API
pa_context_new
创建连接上下文,"Simple PA test application"为创建的sink-input的application.name。
pa_context * pa_ctx = pa_context_new(pa_mlapi, "Simple PA test application");
pa_context_connect
把上下文连接到一个指定的server,输入NULL指定为default server。
pa_context_connect(pa_ctx, NULL, 0, NULL);
pa_context_set_state_callback
设置状态回调函数,当上下文状态改变时,回调函数会触发,pa_ready为回调函数的参数。
pa_context_set_state_callback(pa_ctx, pa_state_cb, &pa_ready);
回调函数的大致结果如下,根据当前的context状态做具体的操作。
void pa_state_cb(pa_context *c, void *userdata) {pa_context_state_t state = pa_context_get_state(c);switch (state) {// TODO}
}
stream相关API
pa_stream_new
pa_stream_new用来创建一个stream,并指定音频流参数,如下:
pa_sample_spec ss;
ss.rate = 44100;
ss.channels = 1;
ss.format = PA_SAMPLE_S16LE;
playstream = pa_stream_new(pa_ctx, "Playback", &ss, NULL);// create a new stream
if (!playstream) {printf("pa_stream_new failed\n");
}
设置回调函数
可以设置的回调函数比较多,具体的回调函数可以查询API手册,对playback而言最重要的回调函数是write的回调函数,当pulseaudio需要往流中写入数据时会触发该函数,每次调用回调函数的间隔并非等间隔,且每次需要写入数据的大小不定,由pulseaudio的内部机制决定。
pa_stream_set_write_callback(playstream, stream_request_cb, NULL);
write回调函数的原型如下:
typedef void(* pa_stream_request_cb_t) (pa_stream *p, size_t nbytes, void *userdata);
在回调函数中的主要任务就是调用pa_stream_write函数,把数据写入到stream中。
pa_stream_connect_playback
下来要把stream连接 到一个device上,对playback而言就是要连接到一个sink device上,pa_stream_connect_playback的函数原型如下:
int pa_stream_connect_playback (pa_stream * s,const char * dev,const pa_buffer_attr * attr,pa_stream_flags_t flags,const pa_cvolume * volume,pa_stream * sync_stream )
- s : 创建的stream
- dev:stream要连接的sink device,NULL为默认的sink device
- attr:定义了playback和record的缓冲区指标,pulseaudio对playback和record都有自己内部定义的buffer,而attr参 数即是对buffer参数的设置,需要根据自己的实际情况选择合适的参数。
参数
含义
maxlength
buffer大小(字节),-1为能支持的最大值,如果是低延时场景,此值应该设置较小且配合PA_STREAM_ADJUST_LATENCY flag,如果buffer设置小会导致更多的under run。
tlength
仅用于playback。当buffer中的数据少于tlength时会请求向stream写数据,触发write callback函数。如果设置为-1的话,pulseaudio内部会自适应设置一个值。 当 PA_STREAM_ADJUST_LATENCY 未设置时,该值仅影响每个流的播放缓冲区大小。当 PA_STREAM_ADJUST_LATENCY 设置时,sink的延迟加上播放缓冲区大小共同受此值影响。如果对调整总体延迟感兴趣,应设置 PA_STREAM_ADJUST_LATENCY。如果你只对配置服务器端每个流的播放缓冲区大小感兴趣,则不应设置 PA_STREAM_ADJUST_LATENCY。
prebuf
仅用于playback。此值为当buf中大小超过此值时,server才会播放,即初始播放的预留量,此值设为-1时表示此值和tlength一样。
minreq
仅用于playback。write back中请求的最少数据大小,如果设为-1,则由pulseaudio内部生成一个默认的值。
fragsize
仅用于recording。 server以 fragsize 字节大小的块发送数据。较大的值会降低与其他连接上下文操作的交互性,但会减少控制开销。设为-1的话pulseaudio会把其初始化为一个合理的值。如果设置了PA_STREAM_ADJUST_LATENCY,则总体源延迟将根据此值进行调整。如果不设置 PA_STREAM_ADJUST_LATENCY,则源延迟保持不变。
- flags: 设置的额外的flags,具体的参考pa_stream_flags定义。
- volume : 初始的默认音量,建议为NULL
- sync_stream:此stream是否要和其它stream同步,如果设为NULL则各stream独立。
清理工作
当mainloop退出时需要做一些清理工作,回顾前面我们所作的工作,有创建了mainloop,创建了context,创建了stream,所以我们需要在最后清理这些我们创建的实例。 其中stream不用清理,因为pulseaudio用了类似智能指针的技术,当stream的引用计数为0时,会自动清理。所以我们清理的只有context和mainloop。清理的示意代码如下:
// clean up and disconnect pa_context_disconnect(pa_ctx); pa_context_unref(pa_ctx); pa_mainloop_free(pa_ml);参考
https://gavv.net/articles/pulseaudio-under-the-hood/ [1]
Async Playback – Developer Documentation – PulseAudio [2]
相关文章:
pulseaudio的相关操作(二)
这篇文章主要介绍pulseaudio playback的相关API,pulseaudio playback的具体实例可以参考[2]。如果用pulseaudio实现playback,简单地说就是创建一个playback stream,然后指定这个stream的sink,再定期的向这个stream中写数据。 mai…...
Selenium自动化测试工具
一 .Selenium简介 是一个用于Web应用程序测试的工具 Selenium的核心功能之一是测试软件在不同浏览器和操作系统上的兼容性,确保软件功能与用户需求的一致性,提升用户体验。 自动化脚本生成与执行 Selenium支持自动录制用户操作并生成多种编程语言的测…...
优化UVM环境(九)-将interface文件放在env pkg外面
书接上回: 优化UVM环境(八)-整理project_common_pkg文件 My_env_pkg.sv里不能包含interface,需要将my_intf.sv文件放在pkg之外...
mysql 主从安装
登录看第二篇 WINDOWS系统搭建MYSQL 8.0主从模式_windows mysql8.0.34主从配置-CSDN博客 Windows下MySQL8.0最新版本超详细安装教程_windowsserver安装mysql8.0-CSDN博客 启动两个服务 可执行文件路径一致问题解决: windows,同一台机器安装两个mysq…...
【C++刷题】力扣-#121-买卖股票的最佳时机
题目描述 给定一个数组 prices,其中 prices[i] 表示第 i 天的股票价格。假设你可以在第 i 天买入并在第 j 天卖出股票(i ≤ j),设计一个算法来计算你所能获取的最大利润。注意你只能持有一股股票,并且你不能同时参与多…...
Python量化交易(二):金融市场的基础概念
引言 大家好,我是GISer Liu😁,一名热爱AI技术的GIS开发者。本系列文章是我跟随DataWhale 2024年10月学习赛的Python量化交易学习总结文档;在现代社会中,投资已成为个人、机构和政府追求财富增长和资源配置的重要方式。…...
Java方法的递归调用
Java中的方法可以通过调用自身来实现递归调用。 递归调用在解决一些问题时非常有用,特别是那些可以分解为相同结构的子问题的情况。递归调用可以让问题的解决过程更加简洁和优雅。 下面是一个简单的示例,展示了如何使用递归调用来计算一个数字的阶乘&a…...
JavaScript 第30章:综合项目
看起来您想要了解如何在一个JavaScript为主的项目中进行项目规划、技术选型、开发流程以及维护等方面的内容,并且希望结合Java的源代码来进行详细的讲解。不过,JavaScript和Java是两种不同的编程语言,通常它们的应用场景也不同。JavaScript 主…...
GB/T28181-2022规范解读、应用场景和技术实现探究
GB/T28181-2022和GB/T28181-2016区别 GB/T28181-2022《公共安全视频监控联网系统信息传输、交换、控制技术要求》与 GB/T28181-2016 相比,主要有以下区别: 术语和定义方面: 术语删减:GB/T28181-2022 删除了 “联网系统信息”“数…...
Docker容器间链路管理
Docker容器是一个轻量级的、可移植的软件打包技术,它允许开发者将应用程序及其依赖项打包到一个独立的容器中,然后发布到任何支持Docker的环境中运行。容器是完全使用沙箱机制,相互之间不会有任何接口,容器性能开销极低。 可以将…...
python画图|在三维空间的不同平面上分别绘制不同类型二维图
【1】引言 前序已经完成了基础的二维图和三维图绘制教程探索,可直达的链接包括但不限于: python画图|3D参数化图形输出-CSDN博客 python画三角函数图|小白入门级教程_正余弦函数画图python-CSDN博客 在学习过程中,发现一个案例࿱…...
与ai一起作诗(《校园清廉韵》)
与ai对话犹如拷问自己的灵魂,与其说ai助力还不如说在和自己对话。 (笔记模板由python脚本于2024年10月19日 19:18:33创建,本篇笔记适合喜欢python和诗歌的coder翻阅) 【学习的细节是欢悦的历程】 Python 官网:https://www.python.org/ Free&…...
python matplotlib
一、图形函数 函数名称描述Bar绘制条形图Barh绘制水平条形图Boxplot绘制箱型图Hist绘制直方图his2d绘制2D直方图Pie绘制饼状图Plot在坐标轴上画线或者标记Polar绘制极坐标图Scatter绘制x与y的散点图Stackplot绘制堆叠图Stem用来绘制二维离散数据绘制(又称为火柴图&…...
秋招面试题记录_半结构化面试
c八股(可能问的多一点) 1.简单说说C11语法特性 答: 1.auto以及decltype自动类型推导,避免手动声明复杂类型,减少冗长代码提升了可读性和安全性。 2.智能指针 自动释放内存 (具体说说) 有shared和unique 差异主要体现在所有权、内存开销、…...
Java项目-基于springboot框架的疫苗接种管理系统项目实战(附源码+文档)
作者:计算机学长阿伟 开发技术:SpringBoot、SSM、Vue、MySQL、ElementUI等,“文末源码”。 开发运行环境 开发语言:Java数据库:MySQL技术:SpringBoot、Vue、Mybaits Plus、ELementUI工具:IDEA/…...
Android 12.0进程保活白名单功能实现
在Android 12.0系统中,实现进程保活白名单功能是为了确保某些重要的应用程序即使进入后台也能长时间保持运行状态,不被系统自动杀死。这一功能的实现涉及多个核心类和文件,以下是具体的实现步骤和核心功能分析: 一、实现步骤 …...
vscode 功能、设置备忘
2024年10月18日 crtl p 按文件名搜索,输入> 开始搜索命令 设置文件显示过滤和搜索过滤: ctrlp 输入 >settings 选择Preferences:Open Settings(UI),搜索exclude 配置 Files Exclude 修改显示过滤 配置 Search Exclude 修…...
错误 Failed to connect to xx.xx.xx.xx port xx: No route to host
Failed to connect to xx.xx.xx.xx port xx: No route to host 系统环境: Oracle Cloud(OCI)Ubuntu20.4 问题: 连接本机IP正常访问,连接内网ip可正常访问,但连接外网IP报错:Failed to conne…...
Redis环境的搭建
Redis环境的搭建可以分为Linux系统和Windows系统两种情况。 一、Linux系统下Redis的搭建 1. 安装前准备 确保Linux系统已安装GCC环境,可以使用yum install gcc-c命令安装。下载Redis安装包,例如redis-6.2.6.tar.gz,并将其上传到Linux服务器…...
Git Push(TODO)
最近经常碰到GIT push不上去的问题。到处求人解决也真是尴尬,想自己看看,所以刚刚在github上建了一个仓,试了下。结果如下: 暂时可能还不行,因为数据都是加密的,没法看到具体GIT的交互信息。。。 后面再想办…...
(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)
题目:3442. 奇偶频次间的最大差值 I 思路 :哈希,时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况,哈希表这里用数组即可实现。 C版本: class Solution { public:int maxDifference(string s) {int a[26]…...
ESP32 I2S音频总线学习笔记(四): INMP441采集音频并实时播放
简介 前面两期文章我们介绍了I2S的读取和写入,一个是通过INMP441麦克风模块采集音频,一个是通过PCM5102A模块播放音频,那如果我们将两者结合起来,将麦克风采集到的音频通过PCM5102A播放,是不是就可以做一个扩音器了呢…...
使用van-uploader 的UI组件,结合vue2如何实现图片上传组件的封装
以下是基于 vant-ui(适配 Vue2 版本 )实现截图中照片上传预览、删除功能,并封装成可复用组件的完整代码,包含样式和逻辑实现,可直接在 Vue2 项目中使用: 1. 封装的图片上传组件 ImageUploader.vue <te…...
【HTML-16】深入理解HTML中的块元素与行内元素
HTML元素根据其显示特性可以分为两大类:块元素(Block-level Elements)和行内元素(Inline Elements)。理解这两者的区别对于构建良好的网页布局至关重要。本文将全面解析这两种元素的特性、区别以及实际应用场景。 1. 块元素(Block-level Elements) 1.1 基本特性 …...
AI编程--插件对比分析:CodeRider、GitHub Copilot及其他
AI编程插件对比分析:CodeRider、GitHub Copilot及其他 随着人工智能技术的快速发展,AI编程插件已成为提升开发者生产力的重要工具。CodeRider和GitHub Copilot作为市场上的领先者,分别以其独特的特性和生态系统吸引了大量开发者。本文将从功…...
使用 Streamlit 构建支持主流大模型与 Ollama 的轻量级统一平台
🎯 使用 Streamlit 构建支持主流大模型与 Ollama 的轻量级统一平台 📌 项目背景 随着大语言模型(LLM)的广泛应用,开发者常面临多个挑战: 各大模型(OpenAI、Claude、Gemini、Ollama)接口风格不统一;缺乏一个统一平台进行模型调用与测试;本地模型 Ollama 的集成与前…...
算法笔记2
1.字符串拼接最好用StringBuilder,不用String 2.创建List<>类型的数组并创建内存 List arr[] new ArrayList[26]; Arrays.setAll(arr, i -> new ArrayList<>()); 3.去掉首尾空格...
Java求职者面试指南:计算机基础与源码原理深度解析
Java求职者面试指南:计算机基础与源码原理深度解析 第一轮提问:基础概念问题 1. 请解释什么是进程和线程的区别? 面试官:进程是程序的一次执行过程,是系统进行资源分配和调度的基本单位;而线程是进程中的…...
Web中间件--tomcat学习
Web中间件–tomcat Java虚拟机详解 什么是JAVA虚拟机 Java虚拟机是一个抽象的计算机,它可以执行Java字节码。Java虚拟机是Java平台的一部分,Java平台由Java语言、Java API和Java虚拟机组成。Java虚拟机的主要作用是将Java字节码转换为机器代码&#x…...
Git 3天2K星标:Datawhale 的 Happy-LLM 项目介绍(附教程)
引言 在人工智能飞速发展的今天,大语言模型(Large Language Models, LLMs)已成为技术领域的焦点。从智能写作到代码生成,LLM 的应用场景不断扩展,深刻改变了我们的工作和生活方式。然而,理解这些模型的内部…...
