2018-05-29 06:48:35 sinat_37817094 阅读数 18999
  • 音频和视频

    通过实例掌握Linux实际操作技能 掌握Linux运维的全面知识

    28076课时 0分钟 9人学习 刘宏强
    免费试看
(1)ALSA简介
(1)
Native ALSA Application:tinyplay/tinycap/tinymix,这些用户程序直接调用 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



(2)
alsa驱动框架核心层给我们干的活:创建声卡设备的控制接口和PCM设备
snd_soc_init()--->
platform_driver_register(&soc_driver)--->
soc_probe()--->
snd_soc_register_card(card)--->注册自己的声卡设备
snd_soc_instantiate_card(card)--->

static int snd_soc_instantiate_card(struct snd_soc_card *card) 
{
     ret = snd_card_create();创建声卡设备-->snd_ctl_create()-->snd_ctl_dev_register创建声卡设备的控制接口函数-->snd_register_device()-->snd_register_device_for_dev()
     ret = soc_probe_link_dais(card, i, order);  --->soc_new_pcm()创建一个新的PCM设备-->snd_pcm_new()--->_snd_pcm_new()--->snd_pcm_new_stream()
     ret = snd_card_register(card->snd_card);-->snd_pcm_dev_register()创建pcm设备文件-->snd_register_device_for_dev()创建pcm设备节点
}

(3)
在内核设备驱动层,ALSA提供了alsa-driver,同时在应用层,ALSA为我们提供了alsa-lib,应用程序只要调用alsa-lib提供的API,即可以完成对底层音频硬件的控制。
ls sound
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的代码,与平台无关



(4)
alsa驱动的设备文件结构: 字符设备
# ls /dev/snd/ -lh
total 0
crw-rw----    1 root     root      116,   0 Aug 21 16:01 controlC0
crw-rw----    1 root     root      116,  24 Aug 21 16:01 pcmC0D0c
crw-rw----    1 root     root      116,  16 Aug 21 16:01 pcmC0D0p
crw-rw----    1 root     root      116,  25 Aug 21 16:01 pcmC0D1c
crw-rw----    1 root     root      116,  17 Aug 21 16:01 pcmC0D1p
crw-rw----    1 root     root      116,  26 Aug 21 16:01 pcmC0D2c
crw-rw----    1 root     root      116,  33 Aug 21 16:01 timer
controlC0               用于声卡的控制,例如通道选择,混音,麦克风的控制等
pcmC0D0c             用于录音的pcm设备
pcmC0D0p             用于播放的pcm设备
timer                       定时器
C0D0代表的是声卡0中的设备0,pcmC0D0c最后一个c代表capture,pcmC0D0p最后一个p代表playback,这些都是alsa-driver中的命名规则。

(5)
sound/core/sound.c
static int __init alsa_sound_init(void)
{
 if (register_chrdev(major, "alsa", &snd_fops))  //注册alsa字符设备
}
static const struct file_operations snd_fops =                                                                                          
{                                                                                                                                       
    .owner =    THIS_MODULE,                                                                                                            
    .open =     snd_open,                                                                                                               
    .llseek =   noop_llseek,                                                                                                            
};                                                                                                                                      
  
static struct snd_minor *snd_minors[SNDRV_OS_MINORS];
谁来设置snd_minors[]结构体数组,snd_register_device_for_dev函数里面有数组项snd_minors外,为了mdev或udev能自动创建设备节点,我们有class_create()函数创建类,下面创建设备device_create(),类在Sound_ core.c入口函数里面被创建,sound.c的入口函数里面注册字符设备函数,snd_register_device_for_dev()函数里面创建声卡逻辑设备时有device_create()

