【车载Audio】【AudioHal 05】【高通音频架构】【audio_hw_device 核心接口解析】

深入理解 Android Audio HAL:audio_hw_device 核心接口解析

引言

在 Android 音频架构中,Audio HAL (硬件抽象层) 承担着承上启下的核心作用。它向上为 AudioFlinger 提供统一的接口,向下屏蔽底层驱动(如 ALSA、TinyALSA)的复杂性。而 struct audio_hw_device 则是整个 Audio HAL 的灵魂,定义了音频硬件设备必须实现的各种操作契约。

本文将深入探讨 audio_hw_device 的结构、核心成员的功能以及它们在实际音频流处理中的应用场景。

c 复制代码
struct audio_hw_device {
    /**
     * Common methods of the audio device.  This *must* be the first member of audio_hw_device
     * as users of this structure will cast a hw_device_t to audio_hw_device pointer in contexts
     * where it's known the hw_device_t references an audio_hw_device.
     */
    struct hw_device_t common;

    /**
     * used by audio flinger to enumerate what devices are supported by
     * each audio_hw_device implementation.
     *
     * Return value is a bitmask of 1 or more values of audio_devices_t
     *
     * NOTE: audio HAL implementations starting with
     * AUDIO_DEVICE_API_VERSION_2_0 do not implement this function.
     * All supported devices should be listed in audio_policy.conf
     * file and the audio policy manager must choose the appropriate
     * audio module based on information in this file.
     */
    uint32_t (*get_supported_devices)(const struct audio_hw_device *dev);

    /**
     * check to see if the audio hardware interface has been initialized.
     * returns 0 on success, -ENODEV on failure.
     */
    int (*init_check)(const struct audio_hw_device *dev);

    /** set the audio volume of a voice call. Range is between 0.0 and 1.0 */
    int (*set_voice_volume)(struct audio_hw_device *dev, float volume);

    /**
     * set the audio volume for all audio activities other than voice call.
     * Range between 0.0 and 1.0. If any value other than 0 is returned,
     * the software mixer will emulate this capability.
     */
    int (*set_master_volume)(struct audio_hw_device *dev, float volume);

    /**
     * Get the current master volume value for the HAL, if the HAL supports
     * master volume control.  AudioFlinger will query this value from the
     * primary audio HAL when the service starts and use the value for setting
     * the initial master volume across all HALs.  HALs which do not support
     * this method may leave it set to NULL.
     */
    int (*get_master_volume)(struct audio_hw_device *dev, float *volume);

    /**
     * set_mode is called when the audio mode changes. AUDIO_MODE_NORMAL mode
     * is for standard audio playback, AUDIO_MODE_RINGTONE when a ringtone is
     * playing, and AUDIO_MODE_IN_CALL when a call is in progress.
     */
    int (*set_mode)(struct audio_hw_device *dev, audio_mode_t mode);

    /* mic mute */
    int (*set_mic_mute)(struct audio_hw_device *dev, bool state);
    int (*get_mic_mute)(const struct audio_hw_device *dev, bool *state);

    /* set/get global audio parameters */
    int (*set_parameters)(struct audio_hw_device *dev, const char *kv_pairs);

    /*
     * Returns a pointer to a heap allocated string. The caller is responsible
     * for freeing the memory for it using free().
     */
    char * (*get_parameters)(const struct audio_hw_device *dev,
                             const char *keys);

    /* Returns audio input buffer size according to parameters passed or
     * 0 if one of the parameters is not supported.
     * See also get_buffer_size which is for a particular stream.
     */
    size_t (*get_input_buffer_size)(const struct audio_hw_device *dev,
                                    const struct audio_config *config);

    /** This method creates and opens the audio hardware output stream.
     * The "address" parameter qualifies the "devices" audio device type if needed.
     * The format format depends on the device type:
     * - Bluetooth devices use the MAC address of the device in the form "00:11:22:AA:BB:CC"
     * - USB devices use the ALSA card and device numbers in the form  "card=X;device=Y"
     * - Other devices may use a number or any other string.
     */

    int (*open_output_stream)(struct audio_hw_device *dev,
                              audio_io_handle_t handle,
                              audio_devices_t devices,
                              audio_output_flags_t flags,
                              struct audio_config *config,
                              struct audio_stream_out **stream_out,
                              const char *address);

    void (*close_output_stream)(struct audio_hw_device *dev,
                                struct audio_stream_out* stream_out);

    /** This method creates and opens the audio hardware input stream */
    int (*open_input_stream)(struct audio_hw_device *dev,
                             audio_io_handle_t handle,
                             audio_devices_t devices,
                             struct audio_config *config,
                             struct audio_stream_in **stream_in,
                             audio_input_flags_t flags,
                             const char *address,
                             audio_source_t source);

    void (*close_input_stream)(struct audio_hw_device *dev,
                               struct audio_stream_in *stream_in);

