Kernel:
rk29_i2s.c i2s总线设备的驱动程序。
rk30有3个i2s总线设备,分别是定义在devices.c中的三个platform设备,i2s0 i2s1 i2s2,这三个设备在devices.c里面定义。并且在很早就开始加载,他们生成的platform_device设备节点分别是“rk29_i2s.0”、“rk29_i2s.1”、“rk29_i2s.2”。同时还加载了一个platform_device形式的pcm设备“rockchip-audio”。
dai
在rk29_i2s.c中,i2s设备驱动程序platform_driver "rk29_i2s"的probe函数中,定义了一个soc_dai_driver dai,然后会调用snd_soc_register_dai注册一个soc_dai。并且将dai->dev指向rk29_i2s->dev,将dai->driver指向soc_dai_driver dai。并且将soc_dai加入dai_list。在i2s设备的probe函数中,同时完成对DMA的申请。
platform
在rk29_pcm.c中,加载一个名为“rockchip-audio”的platform_driver驱动,从而生成一个platform_device形式的pcm设备“rockchip-audio”。并且在rk29_pcm.c中,定义了一个snd_soc_platform_driver驱动 rockchip_pcm_platform。
在rockchip-audio”的platform_driver驱动的probe函数中,会调用snd_soc_register_platform注册一个soc_platform, 并将此platform->dev指向rockchip->audio.dev, platform->driver 指向rockchip_pcm_platform。并且将此plaform加入platform_list。
codec
在rt5631.c中,定义了一个snd_soc_codec_driver soc_codec_dev_rt5631而在rt5631i2c设备驱动probe中,通过snd_soc_register_codec来注册一个snd_soc_codec codec,并将codec的dev指向i2c->dev,codec->driver指向i2cdriver,同时为此codec分配cache。并将此codec加入codec_list。需要注意的是,codec存在codec_dai, codec_dai是根据codec的功能(比如能否playback/Capture)来定义的,在snd_soc_register_codec中也会调用snd_soc_register_dai来注册codec_dai。而i2s级的dai称之为cpu_dai。
可以在/sys/kernel/debug/asoc,看到已经注册的dais、platforms、codecs。
card
在soc-core.c文件中,定义了一个platform_driver "soc-audio",并加载此驱动。而soc-audio对应的设备platform_device"soc-audio"则是在rk29_rt5631.c中定义并加载。
rk29_rt5631.c中定义的platform_device"soc-audio" rk29_snd_device.通过platform_set_drvdata(rk29_snd_device, &snd_soc_card_rk29)将snd_soc_card_rk29设为rk29_snd_device的私有数据。snd_soc_card_rk29是一个snd_soc_card,即定义了一个声卡数据。声卡名称为"RK29_RT5631",通过其成员dai_link,指定此声卡对应的dai 、platform、codec。一个声卡可以指定多个dai_link。
platform_driver "soc-audio"的驱动soc_probe函数中,通过platform_get_drvdata获取rk29_snd_device的私有数据,即snd_soc_card结构体,并根据此结构体的配置来注册声卡snd_soc_register_card
snd_soc_card*card = platform_get_drvdata(pdev);
card->dev= &pdev->dev;
snd_soc_register_card(card);加此声卡加入card_list,为snd_soc_pcm_runtime card->rtd分配存储空间,并将card的配置信息复制到snd_soc_pcm_runtime中,card->rtd是声卡运行时的一个实例,每个dai_link都对应一个card->rtd,并通过snd_soc_instantiate_card实例化声卡,在实例化声卡中,通过soc_bind_dai_link根据dai_link,遍历dai_list、platform_list,codec_list来绑定声卡的各个对应的部分,之后进行最重要的操作soc_probe_dai_link,执行各个dai_link中platform,dai,codec的probe,完成各个模块的初始化操作,并且创建了一个INIT_DELAYED_WORK(&rtd->delayed_work,close_delayed_work);用于超时关闭声卡。这个超时的时间是可以设置的(pmdown_time)。 ret =device_create_file(&rtd->dev, &dev_attr_pmdown_time); 执行soc_post_component_init,主要是对codec驱动的后续完善工作。之后就是最关键的操作,soc_new_pcm创建PCM设备,将pcm赋给card运行时的实例card->rtd,同时根据codec_dai的功能(是否能播音/录音),为pcm设备创建playback substream 和 capture stream。并把rtd->platform(rk29_pcm.c)中定义的pcm的ops赋给此pcm,并且rtd->platform(rk29_pcm.c)中定义的创建pcm回调函数,为playback substream 和 capture stream分配DMA Buffer(这个与平台相关,不是必须)。至此PCM创建完成,以上都是在soc_probe_dai_link中完成。再之后soc_probe_aux_dev加载一些codec的辅助设备,这个通常是没有的。之后是添加DAMP(动态电源控制,通过开关部件实现降功耗)。之后执行card->late_probe,这个通常是没有的。最好,执行完这些操作后,snd_card_register完成声卡注册。
注意,此时由于dai_list, platform_list可能并未填充。所以,当系统添加dai设备或者platform设备时,都会执行一次实例化声卡的操作。
soc_core.c中定义了四个双向链表dai_list, card_list,codec_list, platform_list. 使用LIST_HEAD来定义,这些链表都是双向链表。
platform-device.dev是platform-device设备的详细描述。
Android
AudioManager.java里面定义各种对音频的操作 ,如加减音量,静音等,这个是最靠近上层的,是被应用程序直接调用的,也是音频控制的唯一的上层借口库。AudioManager中的功能有AudioService来实现。
aidl:
aidl是Android Interface definition language的缩写,它是一种进程通信接口的描述,通过AIDL工具对aidl文件进行转换,生成一个out目录下的java文件,类路径与aidl文件的类路径相同
./out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/media/java/android/media/IAudioService.java
1.aidl文件IAudioService.aidl中定义service的 Interface。
2.AIDL工具根据aidl文件生成IAudioService.java文件(在out目录下)。
3.IAudioService.java中定义定义一个继承android.os.IInterface的InterfaceIAudioService。
4.IAudioService中定义一个抽象类Stub继承自android.os.Binder,并且实现了onTransact方法。
5.Stub中定义一个静态类Proxy,继承自Interface IAudioService,而这个抽象类中实现了Interface IAudioService中定义的方法,实现方法都是通过调用transact方法,与服务器端通信,然后获得服务器的响应。
IAudioService定义:
publicinterface IAudioService extendsandroid.os.IInterface {
Stub定义:
publicstaticabstractclass Stub extends android.os.Binder implements
android.media.IAudioService
Proxy定义:
privatestaticclass Proxy implements android.media.IAudioService {
IAudioService中: