音频开发

  • Linux 音频架构
    • 音频架构图
    • Application层
      • 启动脚本顺序定义
      • 启动脚本书写
    • HAL层
    • kernel
      • machine
      • plarform
      • codec
  • openWRT 音频应用
  • 调试技术
    • 链路上应用层UDP截取文件
    • 链路上 alsa 截取文件
    • 链路上kernel 截取文件
  • 关注我们

Linux 音频架构

音视频的好坏 直接影响 产品体验

音频架构图

openWRT 采用 ALSA 层次图,如下

  1. Application: 上层应用 主要调用alsa-lib 中的接口 实现业务逻辑。使用alsa-util中aplay,arecord,amixer,speaker-test进行相关测试。
  2. HAL层 : 移植alsa-lib 和 alsa-utils. 在openwrt中 feeds 自带了alsa-lib 1.1.01
  3. kernel: 按照ALSA 驱动层进行适配。2

Application层

openwrt中应用启动需要自定义启动脚本,放在目录/etc/init.d 目录下。

启动脚本顺序定义

05 defconfig //加载默认参数
10 boot //启动
39 usb // 加载usbfs
40 network // 设置网卡参数
45 firewall // 防火墙
50 dropbear // sshd server
50 cron // …
50 telnet // 如果没有修改root密码,则启动telnet server
60 dnsmasq // DHCP 和 DNS 服务端
95 done // …
96 led // 指示灯
97 watchdog // …
99 sysctl // 最后,进行必要的内核参数调整

启动脚本书写

按照官方Wiki脚本3,进行自定制。

HAL层

这一层不需要做太多改动,需要配置feeds选择自己需要的版本即可,
具体的接口查询,可以到alsa-project4 查询。

kernel

根据ALSA驱动进行相关分析。

machine

/* SoC machine */
struct snd_soc_card {char *name;...int (*probe)(struct platform_device *pdev);int (*remove)(struct platform_device *pdev);/* the pre and post PM functions are used to do any PM work before and* after the codec and DAIs do any PM work. */int (*suspend_pre)(struct platform_device *pdev, pm_message_t state);int (*suspend_post)(struct platform_device *pdev, pm_message_t state);int (*resume_pre)(struct platform_device *pdev);int (*resume_post)(struct platform_device *pdev);.../* CPU <--> Codec DAI links  */struct snd_soc_dai_link *dai_link;int num_links;...
};

probe/remove 可选,主要侦测machine。
suspend/resume 在codec,DAIs和DMA suspend resume 会相应的触发,也是可选的
machine DAI口配置,配置对应的结构体

/*  digital audio interface glue - connects codec <--> CPU */
static struct snd_soc_dai_link corgi_dai = {.name = "WM8731",.stream_name = "WM8731",.cpu_dai_name = "pxa-is2-dai",.codec_dai_name = "wm8731-hifi",.platform_name = "pxa-pcm-audio",.codec_name = "wm8713-codec.0-001a",.init = corgi_wm8731_init,.ops = &corgi_ops,
};/* audio machine driver */
static struct snd_soc_card snd_soc_corgi = {.name = "Corgi",.dai_link = &corgi_dai,.num_links = 1,
};

plarform

DMA 驱动,Soc DAI 驱动5

/* SoC audio ops */ struct snd_soc_ops { int (*startup)(struct snd_pcm_substream *);void (*shutdown)(struct snd_pcm_substream *);int (*hw_params)(struct snd_pcm_substream *, struct snd_pcm_hw_params *); int (*hw_free)(struct snd_pcm_substream *);int (*prepare)(struct snd_pcm_substream *);int (*trigger)(struct snd_pcm_substream *, int); };
//平台驱动通过DMA接口关联起来
struct snd_soc_platform_driver { char *name;int (*probe)(struct platform_device *pdev);int (*remove)(struct platform_device *pdev);int (*suspend)(struct platform_device *pdev, struct snd_soc_cpu_dai *cpu_dai); int (*resume)(struct platform_device *pdev, struct snd_soc_cpu_dai *cpu_dai);/* pcm creation and destruction */int (*pcm_new)(struct snd_card *, struct snd_soc_codec_dai *, struct snd_pcm *); void (*pcm_free)(struct snd_pcm *);/** For platform caused delay reporting.* Optional.*/ snd_pcm_sframes_t (*delay)(struct snd_pcm_substream *, struct snd_soc_dai *);/* platform stream ops */struct snd_pcm_ops *pcm_ops;};

codec

每个codec codec 驱动必须具备以下功能5

  1. codec DAI 与 PCM 配置
  2. 使用I2C 或者SPI控制IO
  3. mixer audio 控制
  4. codec 音频操作
  5. DAPM 描述
  6. DAPM 事件处理
    可选
  7. DAC mute处理
