首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > .NET > .NET Framework >

音频hal层小结+frameworks 概要

2013-01-21 
音频hal层总结+frameworks 概要音频hal层总结frameworks概要 第一部分三个文件,其中所有类,都为根类.文件

音频hal层总结+frameworks 概要

音频hal层总结+frameworks概要

 

第一部分

三个文件,其中所有类,都为根类.文件地址:

1:Audio.h有四个类

①.audio_stream_out:主要有四个成员函数: *get_latency set_volume  write  get_render_position  并且包含: struct audio_stream common;

 

 ②.audio_stream_in:主要有三个成员函数:set_gain(调音) read  get_input_frames_lost

  函数getInputFramesLost,调用checkRecordThread_l获取录音线程,然后调用线程的getInputFramesLost函数。

  并且包含: struct audio_stream common;

 

 ③.struct audio_module {  struct hw_module_t common; };   

 

④. audio_hw_device包含很多成员函数

 

 

2: audio_effect.h音效文件先不表.

 

3: audio_policy.h策略管理

①.   audio_policy:

 

②.   audio_policy_service_ops

   

 ③.typedef struct audio_policy_module { struct hw_module_t common;} audio_policy_module_t;

 

 ④.audio_policy_device:

    

 

 

第二部分: STUB(模拟测试)程序

  文件目录: 两个文件

1:audio_hw.c

2:audio_policy.c

  这两个程序,其实就是两个Stub(模拟测试)程序.我们hal层可以参照来写.

 

 

 

第三部分:兼容2.3以前的程序文件目录:

1: AudioSystemLegacy.h

从namespace来看,确实4.0以后可能不用到. Using 使用名字空间表示以下代表在status_t和 AudioParameter空间可见..

 

2: AudioHardwareBase.h

 

3:AudioHardwareInterface.h

  有三个类,AudioStreamOut AudioStreamIn   AudioHardwareInterface

 

 例AudioStreamIn 成员函员包括以下

其中Read和 Write函数是最关键的了.

 

4: AudioPolicyInterface.h

5: AudioPolicyManagerBase.h

上面两个都是音频软硬件策略文件了.

 

 

功能如:可以看出包括软硬件的策略管理.

 

 

 

第三部分之二(兼容2.3之前代码)文件路径:

从以下文件名可以知道程序功能:

以前的主程序,主要分为stub  hw_hal   a2dp  policy 等四大块功能.

兼容的方法为如下:

/*

兼容以前的设计,4.0实现一个中间层:hardware/libhardware_legacy/audio/audio_hw_hal.cpp,

结构与其他的audio_hw.c大同小异,差别在于open方法:

 

[cpp] view plaincopystatic int legacy_adev_open(const hw_module_t* module, const char* name, 

                           hw_device_t** device) 

   ...... 

 

   ladev->hwif = createAudioHardware(); 

   if (!ladev->hwif) { 

       ret = -EIO; 

       goto err_create_audio_hw; 

   } 

     ...... 

看到那个熟悉的createAudioHardware()没有?这是以前我提到的Vendor Specific Audio接口,

然后新的接口再调用ladev->hwif的函数就是了。

因此老一套的alsa-lib、alsa-utils和alsa_sound也可以照搬过来,这里的文件被编译成静态库的,

因此你需要修改alsa_sound里面的Android.mk文件,链接这个静态库。还有alsa_sound的命名空间原来是“android”,

现在需要改成“android_audio_legacy”---注意!!!

*/

第四部分:ALSA管理.代码目录:

文件结构

承接frameworks层服务端的总体接口.

如alsa_default.cpp的内容,为s_init s_open s_close等等, s_open里面调用了s_route,设置软硬件参数.

从内容上看这是amlogic在2.3之前的代码的现用程序.重点分析这一部分的数据流走向.

ALSA其实也就代表一种管理方法,简单地说就是这里的程序就是alsa , alsa就是这里.感觉和V4L2还是有一点小小的区别.

 

这部分代码现在google用tinyalsa来代替它,但是仍然保留了接口,可以供厂商不用tinyalsa(功能不够强大)时来代替它,只需要改一下*.mk文件即可.其实看一下也就十个文件,也不是很复杂的.当然,上层flinger和下层 kernel适配的地方同样要复杂一些.

 

ALSA要比v4l2复杂一些.它的内容主要是一些软件方法.而v4l2的内容是一些标准的接口命令.

