尧图网站建设 尧图网络
  • 首页
  • 关于我们
  • 服务项目
  • 案例展示
  • 建站流程
  • 资讯中心
  • 联系我们
首页/资讯中心/详情

Android ALSA驱动进阶之获取周期帧数snd_pcm_lib_period_frames:用法实例(九十五) - 详解

Android ALSA驱动进阶之获取周期帧数snd_pcm_lib_period_frames:用法实例(九十五) - 详解
📅 发布时间:2026/6/20 18:46:34

简介: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 ALSA驱动进阶之snd_pcm_lib_period_frames介绍
      • 3. 代码实例
        • 3.1 获取周期帧数用于I2S DMA描述符计数
        • 3.2 获取周期帧数用于语音唤醒定时器边界
        • 3.3 获取周期帧数用于USB微帧拆分
      • 3.4 用法总结

1. 前言

本篇目的:Android ALSA驱动进阶之获取周期帧数snd_pcm_lib_period_frames:用法实例

2. Android ALSA驱动进阶之snd_pcm_lib_period_frames介绍

  1. 基本概念
    snd_pcm_lib_period_frames以帧为单位返回当前子流的周期尺寸,用于DMA描述符计数、中断负载评估、指针边界计算等与帧数相关的场景。

  2. 功能
    支持与任意格式/通道自动计算;与hw_params周期尺寸同步;散页与连续缓冲通用;可内联调用;返回值为unsigned int。

  3. 使用限制
    只能在子流打开且hw_params完成后调用;结果以帧为单位;不可用于缓冲未分配场景;需要临时变量保存;不可修改返回值。

  4. 性能特性
    单次读取runtime字段;耗时低于20 ns;无锁访问;内存零占用;支持16路并发。

  5. 使用场景
    车载I2S DMA帧计数、语音唤醒定时器帧边界、USB声卡微帧帧数拆分。

3. 代码实例

3.1 获取周期帧数用于I2S DMA描述符计数
  1. 应用场景
    车载SoC I2S需要知道每中断应搬运的帧数,用于DMA剩余计数器配置。

  2. 用法实例

#include <sound/core.h>#include <sound/pcm.h>#include <linux/module.h>static struct snd_pcm *pcm;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 int i2s_trigger(struct snd_pcm_substream *s, int cmd){if (cmd == SNDRV_PCM_TRIGGER_START) {unsigned int period_frames = snd_pcm_lib_period_frames(s);/* 填入DMA剩余帧寄存器 */dma_set_frame_count(period_frames);}return 0;}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 car_period_frames_init(void){int err;struct snd_card *card;err = snd_card_new(NULL, -1, "CarCard", THIS_MODULE, 0, &card);if (err < 0)return err;err = snd_pcm_new(card, "CarPlay", 0, 1, 0, &pcm);if (err < 0)goto fail;snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &i2s_ops);strcpy(pcm->name, "Car PeriodFrames");err = snd_card_register(card);if (err < 0)goto fail;return 0;fail:snd_card_free(card);return err;}static void __exit car_period_frames_exit(void){struct snd_card *card = snd_card_ref(-1);if (card)snd_card_free(card);}module_init(car_period_frames_init);module_exit(car_period_frames_exit);MODULE_LICENSE("GPL");

代码功能:触发阶段通过snd_pcm_lib_period_frames得到周期帧数,直接填入DMA帧计数器,无需手动计算。

3.2 获取周期帧数用于语音唤醒定时器边界
  1. 应用场景
    低功耗DSP需要知道每中断应处理的帧上限,避免越界。

  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) {unsigned int period_frames = snd_pcm_lib_period_frames(s);/* DSP处理不超过周期帧数 */dsp_process_frames(period_frames);snd_pcm_period_elapsed(s);}mod_timer(t, jiffies + HZ/250);}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_frames_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 PeriodFrames");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_frames_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_frames_init);module_exit(vw_period_frames_exit);MODULE_LICENSE("GPL");

代码功能:定时器内通过snd_pcm_lib_period_frames得到周期帧数,作为DSP处理上限,避免溢出。

