在移动设备中,Codec的作用可以归结为4种,分别是:

1.对PCM等信号进行D/A转换,把数字的音频信号转换为模拟信号
2.对Mic、Linein或者其他输入源的模拟信号进行A/D转换,把模拟的声音信号转变CPU能够处理的数字信号
3.对音频通路进行控制,比如播放音乐,收听调频收音机,又或者接听电话时,音频信号在codec内的流通路线是不一样的
4.对音频信号做出相应的处理,例如音量控制,功率放大,EQ控制等等

移动设备中的ALSA(ASoC)

ASoC–ALSA System on Chip ,是为了更好地支持嵌入式处理器和移动设备中的音频Codec的一套软件体系。ASoC不能单独存在,它建立在标准ALSA驱动之上,必须和标准的ALSA驱动框架相结合才能工作。

Machine

是指某一款机器,可以是某款设备,某款开发板,又或者是某款智能手机,由此可以看出Machine几乎是不可重用的,每个Machine上的硬件实现可能都不一样,CPU不一样,Codec不一样,音频的输入、输出设备也不一样,Machine为CPU、Codec、输入输出设备提供了一个载体.

Platform (Soc)

一般是指某一个SoC平台,比如pxaxxx,s3cxxxx,omapxxx等等,与音频相关的通常包含该SoC中的时钟、DMA、I2S、PCM等等,只要指定了SoC,那么我们可以认为它会有一个对应的Platform,它只与SoC相关,与Machine无关,这样我们就可以把Platform抽象出来,使得同一款SoC不用做任何的改动,就可以用在不同的Machine中.实际上,把Platform认为是某个SoC更好理解.

Codec

字面上的意思就是编解码器,Codec里面包含了I2S接口、D/A、A/D、Mixer、PA(功放),通常包含多种输入(Mic、Line-in、I2S、PCM)和多个输出(耳机、喇叭、听筒,Line-out),Codec和Platform一样,是可重用的部件,同一个Codec可以被不同的Machine使用.嵌入式Codec通常通过I2C对内部的寄存器进行控制.

在软件层面, ASoC也把嵌入式设备的音频系统同样分为3大部分, Machine, Platform和Codec

Machine驱动:

跟单板相关,绑定Platform和Codec驱动,即表明使用的是哪个Platform,哪个CPU DAI、DMA、Codec和Codec DAI。

Platform驱动:

它包含了该SoC平台的音频DMA和音频接口DAI的配置和控制( I2S, PCM等等), (DAI: Digital Audio Interface)

Codec驱动:

它包含了一些音频的控件( Controls),音频接口, DAMP(动态音频电源管理)的定义和某些Codec IO功能。所有的Codec驱动都要提供以下特性:
Codec DAI 和 PCM的配置信息;
Codec的IO控制方式( I2C, SPI等);
Mixer和其他的音频控件;
Codec的ALSA音频操作接口;

ASoC把声卡实现为一个Platform Device,然后利用Platform_device结构中的dev字段:dev.drvdata,它实际上指向一个snd_soc_device结构.可以认为snd_soc_device是整个ASoC数据结构的根本,

snd_soc_device结构引出了snd_soc_card
snd_soc_card又引出了snd_soc_platform、snd_soc_dai_link和snd_soc_codec结构
,
**snd_soc_card代表着Machine驱动,
snd_soc_platform则代表着Platform驱动,
snd_soc_codec和soc_codec_device则代表了Codec驱动,**

而snd_soc_dai_link则负责连接Platform和Codec.

ASoC架构中的Machine

Machine驱动,结构alc5623_card, 里面包含dai_link。

Machine驱动在一个重要的数据结构snd_soc_dai_link中,指定了Platform、 Codec、 codec_dai、 cpu_dai的名字,稍后Machine驱动将会利用这些名字去匹配已经在系统中注册的platform, codec, dai,这些注册的部件都是在另外相应的Platform驱动和Codec驱动的代码文件中定义的,这样看来, Machine驱动的设备初始化代码无非就是选择合适Platform和Codec以及dai,用他们填充以上几个数据结构,然后注册Platform设备即可。

