ALSA驱动中-EBADFD错误原因解析及对策

简介: 在alsa驱动中有如下状态:   #define SNDRV_PCM_STATE_OPEN  ((__force snd_pcm_state_t) 0) /* stream is open */#define SNDRV_PCM_STATE_SE...

在alsa驱动中有如下状态:

 

#define SNDRV_PCM_STATE_OPEN  ((__force snd_pcm_state_t) 0) /* stream is open */
#define SNDRV_PCM_STATE_SETUP  ((__force snd_pcm_state_t) 1) /* stream has a setup */
#define SNDRV_PCM_STATE_PREPARED ((__force snd_pcm_state_t) 2) /* stream is ready to start */
#define SNDRV_PCM_STATE_RUNNING  ((__force snd_pcm_state_t) 3) /* stream is running */
#define SNDRV_PCM_STATE_XRUN  ((__force snd_pcm_state_t) 4) /* stream reached an xrun */
#define SNDRV_PCM_STATE_DRAINING ((__force snd_pcm_state_t) 5) /* stream is draining */
#define SNDRV_PCM_STATE_PAUSED  ((__force snd_pcm_state_t) 6) /* stream is paused */
#define SNDRV_PCM_STATE_SUSPENDED ((__force snd_pcm_state_t) 7) /* hardware is suspended */
#define SNDRV_PCM_STATE_DISCONNECTED ((__force snd_pcm_state_t) 8) /* hardware is disconnected */
#define SNDRV_PCM_STATE_LAST  SNDRV_PCM_STATE_DISCONNECTED

 

     在ALSA最底层写函数snd_pcm_lib_write1中,首先检测当前PCM的状态,是 SNDRV_PCM_STATE_PREPARED、SNDRV_PCM_STATE_RUNNING、 SNDRV_PCM_STATE_PAUSED这三种状态下,驱动就开始transfer数据,如果为SNDRV_PCM_STATE_XRUN返回-EPIPE错误,如果为SNDRV_PCM_STATE_SUSPENDED,就返回 -ESTRPIPE;其他状态均返回-EBADFD错误。

    在打开一个PCM流时,PCM的状态为SNDRV_PCM_STATE_OPEN ,给这个流配置参数,如channel数、采样率、采样精度后,PCM的状态配置为SNDRV_PCM_STATE_SETUP,在写数据之前,需要提示驱动去各继各位,准备工作,这时候去prepare一下,就像是考试前的动员大会一样,让你热血沸腾、充满信心,prepare后PCM流的状态为SNDRV_PCM_STATE_PREPARED,开始写数据的过程中,PCM的状态会设置为 SNDRV_PCM_STATE_RUNNING,播放完数据后,通常需要去drain一下来sync,在调snd_pcm_drain过程中,PCM的状态为PCM的状态,drain完以后PCM的状态为会设置为SNDRV_PCM_STATE_SETUP,因此在再次写数据的时候,驱动就会返回-EBADFD的错误,那么如何有效避免呢?

     办法当然是有的,alsa-lib中提供了非常完善的接口。笔者也曾碰到过-EBADFD的错误,很烦人啊!出了错后,alsa驱动就需要恢复错误状态,或者干脆重新打开一次播放流程,但是这样做的后果就是有可能带来“兹兹”噪音或者如“都-都”这样的怪音,这种现象出来对产品来说肯定是不利的,因此在上层再次调用alsa写函数的时候,首先去获取一些当前PCM的状态是什么,用snd_pcm_state函数,如果当前PCM为 SNDRV_PCM_STATE_SETUP,只需要snd_pcm_prepare一下,就可以进行正常的数据写操作。

    在系统进入省电模式时,驱动会执行suspend,PCM状态变为SNDRV_PCM_STATE_SUSPENDED,在唤醒系统后,笔者在adroid系统中发现,PCM的状态仍然为SNDRV_PCM_STATE_SUSPENDED状态,在这种状态下,直接进行写操作,无疑会带来-EBADFD的错误。如果在写数据的之前,检测到的pcm状态为SNDRV_PCM_STATE_SUSPENDED,就可以先snd_pcm_resume,再snd_pcm_prepare一下,alsa就可以回到正常工作状态,可以正常的写数据。

    -EBADFD错误的产生,就是因为alsa的驱动状态没有控制好,得严格按照alsa要求的状态转换去工作,否则会碰壁。

 

