零基础入门多媒体音频(5)-alsa(1)

news/2024/4/29 15:39:45/文章来源:https://blog.csdn.net/weixin_52370850/article/details/137026684

alsa是音频最重要的框架,没有之一。接下来一个月时间在总结工作知识的主线上。单开个音频支线讲解alsa。说实话,alsa这块我也不是很精通。只在过去的项目中增加 一路substream实现低延时。我打算从下面四个方面去学习alsa。
1.alsa官网。网址如下,大家也可以学习后在评论里 交流,互相进步。如果想偷懒也可以直接看我的总结。
https://www.alsa-project.org/wiki/Main_Page

2.阅读在工作项目中alsa的源码。

3.整理网上各类免费的alsa资源。

4.向开发驱动的同事沟通请教。

写PCI驱动的基本流程

定义PCI ID表 (其它类型的驱动应该也有类似的结构体,比如I2S。后续探究一下)
定义probe回调函数
定义remove回调函数
创建struct pci_driver类型的结构体指向上面的三个元素
定义init 函数,在函数中调用pci_register_driver() 来注册上面定义的pci_driver结构体
定义exit函数来执行pci_unregister_driver()

简单总结一下上面的步骤,其实就两部分:1.定义钩子函数。2.将新定义的模块(结构体+函数)加入/移出框架

下面是个示例代码,重点关注snd_mychip_probe函数和snd_mychip_remove。这两个函数怎么暴露到alsa框架调用呢?

#include <linux/init.h>
#include <linux/pci.h>
#include <linux/slab.h>
#include <sound/core.h>
#include <sound/initval.h>/* module parameters (see "Module Parameters") */
/* SNDRV_CARDS: maximum number of cards supported by this module */
static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;/* definition of the chip-specific record */
struct mychip {struct snd_card *card;/* the rest of the implementation will be in section* "PCI Resource Management"*/
};/* chip-specific destructor* (see "PCI Resource Management")*/
static int snd_mychip_free(struct mychip *chip)
{.... /* will be implemented later... */
}/* component-destructor* (see "Management of Cards and Components")*/
static int snd_mychip_dev_free(struct snd_device *device)
{return snd_mychip_free(device->device_data);
}/* chip-specific constructor* (see "Management of Cards and Components")*/
static int snd_mychip_create(struct snd_card *card,struct pci_dev *pci,struct mychip **rchip)
{struct mychip *chip;int err;static const struct snd_device_ops ops = {.dev_free = snd_mychip_dev_free,};*rchip = NULL;/* check PCI availability here* (see "PCI Resource Management")*/..../* allocate a chip-specific data with zero filled */chip = kzalloc(sizeof(*chip), GFP_KERNEL);if (chip == NULL)return -ENOMEM;chip->card = card;/* rest of initialization here; will be implemented* later, see "PCI Resource Management"*/....err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops);if (err < 0) {snd_mychip_free(chip);return err;}*rchip = chip;return 0;
}
// 对外接口
/* constructor -- see "Driver Constructor" sub-section */
static int snd_mychip_probe(struct pci_dev *pci,const struct pci_device_id *pci_id)
{static int dev;struct snd_card *card;struct mychip *chip;int err;/* (1) */if (dev >= SNDRV_CARDS)return -ENODEV;if (!enable[dev]) {dev++;return -ENOENT;}/* (2) */err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE,0, &card);if (err < 0)return err;/* (3) */err = snd_mychip_create(card, pci, &chip);if (err < 0)goto error;/* (4) */strcpy(card->driver, "My Chip");strcpy(card->shortname, "My Own Chip 123");sprintf(card->longname, "%s at 0x%lx irq %i",card->shortname, chip->port, chip->irq);/* (5) */.... /* implemented later *//* (6) */err = snd_card_register(card);if (err < 0)goto error;/* (7) */pci_set_drvdata(pci, card);dev++;return 0;error:snd_card_free(card);return err;
}/* destructor -- see the "Destructor" sub-section */
static void snd_mychip_remove(struct pci_dev *pci)
{snd_card_free(pci_get_drvdata(pci));
}

驱动的构造函数

PCI驱动的真正构造函数时probe回调函数。probe回调函数和所有被probe调用的函数都不可以用__init作为前缀名。因为所有的PCI设备都可能是个热插拔设备。
在probe回调函数中,遵循下面的基本流程。

1)检查和增加device索引。(一个card可以支持多个devcie)

static int dev;
....
if (dev >= SNDRV_CARDS)return -ENODEV;
if (!enable[dev]) {dev++;return -ENOENT;
}

2)创建声卡实例。这个函数是alsa框架提供的。创建alsa的声卡类型。

struct snd_card *card;
int err;
....
err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE,0, &card);

3)创建核心组件(与实际业务关联的结构体),在实例中,分配了PCI资源。

struct mychip *chip;
....
err = snd_mychip_create(card, pci, &chip);
if (err < 0)goto error;

发生异常时,probe函数需要处理异常。在这个示例中,包含一个错误处理逻辑在函数末尾。

error:snd_card_free(card);return err;

