• Android音频(8)——HAL分析


    一、HAL之框架

    1. tiny4412上HAL框架

    audio.primary.tiny4412.so文件的Makefile:
    device/friendly-arm/common/libaudio/Android.mk

    LOCAL_SRC_FILES:= AudioHardware.cpp
    LOCAL_MODULE := audio.primary.$(TARGET_DEVICE)    #TARGET_DEVICE就是tiny4412,生成audio.primary.tiny4412.so,其中primary是在 /system/etc/audio_policy.conf中指定的module的名字。
    LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw
    LOCAL_STATIC_LIBRARIES:= libmedia_helper
    LOCAL_SHARED_LIBRARIES:= 
        libutils 
        liblog 
        libhardware_legacy         # 依赖这个库
        libtinyalsa                 # 依赖这个库
        libaudioutils
    LOCAL_WHOLE_STATIC_LIBRARIES := libaudiohw_legacy

    libaudiohw_legacy依赖文件:

    hardware/libhardware_legacy/audio/Android.mk
    LOCAL_SRC_FILES := 
        AudioHardwareInterface.cpp 
        audio_hw_hal.cpp    # 4412的5.0版Android上是这个HAL,其它的可不一定了
    
    LOCAL_MODULE := libaudiohw_legacy
    LOCAL_MODULE_TAGS := optional
    LOCAL_STATIC_LIBRARIES := libmedia_helper
    LOCAL_CFLAGS := -Wno-unused-parameter
    
    include $(BUILD_STATIC_LIBRARY)

    所以库文件audio.primary.tiny4412.so至少涉及:
    audio_hw_hal.cpp (hardware/libhardware_legacy/audio/audio_hw_hal.cpp)
    audioHardwareInterface.cpp (hardware/libhardware_legacy/audio/audioHardwareInterface.cpp)
    audioHardware.cpp (device/friendly-arm/common/libaudio/audioHardware.cpp) 生成audio.primary.tiny4412.so
    作用:
    audio_hw_hal.cpp:向上提供接口的函数
    audioHardwareInterface.cpp:向厂商制定访问硬件接口的函数
    audioHardware.cpp:厂商实现的访问声卡硬件的文件

    2. 要先弄清楚其框架,才能看懂其代码。

    从图片上可以看出,HAL这一层有audio的HAL,也有Audio_policy的HAL。对于Audio_policy的HAL我们不关系,因为它基本上已经废弃了。

    HAL要向上层提供统一的接口,操作硬件也可能有一组接口或一个类,抓住这两点分析HAL框架。

    3. 见audio_hw_hal.cpp,向上提供的接口就是struct audio_hw_device,它是对hw_device_t结构的封装。

    audio_hw_hal.cpp位于hardware/libhardware_legacy/audio下,既然是旧的,那么有没有新的呢?在hardware/libhardware/modules/audio
    下有个audio_hw.c文件,它就是新的Audio的HAL文件,但是在5.0板中没有使用它,它里面的函数全部为空。在版本的Android8.0中可以看出,
    这个文件同样没有实现,所以libhardware_legacy下的还是起主打作用。但是在Android8.0中的高通的HAL使用的是新的。

    4. audio_hw_hal.cpp
    a.向上提供接口struct audio_hw_device
    b.向下访问硬件class AudioHardware(实现在device/friendly-arm/common/libaudio/audioHardware.cpp) 由厂商提供,里面使用到了tinyalsa
    库的接口。但是厂商肯定不能随意去实现硬件的访问接口,Android指定了一套接口给它。
    类的继承关系:

    AudioHardwareInterface    //hardware/AudioHardwareInterface.cpp
        ↑
    AudioHardwareBase         //hardware/AudioHardwareBase.h 这个应该是audio HAL给厂商定义的接口
        ↑
    AudioHardware            //device/friendly-arm/common/libaudio/audioHardware.cpp

    5. 在厂商的HAL中,AudioHardware (audioHardware.cpp中)表示一个声卡,它使用audio_stream_out结构来表示输出,使用audio_stream_in来表示输入。
    audio_stream_out中有write(),audio_stream_in中有read()


    6. Audio HAL的调用流程总结

      上层应用程序调用audio_hw_hal.cpp中的legacy_adev_open()会得到一个struct audio_hw_device结构体,这个结构体就代表上层使用硬件的接口,这个结构体中有一堆的函数,它们都依赖于厂家提供的struct AudioHardwareInterface结构(在HAL中使用,在厂商代码中实现,此例中是在audioHardware.cpp中实现的),由于HAL对上层直接提供的接口中没有read/write函数,因此,应用程序想要录音或播放声音的时候需要先打卡output或input(调用HAL的open_output_stream/open_input_stream),以使用其里面的write/read函数向声卡硬件写音频数据。

    7. HAL相关的数据结构

    struct legacy_audio_device {
        //规范了向上提供的接口
        struct audio_hw_device device;
        //向上提供的接口依赖厂家提供的这个类来实现
        struct AudioHardwareInterface *hwif;
    };
    下面的legacy_stream_out和legacy_stream_in也是同理
    struct legacy_stream_out {
        struct audio_stream_out stream;
        AudioStreamOut *legacy_out;
    };
    struct legacy_stream_in {
        struct audio_stream_in stream;
        AudioStreamIn *legacy_in;
    };

    上面的也是Android源码中常用的套路。

    8. http://androidxref.com/ 上有各个版本的Android源码,查看代码非常方便

    9. 由于有类的继承关系,SourceInsight工程自动跳转是不准的。

    10. AudioFlinger启动过程中,AudioPolicyService构造过程中会读取配置文件 /system/etc/audio_policy.conf,该配置文件中有一个module名为"primary",根据这个名字, 会去 /system/lib/hw 中打开库文件: audio.primary.XXX.so,比如: audio.primary.tiny4412.so


    11. 框架详细描述
    audio HAL中:
    b.1 向上提供统一接口: audio_hw_device,里面设置了各种函数

    b.2 这些函数要借助声卡的代码才能实现,声卡的功能抽象为AudioHardware对象

    b.3 audio_hw_device中的函数只看到各种set, get,没有看到wirte, read,怎么播放声音、录制声音?

    b.4 要播放声音,
    b.4.1 要先open output:在audio_hw_device中有open_output_stream函数指针

    b.4.2 open_output_stream返回一个audio_stream_out结构体,它是向上提供的"播放接口"

    b.4.3 audio_stream_out也需要厂家提供的代码才能实现,厂家提供的代码抽象为AudioStreamOutALSA对象

    b.5 对于录制声音
    b.5.1 要先open input:在audio_hw_device中有open_input_stream函数指针

    b.5.2 open_input_stream返回一个audio_stream_in结构体,它是向上提供的"录制接口"

    b.5.3 audio_stream_in也需要厂家提供的代码才能实现,厂家提供的代码抽象为AudioStreamInALSA对象

    二、HAL之调用流程源码分析

    1. HAL文件一般位于/system/lib/hardware下面,音频中操作硬件的库文件名称在(厂商提供的HAL部分)在/system/etc/policy_config中指定,如module name为primary,
    就对应audio.primary.tiny4412.so。

    2. 直接使用系统调用控制声卡的是tinyalsa库,位于目录/external/tinyalsa下,编译生成库文件libtinyalsa.so(只涉及两个文件mixer.c,pcm.c),编译生成工具 tinycap,tinymix,tinypcminfo,tinyplay,可用于直接控制音频通道,进行录音播音测试。

    tinyalsa中使用
    pcm_open()来打开声卡
    pcm_write()来播放音乐
    pcm_read()来录音

    3. HAL调用流程源码分析

    a. 确定HAL文件的名字:
    AudioPolicyManager的构造函数读取配置文件/system/etc/audio_policy.conf确定名字(这个名字在tiny4412上只是HAL厂商部分编译生成库的名字,HAL入口是hardware/libhardware_legacy/audio/audio_hw_hal.cpp)

    b. 加载HAL对应的so文件。

    c. 打开HAL文件中的open函数,在HAL中会构造audio_hw_device结构体, 该结构体中有各类函数, 特别是 open_output_stream / open_input_stream

    AudioFlinger根据audio_hw_device结构体构造一个AudioHwDev对象并放入mAudioHwDevs

    d. open output stream: 调用hal结构体audio_hw_device的open_output_stream, 它会构造出一个audio_stream_out结构体, 里面有write函数

    AudioFlinger根据audio_stream_out结构体构造一个MixerThread

    e. 播放声音(这时才真正打开声卡驱动):
    thread->threadLoopg_write => stream.write ==> pcm_open, pcm_write

  • 相关阅读:
    如何查看RabbitMQ日志,Rabbitmq Trace日志的使用
    windows激活 RabbitMQ's Management Plugin(必须)
    UNET
    边缘检测
    Huber Loss
    深度学习之自编码器AutoEncoder(一)
    PU learning简介
    机器学习-稀疏矩阵的处理
    R语言入门-安装R和Rstuido软件
    归一化 (Normalization)、标准化 (Standardization)和中心化/零均值化 (Zero-centered)
  • 原文地址:https://www.cnblogs.com/hellokitty2/p/10943199.html
Copyright © 2020-2023  润新知