3. alsa中的文件(第三部分)

本文详细介绍了Linux ALSA驱动中构建PCM文件的过程,包括snd_pcm_new、snd_pcm、snd_pcm_new_stream等关键函数的使用,以及如何注册和打开播放设备。通过这些函数,驱动开发者能够构建alsa框架所需的pcm模型,并实现音频设备的播放和录音功能。
摘要由CSDN通过智能技术生成

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
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值