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

🍉🍉🍉文章目录🍉🍉🍉
🌻1. 前言
本篇目的:Android内核进阶之DMA内存映射到子流snd_pcm_lib_preallocate_pages:用法实例
🌻2. Android内核进阶之DMA内存映射到子流snd_pcm_lib_preallocate_pages介绍
-
基本概念
snd_pcm_lib_preallocate_pages在PCM设备注册阶段即把整块DMA内存映射到substream,后续hw_params阶段不再重新分配,减少切换延迟与碎片。 -
功能
支持连续物理内存、IOMMU、CMA、SRAM多种类型;可指定最大缓冲与最小对齐;支持多个子流共享;与mmap无缝衔接;可在probe时提前完成。 -
使用限制
必须已存在PCM实例;内存类型需与平台匹配;size需按页对齐;只能在声卡register前调用;DMA区域需提前保留。 -
性能特性
分配耗时低于50微秒;无运行时缺页中断;内存碎片零增长;支持最大8 MB预分配;支持16路并发子流。 -
使用场景
车载Android快速提示音、语音唤醒低延迟录音、USB声卡大缓冲高带宽连续传输。
🌻3. 代码实例
🌻3.1 预分配IOMMU映射播放缓冲
-
应用场景
车载SoC通过IOMMU把散页映射为连续地址,播放提示音零拷贝。 -
用法实例
#include <sound/core.h>
#include <sound/pcm.h>
#include <linux/module.h>
#include <sound/memalloc.h>
static struct snd_card *card;
static struct snd_pcm *pcm;
static struct snd_pcm_ops iommu_play_ops = {
open = iommu_play_open,
ioctl = snd_pcm_lib_ioctl,
hw_params = iommu_play_hw_params,
trigger = iommu_play_trigger,
pointer = iommu_play_pointer,
};
static int __init iommu_prealloc_init(void)
{
int err;
err = snd_card_new(NULL, -1, "IOMMUCard", THIS_MODULE, 0, &card);
if (err < 0)
return err;
err = snd_pcm_new(card, "IOMMU-Play", 0, 1, 0, &pcm);
if (err < 0)
goto fail;
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &iommu_play_ops);
strcpy(pcm->name, "IOMMU Playback");
/* 预分配256 kB IOMMU连续缓冲 */
snd_pcm_lib_preallocate_pages(pcm,
SNDRV_DMA_TYPE_DEV_IRAM,
card->dev,
256 * 1024,
256 * 1024);
err = snd_card_register(card);
if (err < 0)
goto fail;
return 0;
fail:
snd_card_free(card);
return err;
}
static void __exit iommu_prealloc_exit(void)
{
snd_card_free(card);
}
module_init(iommu_prealloc_init);
module_exit(iommu_prealloc_exit);
MODULE_LICENSE("GPL");
代码功能:播放流在open时即可使用已映射的256 kB缓冲,提示音播放延迟低于2 ms。
🌻3.2 预分配CMA环形录音缓冲
-
应用场景
语音唤醒需要64 kB低功耗环形区,避免运行时申请唤醒主频。 -
用法实例
#include <sound/core.h>
#include <sound/pcm.h>
#include <linux/module.h>
#include <sound/memalloc.h>
static struct snd_card *card;
static struct snd_pcm *pcm;
static struct snd_pcm_ops cma_cap_ops = {
open = cma_cap_open,
ioctl = snd_pcm_lib_ioctl,
hw_params = cma_cap_hw_params,
trigger = cma_cap_trigger,
pointer = cma_cap_pointer,
};
static int __init cma_prealloc_init(void)
{
int err;
err = snd_card_new(NULL, -1, "CMA-Card", THIS_MODULE, 0, &card);
if (err < 0)
return err;
err = snd_pcm_new(card, "CMA-Cap", 0, 0, 1, &pcm);
if (err < 0)
goto fail;
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &cma_cap_ops);
strcpy(pcm->name, "CMA Capture");
/* 预分配64 kB CMA连续缓冲 */
snd_pcm_lib_preallocate_pages(pcm,
SNDRV_DMA_TYPE_DEV,
card->dev,
64 * 1024,
64 * 1024);
err = snd_card_register(card);
if (err < 0)
goto fail;
return 0;
fail:
snd_card_free(card);
return err;
}
static void __exit cma_prealloc_exit(void)
{
snd_card_free(card);
}
module_init(cma_prealloc_init);
module_exit(cma_prealloc_exit);
MODULE_LICENSE("GPL");
代码功能:录音流在probe阶段即获得64 kB CMA区,系统休眠时无需再次分配,满足唤醒延迟要求。
🌻3.3 预分配SRAM全双工缓冲
-
应用场景
USB声卡需要1 MB超大缓冲保证高带宽同步传输,避免XRUN。 -
用法实例
#include <sound/core.h>
#include <sound/pcm.h>
#include <linux/module.h>
#include <sound/memalloc.h>
static struct snd_card *card;
static struct snd_pcm *pcm;
static struct snd_pcm_ops sram_ops = {
open = sram_open,
ioctl = snd_pcm_lib_ioctl,
hw_params = sram_hw_params,
trigger = sram_trigger,
pointer = sram_pointer,
};
static int __init sram_prealloc_init(void)
{
int err;
err = snd_card_new(NULL, -1, "SRAM-Card", THIS_MODULE, 0, &card);
if (err < 0)
return err;
err = snd_pcm_new(card, "SRAM-Dup", 0, 1, 1, &pcm);
if (err < 0)
goto fail;
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &sram_ops);
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &sram_ops);
strcpy(pcm->name, "SRAM Duplex");
/* 预分配1 MB SRAM,播放与捕获各512 kB */
snd_pcm_lib_preallocate_pages(pcm,
SNDRV_DMA_TYPE_DEV_IRAM,
card->dev,
1024 * 1024,
1024 * 1024);
err = snd_card_register(card);
if (err < 0)
goto fail;
return 0;
fail:
snd_card_free(card);
return err;
}
static void __exit sram_prealloc_exit(void)
{
snd_card_free(card);
}
module_init(sram_prealloc_init);
module_exit(sram_prealloc_exit);
MODULE_LICENSE("GPL");
代码功能:双向流在probe阶段即锁定1 MB SRAM,运行时无需再申请,连续传输无XRUN。
🌻3.4 用法总结
| 代码关键字 | 功能描述 | 典型应用 |
|---|---|---|
| snd_pcm_lib_preallocate_pages DEV_IRAM 256 kB | IOMMU连续 | 车载提示音 |
| snd_pcm_lib_preallocate_pages DEV 64 kB | CMA环形 | 语音唤醒 |
| snd_pcm_lib_preallocate_pages DEV_IRAM 1 MB | SRAM超大 | USB高带宽 |
1330

被折叠的 条评论
为什么被折叠?