(6)
谁调用snd_register_device_for_dev()(两路调用)
一路:声卡设备的控制接口
另一路:声卡设备的数据接口
声卡设备的控制接口
sound/core/control.c
snd_card_create--->  创建一个snd_card结构体
snd_ctl_create--->
static int snd_ctl_dev_register(struct snd_device *device)-->  //创建声卡设备的控制接口函数
snd_register_device--->
snd_register_device_for_dev()
int snd_ctl_create(struct snd_card *card)
{
    static struct snd_device_ops ops = {
        .dev_free = snd_ctl_dev_free,
        .dev_register = snd_ctl_dev_register,
        .dev_disconnect = snd_ctl_dev_disconnect,
    };   
    if (snd_BUG_ON(!card))
        return -ENXIO;
    return snd_device_new(card, SNDRV_DEV_CONTROL, card, &ops);
}
创建声卡设备的数据接口(声卡驱动)
snd_pcm_new---->  创建一个新的PCM设备
 _snd_pcm_new---> 创建播放流和录音流
static int snd_pcm_dev_register(struct snd_device *device)  //创建声卡设备的数据接口
总结:
(1)构造snd_card结构体,snd_card_create()构造snd_card结构体并自动创建控制接口。调用函数snd_ctrl_create
(2)初始化;如snd_pcm_new(),创建逻辑设备(播放设备或录音设备)
(3)注册 snd_card_register

(2)声卡的创建

(1)
struct snd_card是什么
snd_card可以说是整个ALSA音频驱动最顶层的一个结构,整个声卡的软件逻辑结构开始于该结构,几乎所有与声音相关的逻辑设备都是在snd_card的管理之下,声卡驱动的第一个动作通常就是创建一个snd_card结构体。
struct snd_card {
struct list_head devices     记录该声卡下所有逻辑设备的链表
struct list_head controls    记录该声卡下所有的控制单元的链表
void *private_data            声卡的私有数据,可以在创建声卡时通过参数指定数据的大小
}

snd_soc_init
{
 return platform_driver_register(&soc_driver);
}
static int soc_probe(struct platform_device *pdev) 
{
   return snd_soc_register_card(card); 
}int snd_soc_register_card(struct snd_soc_card *card)
{
  ret = snd_soc_instantiate_card(card); 
}
static int snd_soc_instantiate_card(struct snd_soc_card *card) 
{
     ret = snd_card_create(SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,card->owner, 0, &card->snd_card); -->snd_ctl_create()
     ret = soc_probe_link_dais(card, i, order);  --->soc_new_pcm()-->snd_pcm_new()
     ret = snd_card_register(card->snd_card);
}
snd_card_create(SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,card->owner, 0, &card->snd_card);创建snd_card的一个实例
index:一个整数值,该声卡的编号 id:字符串,声卡的标识符 第四个参数:该参数决定在创建snd_card实例时,需要同时额外分配的私有数据的大小,该数据的指针最终会赋值给snd_card的private_data数据成员
card:返回所创建的snd_card实例的指针
设置Driver的ID和名字
static int __init alsa_sound_init(void)    subsys_initcall(alsa_sound_init);
snd_info_init()-->
snd_card_info_init()-->
snd_card_info_read()-->
{
snd_iprintf(buffer, "%2i [%-15s]: %s - %s\n",idx,card->id,card->driver,card->shortname);
snd_iprintf(buffer, "%s\n",card->longname);
}
创建声卡的功能部件(逻辑设备),例如PCM,Mixer,MIDI等
这时候可以创建声卡的各种功能部件了,还记得开头的snd_card结构体的devices字段吗?每一种部件的创建最终会调用snd_device_new()来生成一个snd_device实例,并把该实例链接到snd_card的devices链表中。
通常,alsa-driver的已经提供了一些常用的部件的创建函数,而不必直接调用snd_device_new(),比如:
    PCM  ----           snd_pcm_new()
    RAWMIDI --       snd_rawmidi_new()
    CONTROL --      snd_ctl_create()
    TIMER   --          snd_timer_new()
    INFO    --           snd_card_proc_new()
    JACK    --           snd_jack_new()

注册声卡 static int snd_soc_instantiate_card(struct snd_soc_card *card) 
{
     ret = snd_card_create(SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,card->owner, 0, &card->snd_card);
     ret = soc_probe_link_dais(card, i, order);  --->soc_new_pcm()-->snd_pcm_new()
     ret = snd_card_register(card->snd_card);

}
比如我们的例子:
sound/soc/ingenic/asoc-board/phoenix_icdc.c 
static int snd_phoenix_probe(struct platform_device *pdev)
{
ret = snd_soc_register_card(&phoenix);
}