同样,由于现在版本是4.0,不用这部分代码了,而用了\external\tinyalsa\.而tinyalsa则简单很多!

 

调用方法为: ./hardware/libhardware_legacy/audio/、hardware/libhardware/modules/audio/、device/samsung/tuna/audio/是同层的。

之一是legacy audio,用于兼容2.2时代的alsa_sound;之二是stub audio接口;之三是Samsung Tuna的音频抽象层实现。

调用层次:AudioFlinger -> audio_hw -> tinyalsa。

 

 

以上除了ALSA部分以外,

全部是audio_hw的处理内容,下面讲第四部分,具体的执行者,tinyslsa.

 

 

第五部分:具体执行者 TinyALSA的分析.

1:下文件asoundlib.h.功能如下

其中: 为主体实现文件,为c语言编写的应用工具.

仅仅两个文件pcm.c和mixer.c,看来TinyALSA确实要简单很多!

而且两个文件都不大,加起来1200行代码. mixer.c主要是一些ioctl open memset等函数.

如:ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_WRITE, &ev);

 

 Pcm.c主要是对数据流的一些操作;

主要函数有:pcm_bytes_to_frames; pcm_frames_to_bytes;

pcm_hw_mmap_status(struct pcm *pcm)中以下两个函数是关键函数.

pcm->mmap_control = mmap(NULL, page_size, PROT_READ | PROT_WRITE,

                            MAP_FILE | MAP_SHARED, pcm->fd, SNDRV_PCM_MMAP_OFFSET_CONTROL);

 

munmap(pcm->mmap_status, page_size);

mmap将一个文件或者其它对象映射进内存。文件被映射到多个页上,如果文件的大小不是所有页的大小之和,最后一个页不被使用的空间将会清零。munmap执行相反的操作,删除特定地址区域的对象映射。

 

pcm_mmap_writeàpcm_mmap_write_areasàpcm_areas_copyàmemcpy.

Mmap的写过程就是以上.

 

而pcm_mmap_commità pcm_sync_ptrà ioctl(pcm->fd, SNDRV_PCM_IOCTL_SYNC_PTR, pcm->sync_ptr);

这就是几个关键的pcm流操作函数,包括memcpy之内,最终由底层硬件实现具体功能.

而音频的响应速度,可以测一下 memcpy 这里的用法,看有没有启用cache等.

 

当然最重要的函数为:pcm_read  pcm_write.

最终通过ioctl(pcm->fd, SNDRV_PCM_IOCTL_PREPARE);操作pcm->fd;

具体就到了/kernel/sound/core/pcm_native.c里面了.

如有疑问请参见以下网址:http://blog.csdn.net/myarrow/article/details/8228437

这个网址所说的alsa库调用方法,需要我们认真掌握.

附记一点,在kernel 里面也是可以使用ioctl的snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_START, NULL);

我这里在kernel中搜出来SNDRV_PCM_IOCTL_START的结果:

可见\kernel\include\sound\Asound.h这个头文件基本上定义了,所有的ALSA接口命令.

 

 

到目前为止没有看到音频格式转化函数.

 

 

第六部分: aml Kernel层代码分析

1:代码树

 

2:代码功能模块

3:硬件数据流及名词解析

4:ALSA设备文件结构

   我们从alsa在linux中的设备文件结构开始我们的alsa之旅.看看我的电脑中的alsa驱动的设备文件结构:

$ cd /dev/snd
$ ls -l