    /**
     * Called by the framework to read available microphones characteristics.
     *
     * \param[in] dev the hw_device object.
     * \param[out] mic_array Pointer to first element on array with microphone info
     * \param[out] mic_count When called, this holds the value of the max number of elements
     *                       allowed in the mic_array. The actual number of elements written
     *                       is returned here.
     *                       if mic_count is passed as zero, mic_array will not be populated,
     *                       and mic_count will return the actual number of microphones in the
     *                       system.
     *
     * \return 0 if the microphone array is successfully filled.
     *         -ENOSYS if there is an error filling the data
     */
    int (*get_microphones)(const struct audio_hw_device *dev,
                           struct audio_microphone_characteristic_t *mic_array,
                           size_t *mic_count);

    /** This method dumps the state of the audio hardware */
    int (*dump)(const struct audio_hw_device *dev, int fd);

    /**
     * set the audio mute status for all audio activities.  If any value other
     * than 0 is returned, the software mixer will emulate this capability.
     */
    int (*set_master_mute)(struct audio_hw_device *dev, bool mute);

    /**
     * Get the current master mute status for the HAL, if the HAL supports
     * master mute control.  AudioFlinger will query this value from the primary
     * audio HAL when the service starts and use the value for setting the
     * initial master mute across all HALs.  HALs which do not support this
     * method may leave it set to NULL.
     */
    int (*get_master_mute)(struct audio_hw_device *dev, bool *mute);

    /**
     * Routing control
     */

    /* Creates an audio patch between several source and sink ports.
     * The handle is allocated by the HAL and should be unique for this
     * audio HAL module. */
    int (*create_audio_patch)(struct audio_hw_device *dev,
                               unsigned int num_sources,
                               const struct audio_port_config *sources,
                               unsigned int num_sinks,
                               const struct audio_port_config *sinks,
                               audio_patch_handle_t *handle);

    /* Release an audio patch */
    int (*release_audio_patch)(struct audio_hw_device *dev,
                               audio_patch_handle_t handle);

    /* Fills the list of supported attributes for a given audio port.
     * As input, "port" contains the information (type, role, address etc...)
     * needed by the HAL to identify the port.
     * As output, "port" contains possible attributes (sampling rates, formats,
     * channel masks, gain controllers...) for this port.
     */
    int (*get_audio_port)(struct audio_hw_device *dev,
                          struct audio_port *port);

    /* Set audio port configuration */
    int (*set_audio_port_config)(struct audio_hw_device *dev,
                         const struct audio_port_config *config);

    /**
     * Applies an audio effect to an audio device.
     *
     * @param dev the audio HAL device context.
     * @param device identifies the sink or source device the effect must be applied to.
     *               "device" is the audio_port_handle_t indicated for the device when
     *               the audio patch connecting that device was created.
     * @param effect effect interface handle corresponding to the effect being added.
     * @return retval operation completion status.
     */
    int (*add_device_effect)(struct audio_hw_device *dev,
                        audio_port_handle_t device, effect_handle_t effect);

    /**
     * Stops applying an audio effect to an audio device.
     *
     * @param dev the audio HAL device context.
     * @param device identifies the sink or source device this effect was applied to.
     *               "device" is the audio_port_handle_t indicated for the device when
     *               the audio patch is created.
     * @param effect effect interface handle corresponding to the effect being removed.
     * @return retval operation completion status.
     */
    int (*remove_device_effect)(struct audio_hw_device *dev,
                        audio_port_handle_t device, effect_handle_t effect);

    /**
     * Fills the list of supported attributes for a given audio port.
     * As input, "port" contains the information (type, role, address etc...)
     * needed by the HAL to identify the port.
     * As output, "port" contains possible attributes (sampling rates, formats,
     * channel masks, gain controllers...) for this port. The possible attributes
     * are saved as audio profiles, which contains audio format and the supported
     * sampling rates and channel masks.
     */
    int (*get_audio_port_v7)(struct audio_hw_device *dev,
                             struct audio_port_v7 *port);
};
typedef struct audio_hw_device audio_hw_device_t;

核心字段功能分类与使用场景总结

为了方便开发者快速查阅,我们将 audio_hw_device 的字段按功能逻辑进行了归类:

1. 基础与初始化 (Basic & Initialization)

字段名 功能描述 使用场景
common 标准硬件设备头信息 必须放在首位 。用于 hw_device_taudio_hw_device 之间的强制类型转换。
init_check 检查硬件初始化状态 系统启动或 AudioServer 重启时,验证音频硬件是否就绪。
get_supported_devices 获取支持的设备位掩码 (旧版 HAL) 询问硬件支持哪些输出输入设备。现代 HAL 更多依赖 audio_policy.conf

2. 流管理 (Stream Management)

字段名 功能描述 使用场景
open_output_stream 创建并打开音频输出流 核心接口。播放音乐、铃声、通知音时,申请硬件资源。
close_output_stream 关闭并释放输出流 停止播放并回收资源。
open_input_stream 创建并打开音频输入流 录音、语音助手通话录音时调用。
close_input_stream 关闭并释放输入流 停止录音。
get_input_buffer_size 获取建议的输入缓冲区大小 录音前根据采样率、格式等计算所需的最小 Buffer。