(2)
int snd_card_create(int idx, const char *xid,struct module *module, int extra_size,struct snd_card **card_ret)
{
     if (extra_size < 0)
        extra_size = 0;
    card = kzalloc(sizeof(*card) + extra_size, GFP_KERNEL);
//根据extra_size参数的大小分配内存,该内存区可以作为芯片的专有数据使用

 if (xid)
        strlcpy(card->id, xid, sizeof(card->id));


    if (idx < 0) {
        for (idx2 = 0; idx2 < SNDRV_CARDS; idx2++)
            /* idx == -1 == 0xffff means: take any free slot */
            if (~snd_cards_lock & idx & 1<<idx2) {
                if (module_slot_match(module, idx2)) {
                    idx = idx2;
                    break;
                }
            }
    }
    if (idx < 0) {
        for (idx2 = 0; idx2 < SNDRV_CARDS; idx2++)
            /* idx == -1 == 0xffff means: take any free slot */
            if (~snd_cards_lock & idx & 1<<idx2) {
                if (!slots[idx2] || !*slots[idx2]) {
                    idx = idx2;
                    break;
                }
            }
    }
//拷贝声卡的ID字符串

    card->number = idx;
    card->module = module;
    INIT_LIST_HEAD(&card->devices);
    init_rwsem(&card->controls_rwsem);
    rwlock_init(&card->ctl_files_rwlock);
    INIT_LIST_HEAD(&card->controls);
    INIT_LIST_HEAD(&card->ctl_files);
    spin_lock_init(&card->files_lock);
    INIT_LIST_HEAD(&card->files_list);
    init_waitqueue_head(&card->shutdown_sleep);
    atomic_set(&card->refcount, 0);
#ifdef CONFIG_PM
    mutex_init(&card->power_lock);
    init_waitqueue_head(&card->power_sleep);
#endif
//初始化snd_card结构中必要的字段

 err = snd_ctl_create(card);
    if (err < 0) {
        snd_printk(KERN_ERR "unable to register control minors\n");
        goto __error;
    }
//建立逻辑设备:Control

 err = snd_info_card_create(card);
    if (err < 0) {
        snd_printk(KERN_ERR "unable to create card info\n");
        goto __error_ctl;
    }
//建立proc文件中的info节点:通常就是/proc/asound/card0

  if (extra_size > 0)
        card->private_data = (char *)card + sizeof(struct snd_card);
    *card_ret = card;
    return 0;
//分配的内存指针放入private_data字段中

}

int snd_card_register(struct snd_card *card)
{
        if (!card->card_dev) {
        card->card_dev = device_create(sound_class, card->dev,
                           MKDEV(0, 0), card,
                           "card%i", card->number);
        if (IS_ERR(card->card_dev))
            card->card_dev = NULL;
    }
//创建sysfs下的设备

if ((err = snd_device_register_all(card)) < 0) 
        return err;
//通过snd_device_register_all()注册所有挂在该声卡下的逻辑设备,snd_device_register_all()实际上是通过snd_card的devices链表,遍历所有的snd_device,并且调用snd_device的ops->dev_register()来实现各自设备的注册的。

最后代码就是建立一些相应的proc和sysfs下的文件或属性节点

}

static int __init init_soundcore(void)  subsys_initcall(init_soundcore)
{
    int rc;

    rc = init_oss_soundcore();
    if (rc)
        return rc;

    sound_class = class_create(THIS_MODULE, "sound");
    if (IS_ERR(sound_class)) {
        cleanup_oss_soundcore();
        return PTR_ERR(sound_class);
    }

    sound_class->devnode = sound_devnode;

    return 0;
}

static char *sound_devnode(struct device *dev, umode_t *mode)
{
    if (MAJOR(dev->devt) == SOUND_MAJOR)
        return NULL;
    return kasprintf(GFP_KERNEL, "snd/%s", dev_name(dev));
}
//声卡的class将会出现在文件系统的/sys/class/sound/下面,并且,sound_devnode()也决定了相应的设备节点也将会出现在/dev/snd/下面。