ASoC的platform_driver在以下文件中定义:sound/soc/soc-core.c。
ASoC定义了三个全局的链表头变量:codec_list、dai_list、platform_list,系统中所有的Codec、DAI、Platform都在注册时连接到这三个全局链表上

  1. platform总线会匹配这两个名字相同的device和driver,同时会触发soc_probe( alc5623_probe())的调用,它正是整个ASoC驱动初始化的入口。

  2. 在soc_probe函数中会完成以下任务:
    调用标准的alsa函数创建声卡实例 (定义 alc5623_card ,注册 snd_soc_register_card))

  3. 挨个调用了codec, dai和platform驱动的probe函数

  4. 调用了soc_new_pcm()函数用于创建标准alsa驱动的pcm逻辑设备
  5. 最后则是调用标准alsa驱动的声卡注册函数对声卡进行注册
static struct snd_soc_dai_link alc5623_dai_link = {.name           = "ASOC-alc5623",.stream_name    = "alc5623 HiFi",.cpu_dai_name   = DEV_NAME_I2S,         /* nxp_snd_i2s_driver name */.platform_name  = DEV_NAME_PCM,         /* nxp_snd_pcm_driver name */.codec_dai_name = "alc5621-hifi",       /* alc5623_dai's name */.codec_name     = "alc562x-codec.0-001a",       /* alc5623_i2c_driver name + '.' + bus + '-' + address(7bit) */.ops            = &alc5623_ops,.symmetric_rates = 1,.init           = alc5623_dai_init,.ops            = &alc5623_ops,
};static struct snd_soc_card alc5623_card = {.name           = "I2S-alc5623",        /* proc/asound/cards */.owner          = THIS_MODULE,.dai_link       = &alc5623_dai_link,.num_links      = 1,.suspend_pre    = &alc5623_suspend_pre,.resume_pre     = &alc5623_resume_pre,.resume_post    = &alc5623_resume_post,
};

ASoC架构中的Codec 是一个i2c_driver

描述Codec的最主要的几个数据结构分别是:
snd_soc_codec_driver,snd_soc_dai_driver

确定snd_soc_codec_driver和snd_soc_dai-driver的实例,并把它们注册到系统中,注册后的codec和dai才能为Machine驱动所用

其中的snd_soc_dai和snd_soc_dai_driver在ASoC的Platform驱动中也会使用到, Platform和Codec的DAI通过snd_soc_dai_link结构,在Machine驱动中进行绑定连接。

Codec驱动的步骤:
定义snd_soc_codec_driver和snd_soc_dai_driver的实例,然后调用snd_soc_register_codec函数对Codec进行注册。

static struct snd_soc_dai_driver alc5632_dai = {.name = "alc5632-hifi",.playback = {.stream_name = "HiFi Playback",.channels_min = 1,.channels_max = 2,.rate_min = 8000,.rate_max = 48000,.rates = SNDRV_PCM_RATE_8000_48000,.formats = ALC5632_FORMATS,},.capture = {.stream_name = "HiFi Capture",.channels_min = 1,.channels_max = 2,.rate_min = 8000,.rate_max = 48000,.rates = SNDRV_PCM_RATE_8000_48000,.formats = ALC5632_FORMATS,},.ops = &alc5632_dai_ops,.symmetric_rates = 1,
};static struct snd_soc_codec_driver soc_codec_device_alc5632 = {.probe = alc5632_probe,.remove = alc5632_remove,.suspend = alc5632_suspend,.resume = alc5632_resume,.set_bias_level = alc5632_set_bias_level,.controls = alc5632_snd_controls,.num_controls = ARRAY_SIZE(alc5632_snd_controls),.dapm_widgets = alc5632_dapm_widgets,.num_dapm_widgets = ARRAY_SIZE(alc5632_dapm_widgets),.dapm_routes = alc5632_dapm_routes,.num_dapm_routes = ARRAY_SIZE(alc5632_dapm_routes),
};ret = snd_soc_register_codec(&client->dev,&soc_codec_device_alc5632, &alc5632_dai, 1);

在snd_soc_register_codec函数中,
传入参数snd_soc_codec_driver和snd_soc_dai_driver, 并创建snd_soc_codec和snd_soc_dai。
它申请了一个snd_soc_codec结构的实例:确定codec的名字,这个名字很重要, Machine驱动定义的snd_soc_dai_link中会指定每个link的codec和dai的名字,进行匹配绑定时就是通过和这里的名字比较(”alc5623-hifi”),从而找到该Codec的!然后初始化snd_soc_codec结构的各个字段,多数字段的值来自上面定义的snd_soc_codec_driver的实例。
通过snd_soc_register_dais函数对本Codec的dai进行注册
在snd_soc_register_dais函数中为每个snd_soc_dai实例分配内存,确定dai的名字,用snd_soc_dai_driver实例的字段对它进行必要初始化
最后,它把codec实例链接到全局链表codec_list中,把dai链接到全局链表dai_list中,并且调snd_soc_instantiate_cards函数触发Machine驱动进行一次匹配绑定操作

