Linux 音频驱动(六) ALSA音频驱动之PCM Write数据传递过程_pcm_write-程序员宅基地

技术标签: 驱动程序  alsa  linux  pcm  Linux Audio  

1. 前言

本文,我们将以回放(Playback,播放音频)为例,讲解PCM Data是如何从用户空间到内核空间,最后传递到Codec。
Linux 音频驱动(一) ASoC音频框架简介中,我们给出了回放(Playback)PCM数据流示意图:

在这里插入图片描述

  1. 对于Linux来说,由于分为 user space 和kernel space,而且两者之间不能随便互相访问。因此用户如果播放音频,则需要调用copy_from_user()将用户数据从user space拷贝到kernel space (DMA Buffer)。
  2. DMA 负责将DMA Buffer中的音频数据搬运到I2S TX FIFO。
  3. 通过I2S总线,将音频数据传送到Codec。
  4. Codec内部经过DAC转换,将模拟信号传到扬声器SPK(头戴式耳机HP、耳塞式耳机Earp)。

下面基于源码讲解PCM Data Flow。

2. PCM Data Flow

内核版本:Kernel 版本:3.10
内核源码文件:
         ./kernel-3.10/sound/core/device.c
         ./kernel-3.10/sound/core/init.c
         ./kernel-3.10/sound/core/pcm.c
         ./kernel-3.10/sound/core/pcm_lib.c
         ./kernel-3.10/sound/core/pcm_native.c
         ./kernel-3.10/sound/soc/soc-pcm.c
Tinyalsa源码文件:
         ./external/tinyalsa/pcm.c
         ./external/kernel-headers/original/uapi/sound/asound.h

User Space

在我的源码包里,用户空间应用程序使用的是 tinyalsa提供的接口write PCM Data,即播放音频文件。
Write PCM逻辑设备是通过 ioctl() 函数完成的,即应用程序将需要播放的音频数据通过pcm_write() --> ioctl() 传递到内核。

// ./external/kernel-headers/original/uapi/sound/asound.h, line 448
struct snd_xferi {
   
    
	snd_pcm_sframes_t result;
	void __user *buf;
	snd_pcm_uframes_t frames;
};
// ./external/tinyalsa/pcm.c, line 483
int pcm_write(struct pcm *pcm, const void *data, unsigned int count)
{
   
    
    struct snd_xferi x;
    ......
    x.buf = (void*)data;
    x.frames = count / (pcm->config.channels *
                        pcm_format_to_bits(pcm->config.format) / 8);
    ......
    ioctl(pcm->fd, SNDRV_PCM_IOCTL_WRITEI_FRAMES, &x);
    ......
}

音频数据中的几个重要概念:
Format:样本长度(采样精度 or 采样深度),音频数据最基本的单位,常见的有 8 位和 16 位;
Channel:声道数,分为单声道 mono 和立体声stereo;
Frame:帧,构成一个完整的声音单元,Frame = Format * Channel;
Rate:又称 sample rate:采样率,即每秒的采样次数,针对帧而言;
Period size:周期,每次硬件中断处理音频数据的帧数,对于音频设备的数据读写,以此为单位;
Buffer size:数据缓冲区大小,这里指runtime 的 buffer size,而不是结构体 snd_pcm_hardware 中定义的buffer_bytes_max;一般来说 buffer_size = period_size * period_count,period_count 相当于处理完一个 buffer 数据所需的硬件中断次数。

为了通过系统调用ioctl()传递音频数据,定义了struct snd_xferi xx.buf指向本次要播放的音频数据,x.frames表示本次音频数据总共有多少帧(frame)。

Kernel Space

通过系统调用ioctl()传递数据到内核,在内核空间是PCM逻辑设备对应的snd_pcm_f_ops[0].unlocked_ioctl()

// ./kernel-3.10/sound/core/pcm_native.c, line 3481
const struct file_operations snd_pcm_f_ops[2] = {
   
    
	{
   
    
		.owner =		THIS_MODULE,
		.write =		snd_pcm_write,
        ......
		.unlocked_ioctl =	snd_pcm_playback_ioctl,
        ......
	},
	{
   
    
		.owner =		THIS_MODULE,
		.read =			snd_pcm_read,
        ......
		.unlocked_ioctl =	snd_pcm_capture_ioctl,
        ......
	}
};

