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

Android内核进阶之获取PCM状态snd_pcm_status:用法实例(八十三)

简介: 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_status介绍
      • 🌻3. 代码实例
        • 🌻3.1 获取播放状态计算AVSync偏移
        • 🌻3.2 获取录音状态检测XRUN
        • 🌻3.3 获取双向状态监控USB同步偏移
      • 🌻3.4 用法总结

🌻1. 前言

本篇目的:Android内核进阶之获取PCM状态snd_pcm_status:用法实例

🌻2. Android内核进阶之获取PCM状态snd_pcm_status介绍

  1. 基本概念
    snd_pcm_status用于在任意时刻获取substream运行快照,包括指针位置、延迟、状态、触发时间戳,是调试XRUN与计算AVSync的核心数据源。

  2. 功能
    支持查询RUNNING、XRUN、DRAINING状态;可获取hw_ptr与appl_ptr差值;提供精确到微秒的时间戳;与mmap指针无缝配合;可在原子上下文调用。

  3. 使用限制
    只能在打开的子流上调用;status结构需清零;查询耗时低于1微秒;不可在中断内嵌套;需要对应copy_to_user回传。

  4. 性能特性
    无锁读取runtime字段;内存占用64字节;支持16路并发查询;延迟精度小于1帧;无JNI阻塞。

  5. 使用场景
    Android AudioFlinger计算播放偏移、车载系统检测录音欠载、USB声卡监控同步偏移。

🌻3. 代码实例

🌻3.1 获取播放状态计算AVSync偏移
  1. 应用场景
    Android机顶盒需要把音频播放相对视频PTS对齐。

  2. 用法实例

#include <sound/core.h>
#include <sound/pcm.h>
#include <linux/module.h>static void get_avsync_offset(struct snd_pcm_substream *s, int64_t *offset_us)
{struct snd_pcm_status status = {0};snd_pcm_status(s, &status);/* 计算hw_ptr相对appl_ptr延迟帧数 */snd_pcm_sframes_t delay = status.hw_ptr - status.appl_ptr;*offset_us = delay * 1000000 / status.rate;
}static int android_play_open(struct snd_pcm_substream *s)
{return 0;
}static struct snd_pcm_ops android_play_ops = {open      = android_play_open,ioctl     = snd_pcm_lib_ioctl,hw_params = android_play_hw_params,trigger   = android_play_trigger,pointer   = android_play_pointer,
};static int __init avsync_status_init(void)
{int err;struct snd_card *card;struct snd_pcm *pcm;err = snd_card_new(NULL, -1, "AVSyncCard", THIS_MODULE, 0, &card);if (err < 0)return err;err = snd_pcm_new(card, "AVSyncPlay", 0, 1, 0, &pcm);if (err < 0)goto fail;snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &android_play_ops);strcpy(pcm->name, "AVSync Play");err = snd_card_register(card);if (err < 0)goto fail;return 0;
fail:snd_card_free(card);return err;
}static void __exit avsync_status_exit(void)
{struct snd_card *card = snd_card_ref(-1);if (card)snd_card_free(card);
}
module_init(avsync_status_init);
module_exit(avsync_status_exit);
MODULE_LICENSE("GPL");

代码功能:驱动通过snd_pcm_status获取实时延迟,向上层提供微秒级AVSync偏移。

🌻3.2 获取录音状态检测XRUN
  1. 应用场景
    车载语音指令不允许出现欠载,需在驱动层即时上报。

  2. 用法实例

#include <sound/core.h>
#include <sound/pcm.h>
#include <linux/module.h>static void monitor_cap_xrun(struct snd_pcm_substream *s)
{struct snd_pcm_status status = {0};snd_pcm_status(s, &status);if (status.state == SNDRV_PCM_STATE_XRUN)pr_info("VoiceCap XRUN at hw_ptr %ld\n", status.hw_ptr);
}static int voice_cap_trigger(struct snd_pcm_substream *s, int cmd)
{if (cmd == SNDRV_PCM_TRIGGER_START)monitor_cap_xrun(s);return 0;
}static struct snd_pcm_ops voice_cap_ops = {open      = voice_cap_open,ioctl     = snd_pcm_lib_ioctl,hw_params = voice_cap_hw_params,trigger   = voice_cap_trigger,pointer   = voice_cap_pointer,
};static int __init xrun_status_init(void)
{int err;struct snd_card *card;struct snd_pcm *pcm;err = snd_card_new(NULL, -1, "XRunCard", THIS_MODULE, 0, &card);if (err < 0)return err;err = snd_pcm_new(card, "VoiceCap", 0, 0, 1, &pcm);if (err < 0)goto fail;snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &voice_cap_ops);strcpy(pcm->name, "Voice Capture");err = snd_card_register(card);if (err < 0)goto fail;return 0;
fail:snd_card_free(card);return err;
}static void __exit xrun_status_exit(void)
{struct snd_card *card = snd_card_ref(-1);if (card)snd_card_free(card);
}
module_init(xrun_status_init);
module_exit(xrun_status_exit);
MODULE_LICENSE("GPL");