/* SoC Audio Codec device */
struct snd_soc_codec {  const char *name;  /* Codec的名字*/  struct device *dev; /* 指向Codec设备的指针 */  const struct snd_soc_codec_driver *driver; /* 指向该codec的驱动的指针 */  struct snd_soc_card *card;    /* 指向Machine驱动的card实例 */  int num_dai; /* 该Codec数字接口的个数,目前越来越多的Codec带有多个I2S或者是PCM接口 */    /* runtime */  ......  /* codec IO */  void *control_data; /* 该指针指向的结构用于对codec的控制,通常和read,write字段联合使用 */  enum snd_soc_control_type control_type;/* 可以是SND_SOC_SPI,SND_SOC_I2C,SND_SOC_REGMAP中的一种 */  unsigned int (*read)(struct snd_soc_codec *, unsigned int);  /* 读取Codec寄存器的函数 */  int (*write)(struct snd_soc_codec *, unsigned int, unsigned int);  /* 写入Codec寄存器的函数 */  /* dapm */  struct snd_soc_dapm_context dapm;  /* 用于DAPM控件 */
};
/* codec driver */
struct snd_soc_codec_driver {  /* driver ops */  int (*probe)(struct snd_soc_codec *);  /* codec驱动的probe函数,由snd_soc_instantiate_card回调 */  int (*remove)(struct snd_soc_codec *);    int (*suspend)(struct snd_soc_codec *);  /* 电源管理 */  int (*resume)(struct snd_soc_codec *);  /* 电源管理 */
....
}/*  * Digital Audio Interface runtime data.  *  * Holds runtime data for a DAI.  */
struct snd_soc_dai {  const char *name;  /* dai的名字 */  struct device *dev;  /* 设备指针 */  /* driver ops */  struct snd_soc_dai_driver *driver;  /* 指向dai驱动结构的指针 */  /* DAI runtime info */  unsigned int capture_active:1;      /* stream is in use */  unsigned int playback_active:1;     /* stream is in use */  /* DAI DMA data */  void *playback_dma_data;  /* 用于管理playback dma */  void *capture_dma_data;  /* 用于管理capture dma */  /* parent platform/codec */  union {  struct snd_soc_platform *platform;  /* 如果是cpu dai,指向所绑定的平台 */  struct snd_soc_codec *codec;  /* 如果是codec dai指向所绑定的codec */  };  struct snd_soc_card *card;  /* 指向Machine驱动中的crad实例 */
};  /*  * Digital Audio Interface Driver.  *  * Describes the Digital Audio Interface in terms of its ALSA, DAI and AC97  * operations and capabilities. Codec and platform drivers will register this  * structure for every DAI they have.  *  * This structure covers the clocking, formating and ALSA operations for each  * interface.  */
struct snd_soc_dai_driver {  /* DAI description */  const char *name;  /* dai驱动名字 */  /* DAI driver callbacks */  int (*probe)(struct snd_soc_dai *dai);  /* dai驱动的probe函数,由snd_soc_instantiate_card回调 */  int (*remove)(struct snd_soc_dai *dai);    int (*suspend)(struct snd_soc_dai *dai);  /* 电源管理 */  int (*resume)(struct snd_soc_dai *dai);    /* ops */  const struct snd_soc_dai_ops *ops;  /* 指向本dai的snd_soc_dai_ops结构 */  /* DAI capabilities */  struct snd_soc_pcm_stream capture;  /* 描述capture的能力 */  struct snd_soc_pcm_stream playback;  /* 描述playback的能力 */
};  
soc-core.c
int snd_soc_register_codec(struct device *dev,const struct snd_soc_codec_driver *codec_drv,struct snd_soc_dai_driver *dai_drv,int num_dai)
{size_t reg_size;struct snd_soc_codec *codec;int ret, i;dev_dbg(dev, "codec register %s\n", dev_name(dev));codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);if (codec == NULL)return -ENOMEM;/* create CODEC component name */codec->name = fmt_single_name(dev, &codec->id);if (codec->name == NULL) {kfree(codec);return -ENOMEM;}if (codec_drv->compress_type)codec->compress_type = codec_drv->compress_type;elsecodec->compress_type = SND_SOC_FLAT_COMPRESSION;codec->write = codec_drv->write;codec->read = codec_drv->read;codec->volatile_register = codec_drv->volatile_register;codec->readable_register = codec_drv->readable_register;codec->writable_register = codec_drv->writable_register;codec->ignore_pmdown_time = codec_drv->ignore_pmdown_time;codec->dapm.bias_level = SND_SOC_BIAS_OFF;codec->dapm.dev = dev;codec->dapm.codec = codec;codec->dapm.seq_notifier = codec_drv->seq_notifier;codec->dapm.stream_event = codec_drv->stream_event;codec->dev = dev;codec->driver = codec_drv;codec->num_dai = num_dai;mutex_init(&codec->mutex);/* allocate CODEC register cache */if (codec_drv->reg_cache_size && codec_drv->reg_word_size) {reg_size = codec_drv->reg_cache_size * codec_drv->reg_word_size;codec->reg_size = reg_size;/* it is necessary to make a copy of the default register cache* because in the case of using a compression type that requires* the default register cache to be marked as __devinitconst the* kernel might have freed the array by the time we initialize* the cache.*/if (codec_drv->reg_cache_default) {codec->reg_def_copy = kmemdup(codec_drv->reg_cache_default,reg_size, GFP_KERNEL);if (!codec->reg_def_copy) {ret = -ENOMEM;goto fail;}}}if (codec_drv->reg_access_size && codec_drv->reg_access_default) {if (!codec->volatile_register)codec->volatile_register = snd_soc_default_volatile_register;if (!codec->readable_register)codec->readable_register = snd_soc_default_readable_register;if (!codec->writable_register)codec->writable_register = snd_soc_default_writable_register;}for (i = 0; i < num_dai; i++) {fixup_codec_formats(&dai_drv[i].playback);fixup_codec_formats(&dai_drv[i].capture);}/* register any DAIs */if (num_dai) {ret = snd_soc_register_dais(dev, dai_drv, num_dai);if (ret < 0)goto fail;}mutex_lock(&client_mutex);list_add(&codec->list, &codec_list);snd_soc_instantiate_cards();mutex_unlock(&client_mutex);

