平台:ubuntu 16.04,kernel版本是4.15.0, 理论任何平台都可以,甚至是android,只要能编译通过。

需要完成的功能:前几篇文章完成了播放/录音功能,声卡驱动就这样完成了吗?某种意义上讲是完成了,但是如果需要控制音量怎么办?这里加一个kcontrol,实现音量控制功能。

目的:就像做数学题一样,看一遍答案,以为自己看懂了,就会了,非也,真到自己去做时,不一定能做出来。那就在自己的驱动里实现一遍。

本文只追求应用,不讲原理。想了解细节可以看官方文档或者看https://blog.csdn.net/droidphone/category_1118446.html。

步骤1:定义snd_kcontrol_new

static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -11925, 75, 0);static const struct snd_kcontrol_new vcodec_codec_controls[] = {SOC_DOUBLE_TLV("DAC volume", VCODEC_DAC_VOL_CTRL, DAC_VOL_L, DAC_VOL_R,0xFF, 0, dac_vol_tlv),
};

这里定义了个数组,成员是snd_kcontrol_new。

SOC_DOUBLE_TLV是一个宏,作用就是填充snd_kcontrol_new,如下:

代码位置:include/sound/soc.h

#define SOC_DOUBLE_TLV(xname, reg, shift_left, shift_right, max, invert, tlv_array) \
{   .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\.access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\SNDRV_CTL_ELEM_ACCESS_READWRITE,\.tlv.p = (tlv_array), \.info = snd_soc_info_volsw, .get = snd_soc_get_volsw, \.put = snd_soc_put_volsw, \.private_value = SOC_DOUBLE_VALUE(reg, shift_left, shift_right, \max, invert, 0) }

参数说明:

  • iface:控件类型,一般是SNDRV_CTL_ELEM_IFACE_XXX,对于mixer就是SNDRV_CTL_ELEM_IFACE_MIXER,对于不属于mixer的全局控制,使用CARD;如果关联到某类设备,则是PCM、RAWMIDI、TIMER或SEQUENCER;

  • name:控件的名字;

  • access:访问权限,SNDRV_CTL_ELEM_ACCESS_TLV_READ就是只读读权限,SNDRV_CTL_ELEM_ACCESS_READWRITE就是读写权限;

  • tlv.p:用来描述寄存器的设定值与它所代表的实际意义之间的映射关系,最常用的就是用于音量控件时,设定值与对应的dB值之间的映射关系,比如这里定义的:

    static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -11925, 75, 0);
    

    DECLARE_TLV_DB_SCALE是一个宏定义,它所代表的值按一个固定的dB值的步长变化,第一个参数是要定义变量的名字,第二个参数是最小值,以0.01dB为单位。第三个参数是变化的步长,也是以0.01dB为单位。如果该control处于最小值时会做出mute时,需要把第四个参数设为1;

    什么意思呢?

    寄存器的最小值对应是-119.25dB,寄存器每增加一,对应的dB数增加是0.75dB(0.01dB*75);由上可知,该控件可设置的最大值为0xFF,所以dB的数值范围是-119.25dB ~ -119.25+255*0.75dB;

  • info:一个回调函数,作用就是获取该控件的信息;

  • get:一个回调函数,作用就是获取控件对应寄存器的值;

  • put:一个回调函数,作用就是设置控件对应寄存器的值;

  • private_value:私有数据,这是给上面3个回调函数传参的,看一下它的参数:

    • reg:该控件对应的寄存器的地址;

    • shift_left:左声道控制位在寄存器中的位移;

    • shift_right:右声道控制位在寄存器中的位移;

    • max:控件可设置的最大值;

    • invert:设定值是否逻辑取反;

另外,SOC_DOUBLE_TLV是控制双声道音量,单声道可用SOC_SINGLE_TLV

到这你可能会有以下问题:

问题一:我们实现的是虚拟声卡,哪来的寄存器?

没错,我们要实现的是不涉及硬件操作的虚拟声卡,但是kcontrol是要操作寄存器的,怎么办呢?这么办:

先定义一些寄存器,如下:

enum reg {VCODEC_DAC_VOL_CTRL,VCODEC_CTRL_NUM
};

然后定义个数组,如下:

static u32 reg_data[VCODEC_CTRL_NUM];

这个数据就是虚拟出来的寄存器了,u32类型占4字节,所以还是32位的寄存器。

问题二:snd_soc_get_volsw()/snd_soc_put_volsw()都不是我们自己定义的寄存器,怎么操作寄存器?

