Linux音频了解

news2024/11/28 10:48:03

ALPHA I.MX6U 开发板支持音频,板上搭载了音频编解码芯片 WM8960,支持播放以及录音功能!

本章将会讨论如下主题内容。

⚫ Linux 下 ALSA 框架概述;

⚫ alsa-lib 库介绍;

⚫ alsa-lib 库移植;

⚫ alsa-lib 库的使用;

⚫ 音频应用编程之播放;

⚫ 音频应用编程之录音

ALSA概述

ALSA 是 Advanced Linux Sound Architecture(高级的 Linux 声音体系)的缩写,目前已经成为了 linux下的主流音频体系架构,提供了音频和 MIDI 的支持,替代了原先旧版本中的 OSS(开发声音系统);ALSA 是 Linux 系统下一套标准的、先进的音频驱动框架,那么这套框架的设计本身是比较复杂的,采用分离、分层思想设计而成。

在应用层,ALSA 为我们提供了一套标准的 API,应用程序只需要调用这些 API 就可完成对底层音频硬

件设备的控制,譬如播放、录音等,这一套 API 称为 alsa-lib

对于我们来说,学习音频应用编程其实就是学习 alsa-lib 库函数的使用、如何基于 alsa-lib 库函数开发音频应用程序。

ALSA 提供了关于 alsa-lib 的使用说明文档,其链接地址为:ALSA project - the C library reference: Index, Preamble and License,

sound 设备节点

在 Linux 内核设备驱动层、基于 ALSA 音频驱动框架注册的 sound 设备会在/dev/snd 目录下生成相应的设备节点文件。

我们编写的应用程序,虽然是调用 alsa-lib 库函数去控制底层音频硬件,但最终也是落实到对 sound

设备节点的 I/O 操作,只不过 alsa-lib 已经帮我们封装好了,在 Linux 系统的/proc/asound 目录下,有很多的文件,这些文件记录了系统中声卡相关的信息。

编写一个简单地 alsa-lib 应用程序

对于 alsa-lib 库的使用,ALSA 提供了一些参考资料来帮助应用程序开发人员快速上手 alsa-lib、基于

alsa-lib 进行应用编程,以下笔者给出了链接:

ALSA Programming HOWTO v.0.0.8

ALSA project - the C library reference: Examples

第一份文档向用户介绍了如何使用 alsa-lib 编写简单的音频应用程序,包括 PCM 播放音频、PCM 录音

等,笔者也是参考了这份文档来编写本章教程,对应初学者,建议大家看一看。

第二个链接地址是 ALSA 提供的一些示例代码,如下所示:

一些基本概念

  • 样本长度(Sample)
  • 声道数(channel)
  • 帧(frame)
  • 采样率(Sample rate)
  • 交错模式(interleaved)
  • 周期(period)
  • 缓冲区(buffer)

音频设备底层驱动程序使用 DMA 来搬运数据,这个 buffer 中有 4 个 period,每当 DMA 搬运完一个period 的数据就会触发一次中断,因此搬运整个 buffer 中的数据将产生 4 次中断。

数据之间的传输

Over and Under Run

2.编写一个音频应用程序

2.1打开 PCM 设备

需要包含头文件<alsa/asoundlib.h>

int snd_pcm_open(snd_pcm_t **pcmp, const char *name, snd_pcm_stream_t stream, int mode)

⚫ pcmp:snd_pcm_t 用于描述一个 PCM 设备,所以一个 snd_pcm_t 对象表示一个 PCM 设备;

snd_pcm_open 函数会打开参数 name 所指定的设备,实例化 snd_pcm_t 对象,并将对象的指针(也

就是 PCM 设备的句柄)通过 pcmp 返回出来。

name:参数 name 指定 PCM 设备的名字。alsa-lib 库函数中使用逻辑设备名而不是设备文件名,命名方式为"hw:i,j",i 表示声卡的卡号,j 则表示这块声卡上的设备号;譬如"hw:0,0"表示声卡 0 上的

PCM 设备 0,在播放情况下,这其实就对应/dev/snd/pcmC0D0p(如果是录音,则对应

/dev/snd/pcmC0D0c)。除了使用"hw:i,j"这种方式命名之外,还有其它两种常用的命名方式,譬如

"plughw:i,j"、"default"等,关于这些名字的不同,本章最后再向大家进行简单地介绍,这里暂时先

不去理会这个问题。

stream:参数 stream 指定流类型,有两种不同类型:SND_PCM_STREAM_PLAYBACK 和