# ls /dev/snd/ -lh
total 0
crw-rw----    1 root     root      116,   0 Aug 21 12:00 controlC0
crw-rw----    1 root     root      116,  24 Aug 21 12:00 pcmC0D0c
crw-rw----    1 root     root      116,  16 Aug 21 12:00 pcmC0D0p
crw-rw----    1 root     root      116,  25 Aug 21 12:00 pcmC0D1c
crw-rw----    1 root     root      116,  17 Aug 21 12:00 pcmC0D1p
crw-rw----    1 root     root      116,  26 Aug 21 12:00 pcmC0D2c
crw-rw----    1 root     root      116,  33 Aug 21 12:00 timer


 ls /sys/class/sound/ -lh
total 0
lrwxrwxrwx    1 root     root           0 Aug 21 12:00 card0 -> ../../devices/platform/ingenic-alsa.0/sound/card0
lrwxrwxrwx    1 root     root           0 Aug 21 12:00 controlC0 -> ../../devices/platform/ingenic-alsa.0/sound/card0/controlC0
lrwxrwxrwx    1 root     root           0 Aug 21 12:00 pcmC0D0c -> ../../devices/platform/ingenic-alsa.0/sound/card0/pcmC0D0c
lrwxrwxrwx    1 root     root           0 Aug 21 12:00 pcmC0D0p -> ../../devices/platform/ingenic-alsa.0/sound/card0/pcmC0D0p
lrwxrwxrwx    1 root     root           0 Aug 21 12:00 pcmC0D1c -> ../../devices/platform/ingenic-alsa.0/sound/card0/pcmC0D1c
lrwxrwxrwx    1 root     root           0 Aug 21 12:00 pcmC0D1p -> ../../devices/platform/ingenic-alsa.0/sound/card0/pcmC0D1p
lrwxrwxrwx    1 root     root           0 Aug 21 12:00 pcmC0D2c -> ../../devices/platform/ingenic-alsa.0/sound/card0/pcmC0D2c
lrwxrwxrwx    1 root     root           0 Aug 21 12:00 timer -> ../../devices/virtual/sound/timer








2017-11-01 08:37:01 u010871058 阅读数 625
  • 音频和视频

    通过实例掌握Linux实际操作技能 掌握Linux运维的全面知识

    28076课时 0分钟 9人学习 刘宏强
    免费试看

一:ALSA音频架构简单介绍

       ALSA是Advanced Linux Sound Architecture,高级Linux声音架构的简称,它在Linux操作系统上提供了音频和MIDI(Musical Instrument Digital Interface,音乐设备数字化接口)的支持。在2.6系列内核中,ALSA已经成为默认的声音子系统,用来替换2.4系列内核中的OSS(Open Sound System。开放声音系统)。ALSA的主要特性包含:高效地支持从消费类入门级声卡到专业级音频设备全部类型的音频接口,全然模块化的设计。 支持对称多处理(SMP)和线程安全。对OSS的向后兼容,以及提供了用户空间的alsa-lib库来简化应用程序的开发。


       ALSA是一个全然开放源码的音频驱动程序集,除了像OSS那样提供了一组内核驱动程序模块之外,ALSA还专门为简化应用程序的编写提供了对应的函数库,与OSS提供的基于ioctl的原始编程接口相比。ALSA函数库使用起来要更加方便一些。利用该函数库,开发人员能够方便快捷的开发出自己的应用程序,细节则留给函数库内部处理。当然 ALSA也提供了类似于OSS的系统接口,只是ALSA的开发人员建议应用程序开发人员使用音频函数库而不是驱动程序的API。


二:ALSA官方站点

     开源ALSA架构的站点例如以下所看到的:http://www.alsa-project.org/main/index.php/Main_Page


我这里下载的不是最新版本号的alsa-lib-1.0.28,而是alsa-lib-1.0.26。其主要原因当然是为了版本号的稳定性才选择低一点版本号。