// DAI PCM配置
static struct snd_soc_dai_ops wm8731_dai_ops = {.prepare   = wm8731_pcm_prepare,.hw_params    = wm8731_hw_params,.shutdown   = wm8731_shutdown,.digital_mute    = wm8731_mute,.set_sysclk  = wm8731_set_dai_sysclk,.set_fmt   = wm8731_set_dai_fmt, };
struct snd_soc_dai_driver wm8731_dai = { .name = "wm8731-hifi",.playback = { .stream_name = "Playback",.channels_min = 1,.channels_max = 2,.rates = WM8731_RATES,.formats = WM8731_FORMATS,},.capture = { .stream_name = "Capture",.channels_min = 1,.channels_max = 2,.rates = WM8731_RATES,.formats = WM8731_FORMATS,}, .ops = &wm8731_dai_ops,.symmetric_rates = 1, };

// i2c 控制 读写

i2c_write
i2c_read

// mixer audio control
codec 说有mixer与control都定义在soc.h中

 #define SOC_SINGLE(xname, reg, shift, mask, invert)
定义单一控制器:-xname  控制名称e.g. "Playback Volume"reg = codec registershift = control bit(s) offset in registermask = control bit size(s) e.g. mask of 7 = 3 bitsinvert = the control is inverted 是否反转其他宏包括: -#define SOC_DOUBLE (xname ,reg ,shift_left ,shift_right ,mask ,invert )
立体声控制#define SOC_DOUBLE_R (xname ,reg_left ,reg_right ,shift ,mask ,invert )
一个跨越2个寄存器的立体声控制#define SOC_ENUM_SINGLE (xreg ,xshift ,xmask ,xtexts )xreg = 寄存器XSHIFT = 控制位(小号)偏移在寄存器 xmask = 控制位(小号)大小xtexts = 指向描述每个设置的字符串数组的指针

//audio 控制操作

/* SoC audio ops */
struct snd_soc_ops { int (*startup)(struct snd_pcm_substream *);void (*shutdown)(struct snd_pcm_substream *);int (*hw_params)(struct snd_pcm_substream *, struct snd_pcm_hw_params *); int (*hw_free (struct snd_pcm_substream *);int (*prepare)(struct snd_pcm_substream *); };

//DAPM
//DAPM handler 参考5

openWRT 音频应用

上面一节介绍了音频框架。在openWRT音频业务主要VOIP通过 ,上/下行通过模块如下:

调试技术

链路上应用层UDP截取文件

知道UDP 下的G711A 对应的buffer

           // 应用层将buffer写到文件 代码块static struct file *file_g711a= NULL;int writelen = 0;if (NULL == fp){file_g711a= file_open("/test1", O_RDWR | O_CREAT, 0777);if(file_g711a == NULL){printf("g711a file  = NULL");}else{printf("g711a file open ok");}   }if(file_g711a != NULL){writelen = fwrite(g711a_buffer, 1, sizeof(g711a_buffer), file_g711a);}printk("writelen:%d\n",writelen);

链路上 alsa 截取文件

转换成PCM后,将对应的buffer 写道文件

           // 应用层将buffer写到文件 代码块static struct file *file_pcm= NULL;int writelen = 0;if (NULL == fp){file_pcm= file_open("/test.pcm", O_RDWR | O_CREAT, 0777);if(file_pcm == NULL){printf("pcm file  = NULL");}else{printf("pcm file open ok");}   }if(file_pcm != NULL){writelen = fwrite(pcm_buffer, 1, sizeof(pcm_buffer), file_pcm);}printk("writelen:%d\n",writelen);

链路上kernel 截取文件

在PCM与DMA通信的函数中 将buffer 写到文件中,

           // kernel 将buffer写到文件 代码块static struct file *fp = NULL;mm_segment_t fs;static loff_t pos = 0;printk("hello enter\n");if (NULL == fp){fp = filp_open("/test.pcm", O_RDWR | O_CREAT, 0777);if (IS_ERR(fp)){printk("create file error\n");return -1;}}fs = get_fs();set_fs(KERNEL_DS);int writelen = vfs_write(fp, buf, size*4, &pos);pos += size*4;printk("writelen:%d pos:%d\n",writelen, pos);

关注我们


  1. feeds ↩︎

  2. alsadriver ↩︎

  3. initscript ↩︎

  4. alsa-api ↩︎

  5. alsa-drvier ↩︎ ↩︎ ↩︎

智能路由器操作系统openwrt 之三 音频开发相关推荐

