精华内容
下载资源
问答
  • 2021-05-11 20:32:28

    一. 概述

    在内核设备驱动层,ALSA提供了alsa-driver,同时在应用层,ALSA为我们提供了alsa-lib,应用程序只要调用alsa-lib提供的API,即可以完成对底层音频硬件的控制。

    forum.php?mod=image&aid=226559&size=300x300&key=5a83085f0ca23c07&nocache=yes&type=fixnone

    图 1.1 alsa的软件体系结构

    由图1.1可以看出,用户空间的alsa-lib对应用程序提供统一的API接口,这样可以隐藏了驱动层的实现细节,简化了应用程序的实现难度。内核空间中,alsa-soc其实是对alsa-driver的进一步封装,他针对嵌入式设备提供了一些列增强的功能。本系列博文仅对嵌入式系统中的alsa-driver和alsa-soc进行讨论。

    二. ALSA设备文件结构

    我们从alsa在linux中的设备文件结构开始我们的alsa之旅. 看看我的电脑中的alsa驱动的设备文件结构:

    $ cd /dev/snd

    $ ls -l

    crw-rw----  1 root audio 116, 8 2011-02-23 21:38 controlC0

    crw-rw----  1 root audio 116, 4 2011-02-23 21:38 midiC0D0

    crw-rw----  1 root audio 116, 7 2011-02-23 21:39 pcmC0D0c

    crw-rw----  1 root audio 116, 6 2011-02-23 21:56 pcmC0D0p

    crw-rw----  1 root audio 116, 5 2011-02-23 21:38 pcmC0D1p

    crw-rw----  1 root audio 116, 3 2011-02-23 21:38 seq

    crw-rw----  1 root audio 116, 2 2011-02-23 21:38 timer

    $

    我们可以看到以下设备文件:

    controlC0 --> 用于声卡的控制,例如通道选择,混音,麦克风的控制等

    midiC0D0 --> 用于播放midi音频

    pcmC0D0c --〉 用于录音的pcm设备

    pcmC0D0p --〉 用于播放的pcm设备

    seq --〉 音序器

    timer --〉 定时器

    其中,C0D0代表的是声卡0中的设备0,pcmC0D0c最后一个c代表capture,pcmC0D0p最后一个p代表playback,这些都是alsa-driver中的命名规则。从上面的列表可以看出,我的声卡下挂了6个设备,根据声卡的实际能力,驱动实际上可以挂上更多种类的设备,在include/sound/core.h中,定义了以下设备类型:

    view plain#define SNDRV_DEV_TOPLEVEL ((__force snd_device_type_t) 0)

    #define SNDRV_DEV_CONTROL ((__force snd_device_type_t) 1)

    #define SNDRV_DEV_LOWLEVEL_PRE ((__force snd_device_type_t) 2)

    #define SNDRV_DEV_LOWLEVEL_NORMAL ((__force snd_device_type_t) 0x1000)

    #define SNDRV_DEV_PCM ((__force snd_device_type_t) 0x1001)

    #define SNDRV_DEV_RAWMIDI ((__force snd_device_type_t) 0x1002)

    #define SNDRV_DEV_TIMER ((__force snd_device_type_t) 0x1003)

    #define SNDRV_DEV_SEQUENCER ((__force snd_device_type_t) 0x1004)

    #define SNDRV_DEV_HWDEP ((__force snd_device_type_t) 0x1005)

    #define SNDRV_DEV_INFO ((__force snd_device_type_t) 0x1006)

    #define SNDRV_DEV_BUS ((__force snd_device_type_t) 0x1007)

    #define SNDRV_DEV_CODEC ((__force snd_device_type_t) 0x1008)

    #define SNDRV_DEV_JACK ((__force snd_device_type_t) 0x1009)

    #define SNDRV_DEV_LOWLEVEL ((__force snd_device_type_t) 0x2000)

    通常,我们更关心的是pcm和control这两种设备。

    三. 驱动的代码文件结构

    在Linux2.6代码树中,Alsa的代码文件结构如下:

    sound

    /core

    /oss

    /seq

    /ioctl32

    /include

    /drivers

    /i2c

    /synth

    /emux

    /pci

    /(cards)

    /isa

    /(cards)

    /arm

    /ppc

    /sparc

    /usb

    /pcmcia /(cards)

    /oss

    /soc

    /codecs

    core 该目录包含了ALSA驱动的中间层,它是整个ALSA驱动的核心部分

    core/oss 包含模拟旧的OSS架构的PCM和Mixer模块

    core/seq 有关音序器相关的代码

    include ALSA驱动的公共头文件目录,该目录的头文件需要导出给用户空间的应用程序使用,通常,驱动模块私有的头文件不应放置在这里

    drivers 放置一些与CPU、BUS架构无关的公用代码

    i2c ALSA自己的I2C控制代码

    pci pci声卡的顶层目录,子目录包含各种pci声卡的代码

    isa isa声卡的顶层目录,子目录包含各种isa声卡的代码

    soc 针对system-on-chip体系的中间层代码

    soc/codecs 针对soc体系的各种codec的代码

    更多相关内容
  • Linux ALSA 之一:ALSA 架构简介

    一、概述

    ALSA是 Advanced Linux Sound Architecture 的缩写,目前已经成为了linux的主流音频体系结构。

    在 Linux 内核设备驱动层,ALSA 提供了 alsa-driver,在应用层,ALSA 为我们提供了 alsa-lib,故在其支持下,Linux 应用程序只需要调用 alsa-lib 提供的 API,即可完成对底层音频硬件的控制。linux内核中alsa的软件结构如下:
    在这里插入图片描述
    用户空间的 alsa-lib 对应用程序提供统一的 API 接口,隐藏了驱动层的实际细节,简化了应用程序的实现难度,但是由于 alsa-lib 也由于过大,因此在 android 等下也经常使用 tiny-alsa,详细描述此处略。

    如上图所示,在 Linux 内核中,有对 alsa-driver 进一步的封装,即 alsa-soc,其针对 alsa 的一些不足之处进行了增强,后面篇幅会详细介绍。

    二、ALSA 设备文件结构

    Linux 系统下看到的设备文件结构如下:

    $ cd /dev/snd
    $ ls -l
    crw-rw----+ 1 root audio 116, 8 2011-02-23 21:38 controlC0
    crw-rw----+ 1 root audio 116, 4 2011-02-23 21:38 midiC0D0
    crw-rw----+ 1 root audio 116, 7 2011-02-23 21:39 pcmC0D0c
    crw-rw----+ 1 root audio 116, 6 2011-02-23 21:56 pcmC0D0p
    crw-rw----+ 1 root audio 116, 5 2011-02-23 21:38 pcmC0D1p
    crw-rw----+ 1 root audio 116, 3 2011-02-23 21:38 seq
    crw-rw----+ 1 root audio 116, 2 2011-02-23 21:38 timer
    

    从上面能看到有如下设备文件:

    controlC0 -->              用于声卡的控制,例如通道选择,混音,麦克控制,音量加减,开关等
    midiC0D0  -->              用于播放midi音频
    pcmC0D0c -->               用于录音的pcm设备
    pcmC0D0p -->               用于播放的pcm设备
    seq  -->                   音序器
    timer -->                  定时器
    

    其中,C0D0代表的是声卡0中的设备0,pcmC0D0c最后一个c代表capture,pcmC0D0p最后一个p代表playback,这些都是alsa-driver中的命名规则,从上面的列表可以看出,我的声卡下挂了6个设备,根据声卡的实际能力,驱动实际上可以挂载更多种类的设备,在include/sound/core.h 中,定义了以下设备类型,通常更关心的是 pcmcontrol 这两种设备,Default 一个声卡对应一个 Control 设备。

    #define    SNDRV_DEV_TOPLEVEL    ((__force snd_device_type_t) 0)
    #define    SNDRV_DEV_CONTROL    ((__force snd_device_type_t) 1)
    #define    SNDRV_DEV_LOWLEVEL_PRE    ((__force snd_device_type_t) 2)
    #define    SNDRV_DEV_LOWLEVEL_NORMAL ((__force snd_device_type_t) 0x1000)
    #define    SNDRV_DEV_PCM        ((__force snd_device_type_t) 0x1001)
    #define    SNDRV_DEV_RAWMIDI    ((__force snd_device_type_t) 0x1002)
    #define    SNDRV_DEV_TIMER        ((__force snd_device_type_t) 0x1003)
    #define    SNDRV_DEV_SEQUENCER    ((__force snd_device_type_t) 0x1004)
    #define    SNDRV_DEV_HWDEP        ((__force snd_device_type_t) 0x1005)
    #define    SNDRV_DEV_INFO        ((__force snd_device_type_t) 0x1006)
    #define    SNDRV_DEV_BUS        ((__force snd_device_type_t) 0x1007)
    #define    SNDRV_DEV_CODEC        ((__force snd_device_type_t) 0x1008)
    #define    SNDRV_DEV_JACK          ((__force snd_device_type_t) 0x1009)
    #define    SNDRV_DEV_COMPRESS    ((__force snd_device_type_t) 0x100A)
    #define    SNDRV_DEV_LOWLEVEL    ((__force snd_device_type_t) 0x2000)
    

    三、Linux ALSA 源码目录结构

    在 LInux 源码中 ALSA 架构的代码在 /sound 下,Linux 5.0 的目录如下:
    在这里插入图片描述
    其中各主要子目录的作用如下:

    core       该目录包含了ALSA 驱动的中间层,它是整个 ALSA 驱动的核心部分
    core/oss   包含模拟旧的 OSS 架构的 PCM 和 Mixer 模块
    core/seq   有关音序器相关的代码
    drivers    放置一些与CPU、BUS架构无关的公用代码
    i2c        ALSA自己的I2C控制代码
    pci        pci声卡的顶层目录,子目录包含各种pci声卡的代码
    isa        isa声卡的顶层目录,子目录包含各种isa声卡的代码
    soc        针对 system-on-chip 体系的中间层代码
    soc/codecs 针对soc 体系的各种 codec 的代码,与平台无关
    
    include    ALSA驱动的公共头文件目录,其路径为 /include/sound,该目录的头文件需要导出给用户空间的应用程序使用,通常,驱动模块私有的头文件不应放置在这里
    

    参考博文:
    Linux ALSA声卡驱动之一:ALSA架构简介
    linux-alsa详解1 基本知识

    加油打气:Linux ALSA 架构是一个难啃的大骨头,继续加油☺!!!

    展开全文
  • 音频ALSA架构简介

    千次阅读 2022-01-03 16:42:48
    ALSA(Advanced Linux Sound Architecture)即高级 Linux 声音架构。 嵌入式移动设备的音频子系统目前主要是ALSA 驱动 asoc 框架,其中包括 codec driver、 platform driver、 machine driver 等。

    一、ALSA架构

    ALSA(Advanced Linux Sound Architecture)即高级 Linux 声音架构。
    嵌入式移动设备的音频子系统目前主要是ALSA 驱动 asoc 框架,其中包括 codec driver、 platform driver、 machine driver 等。 codec driver只关心 codec 本身; platform driver 主要包括平台 cpu dai( 如 i2s) , dma 等部分;machine driver 主要将 platform driver 和 codec driver 连接起来。 platform 和 dai driver 一般修改较少, 主要修改machine 和 codec driver,这也将是我们后续分析的重点。

    ALSA架构图如下:
    ALSA框架图
    可以看看之前写的文章进行对比参照:
    Linux—ALSA音频工具arecord、aplay、amixer使用
    ALSA驱动asoc框架之machine
    ALSA驱动asoc框架之Codec
    ALSA驱动asoc框架之Platform

    二、其他说明

    1.PCM接口

    最简单的音频接口是PCM(脉冲编码调制)接口,该接口由时钟脉冲(BCLK)、帧同步信号(FS)及接收数据(DR)和发送数据(DX)组成。在FS信号的上升沿数据传输从MSB开始,FS频率等于采样频率。FS信号之后开始数据字的传输,单个数据位按顺序进行传输,一个时钟周期传输一个数据字。PCM接口很容易实现,原则上能够支持任何数据方案和任何采样频率,但需要每个音频通道获得一个独立的数据队列。

    2.IIS接口

    IIS接口在20世纪80年代首先被PHILIPS用于消费音频产品,并在一个称为LRCLK(Left/Right CLOCK)的信号机制中经过转换,将两路音频变成单一的数据队列。当LRCLK为高时,左声道数据被传输;LRCLK为低时,右声道数据被传输。与CPM相比,IIS更适合于立体声系统,当然,IIS的变体也支持多通道的时分复用,因此可以支持多通道。

    3.linux ALSA音频设备驱动

    ALSA系统包括包括驱动包alsa-driver、开发包alsa-libs、开发包插件alsa-libplugins、设置管理工具包alsa-utils、其他声音相关处理小程序包alsa-tools、特殊音频固件支持包alsa-firmware、OSS接口兼容模拟层工具alsa-oss供7个子项目,其中只有驱动包是必需的。

    目前ALSA内核提供给用户空间的接口有:

    (1)设备信息接口(/proc/asound)
    (2)设备控制接口(/dev/snd/controlCX)
    (3)混音器设备接口(/dev/snd/mixerCXDX)
    (4)PCM设备接口(/dev/snd/pcmCXDX)
    (5)原始MIDI(迷笛)设备接口(/dev/snd/midiCXDX)
    (6)声音合成(synthesizer)设备接口(/dev/snd/seq)
    (7)定时器接口(/dev/snd/timer)
    这些接口被提供给alsa-lib使用,而不是给应用程序使用,应用程序最好使用alsa-lib,或者更高级的接口比如jack提供的接口。

    4.linux ASoC音频设备驱动

    ASoC是ALSA在SoC方面的发展和演变,它的本质仍然属于ALSA,但是在ALSA架构基础上对CPU相关的代码和Codec相关的代码进行了分离,其原因是采用传统ALSA架构情况下,同一型号的Codec工作于不同的CPU时,需要不同的驱动,这是不符合代码重用的要求的。

    ASoC主要由3部分组成:
    (1)Codec驱动,这一部分只关系Codec本身,与CPU相关的特性不由此部分操作
    (2)平台驱动,这一部分只关心CPU本身,不关系Codec,它主要处理了两个问题:DMA引擎和SoC解除的PCM、IIS或AC’97数字接口控制。
    (3)板驱动,这一部分将平台驱动和Codec驱动绑定在一起,描述了板一级的硬件特征

    以上3部分中,1和2基本都可以仍然是通用的驱动了,即Codec驱动认为自己可以连接任意CPU,而CPU的IIS、PCM、或AC’97接口对应的平台驱动则认为自己可以连接符号其接口类型的Codec,只有3是不通用的,由特定的电路板上具体的CPU和Codec确定,因此它很像一个插座,上面插着Codec和平台这两个插头。ASoC的用户空间编程方法与ALSA完全一致。

    5.card声卡和组件管理

    /* 对于每个声卡,必须创建一个card实例,该函数用于创建card
        参数idx为索引号
        参数id为标识的字符串
        参数module一般指向THIS_MODULE
        参数extra_size是要分配的额外的数据的大小,分配的extra_size大小的内存将作为card->private_data*/
     struct snd_card *snd_card_new(int idx, const char *id,struct module *module, int extra_size)
    
      /* 注册声卡 */
    int snd_card_register(struct snd_card *card)
    
    /* 释放(注销)声卡 */
    int snd_card_free(struct snd_card *card)
    
     /* 创建一个ALSA设备部件
         参数type为设备类型,查看宏SNDRV_DEV_XXX*/
    int snd_device_new(struct snd_card *card, snd_device_type_t type,void *device_data, struct snd_device_ops *ops)
    
      /* 
       释放声卡的设备
       参数device_data指向要设备的私有数据
       */
    int snd_device_free(struct snd_card *card, void *device_data)
    

    6.PCM 设备接口

    /* 创建PCM实例
         参数card指向声卡
         参数id是标识字符串
         参数device为PCM设备引索(0表示第1个PCM设备)
         参数playback_count为播放设备的子流数
         参数capture_count为录音设备的子流数
         参数指向构造的PCM实例*/
    int snd_pcm_new(struct snd_card *card, const char *id, int device,int playback_count, int capture_count,struct snd_pcm ** rpcm)
    
     /* 设置PCM操作函数 
         参数direction,查看宏SNDRV_PCM_STREAM_XXX*/
    void snd_pcm_set_ops(struct snd_pcm *pcm, int direction, struct snd_pcm_ops *ops)
    
     /* 分配DMA缓冲区,仅当DMA缓冲区已预分配的情况下才可调用该函数 */
    int snd_pcm_lib_malloc_pages(struct snd_pcm_substream *substream, size_t size)
    
     /* 释放由snd_pcm_lib_malloc_pages函数分配的一致性DMA缓冲区 */
    int snd_pcm_lib_free_pages(struct snd_pcm_substream *substream)
    
     /* 分配缓冲区的最简单的方法是调用该函数
         type的取值可查看宏SNDRV_DMA_TYPE_* */
    int snd_pcm_lib_preallocate_pages_for_all(struct snd_pcm *pcm,int type, void *data,size_t size, size_t max)
    

    7.控制接口说明

    /* 创建一个control实例----struct snd_kcontrol结构体
         参数ncontrol为初始化记录
         private_data为设置的私有数据 */
    struct snd_kcontrol *snd_ctl_new1(const struct snd_kcontrol_new *ncontrol, void *private_data)
    
     /* 为声卡添加一个控制实例 */
    int snd_ctl_add(struct snd_card *card, struct snd_kcontrol *kcontrol)
    
    /* 驱动程序可中断服务程序中调用该函数来改变或更新一个control*/
    void snd_ctl_notify(struct snd_card *card, unsigned int mask,struct snd_ctl_elem_id *id)
    

    8.基于ALSA音频框架的驱动程序设计

    1:struct snd_card *snd_card_new(int idx, const char *id,struct module *module, int extra_size);/* 创建一个声卡 */
    
    2:static struct snd_device_ops ops = {
    		.dev_free =     xxx_free,
    	};
    
    3:struct snd_kcontrol *snd_ctl_new1(const struct snd_kcontrol_new *ncontrol,void *private_data); /*  创建control实例 */
    
    4:int snd_ctl_add(struct snd_card *card, struct snd_kcontrol *kcontrol);    /* 为声卡添加控制实例 */
    
    5:int snd_device_new(struct snd_card *card, SNDRV_DEV_CODEC,void *device_data, struct snd_device_ops *ops);  /* 创建一个ALSA设备部件-----编解码设备 */
    
    6:int snd_pcm_new(struct snd_card *card, const char *id, int device,int playback_count, int capture_count,struct snd_pcm ** rpcm) /*  创建PCM实例 */
    
    8:int snd_pcm_lib_preallocate_pages_for_all(struct snd_pcm *pcm,int type, void *data,size_t size, size_t max)  /* 分配缓冲区 */
    
    9:void snd_pcm_set_ops(struct snd_pcm *pcm, SNDRV_PCM_STREAM_PLAYBACK, struct snd_pcm_ops *ops)  /* 设置PCM操作函数----播放  */
    
    10:void snd_pcm_set_ops(struct snd_pcm *pcm, SNDRV_PCM_STREAM_CAPTURE, struct snd_pcm_ops *ops)  /* 设置PCM操作函数 ----录音 */
    
    11:/*音频相关的初始化:音频流相关、引脚等相关的初始化*/
    
    12:DMA相关的设置
    
    13:int snd_card_register(struct snd_card *card);  /* 注册声卡 */IRQ_AC97
    

    9.ASoC音频驱动重要结构体

    /*
      *1:ASoC Codec驱动:
      */
    
    struct snd_soc_dai { /* 数字音频接口,描述了Codec DAI(数字音频接口---Digital Audio Interface)和PCM配置 */
    	/* DAI description */
    	char *name;  /* 名字 */
    	unsigned int id;  /* ID */
    	int ac97_control;
    
    	struct device *dev;
    
    	/* DAI callbacks */
    	int (*probe)(struct platform_device *pdev,
    		     struct snd_soc_dai *dai);
    	void (*remove)(struct platform_device *pdev,
    		       struct snd_soc_dai *dai);
    	int (*suspend)(struct snd_soc_dai *dai);
    	int (*resume)(struct snd_soc_dai *dai);
    
    	/* ops */
    	struct snd_soc_dai_ops *ops;  /* DAI操作函数 */
    
    	/* DAI capabilities */
    	struct snd_soc_pcm_stream capture;  /* 录音流 */
    	struct snd_soc_pcm_stream playback; /* 播放流 */
    
    	/* DAI runtime info */
    	struct snd_pcm_runtime *runtime;  /* PCM运行时 */
    	struct snd_soc_codec *codec;  /* 编解码器 */
    	unsigned int active;
    	unsigned char pop_wait:1;
    	void *dma_data;
    
    	/* DAI private data */
    	void *private_data;
    
    	/* parent codec/platform */
    	union {
    		struct snd_soc_codec *codec;  /* 编解码器 */
    		struct snd_soc_platform *platform;  /* 平台驱动----CPU */
    	};
    
    	struct list_head list; /* 用于形成链表 */
    };
    
    struct snd_soc_codec { /* SoC音频编解码器---IO操作、动态音频电源管理以及时钟、PLL等控制 */
    	char *name;  /* 名字 */
    	struct module *owner; /* THIS_MODULE */
    	struct mutex mutex;
    	struct device *dev;
    
    	struct list_head list; /* 用于形成链表 */
    
    	/* callbacks */
    	int (*set_bias_level)(struct snd_soc_codec *,
    			      enum snd_soc_bias_level level); /* 回调函数 */
    
    	/* runtime */
    	struct snd_card *card;  /* 声卡 */
    	struct snd_ac97 *ac97;  /* for ad-hoc ac97 devices */ /* AC97设备 */
    	unsigned int active;
    	unsigned int pcm_devs;
    	void *private_data;
    
    	/* codec IO */
    	void *control_data; /* codec control (i2c/3wire) data */
    	unsigned int (*read)(struct snd_soc_codec *, unsigned int);
    	int (*write)(struct snd_soc_codec *, unsigned int, unsigned int);
    	int (*display_register)(struct snd_soc_codec *, char *,
    				size_t, unsigned int);
    	hw_write_t hw_write;
    	hw_read_t hw_read;
    	void *reg_cache;
    	short reg_cache_size;
    	short reg_cache_step;
    
    	/* dapm */
    	u32 pop_time;
    	struct list_head dapm_widgets;
    	struct list_head dapm_paths;
    	enum snd_soc_bias_level bias_level;
    	enum snd_soc_bias_level suspend_bias_level;
    	struct delayed_work delayed_work;
    
    	/* codec DAI's */
    	struct snd_soc_dai *dai; /* SoC层接口 */
    	unsigned int num_dai;
    
    #ifdef CONFIG_DEBUG_FS
    	struct dentry *debugfs_reg;
    	struct dentry *debugfs_pop_time;
    #endif
    };
    
    struct snd_soc_dai_ops { /* 数字音频接口DAI操作函数集 */
    	/*
    	 * DAI clocking configuration, all optional.
    	 * Called by soc_card drivers, normally in their hw_params.
    	 */
    	int (*set_sysclk)(struct snd_soc_dai *dai,
    		int clk_id, unsigned int freq, int dir); /* 设置系统时钟 */
    	int (*set_pll)(struct snd_soc_dai *dai,
    		int pll_id, unsigned int freq_in, unsigned int freq_out); /* 设置PLL */
    	int (*set_clkdiv)(struct snd_soc_dai *dai, int div_id, int div);  /* 设置时钟分频 */
    
    	/*
    	 * DAI format configuration
    	 * Called by soc_card drivers, normally in their hw_params.
    	 */
    	 /* DAI格式配置 */
    	int (*set_fmt)(struct snd_soc_dai *dai, unsigned int fmt); /* 设置格式 */
    	int (*set_tdm_slot)(struct snd_soc_dai *dai,
    		unsigned int mask, int slots);
    	int (*set_tristate)(struct snd_soc_dai *dai, int tristate);
    
    	/*
    	 * DAI digital mute - optional.
    	 * Called by soc-core to minimise any pops.
    	 */
    	int (*digital_mute)(struct snd_soc_dai *dai, int mute); /* 数字静音 */
    
    	/*
    	 * ALSA PCM audio operations - all optional.
    	 * Called by soc-core during audio PCM operations.
    	 */
    	 /* ALSA PCM音频操作 */
    	int (*startup)(struct snd_pcm_substream *,
    		struct snd_soc_dai *);
    	void (*shutdown)(struct snd_pcm_substream *,
    		struct snd_soc_dai *);
    	int (*hw_params)(struct snd_pcm_substream *,
    		struct snd_pcm_hw_params *, struct snd_soc_dai *);
    	int (*hw_free)(struct snd_pcm_substream *,
    		struct snd_soc_dai *);
    	int (*prepare)(struct snd_pcm_substream *,
    		struct snd_soc_dai *);
    	int (*trigger)(struct snd_pcm_substream *, int,
    		struct snd_soc_dai *);
    };
    
    struct snd_soc_ops { /* SoC操作函数----Codec音频操作 */
    	int (*startup)(struct snd_pcm_substream *);
    	void (*shutdown)(struct snd_pcm_substream *);
    	int (*hw_params)(struct snd_pcm_substream *, struct snd_pcm_hw_params *);
    	int (*hw_free)(struct snd_pcm_substream *);
    	int (*prepare)(struct snd_pcm_substream *);
    	int (*trigger)(struct snd_pcm_substream *, int);
    };
    
    /*
      *2:ASoC平台驱动:
      *
      *在ASoC平台驱动部分,同样存在着Codec驱动中的snd_soc_dai、snd_soc_dai_ops、snd_soc_ops这三个结构体的实例用于描述
      *DAI和DAI的操作,不过不同的是,在平台驱动中,它们只描述CPU相关的部分而不描述Codec。除此之外,在ASoC
      *平台驱动中,必须实现完整的DMA驱动,即传统ALSA的and_pcm_ops结构体成员函数trigger()、pointer()等,因此ASoC平台
      *驱动通常由DAI和DMA两部分组成。
      */
    
    /*
      *ASoC板驱动:
      *在板驱动的模块初始化函数中,会通过platform_device_add()注册一个名为"soc-audio"的platform设备,这是因为soc-core.c
      *注册了一个名为"soc-audio"的platform驱动
      */
    
    struct snd_soc_device { /* SoC设备 */
    	struct device *dev; /* 内嵌的设备模型的设备 */
    	struct snd_soc_card *card; /* SoC卡 */
    	struct snd_soc_codec_device *codec_dev;  /* SoC编解码设备 */
    	void *codec_data;  /* 编解码设备使用的数据 */
    };
    
    struct snd_soc_dai_link  { /* 绑定ASoC Codec驱动和CPU端的平台驱动数据结构 */
    	char *name;			/* Codec name */ /* 编解码器的名字 */
    	char *stream_name;		/* Stream name */ /* 流的名字 */
    
    	/* DAI */
    	struct snd_soc_dai *codec_dai; /* SoC层的接口----编解码器端 */
    	struct snd_soc_dai *cpu_dai;     /* SoC层的接口----CPU端*/
    
    	/* machine stream operations */
    	struct snd_soc_ops *ops; /* SoC操作函数----流操作函数 */
    
    	/* codec/machine specific init - e.g. add machine controls */
    	int (*init)(struct snd_soc_codec *codec);  /* 初始化 */
    
    	/* DAI pcm */
    	struct snd_pcm *pcm; /* 指向pcm */
    };
    
    展开全文
  • 音频alsa架构.rar

    2021-06-30 17:22:38
    linux音频alsa框架,思维导图形式描述
  • alsa 架构分析

    2012-04-01 14:24:55
    介绍ALSA架构,ALSA CODEC CPUDAI, ALSA PLATFORM 的分析
  • Linux ALSA声卡驱动之一:ALSA架构简介

    千次阅读 多人点赞 2019-11-01 11:28:56
    1、概述 ALSA是Advanced Linux Sound Architecture 的缩写,目前已经成为了linux的主流音频体系结构,...在内核设备驱动层,ALSA提供了alsa-driver,同时在应用层,ALSA为我们提供了alsa-lib,应用程序只要调用alsa...

    1、概述

    ALSA是Advanced Linux Sound Architecture 的缩写,目前已经成为了linux的主流音频体系结构,想了解更多的关于ALSA的这一开源项目的信息和知识,请查看以下网址:http://www.alsa-project.org/

    在内核设备驱动层,ALSA提供了alsa-driver,同时在应用层,ALSA为我们提供了alsa-lib,应用程序只要调用alsa-lib提供的API,即可以完成对底层音频硬件的控制。
    在这里插入图片描述
    图 1.1 alsa的软件体系结构

    由图1.1可以看出,用户空间的alsa-lib对应用程序提供统一的API接口,这样可以隐藏了驱动层的实现细节,简化了应用程序的实现难度。内核空间中,alsa-soc其实是对alsa-driver的进一步封装,它针对嵌入式设备提供了一些列增强的功能。本系列博文仅对嵌入式系统中的alsa-driver和alsa-soc进行讨论。

    下图为更详细的alsa软件体系结构图:
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    • ALSA Library API: alsa 用户库接口,常见有 tinyalsa、alsa-lib;
    • ALSA CORE: alsa 核心层,向上提供逻辑设备(PCM/CTL/MIDI/TIMER/…)系统调用,向下驱动硬件设备(Machine/I2S/DMA/CODEC);
    • ASoC CORE: asoc 是建立在标准 alsa core 基础上,为了更好支持嵌入式系统和应用于移动设备的音频 codec 的一套软件体系;
    • Hardware Driver: 音频硬件设备驱动,由三大部分组成,分别是 Machine、Platform、Codec。

    ALSA 标准是一个先进的 linux 声音体系。它包含内核驱动集合, API 库和工具对 Linux 声音进行支持。 ALSA 包含一系列内核驱动对不同的声卡进行支持,还提供了 libasound 的 API 库。用这些进行写程序不需要打开设备等操作,所以编程人员在写程序的时候不会被底层的东西困扰。与此相反 OSS/Free 驱动在内核层次调用,需要指定设备名和调用 ioctl 。为提供向后兼容, ALSA 提供内核模块模仿 OSS/Free 驱动,所以大多数的程序不需要改动。 ALSA 拥有调用插件的能力对新设备提供扩展,包括那些用软件模拟出来的虚拟设备。 ALSA 还提供一组命令行工具包括 mixer, sound file player 和工具控制一些特别的声卡的特别的作用。

    2、分层及特点

    ALSA体系主要分为三层,按照调用关系依次是,app、alsa-lib、kernel driver。

    ALSA的主要特点如下:

    • 支持多种声卡设备。
    • 模块化的内核驱动程序。
    • 支持SMP和多线程。
    • 提供应用开发函数库以简化应用程序开发。
    • 支持OSS API,兼容OSS应用程序。

    ALSA具有更加友好的编程接口,并且完全兼容于OSS,对应用程序来讲无疑是一个更佳地选择。ALSA系统包括驱动包alsa-driver,开发包alsa-libs,开发包插件alsa-libplugins,设置管理工具包alsa-utils,其他声音相关处理小程序包alsa-tools,特殊音频固件支持包alsa-firmware,OSS接口兼容模拟层工具alsa-oss共7个子项目,其中只有驱动包是必须的。

    alsa-driver指内核驱动程序,包括硬件相关的代码和一些公共代码,非常庞大。
    alsa-libs指用户空间的函数库,提供给应用程序使用,应用程序应包括头文件asoundlib.h。并使用共享库libasound.so。
    alsa-utils包含一些基于ALSA的用于控制声卡的应用程序,如alsaconf(侦测系统中声卡并写一个适合的ALSA配置文件),aplay(基于命令行的声音文件播放),arecord(基于命令行的声音文件录制)等。

    3、 Kernel Driver层

    Kernel driver 层,为内核驱动代码,主要在内核源码中的sound目录下,负责对硬件进行控制与操作。驱动创建的设备文件,在文件系统中的/dev/snd/目录下。注意,应用层使用alsa-API中打开的设备文件,并不是/dev/snd/目录下的文件,而是alsa-lib对设备的再一次封装的产物,叫做plugins,如plughw:0,0 ,后面详细解释。

    3.1 ALSA驱动的设备文件结构—字符设备

    下面是我的电脑中alsa驱动的设备文件结构:
    在这里插入图片描述
    我们可以看到以下设备文件:

    controlC0  --> 用于声卡的控制,例如通道选择,混音,麦克风的控制等
    midiC0D0  --> 用于播放midi音频
    pcmC0D0c --> 用于录音的pcm设备
    pcmC0D0p --> 用于播放的pcm设备
    seq    --> 音序器
    timer    --> 定时器

    其中,pcmC0D0p与pcmC0D0c组成一个pcm设备,C0代表0号声卡Card,D0代表0号设备device。C0D0代表的是声卡0中的设备0,pcmC0D0c最后一个c代表capture,pcmC0D0p最后一个p代表playback,这些都是alsa-driver中的命名规则。从上面的列表可以看出,我的声卡下挂了14个设备,根据声卡的实际能力,驱动实际上可以挂上更多种类的设备,在include/sound/core.h中,定义了以下设备类型:

    #define	SNDRV_DEV_TOPLEVEL	      ((__force snd_device_type_t) 0)
    #define	SNDRV_DEV_CONTROL	      ((__force snd_device_type_t) 1)
    #define	SNDRV_DEV_LOWLEVEL_PRE	  ((__force snd_device_type_t) 2)
    #define	SNDRV_DEV_LOWLEVEL_NORMAL ((__force snd_device_type_t) 0x1000)
    #define	SNDRV_DEV_PCM		      ((__force snd_device_type_t) 0x1001)
    #define	SNDRV_DEV_RAWMIDI	      ((__force snd_device_type_t) 0x1002)
    #define	SNDRV_DEV_TIMER		      ((__force snd_device_type_t) 0x1003)
    #define	SNDRV_DEV_SEQUENCER	      ((__force snd_device_type_t) 0x1004)
    #define	SNDRV_DEV_HWDEP		      ((__force snd_device_type_t) 0x1005)
    #define	SNDRV_DEV_INFO		      ((__force snd_device_type_t) 0x1006)
    #define	SNDRV_DEV_BUS		      ((__force snd_device_type_t) 0x1007)
    #define	SNDRV_DEV_CODEC		      ((__force snd_device_type_t) 0x1008)
    #define	SNDRV_DEV_JACK            ((__force snd_device_type_t) 0x1009)
    #define	SNDRV_DEV_LOWLEVEL	      ((__force snd_device_type_t) 0x2000)
    

    通常,我们更关心的是pcm和control这两种设备。

    3.2 驱动的代码文件结构

    在Linux2.6代码树中,Alsa的代码文件结构如下:
    在这里插入图片描述

    • core: 该目录包含了ALSA驱动的中间层,它是整个ALSA驱动的核心部分;
    • core/oss: 包含模拟旧的OSS架构的PCM和Mixer模块;
    • core/seq: 有关音序器相关的代码;
    • include: ALSA驱动的公共头文件目录,该目录的头文件需要导出给用户空间的应用程序使用,通常,驱动模块私有的头文件不应放置在这里;
    • drivers: 放置一些与CPU、BUS架构无关的公用代码;
    • i2c: ALSA自己的I2C控制代码;
    • pci: pci声卡的顶层目录,子目录包含各种pci声卡的代码;
    • isa: isa声卡的顶层目录,子目录包含各种isa声卡的代码;
    • soc: 针对system-on-chip体系的中间层代码;
    • soc/codecs: 针对soc体系的各种codec的代码,与平台无关;

    3.3 kernel层ASoC框架

    在内核中, ALSA依赖ASoC(ALSA System on Chip)驱动模型。ASoC是嵌入式系统使用的音频框架,它从硬件架构的角度来将功能相对独立的硬件单元细分出来,在驱动设备上分为 machine、 platform/CPU和CODEC 三个模块。
    在这里插入图片描述
    可以这么理解:一套嵌入式 硬件平台(Machine)包含了平台AP(Platform)和音频CODEC芯片(Codec),对应ASoC的三个设备驱动。这三个设备分别注册各自功能的dev设备,但都是以内核platform设备模型来创建。 ASoC主要代码位于kernel/sound/soc下。 下面分别来介绍一下:

    3.3.1 MAchine设备驱动

    Machine设备可以看成是一块嵌入式主板(Board) 或者一块声卡。machine设备驱动是ASoC驱动框架的入口, 主要功能是负责platform/cpu和codec之间的连接和控制,或者响应独立于Platform功能和Codec功能之外的特殊音频事件,如平台GPIO控制外置功放等,这些属于machine本身的特定操作代码,都会放到machine驱动里。

    Machine设备驱动的主要功能是定义各种DAI(Digital Audio Interface) links,它的作用是把platform/cpu和codec设备驱动连接起来,形成完整的音频通路。

    在内核设备树中,平台会定义一个声卡设备,它就是ASoC框架里的machine设备。 machine设备的初始化是整个ASoC驱动的入口。 machine设备的probe()会调用snd_soc_register_card()去注册声卡,然后在snd_soc_instantiate_card()里实例化声卡设备的时候,调用Platform和Codec设备各自的probe(),完成这两个设备的初始化。如果没有错误,那么声卡会注册成功,我们在/dev/snd下可以看到多个音频设备。

    3.3.2 platform设备驱动

    Platform设备可看作是平台AP(SoC主控,或CPU)。 它负责提供嵌入式平台端的音频功能, 如播放、录音、 Voice通话等。平台驱动中包括音频DMA引擎驱动,数字接口驱动(I2S, AC97, PCM)以及该平台相关的任何音频DSP驱动。此Platform可以重用,在不同的Machine中可以直接重复使用。

    Platform设备驱动主要有两个作用:
    (1)transfer:负责平台AP端的audio/voice数据流(stream)和DSP之间的传输;
    (2)routing:将stream数据流按照特定的路线对应到其他音频模块中。

    ASoC会注册多个Platform设备来负责不同功能的音频模块:
    (1)负责audio回放/录音
    (2)负责voice通话
    (3)负责VoIP通话
    (4)负责压缩格式的audio播放
    (5)负责stream数据流的路线指定

    3.3.3 CODEC设备驱动

    对于一块嵌入式设备的主板来说,一般会集成一颗音频CODEC芯片。 ASoC架构下的CODEC设备功能和物理CODEC对应, 其在machine的控制下和platform设备连接,负责音频的实际处理,如声音播放(D/A)、声音采集(A/D) 和各种音频control控件的设置。

    平台一般会集成一个CODEC单元,也会有添加外部独立CODEC芯片,已达到更好的音质。如Wolfson的WM8998芯片,它是一颗独立的CODEC,基于I2S接口从平台获取音频数据,在其内部经过DAC输出到耳机或speaker。高通有自己的外置CODEC芯片,如WCD9326/9335等,和平台AP的音频数据接口叫Slimbus,其实是和I2S复用的GPIO口。

    CODEC芯片可能需要I2C或SPI控制。

    COCEC设备支持耳机插拔及按键检测功能。

    CODEC设备驱动中定义了大量的mixer、 mux和各种开关的kcontrol,以及DAPM使用的widget和route。

    4、ALSA-Lib层

    4.1 基本概念

    1. 通道(channel):即我们熟知的声道数。左/右声道,5.1channel等等。
    2. 样本(sample):sample即一次采样的样本,是记录音频数据最基本的单位。通常的sample bit指的是一个channnel上,一次采样的bit数(常见的sample bit 8/16/24/32bits)。
    3. 帧(frame):帧记录了一个声音单元,一个frame是一次采样时所有channel上的sample bit.即frame = channels * (sample bit)。
    4. 采样率(rate):每秒钟采样次数,该次数是针对帧而言。
    5. 周期(period):音频设备一次处理所需要的帧数,对于音频设备的数据访问以及音频数据的存储,都是以此为单位。每当hardware buffer 中有peroid size个frame的空间时,硬件就产生中断,来通知alsa driver来往硬件写数据。
    6. buffer size:hardware buffer size 是由多个peroid组成。buffer size = peroid size * peroids。
      在这里插入图片描述
    7. Data access and layout
      在一个period以内(interleaved和non-interleaved是在一个period里面排),数据是按照channel1排完了再排channel2呢,还是一个frame一个frame的来排(frame在alsa里指的是一次采样时间内,两个channel的数据放一块儿就是一个frame)上图是interleaved。
      交错模式(interleaved):是一种音频数据的记录方式,在交错模式下,数据以连续帧的形式存放,即首先记录完帧1的左声道样本和右声道样本(假设为立体声格式),再开始帧2的记录。而在非交错模式下,首先记录的是一个周期内所有帧的左声道样本,再记录右声道样本,数据是以连续通道的方式存储。不过多数情况下,我们只需要使用交错模式就可以了。
    8. Hardware parameter
      Hardware parameter是作用于声卡硬件的,包括sample rate, sample format, interupt intervals, data access and layout, buffer size。
    9. Software parameter
      software parameter 是作用于alsa core的。通常用来控制When to start the device, what to do about xruns, Available minimum space/data for wakeup,Transfer chunk size。
      (1)When to start the device
      我们可以通过API snd_pcm_sw_params_set_start_threshold来设置什么时候开始启动声卡。对于playback,假设第设置start threshold 为320,那么就是说,当用户调用writei,写入的数据,将暂时存在alsa驱动空间里,当这个数据量达到 320帧时,alsa驱动才开始将数据写入hardware buffer,并启动DA转换。
      (2)What to do about xruns
      xrun指的是,声卡period一到,引发一个中断,告诉alsa驱动,要填入数据,或读走数据,但是,问题在于alsa的读取和写入操作必须用户调用writei和readi才会发生的,它不会去缓存数据。如果上层没有用户调用writei和readi,那么就会产生 overrun(录制时,数据都满了,还没被alsa驱动读走)和underrun(需要数据来播放,alsa驱动却不写入数据),统称为xrun。
      当xrun发生时,可以在空余空间超过stop threshold时,stop audio interface。
      也可以通过设置silence threshold,当空余空间超过silence threshold时,就hardware buffer 写入silence。
      适当地设计应用程序可以最小化xrun并且可以从中恢复过来。
      (3)Available minimum space/data for wakeup
      这个software parameters仅用在interrupt-driven模式。这个模式是alsa驱动层的,不是硬件interrupt。它的意思是,用户使用 snd_pcm_wait()时,这个实际封装的是系统的poll调用,表示用户在等待,那么在等待什么呢?对于playback来讲,就是等待下面的声卡的hardware buffer里有一定数量的空间,可以放入新的数据了,对于record来讲,就是等待下面声卡新采集的数据达到了一定数量了。这个一定数量,就是用 snd_pcm_sw_params_set_avail_min来设置,单位是frame。
      (4)Transfer chunk size
      this determines the number of frames used when transferring data to/from the device hardware buffer.
      这决定了在向设备硬件缓冲区传输数据(或从设备硬件缓冲区取数据)时使用的帧数。
    10. 声音缓存和数据传输
      每个声卡都有一个硬件缓存区来保存记录下来的样本。当缓存区足够满时,声卡将产生一个中断。内核声卡驱动然后使用直接内存(DMA)访问通道将样本传送到内存中的应用程序缓存区。类似地,对于回放,任何应用程序使用DMA将自己的缓存区数据传送到声卡的硬件缓存区中。
      这样硬件缓存区是环缓存。也就是说当数据到达缓存区末尾时将重新回到缓存区的起始位置。ALSA维护一个指针来指向硬件缓存以及应用程序缓存区中数据操作的当前位置。从内核外部看,我们只对应用程序的缓存区感兴趣,所以本文只讨论应用程序缓存区。
      应用程序缓存区的大小可以通过ALSA库函数调用来控制。缓存区可以很大,一次传输操作可能会导致不可接受的延迟,我们把它称为延时(latency)。为了解决这个问题,ALSA将缓存区拆分成一系列周期(period)(OSS/Free中叫片断fragments)。ALSA以period为单元来传送数据。
      一个周期(period)存储一些帧(frames)。每一帧包含时间上一个点所抓取的样本。对于立体声设备,一个帧会包含两个信道上的样本。分解过程:一个缓存区分解成周期,然后是帧,然后是样本。左右信道信息被交替地存储在一个帧内。这称为交错 (interleaved)模式。在非交错模式中,一个信道的所有样本数据存储在另外一个信道的数据之后。

    4.2 ALSA-Lib接口

    Alsa-lib层,为不同的驱动提供统一的接口alsa API,简化了开发人员对于驱动层的调用开发。主要有如下接口:

    网址:https://www.alsa-project.org/alsa-doc/alsa-lib/

    The currently designed interfaces are listed below:

    • Information Interface (/proc/asound) 信息接口
    • Control Interface (/dev/snd/controlCX) 控制接口:提供管理声卡注册和请求可用设备的通用功能
    • Mixer Interface (/dev/snd/mixerCXDX) 混音器接口:控制发送信号和控制声音大小的声卡上的设备。
    • PCM Interface (/dev/snd/pcmCXDX) PCM 接口:管理数字音频回放(playback)和录音(capture)的接口。后续重点放在这个接口上,因为它是开发数字音频程序最常用到的接口。
    • Raw MIDI Interface (/dev/snd/midiCXDX) 原始MIDI接口:支持MIDI(Musical Instrument Digital Interface),标准的电子乐器。这些API提供对声卡上MIDI总线的访问。这个原始接口基于MIDI事件工作,由程序员负责管理协议以及时间处理。
    • Sequencer Interface (/dev/snd/seq) 音序器接口:一个比原始 MIDI 接口高级的 MIDI 编程和声音同步高层接口。它可以处理很多的 MIDI 协议和定时器。
    • Timer Interface (/dev/snd/timer) 定时接口:为同步音频事件提供对声卡上时间处理硬件的访问。

    我们在应用中,主要使用的是 PCM 接口。如Snd_pcm_open()函数。

    除了Alsa-API接口以外,alsa-lib还可以通过配置文件,开放其附加功能,如采样率转换、软件混音等。

    我们就是利用alsa-lib的附加功能实现我们的重采样功能,修改的地方主要包括alsa-lib的配置和APP调用两方面。下一小节对如何利用alsa-lib的配置文件开放其采样率转换功能进行描述。

    4.3 配置文件asound.conf

    asound.conf配置文件,是alsa-lib的默认配置文件,路径在 /etc/,可以用来配置alsa库的一些附加功能。这个文件不是alsa库运行时所必须的,没有它alsa库也可以正常运行。

    关于asound.conf的配置,可以参考以下文档:

    http://www.alsa-project.org/main/index.php/Asoundrc

    先阐述一些重要的名词:

    • Card: 声卡,直接对应硬件,ID从0开始计数。
    • Device: 设备,在一个card上,可以有多个device,每个device可以独立被打开和使用,ID从0开始计数。
    • Plugin: 插件,前文说过,应用层调用alsa库时,操作的并不是驱动层创建的设备文件,而是这个plugins,plugin是alsa库对音频处理设备的抽象,hw plugin为硬件设备抽象出的plugin,是最基础的模块,不需要对alsa-lib进行配置即可使用,我们常见的plughw:0,0含义就是类型为hw的plugin,编号声卡0上面的设备0。除了hw类型的plugin外,还有一些纯软件实现的模块,可以用来进行音频处理,例如,可以实现音频采样率转换的rate plugin,可以用来混音的dmix plugin等等。
    • Slave: 从属设备,可以把几个plugin连接起来,sink端的设备就是source端设备的slave。

    需要使用这些附加的plugin,就要对配置文件(asound.conf)进行配置,这个配置是实时生效的,所以我们不必修改文件系统中的文件,而是在运行我们的应用程序之前,将自己的配置文件拷贝到/etc/下,对默认的配置文件进行覆盖就行了。

    具体如何配置,书写格式,请参看Asoundrc文档。

    以下就是我的配置,

    pcm_slave.sl2 {
    	pcm "plughw:0,1"
    	rate 48000
    }
    
    pcm.rate_convert {
    	type rate
    	slave sl2
    }
    

    这个配置的含义是,

    下面一段:创建一个使用pcm API接口的设备,叫做rate_convert,它的类型是rate(可以实现采样率转换的plugin),它有一个slave叫做sl2;

    上面一段:定义一个使用pcm接口的slave,叫做sl2,他实际上是plughw:0,1这个设备的别名,即等同于plughw:0,1(对应我用于播放的AIC3104芯片),这个设备需要的采样率是48KHz。

    通过这个配置,就可以在app中,使用pcm API打开rate_convert这个设备,并把解码后的8K采样率的PCM数据,直接使用snd_pcm_writei写入设备,rate_convert这个设备就可以自动将PCM数据重采样至48KHz,然后自动传递给plughw:0,1进行播放。

    在看Asoundrc的文档中,一直不明白,为什么在配置文件中,只有输出的采样率配置,而没有输入的采样率配置,要重采样,alsa-lib总得知道把啥转换成48K吧,

    在实践中发现,可以通过APP调用alsa-API中的snd_pcm_hw_params_set_rate_near()函数将数据源的采样率为8K传递给alsa-lib。下面一章对app调用alsa-API进行说明。

    注意:设备命名
    API库使用逻辑设备名而不是设备文件。设备名字可以是真实的硬件名字也可以是插件名字。硬件名字使用hw:i,j这样的格式。其中i是卡号,j是这块声卡上的设备号。
    第一个声音设备是hw:0,0.这个别名默认引用第一块声音设备并且在本文示例中一真会被用到。
    插件使用另外的唯一名字,比如 plughw:,表示一个插件,这个插件不提供对硬件设备的访问,而是提供像采样率转换这样的软件特性,硬件本身并不支持这样的特性。

    5、App调用方法:

    在app调用这块儿,其他的通用调用流程在这里就不累述了,使用个项目原来的那套代码就行,只有三块儿需要修改和注意:

    • 1、使用snd_pcm_open()打开的设备文件rate_convert(不需再打开plughw:0,1了),PCM数据的原始采样率,用snd_pcm_hw_params_set_rate_near()对rate_convert进行配置。

    • 2、重要的参数Period_size,即播放周期大小,单位为Byte,需使用snd_pcm_hw_params_set_period_size_near()进行配置,如果period_size配的不对,或者不配置,会发生underRun,播放声音断断续续。
      8K pcm, 配置sample_rate为8000,配置period_size为256
      48K pcm, 配置sample_rate为48000,配置period_size为1024

    • 3、配置负责playback的AIC3104的采样率为48K

    6、声卡的缓存和数据的传输:

    一块声卡有一个声卡内存用来存储记录的样本。当它被写满时就产生中断。内核驱动就使用 DMA 将数据传输到内存中。同样地,当在播放时就将内存中的声音样本使用 DMA 传到声卡的内存中!

    声卡的缓存是环状的,这里只讨论应用程序中的内存结构: ALSA 将数据分成连续的片段然后传到按单元片段传输。

    典型的声音程序结构:

    open interface for capture or playback
    set hardware parameters
    (access mode, data format, channels, rate, etc.)
    while there is data to be processed:
    read PCM data (capture)
    or write PCM data (playback)
    close interface
    

    7、参考文档与例子

    (1)在 ALSA 的文档页面上有两篇为应用程序开发者提供的文章:
    ALSA 0.9.0 HOWTO [ http://www.suse.de/~mana/alsa090_howto.html ]
    (2)当然,还有音频库API的在线参考: http://www.alsa-project.org/alsa-doc/alsa-lib
    (3)音频库API中各个函数的使用说明:http://www.alsa-project.org/alsa-doc/alsa-lib/modules.html
    (4)http://www.sabi.co.uk/Notes/linuxSoundALSA.html
    (5)a LINUX Journal article about basic ALSA programming 包含一些示例代码
    (6)tutorials on the ALSA project web site 包含一些示例代码

    展开全文
  • ALSA架构应用程序aplay及amixer调用关系(应用层到内核驱动)
  • 一、概述 1、硬件 ...内核空间中,alsa soc其实是对alsa驱动的封装统一,为了兼容不同平台的驱动,同时风格更统一,下面会进一步讨论。 3、音频驱动架构 音频驱动里有三个很重要的部分,cpu_dai、codec_
  • Linux ALSA驱动框架(一)--ALSA架构简介--声卡的创建

    万次阅读 多人点赞 2018-05-29 06:48:35
    (1)ALSA简介(1)Native ALSA Application:tinyplay/tinycap/tinymix,这些用户程序直接调用 alsa 用户库接口来实现放音、录音、控制ALSA Library API:alsa 用户库接口,常见有 tinyalsa、alsa-libALSA ...
  • linux下C语言的程序,可以实现ALSA架构的声音采集,并且生成wav格式的音频文件,实现播放的功能。
  • ALSA架构音频播放

    2016-12-29 11:07:20
    ALSA架构下音频播放
  • alsa架构分析(二)

    2016-06-12 10:41:00
    Linux ALSA声卡驱动之六:ASoC架构中的Machine   前面一节的内容我们提到,ASoC被分为Machine、Platform和Codec三大部分,其中的Machine驱动负责Platform和Codec之间的耦合以及部分和设备或板子特定的代码,...
  • ALSA架构声卡相关资料

    2012-10-06 14:10:42
    基于ALSA架构的开发的技术文档,也是自己总结的最好的资料,分析ALSA架构的源码,并给出开发alsa声卡的实例。
  • ALSA是Advanced Linux Sound Architecture 的缩写,目前已经成为了linux的主流音频体系结构,想了解更多的关于ALSA的这一开源项目的信息和知识,请查看以下网址:http://www.alsa-project.org/。 在内核设备驱动层...
  • 本资源是基于嵌入式硬件Devkit8600和嵌入式linux系统软件的QT开发环境下编写的基于ALSA架构的语音录制和播放的源代码,源代码编译时需要asoundlib库,网络上有下载。本资源可适用于基于ALSA架构的嵌入式linux语音...
  • 一. 概述ALSA 是 Advanced Linux Sound Architecture 的缩写,目前已经成为了linux的主流音频体系结构,想了解更多的关于...ALSA提供了alsa-driver,同时在应用层,ALSA为我们提供了alsa-lib,应用程序只要调用als...
  • 原文见链接Linux ALSA声卡驱动之一:ALSA架构简介 分析 精辟
  • alsa架构分析

    千次阅读 2016-05-31 14:01:38
    这个函数本身架构很简单,和前面说的逻辑一样,先调用了 cpu 级别的 probe ,再是 codec 级别的,最后是 platform 的(这里三个的顺序就不一样),但是因为 cpu 级别的和 platform 级别的都为空,最后都调用了 codec...
  • alsa体系架构

    2013-01-29 21:33:29
    ALSA是Advanced Linux Sound Architecture 的缩写,目前已经成为了linux的主流音频体系结构
  • 简单粗暴,直接上图: 如果是capture的话,只需要修改: a.SND_PCM_STREAM_PLAYBACK -> SND_PCM_STREAM_CAPTURE ... if ((err = snd_pcm_open (&capture_handle, argv[1], SND_PCM_STREAM_CAPTURE, 0)) &...
  • /* * ALSA PCM audio operations - all optional. * Called by soc-core during audio PCM operations. */ int (*startup)(struct snd_pcm_substream *, struct snd_soc_dai *); /*打开设备,设备开始工作的...
  • ALSA架构简介--->转载

    2021-08-06 15:05:23
    对博主【沧月代表我】,表示感谢。如有侵权烦请联系我删除!...ALSA除了像OSS那样提供一组内核驱动程序模块以外,还专门为简化应用程序的编写提供了相应的库函数,与OSS提供的基于ioctl的原始编程接口相比

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 4,030
精华内容 1,612
关键字:

alsa架构