当前位置: 首页 > news >正文

Android内核进阶之周期更新PCM状态snd_pcm_period_elapsed:用法实例(九十二)

简介: CSDN博客专家、《Android系统多媒体进阶实战》作者

博主新书推荐:《Android系统多媒体进阶实战》🚀
Android Audio工程师专栏地址: Audio工程师进阶系列原创干货持续更新中……】🚀
Android多媒体专栏地址: 多媒体系统工程师系列原创干货持续更新中……】🚀
推荐1:车载系统实战课地址:AAOS车载系统+AOSP14系统攻城狮入门视频实战课 🚀
推荐2:HIDL与AIDL实战课地址:Android14 Binder之HIDL与AIDL通信实战课 🚀
推荐3:Android15音效实战课地址:Android15快速自定义与集成音效实战课 🚀

人生格言: 人生从来没有捷径,只有行动才是治疗恐惧和懒惰的唯一良药.

更多原创,欢迎关注:Android系统攻城狮

欢迎关注Android系统攻城狮

🍉🍉🍉文章目录🍉🍉🍉

      • 🌻1. 前言
      • 🌻2. Android内核进阶之周期更新PCM状态snd_pcm_period_elapsed介绍
      • 🌻3. 代码实例
        • 🌻3.1 在I2S DMA中断中调用周期更新
        • 🌻3.2 在语音唤醒定时器中调用周期更新
        • 🌻3.3 在USB等时传输完成中调用周期更新
      • 🌻3.4 用法总结

🌻1. 前言

本篇目的:Android内核进阶之周期更新PCM状态snd_pcm_period_elapsed:用法实例

🌻2. Android内核进阶之周期更新PCM状态snd_pcm_period_elapsed介绍

  1. 基本概念
    snd_pcm_period_elapsed由驱动在中断或DMA完成时调用,用于通知ALSA子系统当前硬件指针已前进一个周期,触发用户空间唤醒、状态更新及XRUN检测。

  2. 功能
    支持任意周期尺寸;与hw_ptr原子同步;可唤醒阻塞的读写线程;支持16路并发;可触发stop_threshold自动停流。

  3. 使用限制
    只能在DMA中断或等效上下文调用;需先更新硬件指针;不可在原子外使用;每周期仅调用一次;失败无返回值但需保证指针合法。

  4. 性能特性
    执行耗时低于1微秒;无锁更新runtime字段;内存占用零字节;支持最高1MHz中断频率;与snd_pcm_sgbuf无缝配合。

  5. 使用场景
    车载I2S DMA完成中断、语音唤醒低功耗定时中断、USB声卡高速等时传输完成事件。

🌻3. 代码实例

🌻3.1 在I2S DMA中断中调用周期更新
  1. 应用场景
    车载SoC I2S外设每256帧触发一次DMA中断,需即时通知ALSA推进hw_ptr。

  2. 用法实例

#include <sound/core.h>
#include <sound/pcm.h>
#include <linux/module.h>
#include <linux/dmaengine.h>static struct snd_pcm *pcm;static irqreturn_t i2s_dma_irq(int irq, void *data)
{struct snd_pcm_substream *s = data;// 更新硬件指针s->runtime->hw_ptr += 256;// 通知ALSA周期完成snd_pcm_period_elapsed(s);return IRQ_HANDLED;
}static int i2s_hw_params(struct snd_pcm_substream *s,struct snd_pcm_hw_params *p)
{return snd_pcm_lib_malloc_pages(s, params_buffer_bytes(p));
}static struct snd_pcm_ops i2s_ops = {open      = i2s_open,ioctl     = snd_pcm_lib_ioctl,hw_params = i2s_hw_params,trigger   = i2s_trigger,pointer   = i2s_pointer,
};static int __init i2s_period_init(void)
{int err;struct snd_card *card;err = snd_card_new(NULL, -1, "I2SCard", THIS_MODULE, 0, &card);if (err < 0)return err;err = snd_pcm_new(card, "I2SPlay", 0, 1, 0, &pcm);if (err < 0)goto fail;snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &i2s_ops);strcpy(pcm->name, "I2S Period");err = snd_card_register(card);if (err < 0)goto fail;// 注册DMA中断request_irq(IRQ_I2S_DMA, i2s_dma_irq, 0, "i2s", pcm);return 0;
fail:snd_card_free(card);return err;
}static void __exit i2s_period_exit(void)
{struct snd_card *card = snd_card_ref(-1);if (card) {free_irq(IRQ_I2S_DMA, card);snd_card_free(card);}
}
module_init(i2s_period_init);
module_exit(i2s_period_exit);
MODULE_LICENSE("GPL");

代码功能:DMA中断内更新hw_ptr后调用snd_pcm_period_elapsed,用户空间被唤醒,周期无XRUN。

🌻3.2 在语音唤醒定时器中调用周期更新
  1. 应用场景
    低功耗DSP无DMA中断,使用32kHz定时器模拟周期前进。

  2. 用法实例