crw-rw----+ 1 root audio 116, 8 2011-02-23 21:38 controlC0
crw-rw----+ 1 root audio 116, 4 2011-02-23 21:38 midiC0D0
crw-rw----+ 1 root audio 116, 7 2011-02-23 21:39 pcmC0D0c
crw-rw----+ 1 root audio 116, 6 2011-02-23 21:56 pcmC0D0p
crw-rw----+ 1 root audio 116, 5 2011-02-23 21:38 pcmC0D1p
crw-rw----+ 1 root audio 116, 3 2011-02-23 21:38 seq
crw-rw----+ 1 root audio 116, 2 2011-02-23 21:38 timer

   我们可以看到以下设备文件:

  • controlC0 -->                用于声卡的控制,例如通道选择,混音,麦克风的控制等
  • midiC0D0  -->                用于播放midi音频
  • pcmC0D0c --〉              用于录音的pcm设备
  • pcmC0D0p --〉              用于播放的pcm设备
  • seq  --〉                       音序器
  • timer --〉                      定时器

    其中,C0D0代表的是声卡0中的设备0,pcmC0D0c最后一个c代表capture,pcmC0D0p最后一个p代表playback,这些都是alsa-driver中的命名规则。从上面的列表可以看出,我的声卡下挂了6个设备,根据声卡的实际能力,驱动实际上可以挂上更多种类的设备,在 include/sound/core.h中,定义了以下设备类型:

    1.       #define SNDRV_DEV_TOPLEVEL  ((__force snd_device_type_t) 0)  

    2.       #define SNDRV_DEV_CONTROL   ((__force snd_device_type_t) 1)  

    3.       #define SNDRV_DEV_LOWLEVEL_PRE  ((__force snd_device_type_t) 2)  

    4.       #define SNDRV_DEV_LOWLEVEL_NORMAL ((__force snd_device_type_t) 0x1000)  

    5.       #define SNDRV_DEV_PCM       ((__force snd_device_type_t) 0x1001)  

    6.       #define SNDRV_DEV_RAWMIDI   ((__force snd_device_type_t) 0x1002)  

    7.       #define SNDRV_DEV_TIMER     ((__force snd_device_type_t) 0x1003)  

    8.       #define SNDRV_DEV_SEQUENCER ((__force snd_device_type_t) 0x1004)  

    9.       #define SNDRV_DEV_HWDEP     ((__force snd_device_type_t) 0x1005)  

    10.     #define SNDRV_DEV_INFO      ((__force snd_device_type_t) 0x1006)  

    11.     #define SNDRV_DEV_BUS       ((__force snd_device_type_t) 0x1007)  

    12.     #define SNDRV_DEV_CODEC     ((__force snd_device_type_t) 0x1008)  

    13.     #define SNDRV_DEV_JACK          ((__force snd_device_type_t) 0x1009)  

    14.     #define SNDRV_DEV_LOWLEVEL  ((__force snd_device_type_t) 0x2000)  

     通常,我们更关心的是pcm和control这两种设备。

     5:---驱动,后续再分析,主要查看内存,及格式操作即可.也可以用通用的程序测试.

     

     

     

     

     

    第七部分: FrameWorks层代码分析

    1:文件架构

    文件说明:由下至上.

    audioflinger当然是核心处理文件.

            Mediaserver 多媒体交互文件

            Libstagefright 取代老的opencore程序功能.

            Libeffects 音效处理类.

     

            Libmedia:重点文件夹(重点说明):

                BP(binder proxy)和BN(binder native)是通过binder来通信的。Bp主要是用来处理java层传下来的服务请求。然后通过transact将处理请求传给bn(通过binder)。

            打开里面的这个文件夹,可以看到Bp*(承接java层本地端) Bn*(接c++远程服务端)类以及通用的流控制文件都在这里.因些可以断定audio从 jni下来之后到Hal的frameworks层的主要代码的主要代码都在这里.

              包含了native及binder的两端本地 -------服务的代码.测试录音时,可以在这里增加对帧速的测试点.同时在Hal层也设立测试点,这样基本上可以判断是哪一层的音频处理的问题了.

            

     右边这个是audio java库架层代码,jni上面一层的代码.给应用提供底层接口.

            

            再右边这个,不用解释binder 和 jni层.

            

            

     

     

     

     

    2:核心audioFlinger架构文件分析

    默认的情况下,Android放音的采样率固定为44.1khz,录音的采样率固定为8khz,因此底层的音频设备驱动只需设置好这两个固定的采样率。如果上层传过来的采样率与其不符的话,则Android Framework层会对音频流做resample(重采样)处理。具体重采样的文章可以参阅以下文章:http://blog.csdn.net/zoe6553/article/details/7199543

    排除掉重采样,可以发现AudioFlinger模块核心是四部分,buffer flinger mixer Policy;

    具体分析flinger部分.

    以上为audioflinger总的类图关系.

     

    有以下类及主要功能:

    ①.class AudioFlinger : public BinderService<AudioFlinger>, public BnAudioFlinger

      包括音频数据流和命令流的主要操作.

     以下都是他的类中类.嵌套类中说明的成员不是外围类中对象的成员,反之亦然。嵌套类的成员函数对外围类的成员没有访问权,反之亦然。国此,在分析嵌套类和外围类的成员访问关系时,往往把嵌套类看作非嵌套类来处理。

     

    ②.class Client : public RefBase

    本地端通信功能.

     

    ③.class NotificationClient : public IBinder::DeathRecipient

    用于binder通信事件通知处理类.

     

    ④.class ThreadBase : public Thread

    他包含四个子类:class TrackBase : public AudioBufferProvider, public RefBase

              class ConfigEvent

              class PMDeathRecipient : public IBinder::DeathRecipient

    class SuspendedSessionDesc : public RefBase

      音频frameworks层的总的线程管理程序.

     

    ⑤.class PlaybackThread : public ThreadBase

    他包含2个子类:class Track : public TrackBase

                              如图OutputTrack

                               

      播放线程.                       

     

    ⑥.class MixerThread : public PlaybackThread

      播放中的mixer操作.

     

    ⑦.class DirectOutputThread : public PlaybackThread

      先看看AudioFlinger::PlaybackThread::addEffectChain_l函数中的处理,
     函数中根据是否为DIRECT output thread,有两种处理方式:
     一种是处理direct output thread:
    调用函数setMainBuffer将PlaybackThread的mMixBuffer告诉给Track,即告诉Track,在AudioMixer中往PlaybackThread的mMixBuffer中copy数据。然后将effect  chain的input buffer和output buffer都设置为PlaybackThread的mMixBuffer。(目的是让该effect chain不起作用?存在注释“Only one effect chain can be present in direct output thread and it usesthe mix buffer as input”)
    另一种是处理非direct output thread:
    new一段buffer出来。调用函数setMainBuffer将新buffer告诉给Track,即告诉Track,在AudioMixer中往新buffer中copy数据。
    调用函数setInBuffer来实装chain的input buffer。(发现函数AudioFlinger::PlaybackThread::createTrack_l中其实有将chain的input buffer赋值给Track的main buffer)。然后将PlaybackThread的mMixBuffer赋值给chain的output buffer。
    也就是说,Track将数据copy到自己的main buffer(即effect chain的input buffer),effect chain对数据进行处理,然后将处理过的数据赋值给自己的output buffer(即PlaybackThread的mMixBuffer)
    mMixBuffer是如何被使用的呢?

     

    从上可以看出是数据的copy的一种方式.

     

    ⑧.class DuplicatingThread : public MixerThread

     AudioFlinger中有一个特殊的线程类:DuplicatingThread,从图可以知道,它是MixerThread的子类。当系统中有两个设备要同时输出时,DuplicatingThread将被创建,通过IAudioFlinger的openDuplicateOutput方法创建DuplicatingThread。

     

    ⑨.class TrackHandle : public android::BnAudioTrack

     

     对音频播放的操作.

     问题:这里的start stop和 flinger 里面的start stop 有何不同.

     答:不同的内容.flinger类并没有这两个方法,在其子类中有.

     从这里看出,另flinger并不只是对数据流进行操作,还提供了给上面应用的调用的接口.

     

    ⑩.class RecordThread : public ThreadBase, public AudioBufferProvider

    他包含子类:class RecordTrack : public TrackBase

    录音的流程和放音差不多,只不过数据流动的方向相反,录音线程变成RecordThread,Track变成了

    RecordTrack,openRecord返回RecordHandle.

     

    ⑾.class RecordHandle : public android::BnAudioRecord

      和TrackHandle相反的数据流操作.

     

    ⑿.class EffectModule: public RefBase

    ⒀.class EffectChain: public RefBase及子类class SuspendedEffectDesc : public RefBase

    对音效的修正.

     

    ⒁.struct AudioStreamOut

    ⒂.struct AudioStreamIn

    ⒃.struct AudioSessionRef

     

    /* AudioTrack对象的创建过程时,了解到,创建一个AudioTrack对象,必须指定一个SessionId,并与其他使用该SessionId的AudioTrack和MediaPlayer共享AudioEffect。

    如果不指定SessionId,将会自动生成一个SessionId,AudioEffect会将该SessionId与新创建的AudioTrack对象关联起来。 别人可以通过getAudioSessionId函数取得该SessionId。

    */

     

    还加入友元类

    friend class RecordThread;

    friend class PlaybackThread;

     

     

     

     

热点排行