而ALSA-lib的文件架构例如以下所看到的:



三:ALSA移植和编译

     在ALSA-lib的移植其中,还是出现过非常多奇怪的问题,当然这个跟我当前全部的uClibc的版本号有关,对于低于uClibc-0.9.23的版本号地uClibc,须要对ALSA的库源代码进行更新,否则会出现编译失败的问题,这个我一一道来。

     1):'versionsort' undeclared的错误

       'versionsort' undeclared错误的提示信息例如以下所看到的:


       这个是由于uClibc假设低于0.9.23的话,就会出现这个问题,由于在uClibc-0.9.32下面的版本号没有versionsort函数导致的。这个能够在uClibc的源代码中看到的。在uClibc-0.9.32的版本号里就有versionsort函数。例如以下所看到的:


低于这个版本号uClibc的就没有这个函数和文件的,那么就须要下载一个补丁包,而且将其移植到ALSA-lib中去。假设你的uClibc本身的版本号就比这个高的话。能够跳过这个部分。

其补丁包文件例如以下所看到的:


将这个补丁打上。採用例如以下命令,例如以下所看到的:


这个仅仅是第一步,假设仅仅是这样打下补丁,还是会出现'versionsort' undeclared错误的提示,只是不是在parse.c文件里,而是在conf.c文件里,例如以下所看到的:


这样就不能採用上面的方法再来打补丁的方式来解决,否则会出现versionsort反复定义的错误。怎么办呢,那就仅仅能将versionsort移植到alsa-lib库中去。

首先从alsa-lib/src/ucm/parse.c中复制出versionsort的那部分函数代码。又一次新建一个versionsort.c文件在alsa-lib/src/下,例如以下所看到的:


同一时候改动上图中的Makefile.am文件,加上这个文件,例如以下所看到的:


还须要在alsa-lib/include/local.h文件里增加一行代码,例如以下所看到的:


又一次改动编译脚本build.sh文件,加上一行代码:autoreconf -ivf,例如以下所看到的:


     又一次编译整个alsa-lib库。

     2):' atomic_add'之类的反复定义的错误

     假设在编译中遇到这个问题的话。就须要改动configure和configure.ac文件,假设没有这类错误就不须要改动。例如以下所看到的:


         就须要将-D__arm__拿掉,之后又一次编译整个alsa-lib库...

      3):--with-versioned的问题

      这个问题是最难找的问题,只是不加--with-versioned=no的话,会出现静态库调用snd_pcm_hw_params_get_buffer_size(x,x)能够正确的返回buffer_size的大小,而动态库却无法正确返回。总是返回0。

这个地方我整整查了两天,才找到是这里导致的问题。


四:ALSAlib库移植总结

      在移植过程中出现过非常多状况。只是这也是一个学习的机会,只是好在问题都所有找到并解决啦。

2017-10-12 10:27:50 u013636122 阅读数 0
  • 音频和视频

    通过实例掌握Linux实际操作技能 掌握Linux运维的全面知识

    28076课时 0分钟 9人学习 刘宏强
    免费试看
Linux ALSA 系统架构

ALSA 是Linux声卡驱动的架构,下面基于linux-2.6.32描述下ALSA系统架构。ALSA系统可以分为alsa-lib、alsa- driver,而alsa-driver又分为core层和底层硬件层。作为开发者,我们只需移植底层硬件层,根据自己硬件特性,实现底层的移植。而 core层基本属于ALSA标准框架,不需要自己实现。介绍ALSA框架,下面是大体框架图。




 

     如上图所示,alsa驱动最终会被上层应用调用,这是通过alsa-lib实现的,alsa-lib为alsa-driver封装了许多API,通过这 些API,上层应用可以调用到驱动层。而alsa-lib中的这些API,我们可暂时把他们当做一个黑盒子,里面具体实现不需要去关注,下面以 linux-2.6.32中ALSA调用函数关系说明其架构。先分析ALSA驱动的注册过程。

一、ALSA驱动的注册


 

注册流程查看上图,具体的注册过程不在此赘述。

二、打开流程

