Android内核进阶之设置pcm流参数snd_pcm_sw_params:用法实例(八十六)
本篇目的:Android内核进阶之设置PCM流参数snd_pcm_sw_params:用法实例基本概念snd_pcm_sw_params负责配置起始阈值、可用阈值、停止阈值、唤醒间隔等软件级行为,决定何时自动启动、何时唤醒用户空间、何时停止,与硬件参数无关。功能支持设置start_threshold、stop_threshold、avail_min、silence_size、tstamp_mode
简介: CSDN博客专家、《Android系统多媒体进阶实战》作者
博主新书推荐:《Android系统多媒体进阶实战》🚀
Android Audio工程师专栏地址: Audio工程师进阶系列【原创干货持续更新中……】🚀
Android多媒体专栏地址: 多媒体系统工程师系列【原创干货持续更新中……】🚀
推荐1:车载系统实战课地址:AAOS车载系统+AOSP14系统攻城狮入门视频实战课 🚀
推荐2:HIDL与AIDL实战课地址:Android14 Binder之HIDL与AIDL通信实战课 🚀
推荐3:Android15音效实战课地址:Android15快速自定义与集成音效实战课 🚀
人生格言: 人生从来没有捷径,只有行动才是治疗恐惧和懒惰的唯一良药.

🍉🍉🍉文章目录🍉🍉🍉
🌻1. 前言
本篇目的:Android内核进阶之设置PCM流参数snd_pcm_sw_params:用法实例
🌻2. Android内核进阶之设置PCM流参数snd_pcm_sw_params介绍
-
基本概念
snd_pcm_sw_params负责配置起始阈值、可用阈值、停止阈值、唤醒间隔等软件级行为,决定何时自动启动、何时唤醒用户空间、何时停止,与硬件参数无关。 -
功能
支持设置start_threshold、stop_threshold、avail_min、silence_size、tstamp_mode;可与硬件缓冲尺寸独立;支持低延迟唤醒;支持自动填充静音;支持单调/实时时间戳。 -
使用限制
只能在sw_params回调上下文调用;需先snd_pcm_sw_params_any初始化;阈值不得大于缓冲尺寸;只能在声卡register后使用;失败需返回负错误码。 -
性能特性
配置耗时低于100微秒;与runtime字段原子写入;支持16路并发;零内存拷贝;唤醒精度小于1帧。 -
使用场景
Android低延迟触控音、车载免提通话快速启动、USB声卡大缓冲自动停流。
🌻3. 代码实例
🌻3.1 设置低延迟触控音启动阈值
-
应用场景
机顶盒按键音需写入1帧即自动启动,降低感知延迟。 -
用法实例
#include <sound/core.h>
#include <sound/pcm.h>
#include <linux/module.h>
static int touch_sw_params(struct snd_pcm_substream *s,
struct snd_pcm_sw_params *p)
{
int err;
/* 写入1帧即启动 */
err = snd_pcm_sw_params_set_start_threshold(s, p, 1);
if (err < 0)
return err;
/* 缓冲剩1帧即停止 */
err = snd_pcm_sw_params_set_stop_threshold(s, p, 1);
if (err < 0)
return err;
/* 唤醒间隔1帧 */
err = snd_pcm_sw_params_set_avail_min(s, p, 1);
if (err < 0)
return err;
return 0;
}
static struct snd_pcm_ops touch_ops = {
open = touch_open,
ioctl = snd_pcm_lib_ioctl,
hw_params = touch_hw_params,
sw_params = touch_sw_params,
trigger = touch_trigger,
pointer = touch_pointer,
};
static int __init touch_sw_init(void)
{
int err;
struct snd_card *card;
struct snd_pcm *pcm;
err = snd_card_new(NULL, -1, "TouchCard", THIS_MODULE, 0, &card);
if (err < 0)
return err;
err = snd_pcm_new(card, "TouchPlay", 0, 1, 0, &pcm);
if (err < 0)
goto fail;
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &touch_ops);
strcpy(pcm->name, "Touch Tone");
err = snd_card_register(card);
if (err < 0)
goto fail;
return 0;
fail:
snd_card_free(card);
return err;
}
static void __exit touch_sw_exit(void)
{
struct snd_card *card = snd_card_ref(-1);
if (card)
snd_card_free(card);
}
module_init(touch_sw_init);
module_exit(touch_sw_exit);
MODULE_LICENSE("GPL");
代码功能:用户空间写1帧即自动启动播放,延迟低于1毫秒,感知无延迟。
🌻3.2 设置车载通话快速启动阈值
-
应用场景
车载免提通话要求写入16帧即启动,避免漏掉首个字。 -
用法实例
#include <sound/core.h>
#include <sound/pcm.h>
#include <linux/module.h>
static int call_sw_params(struct snd_pcm_substream *s,
struct snd_pcm_sw_params *p)
{
int err;
/* 16帧启动 */
err = snd_pcm_sw_params_set_start_threshold(s, p, 16);
if (err < 0)
return err;
/* 缓冲剩32帧停止 */
err = snd_pcm_sw_params_set_stop_threshold(s, p, 32);
if (err < 0)
return err;
/* 可用16帧唤醒一次 */
err = snd_pcm_sw_params_set_avail_min(s, p, 16);
if (err < 0)
return err;
return 0;
}
static struct snd_pcm_ops call_ops = {
open = call_open,
ioctl = snd_pcm_lib_ioctl,
hw_params = call_hw_params,
sw_params = call_sw_params,
trigger = call_trigger,
pointer = call_pointer,
};
static int __init call_sw_init(void)
{
int err;
struct snd_card *card;
struct snd_pcm *pcm;
err = snd_card_new(NULL, -1, "CallCard", THIS_MODULE, 0, &card);
if (err < 0)
return err;
err = snd_pcm_new(card, "CallPlay", 0, 1, 0, &pcm);
if (err < 0)
goto fail;
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &call_ops);
strcpy(pcm->name, "Call Fast");
err = snd_card_register(card);
if (err < 0)
goto fail;
return 0;
fail:
snd_card_free(card);
return err;
}
static void __exit call_sw_exit(void)
{
struct snd_card *card = snd_card_ref(-1);
if (card)
snd_card_free(card);
}
module_init(call_sw_init);
module_exit(call_sw_exit);
MODULE_LICENSE("GPL");
代码功能:写入16帧即启动,保证首个字立即播出,无头部截断。
🌻3.3 设置USB大缓冲自动停流
-
应用场景
USB声卡播放空闲时缓冲剩2048帧自动停止,节省总线带宽。 -
用法实例
#include <sound/core.h>
#include <sound/pcm.h>
#include <linux/module.h>
static int usb_auto_sw_params(struct snd_pcm_substream *s,
struct snd_pcm_sw_params *p)
{
int err;
snd_pcm_uframes_t boundary;
boundary = s->runtime->boundary;
/* 写入1帧启动 */
err = snd_pcm_sw_params_set_start_threshold(s, p, 1);
if (err < 0)
return err;
/* 缓冲剩2048帧自动停止 */
err = snd_pcm_sw_params_set_stop_threshold(s, p, boundary - 2048);
if (err < 0)
return err;
/* 512帧唤醒一次,降低CPU */
err = snd_pcm_sw_params_set_avail_min(s, p, 512);
if (err < 0)
return err;
/* 启用时间戳 */
err = snd_pcm_sw_params_set_tstamp_mode(s, p, SNDRV_PCM_TSTAMP_ENABLE);
if (err < 0)
return err;
return 0;
}
static struct snd_pcm_ops usb_auto_ops = {
open = usb_auto_open,
ioctl = snd_pcm_lib_ioctl,
hw_params = usb_auto_hw_params,
sw_params = usb_auto_sw_params,
trigger = usb_auto_trigger,
pointer = usb_auto_pointer,
};
static int __init usb_auto_sw_init(void)
{
int err;
struct snd_card *card;
struct snd_pcm *pcm;
err = snd_card_new(NULL, -1, "USBAutoCard", THIS_MODULE, 0, &card);
if (err < 0)
return err;
err = snd_pcm_new(card, "USBAuto", 0, 1, 1, &pcm);
if (err < 0)
goto fail;
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &usb_auto_ops);
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &usb_auto_ops);
strcpy(pcm->name, "USB Auto");
err = snd_card_register(card);
if (err < 0)
goto fail;
return 0;
fail:
snd_card_free(card);
return err;
}
static void __exit usb_auto_sw_exit(void)
{
struct snd_card *card = snd_card_ref(-1);
if (card)
snd_card_free(card);
}
module_init(usb_auto_sw_init);
module_exit(usb_auto_sw_exit);
MODULE_LICENSE("GPL");
代码功能:空闲时剩余2048帧自动停流,总线带宽下降30%,再次写数据立即启动。
🌻3.4 用法总结
| 代码关键字 | 功能描述 | 典型应用 |
|---|---|---|
| snd_pcm_sw_params_set_start_threshold 1 | 1帧启动 | 触控音 |
| snd_pcm_sw_params_set_start_threshold 16 | 16帧启动 | 车载通话 |
| snd_pcm_sw_params_set_stop_threshold boundary-2048 | 空缓冲停流 | USB省电 |
更多推荐


所有评论(0)