4)设置驱动的ID和名字。(这里的结构体是通过alsa框架函数获取的。实现了类似将驱动注册到alsa框架的效果)

strcpy(card->driver, "My Chip");
strcpy(card->shortname, "My Own Chip 123");
sprintf(card->longname, "%s at 0x%lx irq %i",card->shortname, chip->port, chip->irq);

驱动的字段包含芯片的ID字段。alsa-lib的配置器会使用这个字段。这个字段尽量做到简单和唯一。即使是同一个驱动也可以使用不同的驱动ID。通过不同的ID来区别不同功能的芯片。shortname 字段是个更加冗余的名字。而longname 字段包含了显示在 /proc/asound/cards的信息。

5)创建其它的组件,包括mixer,MIDI,以及其他的接口。如果需要有proc信息的功能,也可以定义在这里。

6)将PCI驱动注册到alsa框架

err = snd_card_register(card);
if (err < 0)goto error;

7)把驱动特定数据设置到card结构体

pci_set_drvdata(pci, card);
dev++;
return 0;

在上面的代码中,card的数据被保存下来了。这个指针会在回调函数中使用。

析构函数

remove回调函数就是析构函数,它会释放card实例。ALSA中间层会自动释放所有绑定的组件。
比较常见的方法就是调用snd_card_free()函数。

static void snd_mychip_remove(struct pci_dev *pci)
{snd_card_free(pci_get_drvdata(pci));
}

上述代码的前提是card指针被设置到PCI的驱动数据中。

从声卡card角度看,初始化共进行了这些操作。
snd_card_new 分配声卡
snd_card_register 注册声卡
pci_set_drvdata 绑定声卡
这些都是alsa-core的接口,也就是我们的驱动通过这些接口与alsa框架建立链接。

snd_device_new()来生成一个snd_device实例,并把该实例链接到snd_card的devices链表中

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

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

相关文章

maven的依赖继承

先说一下创建子maven工程的步骤 继承 继承的作用&#xff1a;在父工程中&#xff0c;统一管理项目中的依赖信息&#xff0c;进行统一的版本控制 继承的背景是&#xff1a;对一个大型的项目进行了模块拆分&#xff0c;一个project下&#xff0c;创建了很多的module&#xff0c…

golang grpc和protobuf的版本降级问题(version4 -> version3)

最后更新于2024年3月28日 10:57:52 简中没查到类似的文章。一点小事闹麻了&#xff0c;搞了一天&#xff0c;特意发出来造福大家。 所谓的版本就是下面这个东西proto.ProtoPackageIsVersion4或者proto.ProtoPackageIsVersion3&#xff1a; 目的 为了适配旧代码&#xff0c…

linux shell命令(进程管理、用户管理)

一、进程的概念 主要有两点&#xff1a; 1.进程是一个实体。每一个进程都有它自己的地址空间&#xff0c;一般情况下&#xff0c;包括文本区域&#xff08;text region&#xff09;、数据区域&#xff08;data region&#xff09;和堆栈&#xff08;stack region&#xff09;…

百度智能小程序源码系统简洁版 SEO关键词排名推广优化 带完整的安装代码包以及搭建教程

移动互联网的快速发展&#xff0c;小程序以其轻量级、无需下载、即用即走的特点&#xff0c;迅速成为了各大平台争相推广的重要产品形态。百度智能小程序作为百度生态下的重要一环&#xff0c;凭借其强大的流量入口和丰富的功能组件&#xff0c;为开发者提供了广阔的创作空间。…

fastadmin学习05-开启debug以及配置

FastAdmin 框架提供了对 .env 环境变量配置的支持&#xff0c;并附带一个默认示例文件 .env.sample。在安装后&#xff0c;框架并不会自动启用 env 环境变量&#xff0c;需要手动将 .env.sample 复制为 .env 并进行配置。 如果不开启.env会读取database.php中的配置 下面测试…

基于单片机智能可控电源系统设计

**单片机设计介绍&#xff0c;基于单片机智能可控电源系统设计 文章目录 一 概要二、功能设计设计思路 三、 软件设计原理图 五、 程序六、 文章目录 一 概要 基于单片机智能可控电源系统设计的主要目标是实现电源的智能控制、监测和保护功能&#xff0c;以满足不同应用场景下…

计算机网络:物理层 - 信道极限容量

计算机网络&#xff1a;物理层 - 信道极限容量 实际信道中的数字信号奈式准则香农公式练习 实际信道中的数字信号 信号在传输过程中会受到各种因素的影响&#xff0c;如图所示&#xff1a; 这是一个数字信号&#xff0c;当它通过实际的信道后&#xff0c;波形会产生失真&#…

LLM2LLM: Boosting LLMs with Novel Iterative Data Enhancement

LLM2LLM: Boosting LLMs with Novel Iterative Data Enhancement 相关链接&#xff1a;arXiv GitHub 关键字&#xff1a;LLM、Data Augmentation、Fine-tuning、NLP、Low-data Regime 摘要 预训练的大型语言模型&#xff08;LLMs&#xff09;目前是解决绝大多数自然语言处理任…