SND_PCM_STREAM_CAPTURE ; SND_PCM_STREAM_PLAYBACK 表 示 播 放 ,SND_PCM_STREAM_CAPTURE 则表示采集。

mode:最后一个参数 mode 指定了 open 模式,通常情况下,我们会将其设置为 0,表示默认打开

模式,默认情况下使用阻塞方式打开设备;当然,也可将其设置为 SND_PCM_NONBLOCK,表示

以非阻塞方式打开设备。

关闭PCM设备API

int snd_pcm_close(snd_pcm_t *pcm);

2.2硬件参数设置

打开 PCM 设备之后,接着我们需要对设备进行设置,包括硬件配置和软件配置。软件配置就不再介绍

了,使用默认配置即可!我们主要是对硬件参数进行配置,譬如采样率、声道数、格式、访问类型、period周期大小、buffer 大小等。

snd_pcm_hw_params_t 数据类型描述PCM设备

在配置之前,需要实例化一个snd_pcm_hw_params_t对象。

snd_pcm_hw_params_t *hwparams = NULL;
//创建对象,申请内存
//方法一
snd_pcm_hw_params_malloc(&hwparams);
//方法二
snd_pcm_hw_params_alloca(&hwparams);

//释放对象
void snd_pcm_hw_params_free(snd_pcm_hw_params_t *obj)

补充:

mallocalloca区别

mallocalloca都是用于动态分配内存的函数,但是它们有一些区别。

malloc是C标准库中的函数,它的作用是在堆上分配一块指定大小的内存区域,并返回该内存区域的地址。使用malloc分配的内存区域在程序运行期间一直存在,直到显式调用free函数释放该内存区域,或者程序结束时操作系统自动回收。

alloca是一个非标准的函数,它通常由编译器提供支持。它的作用是在栈上分配一块指定大小的内存区域,并返回该内存区域的地址。使用alloca分配的内存区域在函数返回时被自动释放,因此不需要显式调用free函数来释放内存。但是,由于alloca分配的内存区域在函数返回时被释放,因此不能在函数外部使用该内存区域。

在使用mallocalloca时需要注意以下几点:

  1. malloc可以分配任意大小的内存区域,而alloca只能分配栈大小范围内的内存区域。
  2. malloc分配的内存区域需要手动释放,而alloca分配的内存区域在函数返回时会自动释放。
  3. alloca分配的内存是存储在栈中的,而栈的大小是有限的。如果分配的内存区域过大,可能会导致栈溢出。
  4. alloca是一个非标准的函数,不是所有的编译器都支持。如果需要在不同的编译器间移植代码,最好不要使用alloca

因此,mallocalloca适用于不同的场景。malloc适用于需要动态分配大量内存的场景,而alloca适用于需要动态分配小量内存的场景,并且内存区域的大小可以在编译期间确定。

初始化 snd_pcm_hw_params_t 对象

snd_pcm_hw_params_any(pcm_handle, hwparams);

对硬件参数进行设置

alsa-lib 提供了一系列的 snd_pcm_hw_params_set_xxx 函数用于设置 PCM 设备的硬件参数,同样也提供了一系列的 snd_pcm_hw_params_get_xxx 函数用于获取硬件参数。

(1)设置 access 访问类型:snd_pcm_hw_params_set_access()

int snd_pcm_hw_params_set_access(snd_pcm_t *pcm,
snd_pcm_hw_params_t * params,
snd_pcm_access_t access 
)

(2)设置数据格式:snd_pcm_hw_params_set_format()

(3)设置声道数:snd_pcm_hw_params_set_channels()

(4)设置采样率大小:snd_pcm_hw_params_set_rate()

(5)设置周期大小:snd_pcm_hw_params_set_period_size()

(6)设置 buffer 大小:snd_pcm_hw_params_set_buffer_size()

(7)安装/加载硬件配置参数:snd_pcm_hw_params()

2.3读/写数据

//播放
snd_pcm_sframes_t snd_pcm_writei(snd_pcm_t *pcm,
const void *buffer,
snd_pcm_uframes_t size
)
//录音
snd_pcm_sframes_t snd_pcm_readi(snd_pcm_t *pcm,
void *buffer,
snd_pcm_uframes_t size
)
//注意;参数 buffer 指的是应用程序的缓冲区,不要与驱动层的环形缓冲区搞混了

阻塞与非阻塞