一般编解码芯片跟主控是通过I2C、USB等接口传递控制参数,asoc-core层是不知道的,也不关心,当它需要传递控制参数时,就调用codec的read/weite函数。所以snd_soc_get_volsw()/snd_soc_put_volsw()最终调用的是snd_soc_codec_driver里的read/write函数来操作寄存器, 定义如下:

static struct snd_soc_codec_driver soc_vcodec_drv = {....read = vcodec_reg_read,.write = vcodec_reg_write,...
};

vcodec_reg_read/vcodec_reg_write实现对寄存器(reg_data)的读写操作。

步骤2:注册

ret = snd_soc_add_codec_controls(codec, vcodec_codec_controls,ARRAY_SIZE(vcodec_codec_controls));

vcodec_codec_controls的成员最终会注册到card的controls链表中,看一下调用流程:

snd_soc_add_codec_controls() -->snd_soc_add_component_controls -->snd_soc_add_controls -->for (i = 0; i < num_controls; i++) //for循环注册每一个controlconst struct snd_kcontrol_new *control = &controls[i];//将kcontrol注册到card的controls链表中,data就是codec//snd_soc_cnew()函数将kcontrol_new转换成kcontrolerr = snd_ctl_add(card, snd_soc_cnew(control, data,control->name, prefix));}

步骤3:测试

在ubuntu下测试需要另外安装驱动,如下:

sudo insmod /lib/modules/4.15.0-112-generic/kernel/sound/core/snd-compress.ko
sudo insmod /lib/modules/4.15.0-112-generic/kernel/sound/core/snd-pcm-dmaengine.ko
sudo insmod /lib/modules/4.15.0-112-generic/kernel/sound/soc/snd-soc-core.ko

为什么是/lib/modules/4.15.0-112-generic/kernel/sound/core/这个目录,请看前几篇文章。

然后安装我们的驱动

sudo insmod vplatform.ko
sudo insmod vcodec.ko
sudo insmod vmachine.ko

如果你是在开发板上测试,就不需要这么麻烦,直接安装驱动

安装完驱动之后,就可以看到自己的声卡,如下:

vbox@vbox-pc:~$ aplay -l
**** List of PLAYBACK Hardware Devices ****
card 0: I82801AAICH [Intel 82801AA-ICH], device 0: Intel ICH [Intel 82801AA-ICH]Subdevices: 1/1Subdevice #0: subdevice #0
card 1: mycodec [my-codec], device 0: MY-CODEC vcodec_dai-0 []Subdevices: 1/1Subdevice #0: subdevice #0

可见我们注册的是card 1,ubuntu本身有自己的声卡,再看看自己注册的controls

vbox@vbox-pc:~$ amixer -D hw:1 contents
numid=1,iface=MIXER,name='DAC volume'; type=INTEGER,access=rw---R--,values=2,min=0,max=255,step=0: values=50,60| dBscale-min=-119.25dB,step=0.75dB,mute=0

ps:如果你是在android下测试,就用tinymix命令。

同样可以使用以下命令看当前音量值

vbox@vbox-pc:~$ amixer -D hw:1 cget numid=1
numid=1,iface=MIXER,name='DAC volume'; type=INTEGER,access=rw---R--,values=2,min=0,max=255,step=0: values=50,60| dBscale-min=-119.25dB,step=0.75dB,mute=0

设置一下音量

vbox@vbox-pc:~$ amixer -D hw:1 cset numid=1 30,40
numid=1,iface=MIXER,name='DAC volume'; type=INTEGER,access=rw---R--,values=2,min=0,max=255,step=0: values=30,40| dBscale-min=-119.25dB,step=0.75dB,mute=0

就那么简单,完事。

代码

代码位置:https://codechina.csdn.net/u014056414/myalsa

后续会增加其他的功能,完成本文的提交是: 8.加一个kcontrol, 模拟音量控制

初学者可以按照此提交学习,以免新提交干扰。