ASoC架构中的Platform

Platform驱动的主要作用是完成音频数据的管理,最终通过CPU的数字音频接口( cpu_dai)把音频数据传送给Codec进行处理,最终由Codec输出驱动耳机或者是喇叭的音信信号。

在具体实现上, ASoC有把Platform驱动分为两个部分: snd_soc_platform_driver和snd_soc_dai_driver。其中, platform_driver负责管理音频数据,把音频数据通过dma或其他操作传送至cpu dai中, dai_driver则主要完成cpu一侧的dai的参数配置,同时也会通过一定的途径把必要的dma等参数与snd_soc_platform_driver进行交互。

snd_soc_platform_driver

platform驱动一般平台相关(nxp-pcm.c)

driver:
ASoC把snd_soc_platform_driver注册为一个系统的platform_driversnd_soc_register_platform()
device:
platform_device_register(&pcm_device);
dai_driver

主要完成cpu一侧的dai的参数配置
cpu dai 驱动也定义为platform_device
dai驱动通常对应cpu的一个或几个I2S/PCM接口

driver:
nxp-i2s.c platform_driver_register(&i2s_driver);

定义一个snd_soc_dai_driver结构的实例;
在对应的platform_driver中的probe回调中通过API:snd_soc_register_dai或者snd_soc_register_dais,注册snd_soc_dai实例;
实现snd_soc_dai_driver结构中的probe、suspend等回调;
实现snd_soc_dai_driver结构中的snd_soc_dai_ops字段中的回调函数;

device : S5p4418/Devices.c   platform_device i2s_device_ch0 ....