调用 snd_pcm_open()打开设备时,若指定为阻塞方式,则调用 snd_pcm_readi/snd_pcm_writei 以阻塞方式进行读/写。对于 PCM 录音来说,当 buffer 缓冲区中无数据可读时,调用 snd_pcm_readi()函数将会阻塞,直到音频设备向 buffer 中写入采集到的音频数据;同理,对于 PCM 播放来说,当 buffer 缓冲区中的数据满时,调用 snd_pcm_writei()函数将会阻塞,直到音频设备从 buffer 中读走数据进行播放。

若调用 snd_pcm_open()打开设备时,指定为非阻塞方式,则调用 snd_pcm_readi/snd_pcm_writei 以非阻塞方式进行读/写。对于 PCM 录音来说,当 buffer 缓冲区中无数据可读时,调用 snd_pcm_readi()不会阻塞、而是立即以错误形式返回;同理,对于 PCM 播放来说,当 buffer 缓冲区中的数据满时,调用 snd_pcm_writei()函数也不会阻塞、而是立即以错误形式返回。

snd_pcm_readn 和 snd_pcm_writen

snd_pcm_readi/snd_pcm_writei 适用于交错模式(interleaved)读/写数据,如果用户设置的访问类型并不是交错模式,而是非交错模式(non interleaved),此时便不可再使用 snd_pcm_readi/snd_pcm_writei 进行读写操作了,而需要使用 snd_pcm_readn 和 snd_pcm_writen 进行读写。

3.编写播放器代码

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/952175.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

8.30 QT界面 常用组件 和 类的 设置

this -> setFixedSize(540, 410); //固定窗口大小this -> setWindowTitle("啊啊啊"); //设置窗口标题this -> setWindowIcon(QIcon("E:/1.png")); //设置窗口图标QLabel *lab1 new QLabel(this); //构造一个标签lab1 -> setPixmap(QPi…

Doris数据库BE——Stream load流程中事务状态

Stream Load的事务管理由FE负责&#xff0c;Doris的事务状态包括&#xff1a;PREPARE、COMMITTED、VISIBLE和ABORTED。 数据导入开始之前&#xff0c;Coordinator BE节点会向FE发送Begin Transaction请求&#xff0c;FE会为当前label开启一个新的事务&#xff0c;并为事务分配…

从零开始探索C语言(四)----循环

文章目录 1. C 循环1.1 while 循环1.2 for 循环1.3 do...1.4 嵌套循环 2. 循环控制语句2.1 break 语句2.2 continue 语句2.3 goto 语句 1. C 循环 有的时候&#xff0c;我们可能需要多次执行同一块代码。一般情况下&#xff0c;语句是按顺序执行的&#xff1a;函数中的第一个语…

Servlet与过滤器

目录 Servlet 过滤器 Servlet Servlet做了什么 本身不做任何业务处理,只是接收请求并决定调用哪个JavaBean去处理请求,确定用哪个页面来显示处理返回的数据 Servlet是什么 ServerApplet&#xff0c;是一种服务器端的Java应用程序 只有当一个服务器端的程序使用了Servlet…

Hive-启动与操作(2)

&#x1f947;&#x1f947;【大数据学习记录篇】-持续更新中~&#x1f947;&#x1f947; 个人主页&#xff1a;beixi 本文章收录于专栏&#xff08;点击传送&#xff09;&#xff1a;【大数据学习】 &#x1f493;&#x1f493;持续更新中&#xff0c;感谢各位前辈朋友们支持…

基于FPGA的图像sobel边缘提取算法开发,包括tb测试文件以及matlab验证代码

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 5.算法完整程序工程 1.算法运行效果图预览 2.算法运行软件版本 vivado2019.2 matlab2022a 3.部分核心程序 timescale 1ns / 1ps // // Company: // Engineer: // // Create Date: 202…

(一)KITTI数据集用于3D目标检测

KITTI数据集介绍 数据基本情况 KITTI是德国卡尔斯鲁厄科技学院和丰田芝加哥研究院开源的数据集,最早发布于2012年03月20号。 对应的论文Are we ready for Autonomous Driving? The KITTI Vision Benchmark Suite发表在CVPR2012上。 KITTI数据集搜集自德国卡尔斯鲁厄市&…

QT基础教程之九Qt文件系统

QT基础教程之九Qt文件系统 文件操作是应用程序必不可少的部分。Qt 作为一个通用开发库&#xff0c;提供了跨平台的文件操作能力。Qt 通过QIODevice提供了对 I/O 设备的抽象&#xff0c;这些设备具有读写字节块的能力。下面是 I/O 设备的类图&#xff08;Qt5&#xff09;&#…

Leetcode Top 100 Liked Questions(序号105~139)

