ALSA学习笔记 (3)PCM
1. 概述
每个pcm实例对应一个pcm设备文件。一个pcm实例由一个playback stream和一个capture stream组成,而每个 pcm stream由一个或多个pcm子流组成。当一个子流已经存在,并且已经被打开,当再次被打开的时候,会被阻塞。
相关结构体:
snd_pcm: 是挂在snd_card下面的一个snd_device
snd_pcm_str streams[2]: 该数组中的两个元素指向两个snd_pcm_str结构,分别代表playback stream和capture stream, 其中用户空间中每个PCM设备对应一个pcm 流,设备号相同的设备对应成对的两个pcm流。
snd_pcm_substream: snd_pcm_str中的substream字段,指向snd_pcm_substream结构,snd_pcm_substream是pcm中间层的核心,绝大部分任务都是在substream中处理,尤其是他的 snd_pcm_ops ops字段,许多user空间的应用程序通过alsa-lib对驱动程序的请求都是由该结构中的函数处理。
runtime字段则指向snd_pcm_runtime结构, snd_pcm_runtime记录这substream的一些重要的软件和硬件运行环境和参数。
2. 示例代码
2.1 创建pcm实例
struct snd_pcm *pcm;
snd_pcm_new(chip->card, “My Chip”, 0 , 1, 1,&pcm)
2.2 设置PCM设备的操作函数
snd_pcm_set_ops(pcm,SNDRV_PCM_STREAM_PLAYBACK, &snd_mychip_playback_ops);
snd_pcm_set_ops(pcm,SNDRV_PCM_STREAM_CAPTURE, &snd_mychip_capture_ops);
2.3 定义PCM的操作函数
/* playback 操作函数*/
static struct snd_pcm_ops snd_mychip_playback_ops = {
.open = snd_mychip_playback_open,
.close = snd_mychip_playback_close,
// .................
};
/* capture 操作函数*/
static struct snd_pcm_ops snd_mychip_capture_ops = {
.open = snd_mychip_capture_open,
.close = snd_mychip_capture_close,
// .................
};
/* open 函数中需要传入一个定义好的硬件参数*/
static int snd_mychip_playback_open(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
runtime->hw = snd_mychip_playback_hw;
}
2.4 定义硬件参数
static struct snd_pcm_hardware snd_mychip_playback_hw = {
.info = (SNDRV_PCM_INFO_MMAP |
SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_BLOCK_TRANSFER |
SNDRV_PCM_INFO_MMAP_VALID),
.formats = SNDRV_PCM_FORMAT_S16_LE,
.rates = SNDRV_PCM_RATE_8000_48000,
.rate_min = 8000,
.rate_max = 48000,
.channels_min = 2,
.channels_max = 2,
.buffer_bytes_max = 32768,