1. 初始化工程

    1) AudioPlicyService被第一次实例化后,将会调用onFirstRef,其中实例化了两个全局变量,一个是mAudioPolicyClient,一个是mAudioPolicyManager。
    2) mAudioPolicyClient是AudioPolicyClient类型的,具体实现在AudioPolicyClientImpl.cpp,该类中保存了AudioPolicyService的指针。
    3) mAudioPolicyManager的类型为AudioPolicyInterface,它被工厂类实例化为AudioPolicyManager。
    AudioPolicyManager被实例化时,将会初始化audio设备的信息。
    首先会查找/vendor/etc/audio_policy.conf中的文件,如果没有此文件,会查找/system/etc/audio_policy.conf,如果仍然没有此文件,将会使用默认的策略文件。
    audio_policy.conf格式类似如下:
    audio_hw_modules {
    primary {
    ……..
    }
    }
    该文件定义了音频设备的信息,如上面就定义了一个audio设备primary,里面的信息会逐一读取,并保存到mHwModules容器中。
    接着,会通过Binder调用audioflinger的loadHwModule逐一加载硬件设备,loadHwModule会返回一个int只,作为每一个设备的唯一号保存在mHwModules容器中的mHandler变量中,同时在audioflinger中作为mAudioHwDevs容器的索引。
  2. 加载硬件过程

    1) loadHwModule中会传进来要加载的硬件的名称,是从audio_policy.conf读取的,比如primary,所以,最后hw_get_module_by_class调用的形参如下:
    hw_get_module_by_class(“audio”, “primary”, &mod);
    2) hw_get_module_by_class是hardware.c的一个函数,hardware.c位于hardware/libhardware/hardware.c中,它根据传进去的两个参数,拼接成audio.primary这种名字,然后在根据手机中的属性值,查找 究竟使用的是哪一个库,实际上也就是一个一个是,比如首先看audio.primary.mt6735.so是否在/vendor/lib64/hw或/system/lib64/hw文件夹中,如果存在,就代表要使用这个动态库,不再查找其他动态库。
    3) Load函数就是在动态加载HAL库即audio.primary.mt6735.so并找到其符号HAL_MODULE_INFO_SYM的地址,HAL_MODULE_INFO_SYM是一个hw_module_t类型的结构,该值是从hw_get_module_by_class中的第三个形参过来的,也就是mod,该值会被传到audioflinger中的mod中去。
    4) audio_hw_device_open实际上是使用的上一步中获得的mod的指针的open函数(根据上一步的操作,open函数最终指向了legacy_adev_open方法),其中仍需注意第二个参数dev,它是一个audio_hw_device_t类型的指针,将会通过open返回到audioflinger中。
    legacy_adev_open将会创建一个legacy_audio_device指针,最后返回audiofliger一个hw_device_t类型的指针给dev。需要注意的一点,dev原来是一个audio_hw_device_t类型,现在变成了hw_device_t,这是不是就是说出了第一个参数common被初始化了,其他的成员函数并没有被初始化?不是!
    *device = &ladev->device.common;
    也就是将ladev的首地址传上去了,剩下的成员都是依次排列的,通过指针可以访问到所有的成员。这是C语言常用的技术。
    legacy_adev_open还创建了一个AudioALSAHardware的实例,这一点也很重要。
    5) AudioALSAHardware中初始化了几个干活的实例,如mStreamManager,它是AudioALSAStreamManager对象的实例。
    6) 最后,将dev保存到AudioHwDevice实例中,并将AudioHwDevice实例放入到mAudioHwDevs容器中。
    audio_hw_hal.cpp: vendor/mediatek/proprietary/platform/common/hardware/audio/aud_drv/audio_hw_hal.cpp
    AudioALSAHardware.cpp:
    vendor/mediatek/proprietary/platform/common/hardware/audio/V3/aud_drv/AudioALSAHardware.cpp
  3. AudioStreamIn指针的建立
    AudioStreamIn代表的是录音时的输入流,所以以AudioRecord为例

    1) openInput_l首先根据唯一的handle值找到AudioHwDevice,这时上章加载硬件是产生的,然后通过由HAL层返回的指针去调用open_input_stream,注意该函数的第5个参数,该值是个指向指针的指针,其类型为audio_stream_in,以后会被广泛使用,其值会通过open_input_stream返回上来。
    2) adev_open_input_stream运行时,会创建一个adev_open_input_stream指针,该指针的首地址即是open_input_stream的第5个参数,会被传送到audioflinger层。该指针中还有一个AudioStreamIn类型的legacy_in指针,该指针最终被实例化为AudioALSAStreamIn,非常重要,最后干活的将是这个对象:
    in->legacy_in = ladev->hwif->openInputStream(devices, (int *) &config->format,
    &config->channel_mask, &config->sample_rate,
    &status, (AudioSystem::audio_in_acoustics)0);
    3) 截止到目前,我们得到了两个重要的指针,一个是audio_hw_device_t类型的指针,通过该指针,我们操作HAL层对我们暴露的基本方法,如get_supported_devices等方法。
    另一个指针是audio_stream_in_t类型的指针,通过此指针,我们可以完成相应的流操作,如读取等。
    这两个指针被传入到AudioStreamIn对象,作为RecordThread的mInput实例保存起来。
  4. RecordThread和HAL的数据交换

    在AudioFlinger::RecordThread::threadLoop中会调用mInput->stream->read读取数据,stream就是audio_stream_in_t类型的指针,在执行open_input_stream时被初始化,先在它其实是一个legacy_stream_in类型的指针。当调用read时,in_read将会被调用。然后真正执行的是AudioStreamIn类中的read函数。
    在该函数中,如果AudioALSACaptureHandlerBase类型的mCaptureHandler指针还没被初始化,将会调用AudioALSAStreamManager中的createCaptureHandler创建一个mCaptureHandle指针。AudioALSAStreamManage使用的是工厂模式,根据不同的设备类型,创建不同的执行类,如果是使用的MIC,将会创建AudioALSACaptureHandlerNormal类型的实例。
  5. Read分析

    在第3步创建AudioStreamIn的指针过程中,AudioFlinger调用open_input_stream会创建一个AudioStreamIn指针,创建过程中,AudioALSAStreamManager是一个单例,但AudioStreamIn并不是单例,只要open_input_stream函数被调用,就会创建一个AudioStreamIn实例,AudioStreamIn创建的获取采集数据的mCaptureHandler也不是单例。
    但是,在创建mCaptureHandler的AudioALSACaptureDataClient实例时,第一个参数为AudioALSACaptureDataProviderBase类型的指针,它是一个单例,是通过AudioALSACaptureDataProviderNormal::getInstance()传进去的。
    创建AudioALSACaptureDataClient实例时,做了几个重要的工作,1个是创建了一个环形缓冲区,buffer大小为32k,用来保存数据,AudioFlinger读取数据时,就是从该缓冲区中读取的,另一个就是向AudioALSACaptureDataProviderNormal注册了一个观察者,当有数据的时候,会将数据拷贝到AudioALSACaptureDataClient的环形buffer中。
    所以这样即使有多个AudioStreamIn,但每个AudioStreamIn实例中有各自的环形buffer,从硬件来的数据会扔到各自的环形buffer中,从而互不影响。

更多相关文章

  1. Cocos2D-HTML5 Android项目编译
  2. 运用WindowManager,当滚动列表时显示一个类似Toast的提示(android
  3. Java进制转换
  4. 实例6--文字滚屏
  5. Android(安卓)Camera Framework层分析
  6. Android基于名称、修改时间、大小实现文件夹排序
  7. Context的子类实现:ContextImpl的初始化
  8. Android(安卓)JUnit单元测试基础实例
  9. Activity状态转换和Activity栈

随机推荐

  1. OKhttp上传头像,调用相机相册进行裁剪
  2. Android(安卓)Camera CTS related
  3. Android.Bundle savedInstanceState 的意
  4. 基于android平台开发的计算器
  5. Creating Release Keys and Signing Buil
  6. 按返回键返回到主界面
  7. 编译android源码前的准备
  8. android项目中单实例数据库类
  9. IOS 实现android Toast效果
  10. 自定义view之自定义圆角矩形imageview