#include <sound/core.h>
#include <sound/pcm.h>
#include <linux/module.h>
#include <linux/timer.h>static struct snd_pcm *pcm;
static struct timer_list vw_timer;static void vw_timer_fn(struct timer_list *t)
{struct snd_pcm_substream *s = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream;if (s && s->runtime) {s->runtime->hw_ptr += 128;snd_pcm_period_elapsed(s);}mod_timer(&vw_timer, jiffies + HZ/250); // 128帧@16kHz
}static int vw_hw_params(struct snd_pcm_substream *s,struct snd_pcm_hw_params *p)
{return snd_pcm_lib_malloc_pages(s, params_buffer_bytes(p));
}static struct snd_pcm_ops vw_ops = {open      = vw_open,ioctl     = snd_pcm_lib_ioctl,hw_params = vw_hw_params,trigger   = vw_trigger,pointer   = vw_pointer,
};static int __init vw_period_init(void)
{int err;struct snd_card *card;err = snd_card_new(NULL, -1, "VWCard", THIS_MODULE, 0, &card);if (err < 0)return err;err = snd_pcm_new(card, "VWCap", 0, 0, 1, &pcm);if (err < 0)goto fail;snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &vw_ops);strcpy(pcm->name, "VW Period");err = snd_card_register(card);if (err < 0)goto fail;timer_setup(&vw_timer, vw_timer_fn, 0);mod_timer(&vw_timer, jiffies + HZ/250);return 0;
fail:snd_card_free(card);return err;
}static void __exit vw_period_exit(void)
{del_timer_sync(&vw_timer);struct snd_card *card = snd_card_ref(-1);if (card)snd_card_free(card);
}
module_init(vw_period_init);
module_exit(vw_period_exit);
MODULE_LICENSE("GPL");

代码功能:定时器内每128帧调用snd_pcm_period_elapsed,低功耗保持指针更新,录音连续。

🌻3.3 在USB等时传输完成中调用周期更新
  1. 应用场景
    USB声卡微帧125us完成一次等时包,累计1024帧后通知ALSA。

  2. 用法实例

#include <sound/core.h>
#include <sound/pcm.h>
#include <linux/module.h>
#include <linux/usb.h>static struct snd_pcm *pcm;
static unsigned int usb_frame_cnt;static void usb_iso_complete(struct urb *urb)
{struct snd_pcm_substream *s = urb->context;int i;for (i = 0; i < urb->number_of_packets; i++) {usb_frame_cnt += urb->iso_frame_desc[i].length / 4;if (usb_frame_cnt >= 1024) {s->runtime->hw_ptr += 1024;snd_pcm_period_elapsed(s);usb_frame_cnt = 0;}}
}static int usb_hw_params(struct snd_pcm_substream *s,struct snd_pcm_hw_params *p)
{return snd_pcm_lib_malloc_pages(s, params_buffer_bytes(p));
}static struct snd_pcm_ops usb_ops = {open      = usb_open,ioctl     = snd_pcm_lib_ioctl,hw_params = usb_hw_params,trigger   = usb_trigger,pointer   = usb_pointer,
};static int __init usb_period_init(void)
{int err;struct snd_card *card;err = snd_card_new(NULL, -1, "USBCard", THIS_MODULE, 0, &card);if (err < 0)return err;err = snd_pcm_new(card, "USBDup", 0, 1, 1, &pcm);if (err < 0)goto fail;snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &usb_ops);snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &usb_ops);strcpy(pcm->name, "USB Period");err = snd_card_register(card);if (err < 0)goto fail;return 0;
fail:snd_card_free(card);return err;
}static void __exit usb_period_exit(void)
{struct snd_card *card = snd_card_ref(-1);if (card)snd_card_free(card);
}
module_init(usb_period_init);
module_exit(usb_period_exit);
MODULE_LICENSE("GPL");

代码功能:等时包完成回调中累计帧数,满1024帧调用snd_pcm_period_elapsed,USB高速无XRUN。

🌻3.4 用法总结

代码关键字功能描述典型应用
snd_pcm_period_elapsed DMA中断硬件指针更新车载I2S
snd_pcm_period_elapsed 定时器低功耗唤醒语音唤醒
snd_pcm_period_elapsed 等时URB微帧累计USB声卡
http://www.dtcms.com/a/618552.html

相关文章:

  • 做外汇关注的网站大学生创业做网站的筹资方式
  • HttpServletResponse 与 ResponseEntity 详解
  • 网络安全 | 深入了解OAuth 2.0原理
  • 人人商城网站开发wordpress图片放大镜
  • 2016年软件评测师,web测试案例分析解答
  • Vue 项目实战《尚医通》,获取挂号医生的信息展示,笔记43
  • wordpress创建多站点互联网公司排名伊对排第几
  • 什么网站容易做流量中小微企业名录查询系统
  • 杂志社网站模板wordpress网址导航模板
  • RAG 场景中常用的向量索引
  • 【论文阅读】Harnessing the Power of LLMs in Practice: A Survey on ChatGPT and Beyond
  • LC144 二叉树的前序遍历
  • Map的遍历方式
  • 有没有找人做标书的网站建网站用自己的主机做服务器
  • Day18:二叉树part8(669.修剪二叉搜索树、108.将有序数组转换为二叉搜索树、538.把二叉搜索树转换为累加树)
  • 常见的简单的营销软件宁波seo哪家最便宜
  • 电力系统设备故障因果推理与深度学习驱动的根因分析优化
  • ElasticSearch详解(篇二)
  • 重庆网站建设怎么样来个手机能看的网站2021
  • 网站建设的财务分析wordpress阶梯插件
  • CSS Position(定位)
  • redis安装与部署
  • 做网站的毕业设计做网站用什么语言高效
  • 长春好的做网站公司排名软件推广公司
  • VSCode终极版
  • NFS服务器
  • MYSQL索引的底层数据结构
  • 进程等待
  • 【数学速通】初中高中数学完整内容体系总结
  • 哪个网站做推销产品oshin wordpress