第一部分 alsa子系统关键结构体对象等
1.声卡设备类型定义
- #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)
一个声卡可以有多个声卡设备,alsa中用snd_card描述声卡对象,用snd_device描述声卡设备对象
2.声卡结构体
- struct snd_card {
- int number; //声卡索引号
- char id[16]; //id识别字串
- char driver[16]; //驱动名
- char shortname[32]; //短名
- char longname[80]; //长名
- char mixername[80]; /* mixer name */
- char components[128]; /* card components delimited with space */
- struct module *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; //设备链表
- 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; //控制链表
- struct list_head ctl_files; /* active control files */
- 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;
- struct device *dev; //设备文件
- struct device *card_dev; //声卡设备文件
- #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
- };
2.1.全局变量snd_cards
在"/sound/core/init.c"
- struct snd_card *snd_cards[SNDRV_CARDS];
SNDRV_CARDS为8也就是声卡最多8个
3.声卡设备结构体
- struct snd_device {
- struct list_head list; //链表
- struct snd_card *card; //所属的声卡
- snd_device_state_t state; //设备状态
- snd_device_type_t type; //设备类型
- void *device_data; /* device structure */
- struct snd_device_ops *ops; //声卡设备操作函数集
- };
3.1 设备状态的值
- #define SNDRV_DEV_BUILD ((__force snd_device_state_t) 0)//创建
- #define SNDRV_DEV_REGISTERED ((__force snd_device_state_t) 1)//注册
- #define SNDRV_DEV_DISCONNECTED ((__force snd_device_state_t) 2)//断开连接
3.2 设备类型
也就是上面 1.声卡设备类型定义 所指定的类型
4.声卡操作函数集
- struct snd_device_ops {
- int (*dev_free)(struct snd_device *dev); //释放
- int (*dev_register)(struct snd_device *dev); //注册
- int (*dev_disconnect)(struct snd_device *dev); //断开连接
- };
第二部分 声卡
1.声卡创建
传递进来的idx为负值,则系统会分配一个idx作为全局snd_cards数组的索引项值,xid字串用来区分描述声卡id,module一般为THIS_MODULE...
- int snd_card_create(int idx, const char *xid,struct module *module, int extra_size,struct snd_card **card_ret)
- {
- struct snd_card *card;
- int err, idx2;
- if (snd_BUG_ON(!card_ret))
- return -EINVAL;
- *card_ret = NULL;
- if (extra_size < 0)
- extra_size = 0;
- card = kzalloc(sizeof(*card) + extra_size, GFP_KERNEL); //分配声卡对象和额外空间的内存
- if (!card)
- return -ENOMEM;
- if (xid) //若需要填充声卡id识别字串
- strlcpy(card->id, xid, sizeof(card->id)); //card->id=xid 声卡id识别字串
- err = 0;
- mutex_lock(&snd_card_mutex); //idx为负值则交由系统选择一个值______________________<
- 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;
- }
- }
- }
- if (idx < 0)
- err = -ENODEV;
- else if (idx < snd_ecards_limit) {
- if (snd_cards_lock & (1 << idx))
- err = -EBUSY; /* invalid */
- } else if (idx >= SNDRV_CARDS)
- err = -ENODEV;
- if (err < 0) {
- mutex_unlock(&snd_card_mutex);
- snd_printk(KERN_ERR "cannot find the slot for index %d (range 0-%i), error: %d\n",idx, snd_ecards_limit - 1, err);
- goto __error;
- }
- snd_cards_lock |= 1 << idx; /* lock it */
- if (idx >= snd_ecards_limit)
- snd_ecards_limit = idx + 1; /* increase the limit */
- mutex_unlock(&snd_card_mutex); //______________________>
- card->number = idx; //声卡对象索引号 全局数组snd_cards的数组下标
- card->module = module; //声卡对象模块所有者THIS_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); //初始化关机队列头
- #ifdef CONFIG_PM
- mutex_init(&card->power_lock); //初始化电源互斥锁
- init_waitqueue_head(&card->power_sleep); //初始化睡眠等待队列头
- #endif
- err = snd_ctl_create(card); //创建用于控制的声卡设备对象
- if (err < 0) {
- snd_printk(KERN_ERR "unable to register control minors\n");
- goto __error;
- }
- err = snd_info_card_create(card); //proc下面的接口
- if (err < 0) {
- snd_printk(KERN_ERR "unable to create card info\n");
- goto __error_ctl;
- }
- if (extra_size > 0) //有额外数据
- card->private_data = (char *)card + sizeof(struct snd_card);
- *card_ret = card;
- return 0;
- __error_ctl:
- snd_device_free_all(card, SNDRV_DEV_CMD_PRE);
- __error:
- kfree(card);
- return err;
- }
- EXPORT_SYMBOL(snd_card_create);
这里主要是初始化了声卡的devices声卡设备链表,以后创建的声卡设备将挂在该链表上
并调用了snd_ctl_create创建了用于控制的声卡设备对象,这我们可以得出一个结论每个声卡都有一个声卡控制设备对象
第三部分 声卡设备
1.创建声卡设备
在这里 声卡设备与声卡捆绑,指定声卡设备类型,设置声卡设备状态,捆绑对应的snd_device_ops方法,添加声卡设备到声卡的devices链表
- int snd_device_new(struct snd_card *card, snd_device_type_t type,void *device_data, struct snd_device_ops *ops)
- {
- struct snd_device *dev;
- if (snd_BUG_ON(!card || !device_data || !ops))
- return -ENXIO;
- dev = kzalloc(sizeof(*dev), GFP_KERNEL); //分配声卡设备内存
- if (dev == NULL) {
- snd_printk(KERN_ERR "Cannot allocate device\n");
- return -ENOMEM;
- }
- dev->card = card; //设备捆绑对象
- dev->type = type; //指定设备类型
- dev->state = SNDRV_DEV_BUILD; //设备状态 已创建
- dev->device_data = device_data; //设备数据
- dev->ops = ops; //设备操作函数集
- list_add(&dev->list, &card->devices); //添加到声卡对象的设备devices链表中
- return 0;
- }
- EXPORT_SYMBOL(snd_device_new);
这里声卡设备的snd_device_ops是传递进来的结构体指针,实际操作中一般调用以下API来创建不同类型的声卡
1.1 创建声卡设备常见API
- snd_ctl_create -->snd_device_new(card, SNDRV_DEV_CONTROL, card, &ops);
- snd_card_proc_new -->snd_device_new(card, SNDRV_DEV_INFO, entry, &ops)
- snd_timer_new -->snd_device_new(card, SNDRV_DEV_TIMER, timer, &ops)
- snd_jack_new -->snd_device_new(card, SNDRV_DEV_JACK, jack, &ops)
- snd_pcm_new -->snd_device_new(card, SNDRV_DEV_PCM, pcm, &ops)
- snd_rawmidi_new -->snd_device_new(card, SNDRV_DEV_RAWMIDI, rmidi, &ops)
- snd_seq_device_new -->snd_device_new(card, SNDRV_DEV_SEQUENCER, dev, &dops)
- snd_hwdep_new -->snd_device_new(card, SNDRV_DEV_HWDEP, hwdep, &ops)
- snd_i2c_bus_create -->snd_device_new(card, SNDRV_DEV_BUS, bus, &ops)
- snd_hda_bus_new -->snd_device_new(card, SNDRV_DEV_BUS, bus, &dev_ops)
- snd_ac97_bus -->snd_device_new(card, SNDRV_DEV_BUS, bus, &dev_ops)
- ...//不完整
这些API都静态设置了对应类型的snd_device_ops结构体ops,然后调用snd_device_new并将ops传递进来
后面我们再针对不同的声卡设备类型展开分析
创建声卡设备后系统大致入下图描述
创建后的声卡设备的state值为SNDRV_DEV_BUILD
第四部分 注册声卡
1.注册声卡
- int snd_card_register(struct snd_card *card)
- {
- int err;
- if (snd_BUG_ON(!card))
- return -EINVAL;
- if (!card->card_dev) {
- //创建设备文件"/sys/class/sound/cardX"
- 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) //-->1.1.注册所有的声卡设备
- return err;
- mutex_lock(&snd_card_mutex);
- if (snd_cards[card->number]) { //判断对应数组项是否已给占用"/sound/core/init.c" struct snd_card *snd_cards[SNDRV_CARDS];
- mutex_unlock(&snd_card_mutex);
- return 0;
- }
- snd_card_set_id_no_lock(card, card->id[0] == '\0' ? NULL : card->id);
- snd_cards[card->number] = card; //填充全局snd_cards数组
- mutex_unlock(&snd_card_mutex);
- init_info_for_card(card); //proc接口
- #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;
- }
- EXPORT_SYMBOL(snd_card_register);
主要是调用snd_device_register_all函数注册所有声卡设备,其次是填充了全局snd_cards数组对应的数组项
1.1注册挂在该声卡下面的所有声卡设备
- 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) { //遍历声卡的设备devices链表
- if (dev->state == SNDRV_DEV_BUILD && dev->ops->dev_register) {//状态为已建立且存在dev_register方法
- if ((err = dev->ops->dev_register(dev)) < 0) //调用声卡设备的dev_register方法
- return err;
- dev->state = SNDRV_DEV_REGISTERED; //修改状态为已注册
- }
- }
- return 0;
- }
这里会遍历声卡对象的devices设备链表,然后调用声卡设备所捆绑的声卡设备操作函数集合的dev_register方法,注册初始化对应的声卡设备
注册完声卡后,声卡设备的state值修改为SNDRV_DEV_REGISTERED
第五部分 注册声卡设备
不同类型的声卡设备的操作函数集的dev_register不同,但是也有其共性,下面主要是针对共性来分析
1.snd_minor声卡字符设备结构体
- struct snd_minor {
- int type; //声卡设备类型 SNDRV_DEVICE_TYPE_XXX
- int card; //声卡索引号
- int device; /* device number */
- const struct file_operations *f_ops; //文件操作函数集
- void *private_data; //私有数据
- struct device *dev; //设备文件
- };
- enum {
- SNDRV_DEVICE_TYPE_CONTROL, //控制
- SNDRV_DEVICE_TYPE_SEQUENCER, //音序器
- SNDRV_DEVICE_TYPE_TIMER, //定时器
- SNDRV_DEVICE_TYPE_HWDEP, //硬件依赖层
- SNDRV_DEVICE_TYPE_RAWMIDI, //raw midi
- SNDRV_DEVICE_TYPE_PCM_PLAYBACK, //PCM回放
- SNDRV_DEVICE_TYPE_PCM_CAPTURE, //PCM捕捉
- };
- static struct snd_minor *snd_minors[SNDRV_OS_MINORS];
封装了(2.1)snd_register_device_for_dev函数
- static inline int snd_register_device(int type, struct snd_card *card, int dev,const struct file_operations *f_ops,void *private_data,const char *name)
- {
- return snd_register_device_for_dev(type, card, dev, f_ops,private_data, name,snd_card_get_device_link(card));
- }
- int snd_register_device_for_dev(int type, struct snd_card *card, int dev,const struct file_operations *f_ops,
- void *private_data,const char *name, struct device *device)
- {
- int minor; //次设备号
- struct snd_minor *preg; //声明一个snd_minor结构体
- if (snd_BUG_ON(!name))
- return -EINVAL;
- preg = kmalloc(sizeof *preg, GFP_KERNEL); //分配snd_minor结构体内存
- if (preg == NULL)
- return -ENOMEM;
- preg->type = type; //设置snd_minor类型
- preg->card = card ? card->number : -1; //声卡索引号
- preg->device = dev; //设备文件
- preg->f_ops = f_ops; //文件操作函数集合
- preg->private_data = private_data; //私有数据
- mutex_lock(&sound_mutex);
- #ifdef CONFIG_SND_DYNAMIC_MINORS
- minor = snd_find_free_minor();
- #else
- minor = snd_kernel_minor(type, card, dev); //获取次设备号
- if (minor >= 0 && snd_minors[minor])
- minor = -EBUSY;
- #endif
- if (minor < 0) {
- mutex_unlock(&sound_mutex);
- kfree(preg);
- return minor;
- }
- snd_minors[minor] = preg; //填充全局snd_minors数组项
- preg->dev = device_create(sound_class, device, MKDEV(major, minor),private_data, "%s", name); //创建"/dev/snd/XXX"
- if (IS_ERR(preg->dev)) {
- snd_minors[minor] = NULL;
- mutex_unlock(&sound_mutex);
- minor = PTR_ERR(preg->dev);
- kfree(preg);
- return minor;
- }
- mutex_unlock(&sound_mutex);
- return 0;
- }
- EXPORT_SYMBOL(snd_register_device_for_dev);
第六部分 声卡驱动的编写框架
综合上面五个部分得出下图
编写过程为先调用snd_card_create创建声卡,接着调用创建声卡设备的API创建不同类型的声卡设备组件,接着调用snd_card_register注册声卡就行.
大致走完上面的流程后系统的框图
第七部分 声卡核心子系统的初始化工作
1.声明子系统
- subsys_initcall(init_soundcore);
2.子系统初始化
- static int __init init_soundcore(void)
- {
- int rc;
- rc = init_oss_soundcore();//初始化oss子系统部分
- if (rc)
- return rc;
- sound_class = class_create(THIS_MODULE, "sound"); //创建设备类"/sys/class/sound/"
- if (IS_ERR(sound_class)) {
- cleanup_oss_soundcore();
- return PTR_ERR(sound_class);
- }
- sound_class->devnode = sound_devnode; //创建设备节点的方法
- return 0;
- }
主要初始化oss子系统部分
2.1 oss子系统初始化
- static int __init init_oss_soundcore(void)
- {
- if (preclaim_oss && register_chrdev(SOUND_MAJOR, "sound", &soundcore_fops) == -1) {//创建字符设备
- printk(KERN_ERR "soundcore: sound device already in use.\n");
- return -EBUSY;
- }
- return 0;
- }
2.2 指定sound_class类的创建设备节点方法sound_devnode
- static char *sound_devnode(struct device *dev, mode_t *mode)
- {
- if (MAJOR(dev->devt) == SOUND_MAJOR) //主设备号14 oss子系统
- return NULL;
- return kasprintf(GFP_KERNEL, "snd/%s", dev_name(dev)); //alsa子系统 "/dev/sndX/"
- }
所以alsa子系统的音频设备会出现在/dev/snd/目录下
这里我们可以得知alsa架构的设备节点在/dev/snd/目录下,oss架构的设备节点在/dev下
alsa的主设备号为116,oss架构的主设备号为14
alsa的主设备号在/sound/core/sound.c中定义
- static int major = CONFIG_SND_MAJOR;
- #define CONFIG_SND_MAJOR 116
第八部分 声卡控制设备浅析
前面讲到每个声卡都有一个声卡控制设备对象,所以研究下声卡控制设备
在声卡创建函数snd_card_create中调用了snd_ctl_create函数创建声卡控制设备,并将声卡对象作为参数传递进来
1.创建声卡控制设备
- int snd_ctl_create(struct snd_card *card)
- {
- static struct snd_device_ops ops = {//静态初始化snd_device_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_device_new函数的参数,发现声卡控制设备的device_data是指向声卡对象的
在注册声卡过程中会调用snd_device_register_all函数,该函数则调用声卡控制设备dev_register方法,既snd_ctl_dev_register函数
2.注册声卡控制设备
- static int snd_ctl_dev_register(struct snd_device *device)
- {
- struct snd_card *card = device->device_data; //获取声卡对象
- int err, cardnum;
- char name[16];
- if (snd_BUG_ON(!card))
- return -ENXIO;
- cardnum = card->number; //获取声卡索引号
- if (snd_BUG_ON(cardnum < 0 || cardnum >= SNDRV_CARDS))
- return -ENXIO;
- sprintf(name, "controlC%i", cardnum); //设置名字-->"/dev/snd/controlCx"
- if ((err = snd_register_device(SNDRV_DEVICE_TYPE_CONTROL, card, -1,&snd_ctl_f_ops, card, name)) < 0) //注册声卡控制设备
- return err;
- return 0;
- }
通过snd_register_device创建了/dev/snd/controlC0设备文件,假设是0号声卡吧!并捆绑了snd_ctl_f_ops设备文件操作函数集
3.声卡控制设备对应的设备文件操作函数集
- static const struct file_operations snd_ctl_f_ops =
- {
- .owner = THIS_MODULE,
- .read = snd_ctl_read, //读方法
- .open = snd_ctl_open, //打开方法
- .release = snd_ctl_release, //释放方法
- .llseek = no_llseek,
- .poll = snd_ctl_poll, //轮询方法
- .unlocked_ioctl = snd_ctl_ioctl, //命令控制
- .compat_ioctl = snd_ctl_ioctl_compat, //32位兼容的命令控制
- .fasync = snd_ctl_fasync, //同步方法
- };
这样就提供了应用层的接口方法了,比较重要的是命令控制方法,主要有以下控制命令
- #define SNDRV_CTL_IOCTL_PVERSION _IOR('U', 0x00, int)//打印alsa版本
- #define SNDRV_CTL_IOCTL_CARD_INFO _IOR('U', 0x01, struct snd_ctl_card_info)//获取声卡信息
- #define SNDRV_CTL_IOCTL_ELEM_LIST _IOWR('U', 0x10, struct snd_ctl_elem_list)
- #define SNDRV_CTL_IOCTL_ELEM_INFO _IOWR('U', 0x11, struct snd_ctl_elem_info)
- #define SNDRV_CTL_IOCTL_ELEM_READ _IOWR('U', 0x12, struct snd_ctl_elem_value)
- #define SNDRV_CTL_IOCTL_ELEM_WRITE _IOWR('U', 0x13, struct snd_ctl_elem_value)
- #define SNDRV_CTL_IOCTL_ELEM_LOCK _IOW('U', 0x14, struct snd_ctl_elem_id)
- #define SNDRV_CTL_IOCTL_ELEM_UNLOCK _IOW('U', 0x15, struct snd_ctl_elem_id)
- #define SNDRV_CTL_IOCTL_SUBSCRIBE_EVENTS _IOWR('U', 0x16, int)
- #define SNDRV_CTL_IOCTL_ELEM_ADD _IOWR('U', 0x17, struct snd_ctl_elem_info)
- #define SNDRV_CTL_IOCTL_ELEM_REPLACE _IOWR('U', 0x18, struct snd_ctl_elem_info)
- #define SNDRV_CTL_IOCTL_ELEM_REMOVE _IOWR('U', 0x19, struct snd_ctl_elem_id)
- #define SNDRV_CTL_IOCTL_TLV_READ _IOWR('U', 0x1a, struct snd_ctl_tlv)
- #define SNDRV_CTL_IOCTL_TLV_WRITE _IOWR('U', 0x1b, struct snd_ctl_tlv)
- #define SNDRV_CTL_IOCTL_TLV_COMMAND _IOWR('U', 0x1c, struct snd_ctl_tlv)
- #define SNDRV_CTL_IOCTL_POWER _IOWR('U', 0xd0, int)//还没支持
- #define SNDRV_CTL_IOCTL_POWER_STATE _IOR('U', 0xd1, int)//电源状态
如何与应用层交互参考alsa-lib的说明http://www.alsa-project.org/main/index.php/Main_Page
alsa提供了很多工具可以使用
alsa-utils工具集
- aconnect is a utility for connecting and disconnecting two existing ports in the ALSA sequencer system.
- alsaconf is a configuration tool which tries to detect the sound cards on your system and write a suitable configuration file for ALSA. This program is incompatible with Udev.
- alsactl is used to control advanced settings for the ALSA sound card drivers.
- alsaloop allows creation of a PCM loopback between a PCM capture device and a PCM playback device.
- alsamixer is an Ncurses based mixer program for use with the ALSA sound card drivers.
- amidi is used to read from and write to ALSA RawMIDI ports.
- amixer allows command-line control of the mixers for the ALSA sound card drivers.
- aplay is a command-line soundfile player for the ALSA sound card drivers.
- aplaymidi is a command-line utility that plays the specified MIDI file(s) to one or more ALSA sequencer ports.
- arecord is a command-line soundfile recorder for the ALSA sound card drivers.
- arecordmidi is a command-line utility that records a standard MIDI file from one or more ALSA sequencer ports.
- aseqdump is a command-line utility that prints the sequencer events it receives as text.
- aseqnet is an ALSA sequencer client which sends and receives event packets over a network.
- iecset is a small utility to set or dump the IEC958 (or so-called “S/PDIF”) status bits of the specified sound card via the ALSA control API.
- speaker-test is a command-line speaker test tone generator for ALSA.
还有一个带图形界面的alsamixer工具,相当强大
alsa-utils工具的使用
alsact
l用来对alsa声卡驱动进行一些高级的设置.系统中装有多个声卡,它也可以支持.
有时在音量控制面板无法调整的选项,可以使用alsactl来实现.
alsactl可以将指定声卡的驱动程序设置信息保存到配置文件.或从配置文件中恢复指定
声卡的驱动程序的设置信息.
alsactl格式: alsactl [options] [store|restore] <card # or id> 选项: -h, --help 打印帮助信息 -f, --file 指定使用的配置文件,默认为/etc/asound.state. -F, --force 与恢复命令一起使用.表示最大限度的恢复设置值. -d, --debug 调试模式,输出更多细节信息. -v, --version 打印alsactl版本号. 文件: /etc/asound.state(或使用-f指定的文件)保存有声卡所有混合器的设置信息.
示例:
# rm /etc/asound.state -f # alsactl store
aconnect
是ALSA音序器的连接管理器.用来连接或断开ALSA音序器上的端口.端口是
可以随意定义的.
如,使用aconnect可以连接到任何由aseqview建立的设备端口.
命令格式:
aconnect [-d] [-options] sender receiver aconnect -i|-o [-options] aconnect -x 选项: 连接管理 -d, --disconnect 断开连接. -e, --exclusive 使用独占模式连接端口.发送和接收端口将不能再与其他端口相连. -r, --real queue 将时间包的时间戳,转换为真实时间队列的当前值. 显示端口 -i, --input 显示存在的输入端口. -o, --output 显示存在的输出端口. -l, --list 显示当前的连接状态. 删除连接 -x, --removeall 删除所有连接.
示例:
连接端口64:0到65:0: % aconnect 64:0 65:0 这个连接是单向的,所有到发送端口64:0的数据,将被重定向到接收65:0端口.如果有另一个端口65:1,也使用64:0作为发送端口,则数据会同时发送到2个接收端口. 端口连接时,使用: % aconnect -d 64:0 65:0 地址也可以使用客户端的名字来代替: % aconnect External:0 Emu8000:1 使用-i打印出输入端口信息.-o打印出输出端口信息. % aconnect -i client 0: ’System’ [type=kernel] 0 ’Timer ’ 1 ’Announce ’ client 64: ’External MIDI-0’ [type=kernel] 0 ’MIDI 0-0 ’ 可以使用-x选项来清除所有的连接. % aconnect -x
alsamixer
是一个终端界面的声卡音量调节器.
命令格式: alsamixer [options] 选项: -h, -help 显示帮助信息. -c <card number or idenfication> 指定需要设置的声卡.默认为0. -D <device identification> 选择需要控制的调节器. -g 设置界面颜色. -s 最小化界面窗口. 快捷键: 进入alsamixer界面后,可以使用下面快捷键进行控制: 常规控制: 左右箭头或n,p 用来选择通道. 上下箭头或+,- 同时调整选定通道的左右声道的音量. B,= 设置左右声道音量相同. M 静音当前通道.<,>分别对左,右声道静音. 空格 选择录音源.在选定的通道上按"空格",可以标记此通道为录音源.此操作仅限输入设备.插入键或";",删除键或"'"分别选定左右通道. L 刷新屏幕. 快捷设置 PageUp 增大5格音量. PageDown 减小5格音量. End 设置音量为0. 分别调整左,右或整个通道的音量. Q,W,E 增大 左,右,通道 的音量. Z,X,C 减小 左,右,通道 的音量. alt-q,ESC 退出.
amidi
的作用是对ALSA的RawMIDI端口进行读写.
amidi是一个命令行工具,允许你以独占模式向MIDI设备读/写数据.
命令格式: amidi options 选项: -h,-V,-l,-L 用于显示信息. -s,-r,-S,-d 用于发送/接收数据. -h, --help 打印帮助信息. -V, --version 打印版本号. -l, --list-devices 打印所有硬件MIDI端口的列表. -L, --list-rawmidis 打印所有RawMIDI定义. -p, --port=name 设置要使用的ALSA RawMIDI端口.若不指定,则使用声卡0的端口0. -s, --send=filename 发送指定文件的内容到MIDI端口.文件中必须包含raw MIDI命令(.syx,.mid文件). -r, --receive=filename 将MIDI端口接收的数据写入指定文件. -S, --send-hex="..." 发送十六进制字节到MIDI端口. -d, --dump 从MIDI端口接收数据,然后以十六进制形式打印出来. -t, --timeout=秒 指定超时,当端口无数据输出达到超时时长时,将停止接收数据.
示例:
amidi -p hw:0 -s my_settings.syx 发送my_settings.syx终端MIDI命令到端口 hw:0. amidi -S ’ 发送XG复位到默认端口. amidi -p virtual -d 建立一个虚拟RawMIDI端口,然后发送所有数据到这个端口.
amixer
是命令行的ALSA声卡驱动调节器工具.
amixer用来在命令行控制ALSA的调节器,并且支持多声卡.
amixer不加参数时,将打印默认声卡的设置信息.
命令格式:
amixer [-c card] [cmd] 命令: help 显示语法帮助. info 显示调节器设备的信息. scontrols 显示调节器器的完整列表 . scontents 显示包含详细信息的调节器的完整列表. set or sset <SCONTROL> <PARAMETER> ...设置调节器信息. get or sget <SCONTROL> 显示调节器的信息. controls 显示声卡控制器的信息. contents 显示完整的声卡控制器信息. cset <CONTROL> <PARAMETER> ... 设置声卡控制器信息. cget <CONTROL> 显示声卡控制器的信息. 选项: [-c card] 选择指定的声卡. [-D device] 选择需要控制的设备名.默认是 default. -h Help 显示帮助信息. -q 安静模式.不输出设置结果.
示例:
# amixer -c 1 sset Line,0 80%,40% unmute cap 设置第2块声卡的"line"的左声道音量为80%,右声道为40%,取消静音,并设置它为声音源. # amixer -c 2 cset numid=34 40% 设置第34个声卡元素为40%.
arecord,aplay
是命令行的ALSA声卡驱动的录音和播放工具.
arecord是命令行ALSA声卡驱动的录音程序.支持多种文件格式和多个声卡.
aplay是命令行播放工具,支持多种文件格式.
命令格式:
arecord [flags] [filename] aplay [flags] [filename [filename]] ... 选项: -h, --help 帮助. --version 打印版本信息. -l, --list-devices 列出全部声卡和数字音频设备. -L, --list-pcms 列出全部PCM定义. -D, --device=NAME 指定PCM设备名称. -q --quiet 安静模式. -t, --file-type TYPE 文件类型(voc,wav,raw或au). -c, --channels=# 设置通道号. -f --format=FORMAT 设置格式.格式包括:S8 U8 S16_LE S16_BE U16_LE U16_BE S24_LE S24_BE U24_LE U24_BE S32_LE S32_BE U32_LE U32_BE FLOAT_LE FLOAT_BE FLOAT64_LE FLOAT64_BE IEC958_SUBFRAME_LE IEC958_SUBFRAME_BE MU_LAW A_LAW IMA_ADPCM MPEG GSM -r, --rate=#<Hz> 设置频率. -d, --duration=# 设置持续时间,单位为秒. -s, --sleep-min=# 设置最小休眠时间. -M, --mmap mmap流. -N, --nonblock 设置为非块模式. -B, --buffer-time=# 缓冲持续时长.单位为微妙. -v, --verbose 显示PCM结构和设置. -I, --separate-channels 设置为每个通道一个单独文件.
示例:
aplay -c 1 -t raw -r 22050 -f mu_law foobar 播放raw文件foobar.以22050Hz,单声道,8位,mu_law格式. arecord -d 10 -f cd -t wav -D copy foobar.wav 以CD质量录制foobar.wav文件10秒钟.使用PCM的"copy".
aplaymidi
用来播放标准的MIDI文件.
aplaymidi是一个命令行工具,可以在一个或多个ALSA端口上播放MIDI
文件.
命令格式:
aplaymidi -p client:port[,...] [-d delay] midifile ... 选项: -h, --help 输出帮助信息. -V, --version 输出版本信息. -l, --list 输出可以使用的输出端口列表. -p, --port=client:port,... 设置端口. -d, --delay=seconds 设置MIDI文件结束后,等待时长.
arecordmidi
用于录制标准的MIDI文件.
arecordmidi可以从一个或多个ALSA端口上,录制一个标准MIDI文件.
命令格式:
arecordmidi -p client:port[,...] [options] midifile 选项: -h,--help 打印帮助信息. -V,--version 打印版本号. -l,--list 打印可以使用的输入端口. -p,--port=client:port,... 设置端口. -b,--bpm=beats 设置MIDI文件的速率,默认为120 BPM. -f,--fps=frames 设置帧率. -s,--split-channels 设置每个通道将录制成一个单独的MIDI文件. -d,--dump 在标准输出上,以文本形式显示接受到的事件信息
aseqnet
是ALSA调节器的网络连接工具.
aseqnet是ALSA调节器的客户端程序,可以从网络上发送和接收事件数据包.
网络上有主机A,主机B.A为服务器端,B为客户端.ALSA调节器系统必须同事运行
在两个服务器上.然后建立服务器端口:
hostA% aseqnet sequencer opened: 128:0
在HostB上执行:
hostB% aseqnet hostA sequencer opened: 132:0
现在所有发送到HostA:128:0的数据将被传送到HostB:132:0上,反之亦然.
命令格式:
aseqnet [remotehost] 选项: -p port 指定TCP端口号或服务名. -s addr 设置指定地址用于读操作. -d addr 设置指定地址用于写操作. -v 详细输出模式.
设置或输出IEC958状态位.
iecset
是个小工具,通过ALSA的API,设置或输出IEC958(或称S/PDIF)状态位信息.
直接运行iecset将输出当前IEC958的状态信息. 命令格式:
iecset [options] [cmd arg...] 选项: -D device 设置需要打开的设备名. -c card 设置需要打开的网卡名. -x 输出AESx字节格式的状态信息. -i 从标准输入读取命令信息,每行一个命令. 命令: professional <bool> 专业模式(true)或用户模式(false). audio <bool> 音频模式(true). rate <int> 采样频率,单位Hz. emphasis <int> 设置加强值.0 = none, 1 = 50/15us, 2 = CCITT. lock <bool> 速率锁. sbits <int> 采样位:2 = 20bit, 4 = 24bit, 6 = undefined. wordlength <int> 设置字长:0 = No, 2 = 22-18 bit, 4 = 23-19 bit, 5 = 24-20 bit, 6 = 20-16 bit. category <int> 分类:值从0到0x7f. copyright <bool> 设置是否包含版权. original <boo> 原始标记:
示例:
输出当前IEC958信息. $ iecset Mode: consumer Data: audio Rate: 44100 Hz Copyright: permitted Emphasis: none Category: general Original: 1st generation Clock: 1000 ppm 显示当前第1块声卡的IEC958状态位. $ iecset -Dhw:0 Mode: consumer Data: non-audio Rate: 44100 Hz Copyright: permitted Emphasis: none Category: general Original: 1st generation Clock: 1000 ppm 设置当前为用户模式,并打开"非音频"位. $ iecset pro off audio off Mode: consumer Data: non-audio Rate: 44100 Hz Copyright: permitted Emphasis: none Category: general Original: 1st generation Clock: 1000 ppm
speaker-test
是一个针对 ALSA驱动的声音测试工具.
speaker-test可以分别对左右声道进行单独的测试.
命令格式:
speaker-test [-options] 选项: -c | --channels NUM 设置通道数目. -D | --device NAME 设置使用的PCM设备名. -f | --frequency FREQ 设置声音频率. --help 输出帮助信息. -b | --buffer TIME 设置缓冲区时长.0为使用最大的缓冲区大小. -p | --period TIME 设置节拍为多少微秒. -r | --rate RATE 设置音频率. -t | --test pink|sine|wav -t pink 表示测试时使用噪声. -t sine 表示测试时使用音频信号声. -t wav 表示测试时使用WAV文件. -l | --nloops COUNT 设置测试循环的次数. -w | --wavfile 设置测试时播放的wav文件. -W | --wavdir 设置一个包含wav文件的目录.默认为/usr/share/sounds/alsa.
示例:
在一个音频接口上进行立体声测试 # speaker-test -Dplug:front -c2 在两个音频接口上进行4声道测试. # speaker-test -Dplug:surround40 -c4 在立体声接口上进行5.1声道测试. # speaker-test -Dplug:surround51 -c6 测试低音扬声器. # speaker-test -Dplug:surround51 -c6 -s1 -f75