Linux音频了解

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.rhkb.cn/news/114447.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

计算机网络 第二节

目录 一&#xff0c;计算机网络的分类 1.按照覆盖范围分 2.按照所属用途分 二&#xff0c;计算机网络逻辑组成部分 1.核心部分 &#xff08;通信子网&#xff09; 1.1电路交换 1.2 分组交换 两种方式的特点 重点 2.边缘部分 &#xff08;资源子网&#xff09; 进程通信的方…

如何在 iPhone 上检索已删除的短信

我厌倦了垃圾短信。当我例行公事地删除 iPhone 上的这些不需要的消息时&#xff0c;当我分散注意力时&#xff0c;我通过点击错误的按钮清除了所有消息。这些被删除的消息中包含两条团购验证信息。有什么办法可以从 iPhone 检索我的消息吗&#xff1f; 有时我们可能会不小心删…

iOS 使用coreData存贮页面的模型数据中的字典

我们使用coreData时候&#xff0c;会遇到较为复杂的数据类型的存贮&#xff0c;例如&#xff0c;我们要存一个模型&#xff0c;但是一个模型里面有个字典&#xff0c;这时候&#xff0c;我们该如何存贮呢 如图所示&#xff0c;一个对象中含有一个字典 我们实现一个公共的方法…

Python小知识 - 使用Python进行数据分析

使用Python进行数据分析 数据分析简介 数据分析&#xff0c;又称为信息分析&#xff0c;是指对数据进行综合处理、归纳提炼、概括总结的过程&#xff0c;是数据处理的第一步。 数据分析的目的是了解数据的内在规律&#xff0c;为数据挖掘&#xff0c;并应用于商业决策、科学研究…

java 批量下载将多个文件(minio中存储)压缩成一个zip包

我的需求是将minio中存储的文件按照查询条件查询出来统一压成一个zip包然后下载下来。 思路&#xff1a;针对这个需求&#xff0c;其实可以有多个思路&#xff0c;不过也大同小异&#xff0c;一般都是后端返回流文件前端再处理下载&#xff0c;也有少数是压缩成zip包之后直接给…

登录校验-Filter-登录校验过滤器

目录 思路 登录校验Filter-流程 步骤 流程图 登录校验Filter-代码 过滤器类 工具类 测试登录 登录接口功能请求 其他接口功能请求 前后端联调 思路 前端访问登录接口&#xff0c;登陆成功后&#xff0c;服务端会生成一个JWT令牌&#xff0c;并返回给前端&#xff0…

Vue中使用qrcode实现渲染二维码中间添加自定义logo-demo

效果 使用 import QRCode from qrcode; 具体生成过程 <template><div class"banner-login"><img :src"qrDataUrl" /></div> </template><script setup> import { ref, reactive } from vue; import QRCode from q…

IDEA批量处理行尾注释

前言 行尾注释写起来比较方便&#xff0c;所以很多时候我们都会习惯把注释写在行尾。 但这个是不符合编程规范的&#xff0c;写的代码注释主要是给后续接手人进行阅读帮助的。按照正常的阅读方式都是先读注释&#xff0c;然后再看代码&#xff0c;如果先看代码再看注释&#…

浅谈多人游戏原理和简单实现。

&#x1f61c;作 者&#xff1a;是江迪呀✒️本文关键词&#xff1a;websocket、网络、原理、多人游戏☀️每日 一言&#xff1a;这世上有两种东西无法直视&#xff0c;一是太阳&#xff0c;二是人心&#xff01; 一、我的游戏史 我最开始接触游戏要从一盘300游戏…

振动国标2009GB/T 19873.2-2009/ISO 13373-2:2005笔记

国标原文 1.时域&#xff0c;要求&#xff0c;采样率大于最高频率10倍&#xff08;最低频率&#xff1f;&#xff09; 2.频域&#xff0c;要求采样率大于最高频率2倍。 3.3.2 积分和微分&#xff0c;二次积分。 3.3.3 均方根。 3.4 滤波 4.1 奈奎斯特图、极坐标图、坎贝尔…

Linux线程控制

