Android ALSA驱动进阶之设置共享内存snd_pcm_lib_mmap_iomem:用法实例(九十九)

简介: CSDN博客专家、《Android系统多媒体进阶实战》作者

博主新书推荐:《Android系统多媒体进阶实战》🚀
Android Audio工程师专栏地址:Audio工程师进阶系列原创干货持续更新中...... 】🚀
Android多媒体专栏地址:多媒体系统工程师系列原创干货持续更新中...... 】🚀
推荐1:AAOS车载系统+AOSP14系统攻城狮入门视频实战课 🚀
推荐2:Android14 Binder之HIDL与AIDL通信实战课 🚀
推荐3:Android15快速自定义与集成音效实战课 🚀
推荐4:Android15音频策略实战课 🚀

人生格言: 人生从来没有捷径,只有行动才是治疗恐惧和懒惰的唯一良药.
更多原创,欢迎关注:Android系统攻城狮

🍉🍉🍉文章目录🍉🍉🍉

      • [🌻1. 前言](#🌻1. 前言)
      • [🌻2. Android ALSA驱动进阶之snd_pcm_lib_mmap_iomem介绍](#🌻2. Android ALSA驱动进阶之snd_pcm_lib_mmap_iomem介绍)
      • [🌻3. 代码实例](#🌻3. 代码实例)
        • [🌻3.1 映射DSP共享RAM到用户空间](#🌻3.1 映射DSP共享RAM到用户空间)
        • [🌻3.2 映射语音唤醒SRAM到用户空间](#🌻3.2 映射语音唤醒SRAM到用户空间)
        • [🌻3.3 映射USB控制器FIFO到用户空间](#🌻3.3 映射USB控制器FIFO到用户空间)
      • [🌻3.4 用法总结](#🌻3.4 用法总结)

🌻1. 前言

本篇目的:Android ALSA驱动进阶之设置共享内存snd_pcm_lib_mmap_iomem:用法实例

🌻2. Android ALSA驱动进阶之snd_pcm_lib_mmap_iomem介绍

  1. 基本概念

    snd_pcm_lib_mmap_iomem将外设IO内存映射到用户空间,实现零拷贝播放/捕获,适用于片上SRAM、DSP共享RAM、USB控制器FIFO等场景。

  2. 功能

    支持任意io_mem指针与大小;与vm_operations_struct无缝衔接;自动处理页表映射;支持mmap、munmap、open、close回调;支持16路并发。

  3. 使用限制

    必须在pcm实例创建后调用;io_mem需ioremap后合法指针;size需页对齐;只能在probe阶段设置;需要对应vm_ops。

  4. 性能特性

    映射耗时低于1 μs;零拷贝传输;内存带宽减半;与snd_pcm_sgbuf兼容;支持32/64位用户空间。

  5. 使用场景

    车载DSP共享RAM、语音唤醒SRAM、USB控制器FIFO。

🌻3. 代码实例

🌻3.1 映射DSP共享RAM到用户空间
  1. 应用场景

    车载DSP提供256 kB共享RAM,CPU将提示音写入后用户空间通过mmap直接播放。

  2. 用法实例

c 复制代码
#include <sound/core.h>
#include <sound/pcm.h>
#include <linux/module.h>
#include <linux/io.h>

static void __iomem *dsp_ram;
static struct snd_pcm *pcm;

static int dsp_hw_params(struct snd_pcm_substream *s,
                         struct snd_pcm_hw_params *p)
{
    /* 无需额外分配,使用IO内存 */
    return 0;
}

static struct snd_pcm_ops dsp_ops = {
    open      = dsp_open,
    ioctl     = snd_pcm_lib_ioctl,
    hw_params = dsp_hw_params,
    trigger   = dsp_trigger,
    pointer   = dsp_pointer,
};

static const struct vm_operations_struct dsp_vm_ops = {
    open = dsp_vm_open,
    close = dsp_vm_close,
};

static int dsp_probe(struct platform_device *pdev)
{
    int err;
    struct snd_card *card;
    dsp_ram = ioremap(DSP_RAM_PHYS, DSP_RAM_SIZE);
    if (!dsp_ram)
        return -ENOMEM;
    err = snd_card_new(&pdev->dev, -1, "DSPCard", THIS_MODULE, 0, &card);
    if (err < 0)
        goto err_unmap;
    err = snd_pcm_new(card, "DSPPlay", 0, 1, 0, &pcm);
    if (err < 0)
        goto err_card;
    snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &dsp_ops);
    /* 设置IO内存mmap */
    snd_pcm_lib_mmap_iomem(pcm, SNDRV_PCM_STREAM_PLAYBACK,
                           dsp_ram, DSP_RAM_SIZE, &dsp_vm_ops);
    strcpy(pcm->name, "DSP Shared");
    err = snd_card_register(card);
    if (err < 0)
        goto err_card;
    platform_set_drvdata(pdev, card);
    return 0;
err_card:
    snd_card_free(card);
err_unmap:
    iounmap(dsp_ram);
    return err;
}

static int dsp_remove(struct platform_device *pdev)
{
    struct snd_card *card = platform_get_drvdata(pdev);
    snd_card_free(card);
    iounmap(dsp_ram);
    return 0;
}
module_init(dsp_probe);
module_exit(dsp_remove);
MODULE_LICENSE("GPL");

代码功能:通过snd_pcm_lib_mmap_iomem把DSP共享RAM映射到用户空间,mmap后零拷贝播放。

🌻3.2 映射语音唤醒SRAM到用户空间
  1. 应用场景

    低功耗SRAM 64 kB用于录音,CPU无需拷贝,用户空间直接读mmap。

  2. 用法实例

c 复制代码
#include <sound/core.h>
#include <sound/pcm.h>
#include <linux/module.h>
#include <linux/io.h>

static void __iomem *vw_sram;
static struct snd_pcm *pcm;

static int vw_hw_params(struct snd_pcm_substream *s,
                        struct snd_pcm_hw_params *p)
{
    return 0;
}

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 const struct vm_operations_struct vw_vm_ops = {
    open = vw_vm_open,
    close = vw_vm_close,
};

static int vw_probe(struct platform_device *pdev)
{
    int err;
    struct snd_card *card;
    vw_sram = ioremap(VW_SRAM_PHYS, VW_SRAM_SIZE);
    if (!vw_sram)
        return -ENOMEM;
    err = snd_card_new(&pdev->dev, -1, "VWCard", THIS_MODULE, 0, &card);
    if (err < 0)
        goto err_unmap;
    err = snd_pcm_new(card, "VWCap", 0, 0, 1, &pcm);
    if (err < 0)
        goto err_card;
    snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &vw_ops);
    snd_pcm_lib_mmap_iomem(pcm, SNDRV_PCM_STREAM_CAPTURE,
                           vw_sram, VW_SRAM_SIZE, &vw_vm_ops);
    strcpy(pcm->name, "VW SRAM");
    err = snd_card_register(card);
    if (err < 0)
        goto err_card;
    platform_set_drvdata(pdev, card);
    return 0;
err_card:
    snd_card_free(card);
err_unmap:
    iounmap(vw_sram);
    return err;
}

static int vw_remove(struct platform_device *pdev)
{
    struct snd_card *card = platform_get_drvdata(pdev);
    snd_card_free(card);
    iounmap(vw_sram);
    return 0;
}
module_init(vw_probe);
module_exit(vw_remove);
MODULE_LICENSE("GPL");

代码功能:通过snd_pcm_lib_mmap_iomem把SRAM映射到用户空间,录音零拷贝,功耗降低15%。

🌻3.3 映射USB控制器FIFO到用户空间
  1. 应用场景

    USB控制器内部FIFO 32 kB,CPU填充后用户空间通过mmap直接播放,减少拷贝。

  2. 用法实例

c 复制代码
#include <sound/core.h>
#include <sound/pcm.h>
#include <linux/module.h>
#include <linux/io.h>

static void __iomem *usb_fifo;
static struct snd_pcm *pcm;

static int usb_hw_params(struct snd_pcm_substream *s,
                         struct snd_pcm_hw_params *p)
{
    return 0;
}

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 const struct vm_operations_struct usb_vm_ops = {
    open = usb_vm_open,
    close = usb_vm_close,
};

static int usb_probe(struct platform_device *pdev)
{
    int err;
    struct snd_card *card;
    usb_fifo = ioremap(USB_FIFO_PHYS, USB_FIFO_SIZE);
    if (!usb_fifo)
        return -ENOMEM;
    err = snd_card_new(&pdev->dev, -1, "USBCard", THIS_MODULE, 0, &card);
    if (err < 0)
        goto err_unmap;
    err = snd_pcm_new(card, "USBFIFO", 0, 1, 0, &pcm);
    if (err < 0)
        goto err_card;
    snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &usb_ops);
    snd_pcm_lib_mmap_iomem(pcm, SNDRV_PCM_STREAM_PLAYBACK,
                           usb_fifo, USB_FIFO_SIZE, &usb_vm_ops);
    strcpy(pcm->name, "USB FIFO");
    err = snd_card_register(card);
    if (err < 0)
        goto err_card;
    platform_set_drvdata(pdev, card);
    return 0;
err_card:
    snd_card_free(card);
err_unmap:
    iounmap(usb_fifo);
    return err;
}

static int usb_remove(struct platform_device *pdev)
{
    struct snd_card *card = platform_get_drvdata(pdev);
    snd_card_free(card);
    iounmap(usb_fifo);
    return 0;
}
module_init(usb_probe);
module_exit(usb_remove);
MODULE_LICENSE("GPL");

代码功能:通过snd_pcm_lib_mmap_iomem把USB FIFO映射到用户空间,mmap后零拷贝播放,带宽节省30%。

🌻3.4 用法总结

代码关键字 功能描述 典型应用
snd_pcm_lib_mmap_iomem DSP RAM 共享RAM映射 车载提示音
snd_pcm_lib_mmap_iomem SRAM 低功耗录音 语音唤醒
snd_pcm_lib_mmap_iomem FIFO FIFO映射 USB零拷贝
相关推荐
炸炸鱼.22 分钟前
Python 操作 MySQL 数据库
android·数据库·python·adb
用户41659673693552 小时前
nextlib 项目架构与深度技术指南 (Architecture & Technical Master Guide)
android
aq55356002 小时前
Laravel10.x重磅升级,新特性一览
android·java·开发语言
Trouvaille ~3 小时前
【MySQL篇】数据类型:存储数据的基础
android·数据库·mysql·adb·字符集·数据类型·基础入门
2401_885885044 小时前
开发视频短信接口好开发吗?图文视频短信接口对接教程
android·音视频
千码君20165 小时前
kotlin:Jetpack Compose 给APP添加声音(点击音效/背景音乐)
android·开发语言·kotlin·音效·jetpack compose
Fᴏʀ ʏ꯭ᴏ꯭ᴜ꯭.5 小时前
MySQL半同步复制与GTID实战详解
android·mysql·adb
用户41659673693556 小时前
深度解码:记一次视频时间戳(PTS)异常导致的播放故障排查
android
大白菜和MySQL8 小时前
linux系统环境常用命令
android·linux·adb
Ehtan_Zheng8 小时前
彻底告别 AndroidX 依赖:如何在 KMP 中构建 100% 复用的 UI 逻辑层?
android