snd_pcm_playback_ioctl() 直接调用了snd_pcm_playback_ioctl1()

// ./kernel-3.10/sound/core/pcm_native.c, line 2784
static long snd_pcm_playback_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
   
    
	struct snd_pcm_file *pcm_file;
	pcm_file = file->private_data;
    ......
	return snd_pcm_playback_ioctl1(file, pcm_file->substream, cmd, (void __user *)arg);
}

snd_pcm_playback_ioctl1()函数:
a. 定义struct snd_xferi xferi,为了获取用户空间传来的arg;
b. 调用put_user() 清除snd_xferi.result状态;
c. 调用copy_from_user()将取用户空间的arg拷贝到内核空间,即拷贝音频数据存储空间的指针buf和音频数据帧数frames;
d. 调用snd_pcm_lib_write()
e. 调用put_user() 回填write结果_xferi->result。

// ./kernel-3.10/sound/core/pcm_native.c, line 2624
static int snd_pcm_playback_ioctl1(struct file *file, struct snd_pcm_substream *substream, unsigned int cmd, void __user *arg)
{
   
    
    ......
	switch (cmd) {
   
    
	case SNDRV_PCM_IOCTL_WRITEI_FRAMES:
	{
   
    
		struct snd_xferi xferi;
		struct snd_xferi __user *_xferi = arg;
		struct snd_pcm_runtime *runtime = substream->runtime;
		snd_pcm_sframes_t result;
		if (runtime->status->state == SNDRV_PCM_STATE_OPEN)
			return -EBADFD;
		if (put_user(0, &_xferi->result))
			return -EFAULT;
		if (copy_from_user(&xferi, _xferi, sizeof(
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/yangjizhen1533/article/details/114576914

智能推荐

几何光学学习笔记(4)- 2.2 单个折射球面的各种成像倍率以及拉赫不变量-程序员宅基地

文章浏览阅读3.4k次。几何光学学习笔记(3)- 2.2 单个折射球面的各种成像倍率以及拉赫不变量1.垂轴倍率b2.轴向倍率a3.角倍率4.三个倍率间的关系5. 拉格朗日赫姆霍兹不变量(拉霍不变量)1.垂轴倍率b垂轴小线段通过单个球面成像。由三角形相似可得:−y′y=l′−r−l+r{- {{y'}\over{y}}}={{l'-r}\over{-l+r}}−yy′​=−l+rl′−r​垂轴倍率:b=y′y=l′−rl−r=nl′n′lb={y' \over y}={{l'-r}\over{l-r}}={{nl'_拉赫不变量

inner join 与 left join 之间的区别_innerjoin和leftjoin区别-程序员宅基地

文章浏览阅读1.8k次,点赞2次,收藏6次。关于inner join用法;_innerjoin和leftjoin区别

Node.js毕业设计航空订票系统(Express+附源码)_机票预订系统毕业设计-程序员宅基地

文章浏览阅读874次,点赞10次,收藏16次。同时,对于航空公司而言,一个优秀的航空订票系统可以提高其服务质量,吸引更多的用户,从而提高自身的竞争力。因此,开发一个基于现代Web技术的航空订票系统,不仅可以满足用户的需求,还可以为航空公司带来更好的经济效益。此外,通过实践开发航空订票系统,可以锻炼学生的编程能力、团队协作能力和项目实战经验,为学生今后的职业生涯打下坚实的基础。因此,开发一个基于前端技术HTML+CSS+JavaScript+Vue和后端技术Node.js+Express的航空订票系统,具有很高的实用价值。2. 框架:Express。_机票预订系统毕业设计

Android-高级-UI-进阶之路-(七)-SVG-基础使用-+-绘制中国地图_地图svg文件-程序员宅基地

文章浏览阅读595次,点赞27次,收藏22次。在这里我和身边一些朋友特意整理了一份快速进阶为Android高级工程师的系统且全面的学习资料。涵盖了Android初级——Android高级架构师进阶必备的一些学习技能。附上:我们之前因为秋招收集的二十套一二线互联网公司Android面试真题(含BAT、小米、华为、美团、滴滴)和我自己整理Android复习笔记(包含Android基础知识点、Android扩展知识点、Android源码解析、设计模式汇总、Gradle知识点、常见算法题汇总。_地图svg文件

codevs 1995 黑魔法师之门_vscode gong;lue-程序员宅基地

文章浏览阅读385次。题目描述 Description   经过了16个工作日的紧张忙碌,未来的人类终于收集到了足够的能源。然而在与Violet星球的战争中,由于Z副官的愚蠢,地球的领袖applepi被邪恶的黑魔法师Vani囚禁在了Violet星球。为了重启Nescafe这一宏伟的科技工程,人类派出了一支由XLk、Poet_shy和lydrainbowcat三人组成的精英队伍,穿越时空隧道,去往Violet星球拯救领袖_vscode gong;lue

Navicat通过ssh通道连接Mysql数据库_mysql ssh通道连接-程序员宅基地

文章浏览阅读3.6k次,点赞2次,收藏2次。出于数据库的安全性,数据库管理员在配置数据库时会为数据库增加一层“保护伞”,保护用户在连接数据库时的安全和信息不被泄漏,通常的做法就是配置SSH,也就是为数据库增加一个安全协议,这也导致了用户进行远程连接时的困难。可以利用SSH通道来连接远程的Mysql输入服务器ip,端口、账号和密码主机:输入数据库连接地址、用户名:输入授权数据库访问账号、密码:输入数据库访问密码接下来就可以访问数据..._mysql ssh通道连接

随便推点

在swift3.0使用Alamofire-程序员宅基地

文章浏览阅读44次。在项目里新建Podfile文件:source 'https://github.com/CocoaPods/Specs.git'platform :ios, '10.0'use_frameworks!target 'ala03' do pod 'Alamofire', '~> 4.4'end执行pod install代码示例//直接从某个url获取数据 ..._swift almote

selenium点击悬停元素_selenium悬停元素下的内容-程序员宅基地

文章浏览阅读2.2k次。以百度首页的设置为例:鼠标悬停后会出现一个列表代码实现点击列表中的“高级搜索”这个功能#!/usr/bin/env python# -*- coding: utf-8 -*-from selenium.webdriver.common.action_chains import ActionChainsfrom selenium import webdriverfrom selenium.webdriver.support.wait import WebDriverWaitfrom ._selenium悬停元素下的内容

arch linux 安装 键盘,Arch Linux安装-程序员宅基地

文章浏览阅读170次。关键步骤总结:systemctl disable lightdm 关闭X的登陆, 使用start命令可以启动图形界面systemctl enable sshd#禁止服务节省机器资源systemctl disable lvm2-monitor.service编辑配置文件 /etc/pacman.conf[archlinuxcn]Server = https://mirrors.tuna.tsing..._aarch linux 软键盘

linux 蓝牙编程avrcp,bluetooth(蓝牙) AVRCP协议概念及代码流程解析-程序员宅基地

文章浏览阅读2.2k次。一 概念AVRCP全称:The Audio/Video Remote Control Profile (AVRCP) 翻译成中文就是:音视频远程控制协议。概念:AVRCP定义了蓝牙设备之间的音视频传输的特点和流程,来确保不同蓝牙设备之间音视频传输控制的兼容。一般包括暂停,停止,播放,音量控制等远程控制操作。例如,使用蓝牙耳机可以暂停,切换下一曲等操作来控制音乐播放器。基本角色:avrcp是两个设备..._bluez avrcp编程

curl命令上传下载文件_curl 带token下载文件-程序员宅基地

文章浏览阅读5.4w次,点赞8次,收藏27次。转载自:http://www.cnblogs.com/gbyukg/p/3326825.html下载单个文件,默认将输出打印到标准输出中(STDOUT)中curl http://www.centos.org通过-o/-O选项保存下载的文件到指定的文件中:-o:将文件保存为命令行中指定的文件名的文件中-O:使用URL中默认的文件名保存文件到本地# 将文件下载到本地并命名_curl 带token下载文件

Linux基础04(Linux常用命令)_psrtee-程序员宅基地

文章浏览阅读162次。Linux常用命令第四章、Linux常用命令1.基础操作命令1. man2. touch & mkdir3. cp & mv4. find5. grep&管道命令6. wc7. su8. 关机&重启命令9. 系统运行级别&runleve2.文件编辑命令vi1. 三种模式介绍与切换2. 命令模式下常用的命令3. 末行模式下常用的操作3.文件查看命令1. cat..._psrtee