在ALSA驱动注册完毕以后,当应用程序开始调用时,会有一个过程:打开设备、映射、设置硬件参数、准备工作、触发数据流。下图为整个流程。


 带sep0611的是需要自己实现的底层驱动。

三、写数据流程


    图中应用程序通过ALSA-lib的API函数写入数据,ALSA-lib调用等待函数等待底层可写。ALSA-lib通过poll系统调用进入底层驱动 并将poll信号加入sleep队列阻塞进程。硬件的中断信号触发底层驱动注册的中断处理函数,中断处理函数进而调用ALSA-driver中的函数判读 是否该写。ALSA-driver中的函数再调用底层芯片硬件驱动获取硬件当前数据大小。ALSA-driver再判断空闲数据区的大小,如果满足条件就 唤醒sleep队列,poll信号从而被唤醒,进而返回给ALSA-lib,ALSA-lib收到信号后再执行往buffer里写数据。
ALSA- lib通过mmap机制将硬件申请的内存映射到用户空间,从而应用程序只需调用ALSA-lib往相应位置写数据,硬件就可以直接读取了。如果映射内存里 已有数据,通过DMA传输给codec,codec便开始读取数据并进行解码播放声音了。经过测试,基于sep6200的ALSA声卡驱动工作正常,既可 以播放声音也可以录制。、

我对ALSA录音和播音的理解,当我们通过麦克风讲话的声音搜集到声卡里之后,内存从声卡里读取声音数据的过程就是录音过程,即snd_pcm_readi()函数的执行,把内存中的声音数据写入到声卡的过程就是播音过程,即snd_pcm_writei()函数的执行。
2015-06-04 14:00:35 hecong129 阅读数 0
  • 音频和视频

    通过实例掌握Linux实际操作技能 掌握Linux运维的全面知识

    28076课时 0分钟 9人学习 刘宏强
    免费试看

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的软件体系结构

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

2.  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中,定义了以下设备类型:

复制代码
 1 #define    SNDRV_DEV_TOPLEVEL    ((__force snd_device_type_t) 0)
 2 #define    SNDRV_DEV_CONTROL    ((__force snd_device_type_t) 1)
 3 #define    SNDRV_DEV_LOWLEVEL_PRE    ((__force snd_device_type_t) 2)
 4 #define    SNDRV_DEV_LOWLEVEL_NORMAL ((__force snd_device_type_t) 0x1000)
 5 #define    SNDRV_DEV_PCM        ((__force snd_device_type_t) 0x1001)
 6 #define    SNDRV_DEV_RAWMIDI    ((__force snd_device_type_t) 0x1002)
 7 #define    SNDRV_DEV_TIMER        ((__force snd_device_type_t) 0x1003)
 8 #define    SNDRV_DEV_SEQUENCER    ((__force snd_device_type_t) 0x1004)
 9 #define    SNDRV_DEV_HWDEP        ((__force snd_device_type_t) 0x1005)
10 #define    SNDRV_DEV_INFO        ((__force snd_device_type_t) 0x1006)
11 #define    SNDRV_DEV_BUS        ((__force snd_device_type_t) 0x1007)
12 #define    SNDRV_DEV_CODEC        ((__force snd_device_type_t) 0x1008)
13 #define    SNDRV_DEV_JACK          ((__force snd_device_type_t) 0x1009)
14 #define    SNDRV_DEV_LOWLEVEL    ((__force snd_device_type_t) 0x2000)
复制代码

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

3.  驱动的代码文件结构

在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的代码,与平台无关

本文转自:http://blog.csdn.net/droidphone/article/details/6271122

2011-03-23 15:19:00 DroidPhone 阅读数 126825
  • 音频和视频

    通过实例掌握Linux实际操作技能 掌握Linux运维的全面知识

    28076课时 0分钟 9人学习 刘宏强
    免费试看

声明:本博内容均由http://blog.csdn.net/droidphone原创,转载请注明出处,谢谢!


一.  概述

    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在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中,定义了以下设备类型:

 通常,我们更关心的是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的代码,与平台无关

 

alsa音频架构1

阅读数 4100