Android内核进阶之写pcm数据到硬件snd_pcm_lib_write:用法实例(八十九)

简介: 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介绍

  1. 基本概念

    snd_pcm_lib_write是ALSA核心提供的标准写入接口,负责把用户空间音频数据拷贝至DMA缓冲区,处理回绕、缓存、内存屏障,驱动只需实现copy回调即可对接。

  2. 功能

    支持交错与非交错格式;自动处理buffer回绕;支持mmap与rw模式;可统计写入帧数;支持16路子流并发;失败返回负错误码。

  3. 使用限制

    只能在write回调上下文调用;buf需为用户空间指针;size以帧为单位;runtime状态需RUNNING;需要对应snd_pcm_lib_write_*完成拷贝。

  4. 性能特性

    拷贝耗时低于1微秒/帧;支持高速DMA映射;零内核缓存;与hw_ptr原子同步;支持32位与64位用户空间。

  5. 使用场景

    Android触控音快速写入、车载导航提示音、USB声卡高码率流式传输。

🌻3. 代码实例

🌻3.1 使用snd_pcm_lib_write实现触控音快速写入
  1. 应用场景

    机顶盒按键音需低延迟写入,驱动仅提供copy回调。

  2. 用法实例

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实现车载导航提示音
  1. 应用场景

    车载系统需要一次性写入完整提示音,驱动无需额外缓存。

  2. 用法实例

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高码率流式传输
  1. 应用场景

    USB声卡DSD256需要持续写入,驱动利用lib接口完成高速搬运。

  2. 用法实例

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
相关推荐
Android系统攻城狮5 小时前
Android16音频之启动蓝牙SCO链路startBluetoothSco:用法实例(九十六)
音视频·android16·音频进阶·蓝牙sco协议
Android系统攻城狮19 小时前
Android内核进阶之获取DMA地址snd_pcm_sgbuf_get_addr:用法实例(九十一)
android·pcm·android内核·音频进阶·pcm硬件参数
#做一个清醒的人1 个月前
【electron6】Web Audio + AudioWorklet PCM 实时采集噪音和模拟调试
前端·javascript·electron·pcm
长沙红胖子Qt1 个月前
FFmpeg开发笔记(十二):ffmpeg音频处理、采集麦克风音频录音为WAV
ffmpeg·pcm·wav·录音·麦克风
骄傲的心别枯萎2 个月前
RV1126 NO.30:RV1126多线程获取音频AI的PCM数据
linux·ffmpeg·音视频·pcm·视频编解码
小狮子安度因2 个月前
ffplay播放pcm
pcm
froxy2 个月前
音频中的PDM、PCM概念解读
音视频·pcm
音视频牛哥3 个月前
如何计算 PCM 音频与 YUV/RGB 原始视频文件大小?
音视频·pcm·大牛直播sdk·rtsp播放器·rtmp播放器·yuv rgb计算大小·pcm计算大小
我是海飞3 个月前
16进制pcm数据转py波形脚本
音频·pcm