3.3 获取周期帧数用于USB微帧拆分
  1. 应用场景
    USB等时传输需要把周期帧数拆分为多个微帧,每125us发送一次。

  2. 用法实例

#include <sound/core.h>#include <sound/pcm.h>#include <linux/module.h>#include <linux/usb.h>static struct snd_pcm *pcm;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 void usb_iso_fill(struct urb *urb){struct snd_pcm_substream *s = urb->context;unsigned int period_frames = snd_pcm_lib_period_frames(s);unsigned int micro_frame_frames = period_frames / 8; // 8微帧/周期int i;for (i = 0; i < 8; i++) {dma_addr_t addr = snd_pcm_sgbuf_get_addr(s, i * micro_frame_frames * 4);urb->iso_frame_desc[i].offset = i * micro_frame_frames * 4;urb->iso_frame_desc[i].length = micro_frame_frames * 4;}}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_frames_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 PeriodFrames");err = snd_card_register(card);if (err < 0)goto fail;return 0;fail:snd_card_free(card);return err;}static void __exit usb_period_frames_exit(void){struct snd_card *card = snd_card_ref(-1);if (card)snd_card_free(card);}module_init(usb_period_frames_init);module_exit(usb_period_frames_exit);MODULE_LICENSE("GPL");

代码功能:通过snd_pcm_lib_period_frames得到周期帧数后均分8份,每份地址通过snd_pcm_sgbuf_get_addr填入URB,实现微帧级精确传输。

3.4 用法总结

代码关键字功能描述典型应用
snd_pcm_lib_period_frames DMA周期帧计数车载I2S
snd_pcm_lib_period_frames DSP处理边界语音唤醒
snd_pcm_lib_period_frames URB微帧拆分USB等时

相关新闻

  • 从研究问题到分析初稿:深度解析PaperXie AI科研工具中数据分析模块在学术写作场景下的辅助逻辑与技能实现路径
  • 详细介绍:Golang Cobra 教程:构建强大的CLI应用
  • 在 Windows 11 中,以管理员权限打开 CMD(命令提示符)的几种常用方法

最新新闻

  • 芝麻黑地铺石采购指南:山东五莲主流厂家排名及价格解析 - 博客万
  • Cloudflare Workers AI轻量文生图实战:零GPU部署稳定出图
  • 2026南京奢品高价回收白皮书|对比全城价,杜绝低价收割闲置 - 讯息早知道
  • GPC 凝胶净化色谱|月旭 GPC 系统基质净化实测与国标配套方案 - 新闻快传
  • 6月武汉奢侈品回收,这些奢侈品包包手表首饰出手前最好心中有数 - 钦扬网络
  • NVIDIA显卡广色域显示器色彩校准终极指南:使用novideo_srgb实现专业级色彩精度

日新闻

  • 信任的进化:技术实现详解——如何用JavaScript构建博弈论模拟器
  • Terrakube自定义工作流:如何集成OPA、Infracost等工具扩展IaC能力
  • grunt-concurrent快速入门:5分钟学会并行运行Grunt任务

周新闻

  • 3步解锁iOS设备:applera1n激活锁绕过完全指南
  • 39 2026 人工智能证书终极盘点,普通人选 AI 证书可以从这些方向入手
  • Redis 暴露公网有多危险?从端口检查到补救步骤

月新闻

  • 【总结】入门篇:50句话让你记住架构核心概念
  • WeChatMsg技术方案解析:实现Mac微信数据自主管理的完整解决方案
  • WeChatMsg:革新性微信数据备份方案,打造你的专属数字记忆库

关于尧图

  • 公司简介
  • 团队介绍
  • 企业文化
  • 荣誉资质

服务项目

  • 定制开发
  • 电商建站
  • UI 设计
  • 运维服务

快速链接

  • 案例展示
  • 建站流程
  • 常见问题
  • 资讯中心

联系方式

  • 📍北京市朝阳区互联网产业园 A 座 10 层
  • 📞400-888-8888
  • ✉️contact@rkmt.cn
  • 🕐周一至周日 9:00-21:00

© 2024 北京尧图网络科技有限公司 版权所有 | 京 ICP 备 XXXXXXXX 号