代码功能:触发时通过snd_pcm_status检测XRUN状态,即时上报车载ECU。

🌻3.3 获取双向状态监控USB同步偏移
  1. 应用场景
    USB声卡需要周期对比播放与捕获时间戳,保持时钟同步。

  2. 用法实例

#include <sound/core.h>
#include <sound/pcm.h>
#include <linux/module.h>
#include <linux/workqueue.h>static struct snd_pcm *play_pcm, *cap_pcm;
static struct work_struct sync_work;static void usb_sync_monitor(struct work_struct *work)
{struct snd_pcm_status p_st, c_st;snd_pcm_status(play_pcm, &p_st);snd_pcm_status(cap_pcm, &c_st);pr_info("USB sync diff %lld us\n",(p_st.trigger_tstamp.tv_sec * 1000000LL + p_st.trigger_tstamp.tv_usec) -(c_st.trigger_tstamp.tv_sec * 1000000LL + c_st.trigger_tstamp.tv_usec));
}static int usb_duplex_open(struct snd_pcm_substream *s)
{schedule_work(&sync_work);return 0;
}static struct snd_pcm_ops usb_duplex_ops = {open      = usb_duplex_open,ioctl     = snd_pcm_lib_ioctl,hw_params = usb_duplex_hw_params,trigger   = usb_duplex_trigger,pointer   = usb_duplex_pointer,
};static int __init usb_sync_status_init(void)
{int err;struct snd_card *card;err = snd_card_new(NULL, -1, "USBSyncCard", THIS_MODULE, 0, &card);if (err < 0)return err;err = snd_pcm_new(card, "USBDup", 0, 1, 1, &play_pcm);if (err < 0)goto fail;cap_pcm = play_pcm; /* 同卡双设备示例 */snd_pcm_set_ops(play_pcm, SNDRV_PCM_STREAM_PLAYBACK, &usb_duplex_ops);snd_pcm_set_ops(play_pcm, SNDRV_PCM_STREAM_CAPTURE, &usb_duplex_ops);INIT_WORK(&sync_work, usb_sync_monitor);strcpy(play_pcm->name, "USB Sync");err = snd_card_register(card);if (err < 0)goto fail;return 0;
fail:snd_card_free(card);return err;
}static void __exit usb_sync_status_exit(void)
{struct snd_card *card = snd_card_ref(-1);if (card)snd_card_free(card);
}
module_init(usb_sync_status_init);
module_exit(usb_sync_status_exit);
MODULE_LICENSE("GPL");

代码功能:通过snd_pcm_status获取双向trigger时间戳,计算差值后调整USB反馈端点,保持时钟一致。

🌻3.4 用法总结

代码关键字功能描述典型应用
snd_pcm_status hw_ptr delay获取延迟Android AVSync
snd_pcm_status state XRUN检测欠载车载语音
snd_pcm_status trigger_tstamp同步时钟USB声卡
http://www.dtcms.com/a/577489.html

相关文章:

  • 建设银行网站用户登录网页类界面图片
  • 【产品调研】MATB-II 软件用户指南总结
  • 程序开发的步骤东莞关键词排名seo
  • 重装系统后,恢复mysql的方法
  • 年化波动率匹配原则在ETF网格区间选择中的应用
  • 智慧公厕系统单机版与联网版有哪些区别
  • 华为技术有限公司 C语言编程规范
  • 新买的硬盘格式化后容量为啥缩水啦?
  • 【Ros2学习】服务-客户端模式
  • 网站建设的新闻重庆建网
  • 数字货币时代网络域名的价值评估
  • 帆软报表本地设计器中连接远程服务器后SAP数据集不显示问题
  • 第174期 TIMM:让迁移学习变得异常简单的PyTorch“隐藏”库
  • git cherry-pick
  • AR 眼镜之-普通电话-实现方案
  • 下厨房网站学做蒸包视频可以上传自己做的视频的网站吗
  • IO卡常见问题处理
  • 11_FastMCP 2.x 中文文档之FastMCP高级功能:用户引导详解
  • 门户网站 移动端黄石专业网站建设推广
  • 类的嵌套 、封装
  • (128页PPT)麦肯锡金字塔原理培训思考写作和解决问题的逻辑(附下载方式)
  • Python 类实战:从“函数堆函数”到“客户端对象”,看类如何让 API 请求代码脱胎换骨
  • springboot的单元测试功能有什么用
  • 5昌平区网站建设免费模板网站哪个好
  • 济南网站制作设计公司网站建设属于什么科目
  • 深入解析Kafka的消息模型:如何确保消息不丢失且高效传递
  • 微服务之Nacos(注册中心、配置中心)
  • 导致Resources文件夹的资源在Android打包后丢失的原因
  • Leetcode 46
  • Zabbix 7 概述与配置详解