Rockchip RK3399 - ALSA 声卡之PCM设备

本文详细介绍了Rockchip RK3399平台上的ALSA和ASoC框架中关于PCM设备的核心数据结构,包括ALSA的struct pcm_new, struct pcm_str, struct pcm_substream和struct snd_pcm_hw_params,以及ASoC的struct snd_soc_pcm_stream和struct snd_soc_pcm_runtime。通过分析,阐述了PCM设备创建、注册和应用层打开PCM设备的流程。" 111624432,10327343,QC小组成果报告编写与发布会经验分享,"['质量管理', '工程管理', '问题解决', 'PPT制作', '报告编写']
摘要由CSDN通过智能技术生成

----------------------------------------------------------------------------------------------------------------------------

开发板 :NanoPC-T4开发板eMMC :16GBLPDDR3 :4GB显示屏 :15.6英寸HDMI接口显示屏u-boot :2023.04linux   :6.3----------------------------------------------------------------------------------------------------------------------------

我们在Rockchip RK3399 - ALC5651 & I2S基础中实际上已经介绍过PCM,它是一种音频编码格式,更确切的说是一种将声音从模拟信号转换成数字信号的技术。

音频驱动的两大核心任务就是:

  • playback :如何把用户空间的应用程序发过来的PCM数据,转化为人耳可以辨别的模拟音频;
  • capture :把mic拾取到得模拟信号,经过采样、量化,转换为PCM数据送回给用户空间的应用程序;

ALSA CORE已经实现了PCM中间层,我们编写的驱动都是调用PCM相关的API,基本上只需要实现底层的需要访问硬件的函数即可;

  • include/sound/pcm.h:提供访问 PCM 中间层代码的API;
  • include/sound/pcm_params.h:提供访问一些与hw_param 相关的函数;

一、核心数据结构

1.1 ALSA中的数据结构
1.1.1 struct pcm_new

pcm使用struct snd_pcm数据结构来描述,一个pcm实例由一个playback stream和一个capture stream组成,这两个stream又分别有一个或多个substreams组成。

在嵌入式系统中,通常不会像图中这么复杂,大多数情况下是一个声卡,一个pcm实例,pcm下面有一个playback stream和capture stream,playback和capture下面各自有一个substream。

snd_pcm数据结构定义在include/sound/pcm.h;

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 (*private_free) (struct snd_pcm *pcm);
        bool internal; /* pcm is for internal use only */
        bool nonatomic; /* whole PCM operations are in non-atomic context */
        bool no_device_suspend; /* don't invoke device PM suspend */
#if IS_ENABLED(CONFIG_SND_PCM_OSS)
        struct snd_pcm_oss oss;
#endif
};

这里重要的变量如下:

  • card:声卡设备;
  • device:pcm设备编号;
  • streams:数组长度为2,元素0指向playback stream设备,元素1指向capture stream设备;
  • private_data:在很多数据结构里面都可以看到,一般用于指向私有数据;
1.1.2 struct snd_pcm_str

struct snd_pcm_str用于表示pcm stream,定义在include/sound/pcm.h;

struct snd_pcm_str {
        int stream;                             /* stream (direction) */
        struct snd_pcm *pcm;
        /* -- substreams -- */
        unsigned int substream_count;
        unsigned int substream_opened;
        struct snd_pcm_substream *substream;
#if IS_ENABLED(CONFIG_SND_PCM_OSS)
        /* -- OSS things -- */
        struct snd_pcm_oss_stream oss;
#endif
#ifdef CONFIG_SND_VERBOSE_PROCFS
        struct snd_info_entry *proc_root;
#ifdef CONFIG_SND_PCM_XRUN_DEBUG
        unsigned int xrun_debug;        /* 0 = disabled, 1 = verbose, 2 = stacktrace */
#endif
#endif
        struct snd_kcontrol *chmap_kctl; /* channel-mapping controls */
        struct device dev;
};

snd_pcm_str的主要作用是指向snd_pcm_substream,而snd_pcm_substream可以有多个,这也是snd_pcm_str存在的原因,否则snd_pcm直接指向snd_pcm_substream就可以了。