目录
相关文章
|
1月前
|
消息中间件 Cloud Native Java
【Spring云原生系列】SpringBoot+Spring Cloud Stream:消息驱动架构(MDA)解析,实现异步处理与解耦合
【Spring云原生系列】SpringBoot+Spring Cloud Stream:消息驱动架构(MDA)解析,实现异步处理与解耦合
|
6月前
|
存储 边缘计算 数据管理
Docker 存储驱动解析:选择最适合你的存储方案,优化容器化部署性能和数据管理
Docker 存储驱动解析:选择最适合你的存储方案,优化容器化部署性能和数据管理
142 0
|
2月前
|
人工智能 安全 大数据
开源软件全景解析:驱动技术创新与行业革新的力量
开源软件全景解析:驱动技术创新与行业革新的力量
391 0
开源软件全景解析:驱动技术创新与行业革新的力量
|
3月前
|
存储 机器学习/深度学习 数据挖掘
数据仓库与数据湖:解析数据驱动的未来
在数字化时代,数据成为企业决策的核心资源。本文将深入探讨数据仓库和数据湖的概念、特点以及应用场景,分析其在实现数据驱动决策过程中的重要性和优势,并展望数据驱动的未来发展趋势。
51 5
|
4月前
|
C语言 Windows
9.3 Windows驱动开发:内核解析PE结构节表
在笔者上一篇文章`《内核解析PE结构导出表》`介绍了如何解析内存导出表结构,本章将继续延申实现解析PE结构的PE头,PE节表等数据,总体而言内核中解析PE结构与应用层没什么不同,在上一篇文章中`LyShark`封装实现了`KernelMapFile()`内存映射函数,在之后的章节中这个函数会被多次用到,为了减少代码冗余,后期文章只列出重要部分,读者可以自行去前面的文章中寻找特定的片段。
26 0
9.3 Windows驱动开发:内核解析PE结构节表
|
4月前
|
存储 Windows
9.2 Windows驱动开发:内核解析PE结构导出表
在笔者的上一篇文章`《内核特征码扫描PE代码段》`中`LyShark`带大家通过封装好的`LySharkToolsUtilKernelBase`函数实现了动态获取内核模块基址,并通过`ntimage.h`头文件中提供的系列函数解析了指定内核模块的`PE节表`参数,本章将继续延申这个话题,实现对PE文件导出表的解析任务,导出表无法动态获取,解析导出表则必须读入内核模块到内存才可继续解析,所以我们需要分两步走,首先读入内核磁盘文件到内存,然后再通过`ntimage.h`中的系列函数解析即可。
35 0
9.2 Windows驱动开发:内核解析PE结构导出表
|
6月前
|
存储 Linux Go
Docker 存储驱动解析:选择最适合你的存储方案
Docker 存储驱动解析:选择最适合你的存储方案
89 0
|
10月前
|
C语言 Windows
驱动开发:内核解析PE结构节表
在笔者上一篇文章`《驱动开发:内核解析PE结构导出表》`介绍了如何解析内存导出表结构,本章将继续延申实现解析PE结构的PE头,PE节表等数据,总体而言内核中解析PE结构与应用层没什么不同,在上一篇文章中`LyShark`封装实现了`KernelMapFile()`内存映射函数,在之后的章节中这个函数会被多次用到,为了减少代码冗余,后期文章只列出重要部分,读者可以自行去前面的文章中寻找特定的片段。
171 0
|
11月前
|
存储 Windows
驱动开发:内核解析PE结构导出表
在笔者的上一篇文章`《驱动开发:内核特征码扫描PE代码段》`中`LyShark`带大家通过封装好的`LySharkToolsUtilKernelBase`函数实现了动态获取内核模块基址,并通过`ntimage.h`头文件中提供的系列函数解析了指定内核模块的`PE节表`参数,本章将继续延申这个话题,实现对PE文件导出表的解析任务,导出表无法动态获取,解析导出表则必须读入内核模块到内存才可继续解析,所以我们需要分两步走,首先读入内核磁盘文件到内存,然后再通过`ntimage.h`中的系列函数解析即可。
214 0
|
11月前
驱动开发:内核解析内存四级页表
当今操作系统普遍采用64位架构,CPU最大寻址能力虽然达到了64位,但其实仅仅只是用到了48位进行寻址,其内存管理采用了`9-9-9-9-12`的分页模式,`9-9-9-9-12`分页表示物理地址拥有四级页表,微软将这四级依次命名为PXE、PPE、PDE、PTE这四项。关于内存管理和分页模式,不同的操作系统和体系结构可能会有略微不同的实现方式。9-9-9-9-12的分页模式是一种常见的分页方案,其中物理地址被分成四级页表:PXE(Page Directory Pointer Table Entry)、PPE(Page Directory Entry)、PDE(Page Table Entry)
10788 0

推荐镜像

更多