8.声卡驱动05-自己实现alsa驱动-虚拟声卡-kcontrol相关推荐

  1. ubuntu14.04安装oss音频驱动,替换掉alsa驱动

    环境: ubuntu14.04 64位 前言: 由于不知道怎么操作alsa驱动下的音频设备,所以使用oss替换掉alsa.替换之后,就可以使用open函数打开"/dev/dsp"设 ...

  2. 虚拟服务器声卡,如何使用虚拟声卡?虚拟声卡安装教程!

    在没有声卡的机器上播放音频和视频文件时,将出现诸如"找不到音频设备"的提示,并且无法播放. 虚拟声卡是一种软件的名称,可用于在没有声卡的机器上实现诸如声音回放之类的功能. 如何使用 ...

  3. 用ALSA驱动声卡流程详解

    作者:北南南北 来自:LinuxSir.Org 提要:目前大多数发行版都已经支持主流声卡,声卡的驱动无非是用ALSA:本文主要讲述声卡驱动的流程:目的是帮助遇到声卡的驱动问题的弟兄来弄清楚解决问题的流 ...

  4. Linux ALSA驱动框架(一)--ALSA架构简介--声卡的创建

    (1)ALSA简介 (1) Native ALSA Application:tinyplay/tinycap/tinymix,这些用户程序直接调用 alsa 用户库接口来实现放音.录音.控制 ALSA ...

  5. Linux中用ALSA驱动声卡流程详解

    一.什么是ALSA : Advanced Linux Sound Architecture 的简称为 ALSA ,译成中文的意思是 Linux 高级声音体系(这是我直译的,可能译的不对):一谈到体系就 ...

  6. 使用最新 ALSA 驱动解决 UBUNTU LINUX INTEL 集成声卡问题

    刚开始学习alsa驱动,刚开始装就出现了一大堆问题,所以在网上找解决方案,看到一篇不错的文章,转载以供大家分享. 目前用户所抱怨的 Ubuntu 系列的声卡问题,基本上归结为几类:一,找不到声音设备: ...

  7. arm linux alsa驱动使用 usb 声卡

    这里写目录标题 一:添加alsa驱动 二:添加alsa-lib和alsa-utils 三:录音测试 四:播放测试 五:alsa 库文件与头文件 一:添加alsa驱动 alsa内核配置选项: 二:添加a ...

  8. arm linux免驱usb声卡,arm linux利用alsa驱动并使用usb音频设备

    一.背景: arm linux的内核版本是3.13.0 二.准备工作 添加alsa驱动到内核中,也就是在编译内核的时候加入以下选项: 接下来就重新编译内核即可 三.交叉编译alsa-lib和alsa- ...

  9. linux系统声卡安装教程,Linux系统下如何安装声卡驱动?

    装了几次Linux OS,当然也装了几次声卡驱动,一般来说都是安装ALSA(Adcance Linux Sound Architecture)驱动,多装几次以后就会发现非常的简单的. 首先,先决条件, ...

  10. alsa 驱动介绍及user层到hw层文件ioctl操作流程分析

    您当前位置:首页 > php开源 > 综合技术 > alsa 驱动介绍 alsa 驱动介绍 来源:程序员人生   发布时间:2016-07-02 13:40:22 阅读次数:6838 ...

最新文章

  1. 推荐几个BAT大佬的公众号
  2. php 多进程设置,php多进程操作的三个实例
  3. xshell远程连接自动断开的问题解决
  4. 5行代码可实现5倍Scikit-Learn参数调整的更快速度
  5. ASP.NET的ADO(ActiveX Data Objects)
  6. java实时解析mysql日志,利用maxwell 组件实时监听Mysql的Binlog日志,并且把解析的json格式数据发送到kafka窗口供实时消费...
  7. Java开发笔记(一百二十六)Swing的窗口
  8. 解决eclipse乱码问题
  9. 3.MNIST数据集分类
  10. xCat 批量安装系统
  11. UnionPay-银联支付-netcore(一)
  12. 概率论与统计:条件期望与最小二乘法
  13. 12306抢票软件相关接口以及数据格式
  14. 图像标注的基础内容介绍
  15. CSDN每日一练:蛇形矩阵
  16. python报错Ran out of input
  17. CMOS与TTL电路的区别
  18. 聊天室-界面-curses
  19. Python强大的自省机制
  20. iOS开发--音频播放、录音、视频播放、拍照、视频录制

热门文章

  1. JxBrowser 7 Crack 申请试用教程
  2. Red5流媒体服务器的搭建
  3. ETL工具——Taskctl Web应用篇
  4. C++程序设计一、二(二元一次方程与函数、函数指针)
  5. oracle 启动报错03113,oracle数据库无法启动,总报ora-03113错误
  6. 手机远程计算机桌面,win10系统下手机远程连接电脑桌面方法
  7. PDF怎么转换成PPT?用迅读PDF大师,轻松解决教案问题
  8. 药店管理系统/APP/小程序/网站
  9. 计算机毕业设计springboot门诊管理系统
  10. slqmf刀模工具_CAD刀模绘图插件|CAD刀模绘图插件(SLQMF刀模工具)下载v3.0 免费版 - 欧普软件下载...