音频开发

  • 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. windows time 服务无法启动 错误1058 解决方法
  2. python行业中性_市场风险中性假设的r0只是等效r的其中之一
  3. 二柱子2.0编程总结
  4. homework1: 印象深刻的错误
  5. SAP Spartacus Storefront页面的page layout config
  6. UVA719 Glass Beads 最小表示 / 后缀自动机
  7. Java SecurityManager getSecurityContext()方法与示例
  8. 3个提升Python运行速度的方法,很实用
  9. 4大华为云“安全镖局”秘密法宝揭秘
  10. C++数据结构02--链式线性表(单链表的实现)
  11. 了解OutOfMemoryError异常 - 深入Java虚拟机读后总结
  12. docker打包部署nginx,django应用
  13. RenderSettings 渲染设置
  14. RedHat 安装 CentOS yum
  15. mongodb driver c#语法
  16. collect2: error: ld returned 1 exit status
  17. android设备当广告屏使用方法,Android手机与电视无线HDMI同屏器使用教程
  18. lync 2013标准版安装
  19. 如何成为一名机器学习算法工程师?
  20. 开启京东自动化领京豆

热门文章

  1. Python-Django毕业设计房屋中介管理信息系统(程序+Lw)
  2. 个人博客html模板 百度云盘,个人博客模板源码神马百度轻量级原创博客网站模板...
  3. MATLAB代码:基于主从博弈理论的共享储能与综合能源微网优化运行研究
  4. 安装docker 并构建私有库
  5. 程序化广告定量评估收益指标——eCPM
  6. wgc84 笛卡尔_大地坐标系(WGS84)转空间直角坐标系(笛卡尔坐标系XYZ)
  7. 漫画赏析:Linux 内核到底长啥样
  8. 腾讯元老、上市公司CTO赚够钱后辞职到安徽农村隐居,亲手建造200亩农场
  9. 给准备自考本科想学汉语言专业的一些建议
  10. 教会大家—如何快速批量重命名文件