【车载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_t 与 audio_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_parameters 和 get_parameters 是基于字符串键值对(kv_pairs)的。这种设计类似于"逃生舱",当标准的 API 无法满足厂商特定的硬件需求(比如开启某种自研的音效引擎或降噪算法)时,厂商可以通过自定义 Key 来实现。


结语

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

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

相关推荐
TechVoyager_82464 小时前
多形态输入与12 通道音频:IT6615 这颗 HDMI 发射器的接口宽度
音视频·音频芯片·芯片选型·视频发射
Raymond16885 小时前
AI配音工具长文本合成架构技术解析:全局音色锚定与声学状态跟踪
人工智能·架构·实时互动·视觉检测·音视频·语音识别
hflmwl811 小时前
Wise Data Recovery找回误删的文档照片音乐和视频
音视频·datarecovery·找回误删的文档照片音乐和视频·找回误删的文档照片音乐视频
技灵AI11 小时前
AI 视频转场提示词怎么写?让前后画面衔接更自然
人工智能·prompt·aigc·音视频
youandyouyou13 小时前
跨区培训的屏幕共享怎么做才稳?同屏同步与弱网优化实践
音视频·网络通信
开开心心就好13 小时前
课堂随机点名工具,绿色版免安装双击即用
java·服务器·前端·ffmpeg·音视频·perl·symfony
美狐美颜SDK开放平台14 小时前
直播APP集成美颜SDK,如何梳理第三方组件的数据权限?
开发语言·人工智能·深度学习·音视频·第三方美颜sdk
l143723326715 小时前
批量视频硬字幕擦除多少钱?影响报价的关键因素全解析
音视频
重生六道15 小时前
B站视频时长统计:一段JS脚本搞定分P/合集总时长(附倍速计算)
开发语言·javascript·音视频
音视频牛哥15 小时前
不换摄像机,也能接入 WebRTC?SmartMediaKit RTSP/RTMP 转 WHIP 技术实践
音视频·webrtc·smartmediakit·rtsp转whip·rtmp转whip·whip推流·rtsp转webrtc播放