  1. 智能路由器操作系统OpenWrt

    小米路由器的"MiWiFi"又让路由器成了关键词,每台智能路由器的系统是该款产品的亮点之一,其系统肯定有不少"好玩"的地方.为自己的智能路由器量身打造系统,并且 ...

  2. 【智能路由器】openwrt创建用户软件包

    [智能路由器]系列文章连接 http://blog.csdn.net/u012819339/article/category/5803489 openwrt根目录 先看看openwrt初次编译好后的目 ...

  3. 【智能路由器】openwrt实现内网穿透(p2p、n2n)

    [智能路由器]系列文章连接 http://blog.csdn.net/u012819339/article/category/5803489 背景 有时候在对线上设备进行维护,由其是调试的时候希望技术 ...

  4. 【智能路由器】openwrt计划任务

    [智能路由器]系列文章连接 http://blog.csdn.net/u012819339/article/category/5803489 openwrt的计划任务可以让你的程序或脚本在特定的时间启 ...

  5. 【智能路由器】openwrt工具uci使用指南

    [智能路由器]系列文章连接 http://blog.csdn.net/u012819339/article/category/5803489 uci(Unified Configuration Int ...

  6. 《智能路由器开发指南》——第1章 智能路由器概述 1.1 OpenWrt简介

    本节书摘来自异步社区<智能路由器开发指南>一书中的第1章,第1.1节,作者 张永智,李章明,更多章节内容可以访问云栖社区"异步社区"公众号查看. 第1章 智能路由器概述 ...

  7. 《智能路由器开发指南》核心笔记(全)——转载的

    另外:  看     http://openwrt.bjbook.net/ 转载于:http://blog.csdn.net/sinat_36184075/article/details/722319 ...

  8. 《智能路由器开发指南》核心笔记(全)

    转载于:https://blog.csdn.net/sinat_36184075/article/details/72231970 [概述]2017.05.15 openWrt是实现智能路由器功能的最 ...

  9. 一文万字带你入门智能路由器OpenWrt系统,并在虚拟中安装配置OpenWrt

    一.什么是智能路由器 接入网络的家庭用户终端越来越多,路由器控制越来越复杂,因此需要一个智能网关来管理家庭的设备,智能路由器就是这个网关. 另外,这个智能网关直接连在互联网上,需要隔离家庭网和互联网的 ...

最新文章

  1. 12v60ah锂电池组装图_锂电池基本参数,结合电动自行车电池应用分析
  2. 5- vue django restful framework 打造生鲜超市 -完成商品列表页(上)
  3. 去掉烦人的“正在配置Windows”
  4. android hardware architecture
  5. java struts2上传文件_java Struts2框架下实现文件上传功能
  6. matlab光盘映像文件可以删除吗_DVD-Cloner 2020 for mac(DVD光盘刻录工具) 7.00.715
  7. 最新阿里聚划算Java 5轮面试题,涵盖GC收集器、多线程锁等
  8. django 1.8 官方文档翻译: 3-1-3 Django 的快捷函数
  9. Flink的窗口聚合操作(Time\Count Window)
  10. javascript的内置对象
  11. 项目分析:大学生个人财务管理系统的设计与实现
  12. python实现将文件下内每张图片按顺序命名为txt文本文件中的内容
  13. 腾讯“云+未来”峰会亮相山城,助力重庆成为数字中国新标杆
  14. 在PHP中2中特殊数据类型是,@PHP中的数据类型(2)
  15. python数据1-4
  16. C语言编程初体验 作文,我的理想是当编程师作文
  17. VC++实现镜像劫持(360保险箱启动原理)
  18. css手指代码,CSS3动画:通过Animation实现简单的手指点击动画
  19. 微信小程序开发者工具打不开的问题
  20. 如何设计淘宝天猫这种成功而有价值大数据可视化?

热门文章

  1. 03 Vue进阶extend使用方法详讲
  2. 计算机测试杀毒软件的代码,检测你电脑的杀毒软件时候到了 一段代码测试杀毒软件...
  3. 疾病研究:8岁男童成为美国首位接受基因治疗的杜氏进行性肌营养不良患者
  4. C++如何测试dll_Win7系统丢失libcurl.dll怎么办
  5. h5 + vant + ts展示pdf
  6. 水族箱泵市场深度研究分析报告
  7. java游戏开发入门(八) -图像
  8. SEO基础:什么是结构化数据?- WP站长
  9. android编译boost,使用android ndk编译boost动态库
  10. PySide2、nltk、wordcloud、gensim、sklearn、pyinstaller实现词嵌入可视化、绘制词云图、制作GUI并打包的踩坑总结