105. Construct Binary Tree from Preorder and Inorder Traversal105. Construct Binary Tree from Preorder and Inorder Traversal 题意&#xff1a;根据前序遍历和中序遍历来构造二叉树 我的思路 要用递归造树&#xff0c;要同时递归左子树和右子树&#xff0c;造树需要…

Ansible学习笔记9

yum_repository模块&#xff1a; yum_repository模块用于配置yum仓库的。 测试下&#xff1a; [rootlocalhost ~]# ansible group1 -m yum_repository -a "namelocal descriptionlocalyum baseurlfile:///mnt/ enabledyes gpgcheckno" 192.168.17.106 | CHANGED &g…

【微服务部署】08-监控与告警

文章目录 1. PrometheusOperator1.1 优势1.2 配置脚本1.3 部署脚本 2. Granfana实现监控看板2.1 Granfana核心特性2.2 部署文件 目前Kubernetes中最流行的监控解决方案是使用Prometheus和AlertManager 1. PrometheusOperator 1.1 优势 自动化安装将配置资源化灵活的扩展能力 …

2023开学季《乡村振兴战略下传统村落文化旅游设计》许少辉博士八一新书已被北京收录

2023开学季《乡村振兴战略下传统村落文化旅游设计》许少辉博士八一新书已被北京收录

【AI】数学基础——数理统计(假设检验数据处理)

概率论 数理统计&#xff08;概念&参数估计&#xff09; 文章目录 3.8 假设检验3.8.1 提出假设3.8.2 构建检验统计量对均值检验对方差检验 3.8.3 根据显著性水平确定拒绝域临界值显著性水平拒绝域 3.8.4 计算统计量&#xff0c;确定P值3.8.5 根据临界值法决定是否拒绝原假设…

PCD点云文件外部框框坐标计算

PCD点云文件直接提取的是点云的坐标&#xff0c;不是最外面的box的坐标&#xff0c;因此可以通过&#xff1a; max_b octree.get_max_bound() min_b octree.get_min_bound()分别得到最大最小的xyz坐标&#xff0c;之后进行计算 点的序号和位置对应如下&#xff1a; 所有的…

UML用例图三种关系(重点)-架构真题(十七)

某项目包括A、B、C、D四道工序&#xff0c;各道工序之间的衔接关系、正常进度下各工序所需的时间和直接费用、赶工进度下所需的时间和直接费用如下表所示。该项目每天需要间接费用为4.5万元&#xff0c;根据此表&#xff0c;最低成本完成需要&#xff08;&#xff09;天。&…

selenium可以编写自动化测试脚本吗?

Selenium可以用于编写自动化测试脚本&#xff0c;它提供了许多工具和API&#xff0c;可以与浏览器交互&#xff0c;模拟用户操作&#xff0c;检查网页的各个方面。下面是一些步骤&#xff0c;可以帮助你编写Selenium自动化测试脚本。 1、安装Selenium库和浏览器驱动程序 首先…

【QT】使用qml的QtWebEngine遇到的一些问题总结

在使用qt官方的一些QML的QtWebEngine相关的例程的时候&#xff0c;有时在运行会报如下错误&#xff1a; WebEngineContext used before QtWebEngine::initialize() or OpenGL context creation failed 这个问题在main函数里面最前面加上&#xff1a; QCoreApplication::setAttr…

深度学习推荐系统(二)Deep Crossing及其在Criteo数据集上的应用

深度学习推荐系统(二)Deep Crossing及其在Criteo数据集上的应用 在2016年&#xff0c; 随着微软的Deep Crossing&#xff0c; 谷歌的Wide&Deep以及FNN、PNN等一大批优秀的深度学习模型被提出&#xff0c; 推荐系统全面进入了深度学习时代&#xff0c; 时至今日&#xff0c…

【数据分享】2000-2020年全球人类足迹数据(无需转发\免费获取)

人类足迹(Human Footprint)是生态过程和自然景观变化对生态环境造成的压力&#xff0c;是世界各国对生物多样性和生态保护的关注重点。那如何才能获取长时间跨度的人类足迹时空数据呢&#xff1f; 之前我们分享了来自于中国农业大学土地科学与技术学院的城市环境监测及建模&am…

实时语义分割网络 BiSeNet , RK1126 Npu 推理

记录下在rk1126上&#xff0c;实现 BiSeNet 网络推理. https://github.com/CoinCheung/BiSeNet ONNX 生成 onnx 模型 python tools/export_onnx.py --config configs/bisenetv2_city.py --weight-path ./checkpoints/model_final_v2_city.pth --outpath ./checkpoints/mode…