3.4 构建pcm文件
在pcm 文件结构简图中,可以看到与pcm相关的一些结构snd_pcm、snd_pcm_str、snd_pcm_substream。以下将去整理这部分的内容,看看它们是如何生成,怎么去使用的。
3.4.1 snd_pcm_new
如果把alsa理解为一个框架(主要是sound/core下的代码),如简图中所表示的一样,其实有一个整体的模型在哪儿,驱动开发者需要构建这个模型。而框架的另一个功能就是提供构建模型的工具,其实就是一些导出函数。snd_pcm_new就是这么一个函数:
int snd_pcm_new(struct snd_card *card, const char *id, int device,
int playback_count, int capture_count, struct snd_pcm **rpcm)
{
return _snd_pcm_new(card, id, device, playback_count, capture_count,
false, rpcm);
}
这里的参数snd_card,我们后面再展开。id和device其实是留给调用者自己使用的。playback_count和capture_count表示播放设备与录音设备的个数,这两个值一般都是1。rpcm就是要返回的snd_pcm对象。真正的工作是在_snd_pcm_new中完成的:
static int _snd_pcm_new(struct snd_card *card, const char *id, int device,
int playback_count, int capture_count, bool internal,
struct snd_pcm **rpcm)
{
struct snd_pcm *pcm;
int err;
static const struct snd_device_ops ops = {
.dev_free = snd_pcm_dev_free,
.dev_register = snd_pcm_dev_register,
.dev_disconnect = snd_pcm_dev_disconnect,
};
static const struct snd_device_ops internal_ops = {
.dev_free = snd_pcm_dev_free,
};
if (snd_BUG_ON(!card))
return -ENXIO;
if (rpcm)
*rpcm = NULL;
// 生成snd_pcm对象
pcm = kzalloc(sizeof(*pcm), GFP_KERNEL);
if (!pcm)
return -ENOMEM;
pcm->card = card;
pcm->device = device;
pcm->internal = internal;
mutex_init(&pcm->open_mutex);
init_waitqueue_head(&pcm->open_wait);
INIT_LIST_HEAD(&pcm->list);
if (id)
strscpy(pcm->id, id, sizeof(pcm->id));
//生成snd_pcm_substream
err = snd_pcm_new_stream(pcm, SNDRV_PCM_STREAM_PLAYBACK,
playback_count);
if (err < 0)
goto free_pcm;
err = snd_pcm_new_stream(pcm, SNDRV_PCM_STREAM_CAPTURE, capture_count);
if (err < 0)
goto free_pcm;
// 生成pcm设备
err = snd_device_new(card, SNDRV_DEV_PCM, pcm,
internal ? &internal_ops : &ops);
if (err < 0)
goto free_pcm;
if (rpcm)
*rpcm = pcm;
return 0;
free_pcm:
snd_pcm_free(pcm);
return err;
}
这段代码中,看到了snd_device_ops对象,上节已经讲述过,而snd_pcm_dev_register的细节,我们稍后看一下。
后续的代码生成snd_pcm对象并赋值,下节来看看snd_pcm的结构。
snd_pcm_new_stream是为了生成snd_pcm_substream对象,下面展开。
snd_device_new上一节也看到过,生成snd_device并保存。
3.4.2 snd_pcm
再看看snd_pcm的结构吧:
struct snd_pcm {
struct snd_card *card;
struct list_head list;
int device; /* device number */
unsigned int info_flags;
unsigned short dev_class;
unsigned short dev_subclass;
char id[64];
char name[80];
struct snd_pcm_str streams[2];
struct mutex open_mutex;
wait_queue_head_t open_wait;
void *private_data;
void (*pr