Audio Codec相关推荐

  1. Free Lossless Audio Codec

    Free Lossless Audio Codec  http://blog.csdn.net/ytang_/article/details/75268455 1. 简介 FLAC是一套著名的自由音频 ...

  2. Apple Lossless Audio Codec 苹果无损音频解码器

    # 自从苹果开源了一系列的资源,我对苹果操作系统及相关工具非常感兴趣,就利用业务时间研究一下. Apple Open Source 包括: macOS Source macOS-forge Mac T ...

  3. Audio Codec介绍-6(音频设备的3种硬件接口--PCM,IIS和AC97)

    音频设备的3种硬件接口--PCM,IIS和AC97 一些Audio Codec中总是出现PCM字样,一直以为它是一种音频数据编码格式,但是越看Spec觉得越不像,赶紧到网上查了下,发现它是一种类似与I ...

  4. Audio Codec介绍

    Audio Codec的必要性 在理想状况下,对于录音过程,只需要将麦克风获取到的analog信号通过ADC转换为digital信号并存储即可,对于播放音过程,只需要将digital信号通过DAC转换 ...

  5. 视频播放器播放flv报错Flv: Unsupported audio codec idx: 7

    一.详细报错信息如下 [TransmuxingController] > DemuxException: type = CodecUnsupported, info = Flv: Unsuppo ...

  6. WM8960 audio codec

    私下转载,尊重原创:https://community.freescale.com/docs/DOC-106295 由 jimmychan 于 2015-7-12 下午8:17创建,最后由 jimmy ...

  7. 终于成功安装了 SigmaTel High Definition Audio CODEC 驱动

    自从上次重装了系统之后,SigmaTel High Definition Audio CODEC 设备驱动是中都没有装上去,被困扰时间长达几个月之久,看电影.听音乐都必须转到Linux下去才行,还好, ...

  8. 再谈关于我原来写的一篇博文《终于成功安装了 SigmaTel High Definition Audio CODEC 驱动》

    我许久之前写过一篇博文<终于成功安装了 SigmaTel High Definition Audio CODEC 驱动>.在写出来之后,许多朋友看过,或许真的帮有的朋友解决了问题,但是发表 ...

  9. CentOS + Asterisk + FreePBX ——支持蓝牙,AMR-NB audio codec

    CentOS + Asterisk + FreePBX --支持蓝牙,AMR-NB audio codec 配置前的软件包列表以及下载(或者到我个人的百度云网盘下载也可) 网盘地址:http://pa ...

最新文章

  1. Basic005. Intro to statistics basic terms统计名词介绍
  2. 清华校庆正当时,智能小车决赛日
  3. 浅析从小米造车背后探索小米集团的企业网络推广策略会有怎样的灿烂
  4. 【NLP】 理解NLP中网红特征抽取器Tranformer
  5. Apache常用配置项
  6. 未越狱设备提取数据_从三星设备中提取健康数据
  7. python软件下载3版本-Python 3.7.2和3.6.8版本发布下载,附更新说明
  8. Hadoop1.x HDFS系统架构
  9. 用数据追女神:追女生如同创业
  10. 写一个用矩形法求定积分的通用函数,分别求sinx,cosx,expx从0到1的定积分(指针方法处理)——C语言
  11. ObjectiveC基础教程(第2版)
  12. vmware 12 许可证秘钥
  13. 内存错误分析工具----asan(AddressSanitizer)的介绍和使用
  14. spring cloud系列eureka
  15. 中国3D打印软件市场现状分析及发展前景预测报告
  16. QEMU-KVM 安装方法
  17. 计算机连接无线网络的步骤,台式电脑连无线网步骤
  18. 大一计算机专业自我总结,计算机专业大学的毕业生自我鉴定
  19. linux系统做成iso镜像文件,如何在Linux系统中制作可启动img/iso镜像文件
  20. ai人工智能可以干什么_什么是情感AI,为什么要关心

热门文章

  1. 秒杀springboot——未来轻量级高性能的Java云原生微服务框架来啦
  2. 【单片机】继电器控制
  3. Git remote: error: this exceeds file size limit of 100.0 MB
  4. 算法学习笔记【1】:KMP 算法
  5. markdown 转 html c,STATA中的Markdown转换命令markstat
  6. 2019年总结回顾 ~ 开心!评上CSDN博客专家-100篇博文回顾人工智能的前行之路!
  7. ijkplayer使用ffmpeg为视频添加水印avfilter_graph_parse_ptr返回Invalid data found when processing input
  8. 爬取漫画网站漫画(爬虫学习)
  9. 北航计算机学院博士开题,关于硕士生、博士生开题报告的通知及规定-北航电子信息工程学院...
  10. 【方同学】是如何高效的使用IntelliJ IDEA