3. 音量与模式控制 (Volume & Mode Control)

字段名 功能描述 使用场景
set_voice_volume 设置通话音量 在通话过程中调整听筒或免提的音量。
set_master_volume 设置全局主音量 调整整个系统的硬件增益(如果硬件支持)。
set_master_mute 设置全局静音 系统一键静音功能。
set_mode 设置音频模式 切换 NORMAL(普通)、RINGTONE(来电)、IN_CALL(通话中)等模式。

4. 参数配置与微调 (Parameters & Microphones)

字段名 功能描述 使用场景
set_parameters 以键值对形式设置参数 动态调整采样率、路由切换、甚至是一些私有的硬件调试命令。
get_parameters 获取当前硬件参数 查询当前的路由状态或特定的硬件指标。
set_mic_mute 麦克风静音 通话中点击"静音"按钮。
get_microphones 获取麦克风特性 手机有多个麦克风时,获取其位置、方向性等物理信息。

5. 高级路由与补丁 (Advanced Routing / Audio Patch)

字段名 功能描述 使用场景
create_audio_patch 创建音频路径 (Patch) 现代路由核心。直接连接 Source(如输入端)和 Sink(如输出端),支持硬件直连。
release_audio_patch 释放音频路径 销毁当前的硬件直连路径。
get_audio_port_v7 获取音频端口详细信息 查询音频端口支持的 Profile(采样率、格式组合)。

深度解析:关键机制与设计理念

1. 结构体内存布局的精妙之处

struct hw_device_t common 必须是第一个成员。这是 Android HAL 的通用设计模式。由于 common 的地址和 audio_hw_device 的起始地址相同,底层代码可以安全地通过 (struct audio_hw_device *)device 进行指针强转。

2. 从"设备查询"到"策略驱动"的演进

字段 get_supported_devices 在 2.0 版本后已废弃。这标志着 Android 音频系统从"HAL 决定能做什么"转向了"由 Audio Policy 管理器通过配置文件决定"。这种解耦让音频路由更加灵活,支持复杂的车载和专业音频场景。

3. Audio Patch 机制:减少 CPU 干预

create_audio_patch 是 Android 5.0 引入的重要改进。

  • 传统方式:音频数据必须经过 CPU 转发。

  • Patch 方式 :允许 HAL 配置硬件路由(如从 FM Tuner 直接路由到 Speaker),无需数据流经 AudioFlinger,极大地降低了功耗和延迟。

4. 万能的 Parameters 接口

set_parametersget_parameters 是基于字符串键值对(kv_pairs)的。这种设计类似于"逃生舱",当标准的 API 无法满足厂商特定的硬件需求(比如开启某种自研的音效引擎或降噪算法)时,厂商可以通过自定义 Key 来实现。


结语

audio_hw_device 不仅仅是一个结构体定义,它是 Android 系统对音频硬件能力的抽象边界。理解这个接口,就掌握了 Android 音频数据流向的核心路径。随着 Android 版本的演进,该结构体正在从简单的"开关切换"演变为复杂的"路由矩阵管理"。

对于 HAL 层开发者来说,实现这些接口时,不仅要保证功能的正确性,更要考虑线程安全 (AudioFlinger 调用通常是多线程的)以及硬件状态机的健壮性

相关推荐
音视频牛哥12 小时前
RTSP协议规范深度解析与SmartMediaKit的RTSP播放器工程实践
人工智能·计算机视觉·音视频·大牛直播sdk·rtsp播放器·超低延迟rtsp播放器·rtspplayer
sweetone17 小时前
故障现象 并非玄学——LINN(莲)MAJIK功放维修记录
经验分享·音视频
不吃鱼的猫74821 小时前
【从零手写播放器:FFmpeg 音视频开发实战】04-封装格式与多媒体容器
c++·ffmpeg·音视频
九丝城主1 天前
1V1音视频对话4--FLUTTER实现
flutter·音视频
张张说点啥1 天前
能做影视级可商业视频的AI工具,Seedance 2.0 全球首发实测
人工智能·音视频
qq_433502181 天前
收集了一些免费视频背景映月素材网站分享记录
经验分享·学习·音视频·生活
上海合宙LuatOS2 天前
LuatOS核心库API——【hmeta 】硬件元数据
单片机·嵌入式硬件·物联网·算法·音视频·硬件工程·哈希算法
一个人旅程~2 天前
QQ音乐、potplayer、VLC等对音乐格式的支持和加密文件格式的转换有哪些方法?potplayer的音质相对于VLC有哪些特点?
windows·经验分享·电脑·音视频
音视频牛哥2 天前
从协议栈到工程落地:SmartMediaKit全链路模块化架构深度解析
音视频·rtsp播放器·rtmp播放器·安卓rtsp服务器·安卓轻量级rtsp服务·安卓rtsp摄像头推流·安卓摄像头rtmp推流