linux音频子系统

来源:互联网 发布:有哪些很污的淘宝店铺 编辑:程序博客网 时间:2024/06/05 03:18

音频相关术语

  • PCM(Pulse Code Modulation)
    脉冲编码调制,对连续变化的模拟信号进行抽样、量化和编码,在驱动中一般音频流设备都称为pcm设备

  • I2S
    I2S是对PCM格式的数据进行规范化,可以说是PCM的子集,I2S只有左右两通道数据

  • TDM(Time Division Multiplexing)
    时分复用,可以用单根线传送多通道数据

  • midi(Musical Instrument Digital Interface)
    MIDI是编曲界最广泛的音乐标准格式,可称为“计算机能理解的乐谱”。它用音符的数字控制信号来记录音乐。一首完整的MIDI音乐只有几十KB大,而能包含数十条音乐轨道。几乎所有的现代音乐都是用MIDI加上音色库来制作合成的。MIDI 传输的不是声音信号, 而是音符、控制参数等指令, 它指示MIDI 设备要做什么,怎么做, 如演奏哪个音符、多大音量等。

  • timer(音序器)
    音序器,又称声音序列发生器,可将所有MIDI通道中的演奏信息同时自动播放演奏

驱动架构图

OSS(Open Sound System),linux以前的驱动架构,现在已废弃不用

linux目前的音频框架为ALSA(Advanced Linux Sound Architecture),框架如下图所示,分三层,其中ASoc适用于目前的嵌入式设备,在ALSA-core基础上又分出一个小架构

这里写图片描述

其中alsa-core层的主要结构如下,一个声卡用snd_card来表示,在一个声卡上可能集成了好几个子设备,每个子设备负责不用的功能,分为pcm/control/midi/timer等

这里写图片描述

声卡结构体

一个声卡下是由多个设备的,总声卡用结构体snd_card来表示,各个子设备用结构体snd_device来抽象,当然对于具体的子设备,还会有相应的结构体来表示,这个会在子设备的文章中详细介绍

snd_card

(include/sound/core.h)

struct snd_card {    int number;         /* number of soundcard (index to                                snd_cards) */    char id[16];            /* id string of this card */    char driver[16];        /* driver name */    char shortname[32];     /* short name of this soundcard */    char longname[80];      /* name of this soundcard */    char mixername[80];     /* mixer name */    char components[128];       /* card components delimited with                                space */    struct module *module;      /* top-level module */    void *private_data;     /* private data for soundcard */    void (*private_free) (struct snd_card *card); /* callback for freeing of                                private data */    struct list_head devices;   /* devices */---------snd_device加入此链表    unsigned int last_numid;    /* last used numeric ID */    struct rw_semaphore controls_rwsem; /* controls list lock */    rwlock_t ctl_files_rwlock;  /* ctl_files list lock */    int controls_count;     /* count of all controls */    int user_ctl_count;     /* count of all user controls */    struct list_head controls;  /* all controls for this card */---控制设备snd_device加入此链表    struct list_head ctl_files; /* active control files */    struct mutex user_ctl_lock; /* protects user controls against                       concurrent access */    struct snd_info_entry *proc_root;   /* root for soundcard specific files */    struct snd_info_entry *proc_id; /* the card id */    struct proc_dir_entry *proc_root_link;  /* number link to real id */    struct list_head files_list;    /* all files associated to this card */    struct snd_shutdown_f_ops *s_f_ops; /* file operations in the shutdown                                state */    spinlock_t files_lock;      /* lock the files for this card */    int shutdown;           /* this card is going down */    int free_on_last_close;     /* free in context of file_release */    wait_queue_head_t shutdown_sleep;    atomic_t refcount;      /* refcount for disconnection */    struct device *dev;     /* device assigned to this card */    struct device *card_dev;    /* cardX object for sysfs */#ifdef CONFIG_PM    unsigned int power_state;   /* power state */    struct mutex power_lock;    /* power lock */    wait_queue_head_t power_sleep;#endif#if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE)    struct snd_mixer_oss *mixer_oss;    int mixer_oss_change_count;#endif};

snd_device

(include/sound/core.h)

struct snd_device {    struct list_head list;      /* list of registered devices */---加入声卡的链表节点    struct snd_card *card;      /* card which holds this device */-对应的声卡    snd_device_state_t state;   /* state of the device */    snd_device_type_t type;     /* device type */    void *device_data;      /* device structure */------------对于具体子设备的私有数据    struct snd_device_ops *ops; /* operations */------------------对子设备注册的操作};

声卡注册

snd_card_register

(sound/core/init.c)

int snd_card_register(struct snd_card *card){    int err;    if (snd_BUG_ON(!card))        return -EINVAL;    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;    }    if ((err = snd_device_register_all(card)) < 0)-----注册声卡下的所有子设备        return err;    mutex_lock(&snd_card_mutex);    if (snd_cards[card->number]) {        /* already registered */        mutex_unlock(&snd_card_mutex);        return 0;    }    if (*card->id) {        /* make a unique id name from the given string */        char tmpid[sizeof(card->id)];        memcpy(tmpid, card->id, sizeof(card->id));        snd_card_set_id_no_lock(card, tmpid, tmpid);    } else {        /* create an id from either shortname or longname */        const char *src;        src = *card->shortname ? card->shortname : card->longname;        snd_card_set_id_no_lock(card, src,                    retrieve_id_from_card_name(src));    }    snd_cards[card->number] = card;    mutex_unlock(&snd_card_mutex);    init_info_for_card(card);#if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE)    if (snd_mixer_oss_notify_callback)        snd_mixer_oss_notify_callback(card, SND_MIXER_OSS_NOTIFY_REGISTER);#endif    if (card->card_dev) {        err = device_create_file(card->card_dev, &card_id_attrs);        if (err < 0)            return err;        err = device_create_file(card->card_dev, &card_number_attrs);        if (err < 0)            return err;    }    return 0;}

snd_device_register_all

int snd_device_register_all(struct snd_card *card){    struct snd_device *dev;    int err;    if (snd_BUG_ON(!card))        return -ENXIO;    list_for_each_entry(dev, &card->devices, list) {----遍历声卡的设备链表        if (dev->state == SNDRV_DEV_BUILD && dev->ops->dev_register) {            if ((err = dev->ops->dev_register(dev)) < 0)                return err;-----------------调用每个设备注册函数,进行注册            dev->state = SNDRV_DEV_REGISTERED;        }    }    return 0;}

change log

date content linux version 2017/11/20 origin linux 3.10
原创粉丝点击