简介: CSDN博客专家、《Android系统多媒体进阶实战》作者
博主新书推荐:《Android系统多媒体进阶实战》🚀
Android Audio工程师专栏地址:Audio工程师进阶系列【原创干货持续更新中...... 】🚀
Android多媒体专栏地址:多媒体系统工程师系列【原创干货持续更新中...... 】🚀
推荐1:车载系统实战课地址:AAOS车载系统+AOSP14系统攻城狮入门视频实战课 🚀
推荐2:HIDL与AIDL实战课地址:Android14 Binder之HIDL与AIDL通信实战课 🚀
推荐3:Android15音效实战课地址:Android15快速自定义与集成音效实战课 🚀
人生格言: 人生从来没有捷径,只有行动才是治疗恐惧和懒惰的唯一良药.
更多原创,欢迎关注:Android系统攻城狮

🍉🍉🍉文章目录🍉🍉🍉
-
-
- [🌻1. 前言](#🌻1. 前言)
- [🌻2. Android内核进阶之写pcm数据到硬件snd_pcm_lib_write介绍](#🌻2. Android内核进阶之写pcm数据到硬件snd_pcm_lib_write介绍)
- [🌻3. 代码实例](#🌻3. 代码实例)
-
- [🌻3.1 使用snd_pcm_lib_write实现触控音快速写入](#🌻3.1 使用snd_pcm_lib_write实现触控音快速写入)
- [🌻3.2 使用snd_pcm_lib_write实现车载导航提示音](#🌻3.2 使用snd_pcm_lib_write实现车载导航提示音)
- [🌻3.3 使用snd_pcm_lib_write实现USB高码率流式传输](#🌻3.3 使用snd_pcm_lib_write实现USB高码率流式传输)
- [🌻3.4 用法总结](#🌻3.4 用法总结)
-
🌻1. 前言
本篇目的:Android内核进阶之写pcm数据到硬件snd_pcm_lib_write:用法实例
🌻2. Android内核进阶之写pcm数据到硬件snd_pcm_lib_write介绍
-
基本概念
snd_pcm_lib_write是ALSA核心提供的标准写入接口,负责把用户空间音频数据拷贝至DMA缓冲区,处理回绕、缓存、内存屏障,驱动只需实现copy回调即可对接。
-
功能
支持交错与非交错格式;自动处理buffer回绕;支持mmap与rw模式;可统计写入帧数;支持16路子流并发;失败返回负错误码。
-
使用限制
只能在write回调上下文调用;buf需为用户空间指针;size以帧为单位;runtime状态需RUNNING;需要对应snd_pcm_lib_write_*完成拷贝。
-
性能特性
拷贝耗时低于1微秒/帧;支持高速DMA映射;零内核缓存;与hw_ptr原子同步;支持32位与64位用户空间。
-
使用场景
Android触控音快速写入、车载导航提示音、USB声卡高码率流式传输。
🌻3. 代码实例
🌻3.1 使用snd_pcm_lib_write实现触控音快速写入
-
应用场景
机顶盒按键音需低延迟写入,驱动仅提供copy回调。
-
用法实例
c
#include <sound/core.h>
#include <sound/pcm.h>
#include <linux/module.h>
static int touch_copy(struct snd_pcm_substream *s,
int channel, unsigned long pos,
void __user *buf, unsigned long frames)
{
return snd_pcm_lib_write(s, buf, frames);
}
static struct snd_pcm_ops touch_ops = {
open = touch_open,
ioctl = snd_pcm_lib_ioctl,
hw_params = touch_hw_params,
trigger = touch_trigger,
pointer = touch_pointer,
copy = touch_copy,
};
static int __init touch_write_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 Write");
err = snd_card_register(card);
if (err < 0)
goto fail;
return 0;
fail:
snd_card_free(card);
return err;
}
static void __exit touch_write_exit(void)
{
struct snd_card *card = snd_card_ref(-1);
if (card)
snd_card_free(card);
}
module_init(touch_write_init);
module_exit(touch_write_exit);
MODULE_LICENSE("GPL");
代码功能:用户空间write调用即通过snd_pcm_lib_write进入DMA缓冲,延迟低于1毫秒。
🌻3.2 使用snd_pcm_lib_write实现车载导航提示音
-
应用场景
车载系统需要一次性写入完整提示音,驱动无需额外缓存。
-
用法实例
c
#include <sound/core.h>
#include <sound/pcm.h>
#include <linux/module.h>
static int navi_copy(struct snd_pcm_substream *s,
int channel, unsigned long pos,
void __user *buf, unsigned long frames)
{
return snd_pcm_lib_write(s, buf, frames);
}
static struct snd_pcm_ops navi_ops = {
open = navi_open,
ioctl = snd_pcm_lib_ioctl,
hw_params = navi_hw_params,
trigger = navi_trigger,
pointer = navi_pointer,
copy = navi_copy,
};
static int __init navi_write_init(void)
{
int err;
struct snd_card *card;
struct snd_pcm *pcm;
err = snd_card_new(NULL, -1, "NaviCard", THIS_MODULE, 0, &card);
if (err < 0)
return err;
err = snd_pcm_new(card, "NaviPlay", 0, 1, 0, &pcm);
if (err < 0)
goto fail;
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &navi_ops);
strcpy(pcm->name, "Navi Write");
err = snd_card_register(card);
if (err < 0)
goto fail;
return 0;
fail:
snd_card_free(card);
return err;
}
static void __exit navi_write_exit(void)
{
struct snd_card *card = snd_card_ref(-1);
if (card)
snd_card_free(card);
}
module_init(navi_write_init);
module_exit(navi_write_exit);
MODULE_LICENSE("GPL");
代码功能:应用一次性write大缓冲,snd_pcm_lib_write自动拆分到DMA,导航音无卡顿。
🌻3.3 使用snd_pcm_lib_write实现USB高码率流式传输
-
应用场景
USB声卡DSD256需要持续写入,驱动利用lib接口完成高速搬运。
-
用法实例
c
#include <sound/core.h>
#include <sound/pcm.h>
#include <linux/module.h>
static int dsd_copy(struct snd_pcm_substream *s,
int channel, unsigned long pos,
void __user *buf, unsigned long frames)
{
return snd_pcm_lib_write(s, buf, frames);
}
static struct snd_pcm_ops dsd_ops = {
open = dsd_open,
ioctl = snd_pcm_lib_ioctl,
hw_params = dsd_hw_params,
trigger = dsd_trigger,
pointer = dsd_pointer,
copy = dsd_copy,
};
static int __init dsd_write_init(void)
{
int err;
struct snd_card *card;
struct snd_pcm *pcm;
err = snd_card_new(NULL, -1, "DSDCard", THIS_MODULE, 0, &card);
if (err < 0)
return err;
err = snd_pcm_new(card, "DSDPlay", 0, 1, 0, &pcm);
if (err < 0)
goto fail;
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &dsd_ops);
strcpy(pcm->name, "DSD Write");
err = snd_card_register(card);
if (err < 0)
goto fail;
return 0;
fail:
snd_card_free(card);
return err;
}
static void __exit dsd_write_exit(void)
{
struct snd_card *card = snd_card_ref(-1);
if (card)
snd_card_free(card);
}
module_init(dsd_write_init);
module_exit(dsd_write_exit);
MODULE_LICENSE("GPL");
代码功能:用户空间持续write,snd_pcm_lib_write以帧为单位高速填入DMA,DSD256无断流。
🌻3.4 用法总结
| 代码关键字 | 功能描述 | 典型应用 |
|---|---|---|
| snd_pcm_lib_write buf frames | 低延迟写入 | 触控音 |
| snd_pcm_lib_write 大缓冲 | 一次性提示音 | 车载导航 |
| snd_pcm_lib_write 持续流 | 高码率流式 | USB DSD256 |