linux alsa-lib snd_pcm_open函数源码分析(一)

[复制链接]
发表于 2026-1-1 20:33:36 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×
访问原版内容,可直接到博客linux alsa-lib snd_pcm_open函数源码分析(一)
系列文章其他部门:
 linux alsa-lib snd_pcm_open函数源码分析(二)
linux alsa-lib snd_pcm_open函数源码分析(三)
linux alsa-lib snd_pcm_open函数源码分析(四)
linux alsa-lib snd_pcm_open函数源码分析(五)
linux alsa-lib snd_pcm_open函数源码分析(六)

snd_pcm_open通常是打仗alsa-lib的第一个api,也通常是利用alsa举行灌音或播放的第一步。 正如名字中体现的一样,snd_pcm_open用来打开一个pcm音频装备,并得到这个音频装备的句柄, 即便用户利用了alsa的插件,利用时也同样是利用此接口,非常方便。但是这种利用上的方便是以snd_pcm_open及其复杂的实现为代价的。 这篇条记的目标就是尽大概具体的分析这个函数到底做了什么工作,以及这些工作到底是怎么实现的。
1.版本信息



  • alsa-lib-1.1.5
  • alsa-plugins-1.1.5
  • linux-kernel-4.4.167
2.函数原型

snd_pcm_open实现位于alsa-lib/src/pcm/pcm.c中。 从函数实现上紧张有两个功能,第一个是更新设置文件,第二个是打开装备。 这两个函数过程都很复杂,反面我们会继续具体表明。
  1. /*
  2. * \brief Opens a PCM
  3. * \param pcmp 返回pcm句柄
  4. * \param name 要打开的pcm设备的名字
  5. * \param stream 想要的stream类型
  6. * \param mode 打开模式 (see #SND_PCM_NONBLOCK, #SND_PCM_ASYNC)
  7. * \return 0 表示成功,否则返回一个负的错误码
  8. */
  9. int snd_pcm_open(snd_pcm_t **pcmp, const char *name,
  10.          snd_pcm_stream_t stream, int mode)
  11. {
  12.     snd_config_t *top;
  13.     int err;
  14.     assert(pcmp && name);
  15.     err = snd_config_update_ref(&top);
  16.     if (err < 0)
  17.         return err;
  18.     err = snd_pcm_open_noupdate(pcmp, top, name, stream, mode, 0);
  19.     snd_config_unref(top);
  20.     return err;
  21. }
复制代码
3.利用示例

下面是一段播放音频的代码,大部门来自于alsa-utils中的aplay.c文件,为了方便相识利用流程对其做了精简, 此示例仅仅为了分析snd_pcm_open的位置,无法直接编译运行。
4.代码分析

下面是对snd_pcm_open函数的分析过程,函数紧张实现了两个工作:更新设置文件及打开pcm装备。 我们按照这两部门分别举行分析。
4.1 snd_config_update_ref

函数的目标是更新snd_config设置,与snd_config_update_r功能雷同,紧张区别是此函数会增长引用计数, 以是在引用计数为0前获取到设置树将永久不会被删除。同时由于函数利用了锁,以是函数是线程安全的。
留意这里的参数top,是个二级指针。在snd_pcm_open中传下来的是snd_config_t *top;中top的地点。
关键函数snd_config_update_r的具体分析参考inux alsa-lib snd_pcm_open函数具体分析(二)
  1. /* top为出参 */
  2. int snd_config_update_ref(snd_config_t **top)
  3. {
  4.     int err;
  5.     if (top)
  6.         *top = NULL;
  7.     snd_config_lock();  /*加锁保证线程安全*/
  8.     /* 主要功能实现在此,后续文章会继续分析 */
  9.     err = snd_config_update_r(&snd_config, &snd_config_global_update, NULL);
  10.     if (err >= 0) {
  11.         if (snd_config) {
  12.             if (top) {
  13.                 snd_config->refcount++; /*增加引用计数*/
  14.                 *top = snd_config;      /*最终返回结果*/
  15.             }
  16.         } else {
  17.             err = -ENODEV;
  18.         }
  19.     }
  20.     snd_config_unlock();
  21.     return err;
  22. }
复制代码
4.2 snd_pcm_open_noupdate

函数的目标是打开pcm装备,所要打开的具体装备须要依靠上面打开的装备树, 函数担当传入的装备名称,分析名称并在装备树中查找须要打开的装备, 如果设置中有利用插件,函数还须要分析插件,终极打开硬件装备。 留意snd_pcm_open函数终极返回的句柄pcmp着实就是此函数的返回的。
此函数会在反面文章继续分析。
  1. static int snd_pcm_open_noupdate(snd_pcm_t **pcmp, snd_config_t *root,
  2.                  const char *name, snd_pcm_stream_t stream,
  3.                  int mode, int hop)
  4. {
  5.     int err;
  6.     snd_config_t *pcm_conf;
  7.     const char *str;
  8.     err = snd_config_search_definition(root, "pcm", name, &pcm_conf);
  9.     if (err < 0) {
  10.         SNDERR("Unknown PCM %s", name);
  11.         return err;
  12.     }
  13.     if (snd_config_get_string(pcm_conf, &str) >= 0)
  14.         err = snd_pcm_open_noupdate(pcmp, root, str, stream, mode,
  15.                         hop + 1);
  16.     else {
  17.         snd_config_set_hop(pcm_conf, hop);
  18.         err = snd_pcm_open_conf(pcmp, name, root, pcm_conf, stream, mode);
  19.     }
  20.     snd_config_delete(pcm_conf);
  21.     return err;
  22. }
复制代码
各子函数的具体先容参考本系列其他文章
回复

使用道具 举报

登录后关闭弹窗

登录参与点评抽奖  加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表