• Android 音频框架之配置文件解析



    理解Android 框架代码的一些基础,框架中操作的各种模块、设备、流、路由都是从哪里定义的?以及是怎么定义的?这个也是理解AAOS 中caraudioservice的基础,也是后续有关Audiopatch、AudioFlinger、Audiopolicy的基础。

    本文从java层getDevice获取设备展开到框架中理解audio_policy_configuration的解析。

    getDevice返回的信息

    • java 层

    代码位置:

    frameworks\base\media\java\android\media\AudioManager.java

    首先通过mAudioManager.getDevices 获取的是AudioDeviceInfo,这个info是从
    AudioManager.listAudioDevicePorts中获取到的ports构建出来的,从这边构建的port包含了所有的输入和输出的port,而在getDevices的时候根据flags 是输入还是输出来筛选出需要的port。listAudioDevicePorts是调用的
    AudioSystem.listAudioPorts(newPorts, portGeneration) 来获取的

    • c++ 框架层

    代码位置:

    frameworks\av\services\audiopolicy\managerdefault\AudioPolicyManager.cpp

    status_t AudioPolicyManager::listAudioPorts(audio_port_role_t role,
                                                audio_port_type_t type,
                                                unsigned int *num_ports,
                                                struct audio_port_v7 *ports,
                                                unsigned int *generation)
    
    • 1
    • 2
    • 3
    • 4
    • 5

    从java到框架都类似通过jni的这边就跳过。最后会调用到AudioPolicyManager::listAudioPorts 其传递的role和type 是AUDIO_PORT_TYPE_NONE、 AUDIO_PORT_ROLE_NONE这里面的实现是将
    AudioPolicyManagerd的mAvailableOutputDevices 和 mAvailableInputDevices调用toAudioPort 转换为audio_port_v7的ports返回到AudioManager, AudioManager根据输入或者输出在进行筛选返回到应用层。

    • 了解audio_port_v7的结构体
    struct audio_port_v7 {
        audio_port_handle_t      id;                 /* port unique ID */
        audio_port_role_t        role;               /* sink or source */
        audio_port_type_t        type;               /* device, mix ... */
        char                     name[AUDIO_PORT_MAX_NAME_LEN];
        unsigned int             num_audio_profiles; /* number of audio profiles in the following
                                                        array */
        struct audio_profile     audio_profiles[AUDIO_PORT_MAX_AUDIO_PROFILES];
        unsigned int             num_extra_audio_descriptors; /* number of extra audio descriptors in
                                                                 the following array */
        struct audio_extra_audio_descriptor
                extra_audio_descriptors[AUDIO_PORT_MAX_EXTRA_AUDIO_DESCRIPTORS];
        unsigned int             num_gains;          /* number of gains in following array */
        struct audio_gain        gains[AUDIO_PORT_MAX_GAINS];
        struct audio_port_config active_config;      /* current audio port configuration */
        union {
            struct audio_port_device_ext  device;
            struct audio_port_mix_ext     mix;
            struct audio_port_session_ext session;
        } ext;
    };
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    其中audio_port_device_ext为 这个在后续的audiopatch中会用到。

    /* extension for audio port structure when the audio port is a hardware device */
    struct audio_port_device_ext {
        audio_module_handle_t hw_module;    /* module the device is attached to */
        audio_devices_t       type;         /* device type (e.g AUDIO_DEVICE_OUT_SPEAKER) */
        char                  address[AUDIO_DEVICE_MAX_ADDRESS_LEN];
    #ifndef AUDIO_NO_SYSTEM_DECLARATIONS
        uint32_t              encapsulation_modes;
        uint32_t              encapsulation_metadata_types;
    #endif
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    在toAudioPort 的toAudioPortInternal 中 赋值了ext中的hw_module结构体,

        void toAudioPortInternal(T* port) const {
            DeviceDescriptorBase::toAudioPort(port);
            port->ext.device.hw_module = getModuleHandle();
        }
    
    DeviceDescriptorBase::
        void toAudioPortInternal(T* port) const {
            AudioPort::toAudioPort(port);
            toAudioPortConfig(&port->active_config);
            port->id = mId;
            port->ext.device.type = mDeviceTypeAddr.mType;
            port->ext.device.encapsulation_modes = mEncapsulationModes;
            port->ext.device.encapsulation_metadata_types = mEncapsulationMetadataTypes;
            (void)audio_utils_strlcpy_zerofill(port->ext.device.address, mDeviceTypeAddr.getAddress());
        }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    综上getDevice返回的是AudioPolicyManger中可用输入和输出的设备,其结构体中包含了id、role、type等等信息,那么这个mAvailableOutputDevices 和 mAvailableInputDevices是如何构造的呢?这就需要了解android音频配置文件的解析了。

    audio_policy_configuration 的抽象成结构体

    • 代码位置:

    frameworks\av\services\audiopolicy\managerdefault\AudioPolicyManager.cpp

    frameworks\av\services\audiopolicy\common\managerdefinitions\src\Serializer.cpp

    • 解析流程

      解析这个xml是嵌套的, 首先是modules标签,每个modules 存储mixPorts、devicePort、routes。 第一个解析到的是modules标签,modules可以包含多个module,

      • module
        对应的是HwModule类,是属于嵌套的最顶层,包含后续的所有元素。

      • mixPorts
        对应的是IOProfile的类,解析name和role(role只能为source 或者 sink),然后解析mixports嵌套的profile,profile对应的是AudioProfileVector类,解析后将profile设置到IOProfile的mProfiles。profile存储的是format、channel、samplerate。

        解析完mixport之后根据role类型会设置到HwModule中的mOutputProfile/mInputProfiles中,同时也会加到HwModule中的(PolicyAudioPortVector)mPorts中。

      • devicePorts
        对应的类是DeviceDescriptor,首先解析tagName、type、role、address,role同样跟mixport一样可以是source或者sink, type是android定义的类型如OUT_BUS、IN_BUILTIN_MIC等等不同类型的设备。mixport 一样嵌套了profile, 其中还可能会多个gain这样的标签,对应的类是AudioGains(定义了音量调整db的范围和步长)。

        解析完设置HwModule中的mDeclaredDevices中,也会添加到HwModule中的mPorts中。

      • routes

        对应的类是AudioRoute,首先解析type(type有两种类型mix或者mux), 然后解析sink的名字,解析到名字后根据sink的名字从module的mPort(这个port是在上述解析mixport和deviceport中加入的)中找sinkport,找到后将sinkport设置到route中,同时将route设置到sinkport。source解析过程也是类似的,找到所有标签为sources的tag,将sources 设置到routes。一般来说sink这个port为deviceport,source是mixport简

        单的理解为routes 的sink包含了type为sink的mixport和deviceport, source包含了type为source的mixport和deviceport同样解析完设置HwModule中的mRoutes,并设置更新mOutputProfile/mInputProfiles的mSupportedDevices。

        更新的流程是对于mixport type 是source找 type为sink的deviceport。对于mixport type为sink的找type 为source 的deviceport。并将找到的deviceport设置到对应的mSupportedDevices。

        对应的实际的应用 如果是播放音频,那么一个route的mixport是source端 产生数据,deviceport是sink接收数据输出。

      • 解析attach device

        解析attachedDevices的标签, 这些device必须是deviceport中定义的,attachedDevices的device会添加到mOutputDevices 和mInputDevices 当中。

        mOutputDevices是通过audiopolicymanager的mOutputDevicesAll变量 传递进行赋值的。也就是mOutputDevices实际就是mOutputDevicesAll。

      • 解析defaultOutputDevice
        defaultOutputDevice解析之后会存储在mDefaultOutputDevice中。

    • 获取mAvailableOutputDevices 和 mAvailableInputDevices的流程

      • 有了前面的基础, 在获取到mixport(对应mOutputProfiles),attachDevice(对应mOutputDevicesAll),mixport对应的mSupportedDevices(在route中source 类型的mixport 对应的 sink类型的devicePort)之后.

      • 先遍历所有的mOutputProfiles,取出里面里面存储的deviceport,从这些deviceport 找出在attachdevice定义的,新建一个SwAudioOutputDescriptor来对deviceport进行操作。

      • 调用SwAudioOutputDescriptor的open函数打开deviceport(调用流程简单理解会调用的audioflinger 通过hal层 打开device打开成功后创建对应的读写线程)

      • 只有这边open返回成功的设备deviceport 才会加入到mAvailableOutputDevices, mAvailableInputDevices同理。打开成功的 SwAudioOutputDescriptor也会加入到mOutputs。

      • 处理的函数

        void AudioPolicyManager::onNewAudioModulesAvailableInt(DeviceVector *newDevices)

    简单的例子

    比如如下的xml文件,假定所有的设备通过hal都能够成功的打开,那么mAvailableOutputDevices就为Speaker,而mAvailableInputDevices为Built-In Mic。只分析输出mAvailableOutputDevices的情况,首先根据mixPorts的标签得到source类型的mixport为primary output(对应mOutputProfiles),然后通过route的标签可以知道连接到这个mixport的sink类型的deivce有Speaker、Wired Headset、Wired Headphones、Aux Digital、BT SCO、BT SCO Headset、BT SCO Car Kit(这些就是mixport对应的mSupportedDevices)。attachedDevices对应的是Speaker(对应的mOutputDevicesAll)。于是取mOutputDevicesAll 和mSupportedDevices交集也就是speaker。

    
    
        
    
        
            
            
                
                    Speaker
                    Built-In Mic
                
                Speaker
                
                    
                        
                    
                    
                        
                    
                
                
                    
                    
                    
                    
                    
                    
                    
                    
                    
                    
                    
                    
                    
                    
                    
    
                    
                    
                    
                    
                    
                    
                
                
                
                    
                    
                    
                    
                    
                    
                    
                    
                
    
            
    
            
            
    
            
            
    
            
            
    
            
            
    
        
        
    
        
    
        
        
    
        
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
  • 相关阅读:
    Yolo v8数据马赛克数据增强代码详解
    一键关闭 Win11 系统广告「GitHub 热点速览」
    Talk预告 | 普渡大学王虓:如何利用合作对抗学习来提升自监督学习
    openGauss数据库表的创建过程
    小礼盒礼金卡接口分享
    RockTree TOKEN2049 Party爆火,一场千亿规模的“超级聚会”
    为什么电容两端电压不能突变
    MAC地址、IP地址以及ARP协议详细讲解
    【ES6】学习笔记:正则扩展
    Bean Factory 和 ApplicationContext 谁才是 Spring IOC 容器-10
  • 原文地址:https://blog.csdn.net/H2008066215019910120/article/details/132746379