目录 一、线程的简单控制 1.多线程并行 2.线程结束 3.线程等待 &#xff08;1&#xff09;系统调用 &#xff08;2&#xff09;返回值 4.线程取消 5.线程分离 二、C多线程小组件 三、线程库TCB 1.tid 2.局部储存 一、线程的简单控制 1.多线程并行 我们之前学过pt…

Windows SQLYog连接不上VMbox Ubuntu2204 的Mysql解决方法

Windows SQLYog连接不上VMbox Ubuntu2204 的Mysql解决方法 解决方法&#xff1a; 1、先检查以下mysql的端口状态 netstat -anp|grep mysql如果显示127.0.0.1:3306 则说明需要修改&#xff0c;若为: : :3306&#xff0c;则不用。 在**/etc/mysql/mysql.conf.d/mysqld.cnf**&am…

MySQL内置函数

文章目录 MySQL内置函数1. 日期函数1.1 用法演示(1) 获得年月日 - current_date()(2) 获得时分秒 - current_time()(3) 获得时间戳 - current_timestamp()(4) 获得当前时间- now()(5) 获取datetime参数的日期部分 - date(datetime)(6) 在日期的基础上加时间 - date_add(date, i…

JSX底层渲染机制

JSX底层渲染机制 一,.步骤 1.把我们写的jsx语法编译为虚拟DOM【virtualDOM】 虚拟DOM对象&#xff1a;框架自己内部构建的一套对象体系&#xff08;对象的相关成员都是React内部绑定的&#xff09;&#xff0c;基于这些属性描述出我们所构建视图中的DOM接的相关特征 1基于ba…

Linux学习之逻辑卷LVM用途和创建

理论基础 Linux文件系统建立在逻辑卷上&#xff0c;逻辑卷建立在物理卷上。 物理卷处于LVM中的最底层&#xff0c;可以将其理解为物理硬盘、硬盘分区或者RAID磁盘阵列&#xff0c;这都可以。卷组建立在物理卷之上&#xff0c;一个卷组可以包含多个物理卷&#xff0c;而且在卷组…

CSS中如何实现元素的渐变背景(Gradient Background)效果?

聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ CSS 渐变背景效果⭐ 线性渐变背景⭐ 径向渐变背景⭐ 添加到元素的样式⭐ 写在最后 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 记得点击上方或者右侧链接订阅本专栏哦 几何带你启航前端之旅 欢迎来到前端入门之旅&…

安全基础 --- https详解(02)、cookie和session、同源和跨域

https详解&#xff08;02&#xff09;--- 数据包扩展 Request --- 请求数据包Response --- 返回数据包 若出现代理则如下图&#xff1a; Proxy --- 代理服务器 &#xff08;1&#xff09;http和https的区别 http明文传输&#xff0c;数据未加密&#xff1b;http页面响应速度…

FreeSWITCH 1.10.10 简单图形化界面3 - 阿里云NAT设置

FreeSWITCH 1.10.10 简单图形化界面3 - 阿里云NAT设置 0、 界面预览1、 查看IP地址2、 修改协议配置3、 开放阿里云安全组4、 设置ACL5、 设置协议中ACL&#xff0c;让PBX匹配内外网6、 重新加载SIP模块7、 查看状态8、 测试一下 0、 界面预览 http://myfs.f3322.net:8020/ 用…

2023年腾讯云优惠券(代金券)领取方法整理汇总

腾讯云优惠券是腾讯云为了吸引用户而推出的一种优惠凭证&#xff0c;领券之后新购、续费、升级腾讯云的相关产品可以享受优惠&#xff0c;从而节省一点的费用&#xff0c;下面给大家分享腾讯云优惠券领取的几种方法。 一、腾讯云官网领券页面领取 腾讯云官网经常推出各种优惠活…

软件测试/测试开发丨Selenium 高级定位 Xpath

点此获取更多相关资料 本文为霍格沃兹测试开发学社学员学习笔记分享 原文链接&#xff1a;https://ceshiren.com/t/topic/27036 一、xpath 基本概念 XPATH是一门在XML文档中查找信息的语言 XPATH使用路径表达式在XML文档中进行导航 XPATH的应用非常广泛&#xff0c;可以用于UI自…