其中:

  • stream:类类型,比如SNDRV_PCM_STREAM_PLAYBACK表示播放,SNDRV_PCM_STREAM_CAPTURE表示捕获;
  • pcm:指向pcm设备;
  • substream_count:substream的个数;
  • substream_opened:substream打开标志;
  • substream:用于保存所有的substream,struct snd_pcm_substream实是一个链表节点类型的数据结构;
  • dev:设备驱动模型中的device,可以将snd_pcm_str看做其子类;
1.1.3 struct snd_pcm_substream

struct snd_pcm_substream用于表示pcm substream,定义在include/sound/pcm.h;

struct snd_pcm_substream {
        struct snd_pcm *pcm;
        struct snd_pcm_str *pstr;
        void *private_data;             /* copied from pcm->private_data */
        int number;
        char name[32];                  /* substream name */
        int stream;                     /* stream (direction) */
        struct pm_qos_request latency_pm_qos_req; /* pm_qos request */
        size_t buffer_bytes_max;        /* limit ring buffer size */
        struct snd_dma_buffer dma_buffer;
        size_t dma_max;
        /* -- hardware operations -- */
        const struct snd_pcm_ops *ops;
        /* -- runtime information -- */
        struct snd_pcm_runtime *runtime;
        /* -- timer section -- */
        struct snd_timer *timer;                /* timer */
        unsigned timer_running: 1;      /* time is running */
        long wait_time; /* time in ms for R/W to wait for avail */
        /* -- next substream -- */
        struct snd_pcm_substream *next;
        /* -- linked substreams -- */
        struct list_head link_list;     /* linked list member */
        struct snd_pcm_group self_group;        /* fake group for non linked substream (with substream lock inside) */
        struct snd_pcm_group *group;            /* pointer to current group */
        /* -- assigned files -- */
        int ref_count;
        atomic_t mmap_count;
        unsigned int f_flags;
        void (*pcm_release)(struct snd_pcm_substream *);
        struct pid *pid;
#if IS_ENABLED(CONFIG_SND_PCM_OSS)
        /* -- OSS things -- */
        struct snd_pcm_oss_substream oss;
#endif
#ifdef CONFIG_SND_VERBOSE_PROCFS
        struct snd_info_entry *proc_root;
#endif /* CONFIG_SND_VERBOSE_PROCFS */
        /* misc flags */
        unsigned int hw_opened: 1;
};

snd_pcm_substream的内容有些多,此处只需要重要的进行介绍;

  • ops:pcm操作集,这部分具体的操作需要实现者的参与,留给实现者的函数指针集。这个和文件操作的设计策略是一致的;
  • runtime:pcm运行时实例,读写数据的时候由它来控制;
  • next:指向下一个pcm substream,用于将多个snd_pcm_substream对象链接起来;
  • pstrt:指向所属的pcm stream;
  • group:在用户空间可以通过SNDRV_PCM_IOCTL_LINK将多个substream链接起来。然后就可以对这些对象进行统一的操作。
1.1.4 snd_pcm_hw_params 

struct snd_pcm_hw_params定义在include/uapi/sound/asound.h,是用于配置音频硬件参数的结构体,比如通道数、采样率、数据格式等;

struct snd_pcm_hw_params {
        unsigned int flags;
        struct snd_mask masks[SNDRV_PCM_HW_PARAM_LAST_MASK -
                               SNDRV_PCM_HW_PARAM_FIRST_MASK + 1];
        struct snd_mask mres[5];        /* reserved masks */
        struct snd_interval intervals[SNDRV_PCM_HW_PARAM_LAST_INTERVAL -   // 宏的值为19
                                        SNDRV_PCM_HW_PARAM_FIRST_INTERVAL + 1];  // 宏的值为8
        struct snd_interval ires[9];    /* reserved intervals */
        unsigned int rmask;             /* W: requested masks */
        unsigned int cmask;             /* R: changed masks */
        unsigned int info;              /* R: Info flags for returned setup */
        unsigned int msbits;            /* R: used most significant bits */
        unsigned int rate_num;          /* R: rate numerator */
        unsigned int rate_den;          /* R: rate denominator */
        snd_pcm_uframes_t fifo_size;    /* R: chip FIFO size in frames */
        unsigned char reserved[64];     /* reserved for future */
};

该结构体定义了一组成员变量,用于存储和管理音频硬件参数的信息。下面是各成员

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Graceful_scenery

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值