如何选择最适合Shopee店铺的支付方式?

Shopee平台为卖家提供了多元化的收款选项&#xff0c;包括了在线支付、虚拟账户余额支付以及线下支付方式。卖家在选择收款方式时&#xff0c;必须充分考虑到市场适应性这一关键因素。因为不同地区和不同国家的消费者对于支付方式有着不同的偏好和习惯&#xff0c;因此&#xf…

零基础入门数据挖掘系列之「特征工程」

摘要&#xff1a;对于数据挖掘项目&#xff0c;本文将学习应该从哪些角度做特征工程&#xff1f;从哪些角度做数据清洗&#xff0c;如何对特征进行增删&#xff0c;如何使用PCA降维技术等。 特征工程&#xff08;Feature Engineering&#xff09;对特征进行进一步分析&#xf…

AI+软件工程:10倍提效!用ChatGPT编写系统功能文档

系统功能文档是一种描述软件系统功能和操作方式的文档。它让开发团队、测试人员、项目管理者、客户和最终用户对系统行为有清晰、全面的了解。 通过ChatGPT&#xff0c;我们能让编写系统功能文档的效率提升10倍以上。 ​《Leetcode算法刷题宝典》一位阿里P8大佬总结的刷题笔记…

深入理解PHP+Redis实现分布式锁的相关问题

概念 PHP使用分布式锁&#xff0c;受语言本身的限制&#xff0c;有一些局限性。 通俗理解单机锁问题&#xff1a;自家的锁锁自家的门&#xff0c;只能保证自家的事&#xff0c;管不了别人家不锁门引发的问题&#xff0c;于是有了分布式锁。分布式锁概念&#xff1a;是针对多个…

通过Caliper进行压力测试程序,且汇总压力测试问题解决

环境要求 第一步. 配置基本环境 部署Caliper的计算机需要有外网权限;操作系统版本需要满足以下要求:Ubuntu >= 16.04、CentOS >= 7或MacOS >= 10.14;部署Caliper的计算机需要安装有以下软件:python 2.7、make、g++(gcc-c++)、gcc及git。第二步. 安装NodeJS # …

RegSeg 学习笔记(待完善)

论文阅读 解决的问题 引用别的论文的内容 可以用 controlf 寻找想要的内容 PPM 空间金字塔池化改进 SPP / SPPF / SimSPPF / ASPP / RFB / SPPCSPC / SPPFCSPC / SPPELAN &#xfffc; ASPP STDC&#xff1a;short-term dense concatenate module 和 DDRNet SE-ResNeXt …

初识React(一)从井字棋游戏开始

写在前面&#xff1a; 磨磨唧唧了好久终于下定决心开始学react&#xff0c;刚刚接触感觉有点无从下脚...新的语法新的格式跟vue就像两种物种...倒是很好奇路由和store是怎么实现的了~v~&#xff0c;一点一点来吧&#xff01;&#xff01;&#xff01; (一)创建项目 使用vite…

Reactor设计模式和Reactor模型

Reactor设计模式 翻译过来就是反应堆&#xff0c;所以Reactor设计模式本质是基于事件驱动。 角色 Handle&#xff08;事件&#xff09;EventHandler&#xff08;事件处理器&#xff09;ConcreteEventHandler&#xff08;具体事件处理器&#xff09;Synchronous Event Demult…

QT实现蒙层效果

一.蒙层的作用 1.为了其他窗口不被误操作&#xff0c;禁止对其他窗口操作 二.应用场景 1.一些触摸屏设备上弹出一个dialog窗口&#xff0c;在操作这个窗口的时候不希望后面的窗口被误操作 2.之前做一个医疗设备就曾有过这种需求&#xff0c;因为医疗设备对安全性要求非常高&…

利用 Scapy 库编写 ARP 缓存中毒攻击脚本

一、ARP 协议基础 参考下篇文章学习 二、ARP 缓存中毒原理 ARP&#xff08;Address Resolution Protocol&#xff09;缓存中毒是一种网络攻击&#xff0c;它利用了ARP协议中的漏洞&#xff0c;通过欺骗或篡改网络中的ARP缓存来实施攻击。ARP协议是用于将IP地址映射到物理MAC…

各大pdf转word软件都用的哪家的ocr引擎?

国内一般的PDF软件一般都调用某国际PDF原厂的OCR接口&#xff0c;但这家公司是主要做PDF&#xff0c;在OCR方面并不专注&#xff0c;一些不是很复杂的场景还能应付得过来&#xff0c;复杂一点的效果就强差人意了&#xff0c;推荐用金鸣表格文字识别系统&#xff0c;它主要有以下…

基于树莓派实现 --- 智能家居

最效果展示 演示视频链接&#xff1a;基于树莓派实现的智能家居_哔哩哔哩_bilibilihttps://www.bilibili.com/video/BV1Tr421n7BM/?spm_id_from333.999.0.0 &#xff08;PS&#xff1a;房屋模型的搭建是靠纸板箱和淘宝买的家居模型&#xff0c;户型参考了留学时短租的公寓~&a…