Linux设计哲学之,一切皆是文件。感觉上这个论点更多的是针对驱动来说的,从使用者的角度来说,大多的驱动程序的使用与操作文件的方式类似,也就是使用open,read,write,ioctl这些通用的文件操作接口来操作驱动。而对于驱动开发者来说,就需要按照文件的方式来组织驱动接口,以文件的形式来呈现驱动程序。以下我们来具体看看ALSA所呈现的形式。
在ubuntu上,显示/dev/snd下的内容:
/dev/snd$ ls -lh
total 0
drwxr-xr-x 2 root root 60 May 3 02:08 by-path
crw-rw----+ 1 root audio 116, 6 May 3 02:08 controlC0
crw-rw----+ 1 root audio 116, 5 May 3 02:08 midiC0D0
crw-rw----+ 1 root audio 116, 3 May 3 02:08 pcmC0D0c
crw-rw----+ 1 root audio 116, 2 May 3 02:10 pcmC0D0p
crw-rw----+ 1 root audio 116, 4 May 3 02:08 pcmC0D1p
crw-rw----+ 1 root audio 116, 1 May 3 02:08 seq
crw-rw----+ 1 root audio 116, 33 May 3 02:08 timer
以上是在我的虚拟机上显示的内容,如果你查看Android上的内容,内容会更多一些,因为会有一些支持专门用途的声卡,但原理是一致的,这里按照ubuntu的内容来展开相关的内容。
可以看到文件名有一定的格式,其实也就代表了具体的用途。比如pcmC0D1p,这里的pcm表示该文件用来处理音频;C可以理解成card的缩写;一个系统可以有多个card,所以C后的数字表示的是顺序,这里的0表示是第一个card;D可以理解为device的缩写;D后的1表示是第二个设备;p 表示的播放(如果是c表示的就是录制)。pcm设备的用途主要是播放音频,而control的作用就是对音频做必要的控制,比如设定音量等。
学习音频开发,个人感觉一个比较好的起始点是学习tinyalsa,代码量不大,但足够我们熟悉一些基本概念。下面也通过tinyalsa来熟悉一下音频的用法,可以在github上找到tinyalsa的源码。
snprintf(fn, sizeof(fn), "/dev/snd/pcmC%uD%u%c", card, device,
flags & PCM_IN ? 'c' : 'p');
fd = open(fn, O_RDWR | O_NONBLOCK);
以上是打开文件的方法,和普通的文件没什么差别,都是通过open来打开文件。
static int pcm_rw_transfer(struct pcm *pcm, void *data, unsigned int frames)
{
int is_playback;
struct snd_xferi transfer;
int res;
is_playback = !(pcm->flags & PCM_IN);
transfer.buf = data;
transfer.frames = frames;
transfer.result = 0;
res = pcm->ops->ioctl(pcm->data, is_playback
? SNDRV_PCM_IOCTL_WRITEI_FRAMES
: SNDRV_PCM_IOCTL_READI_FRAMES, &transfer);
return res == 0 ? (int) transfer.result : -1;
}
以上是写文件的方式,可以看到传入的数据data,将被保存到snd_xferi 结构中,然后再通过ioctl传到内核。
static int pcm_hw_ioctl(void *data, unsigned int cmd, ...)
{
struct pcm_hw_data *hw_data = data;
va_list ap;
void *arg;
va_start(ap, cmd);
arg = va_arg(ap, void *);
va_end(ap);
return ioctl(hw_data->fd, cmd, arg);
}
再看看pcm->ops->ioctl的具体实现,其实就是函数pcm_hw_ioctl。最终还是通过系统函数ioctl将命令(写数据使用SNDRV_PCM_IOCTL_WRITEI_FRAMES,读使用 SNDRV_PCM_IOCTL_READI_FRAMES)和数据传入到内核。
顺便提一下,其实默认情况下,写数据基本是使用mmap的方式来完成的。mmap的使用要稍微复杂一些,在讲到内核数据同步的时候,会专门讲解这部分的内容。
从以上的内容可以看到,音频设备是以文件的形式存在于系统中,使用方式也同文件类似。所以后续的内容会集中于如何生成这样的文件,以及这些文件是如何响应客户端的请求来展开。