高通Audio Hal学习笔记(1)结构体的关系

以下以高通的开源代码codeaurora.org分析,版本: lito LA.UM.8.13.r1-08500-SAIPAN.0 下载的方式: repo init -u git://codeaurora.org/platform/manifest.git -b
release -m LA.UM.8.13.r1-08500-SAIPAN.0.xml
–repo-url=git://codeaurora.org/tools/repo.git --repo-branch=caf-stable

1. Audio Hal的标准接口相关的结构体

1.1 Module相关的结构体

在audio_hw.c中我们可以看到如下定义

static struct hw_module_methods_t hal_module_methods = {
    .open = adev_open,
};

struct audio_module HAL_MODULE_INFO_SYM = {
    .common = {
        .tag = HARDWARE_MODULE_TAG,
        .module_api_version = AUDIO_MODULE_API_VERSION_0_1,
        .hal_api_version = HARDWARE_HAL_API_VERSION,
        .id = AUDIO_HARDWARE_MODULE_ID,
        .name = "QCOM Audio HAL",
        .author = "The Linux Foundation",
        .methods = &hal_module_methods,
    },
};

1.1.1 HAL_MODULE_INFO_SYM

当AudioFlinger加载AudioHal库之后会找到这个符号,获得audio_module这个结构。每一个Hal必须要有这个符号。
hal_module_methods: 这个结构比较明显是提供一个open的回调函数, 猜测应该是用来打开Hal, 初始化Hal, 获取更多的接口

1.1.2 struct audio_module

内部只有audio_module这个结构,从结构体的描述我们知道,结构体必须以hw_module_t开始,之后可以是模块特有的信息。这样可以用来保证 HAL_MODULE_INFO_SYM 和 common的地址相同,方便通过指针做互相转化。

struct audio_module {
	struct hw_module_t common;
};

1.1.3 struct hw_module_t

这个是标准Hal的接口,用于提供这个Hal的描述以及最基本的接口,关于内部成员的含义可以参考结构体声明部分的注释。

	typedef struct hw_module_t {
		uint32_t tag;
		uint16_t module_api_version;
		uint16_t hal_api_version;
		const char *id;
		const char *name;
		const char *author;
		struct hw_module_methods_t* methods;
	}

1.1.4 struct hw_module_methods_t

这里面只有一个open函数, 比较明显是传入获取的module,返回一个struct hw_device_t结构体指针。

    int (*open)(const struct hw_module_t* module, const char* id,
                      struct hw_device_t** device);

1.2 Device相关的结构体

在AudioHal中会出现很多device的概念,比较容易混淆,其中这里的device我们可以理解为一个声卡设备。
audio_hw_device包含两部分,struct hw_device_t common这个是标准Hal的一个接口,放在了结构体的最前面。也是为了指针转化。接下来的是Audio Hal特有的接口,都是回调函数:
比较重要的是控制输入输出流的接口。其中通过open_output_stream的声明我们可以猜到,用来返回一个struct audio_stream_out结构体指针,这个结构体用来控制播放流。

struct audio_hw_device {

    struct hw_device_t common;

    uint32_t (*get_supported_devices)();
    int (*get_microphones)();
    int (*init_check)();

    int (*create_audio_patch)();
    int (*release_audio_patch)();
    int (*get_audio_port)();
    int (*set_audio_port_config)();

    int (*set_voice_volume)();
    int (*set_master_volume)();
    int (*get_master_volume)();
    int (*set_mic_mute)();
    int (*get_mic_mute)();
    int (*set_master_mute)();
    int (*get_master_mute)();

    int (*set_mode)();
    int (*set_parameters)()
    char * (*get_parameters)();
    size_t (*get_input_buffer_size)();

    int (*open_output_stream)();
    void (*close_output_stream)();
    int (*open_input_stream)();
    void (*close_input_stream)();

    int (*dump)();

1.3 Stream相关的接口

audio_stream_out,audio_stream_in
我们这里的流指的是一个具体的pcm数据流,与AudioFlinge的播放/录音线程相对应。
有两个结构体: audio_stream_out, audio_stream_in
两个结构体都以同一个结构体开头,struct audio_stream common,原因与上面的描述基本相同。
以audio_stream_out为例,内部都是回调函数的指针,其中比较重要指针包括start, stop, write等接口具体的接口可以参考结构体的声明。

2 高通针对接口的扩展

2.1 audio_device结构体

2.1.1 audio_device

是对audio_hw_device的扩展,类似与继承的概念。用来描述整个Audio Hal也就是整个声卡。结构体只有一处定义adev,在接口adev_open处分配空间。因为 audio_device audio_hw_device hw_device_t 结构体指针相同。在之后的操作中有很多接口之间的转化。
audio_device结构体太大,下面只列出来几个比较重要的成员:

struct audio_device {
    struct audio_hw_device device;

    int snd_card;

    struct listnode usecase_list;

    struct mixer *mixer;
    struct audio_route *audio_route;

    struct voice voice;
    void *platform;
};

2.1.2 audio_hw_device

audio hal的标准接口,放在了audio_device最前面。保证结构体指针相同。
这样当AudioFligner传入一个struct audio_hw_device dev指针(通过open获取),我们就可以把dev转化为struct audio_device

2.1.3 snd_card

即声卡的ID,也就是ALSA设备中声卡的ID。audio_device可以理解为对声卡的抽象。

2.1.4 usecase_list

对Audio Hal最重要的应该是PCM数据流。在audio_device中的struct listnode usecase_list链表中保存了pcm流的信息。

struct audio_device {
    struct audio_hw_device device;

    int snd_card;

    struct listnode usecase_list;

    struct mixer *mixer;
    struct audio_route *audio_route;

    struct voice voice;
    void *platform;
};

2.2 stream_out,stream_in

这两个结构体是对audio_stream_out, audio_stream_in的扩展。用来描述一个PCM数据流。
其中有个成员 int pcm_device_id,代表了一个ALSA中的PCM设备的ID。我们就可以理解:
AudioPolicy中的output,AudioFlinger中的Thread,AudioHal的Stream,Alsa的PCM设备都是一一对应的。都是对同一个PCM数据流的抽象。
之后,我们会重点分析一下这个两个结构体。

2.3 struct audio_usecase

这个结构体是对stream_out,stream_in进一步的抽象。特殊的场景,没有PCM设备的场景也会创建一个usecase,例如通话。为了可以对硬件统一操作,防止各种场景下硬件访问的冲突。
其中audio_usecase是在start_output_stream函数中创建的,在stop中清除。所以它一般用来表示正在运行或者stanby状态的流。

	struct audio_usecase {
	    struct listnode list;
	    audio_usecase_t id;
	    usecase_type_t  type;
	    audio_devices_t devices;
	    snd_device_t out_snd_device;
	    snd_device_t in_snd_device;
	    struct stream_app_type_cfg out_app_type_cfg;
	    struct stream_app_type_cfg in_app_type_cfg;
	    union stream_ptr stream;
	};

2.3.1 union stream_ptr stream

联合体中保存着stream_out或stream_in的指针。可以通过use_case->stream.out操作stream_out结构体。

	union stream_ptr {
		struct stream_in *in;
		struct stream_out *out;
		struct stream_inout *inout;
	};

2.3.2 audio_usecase_t id, usecase_type_t type

usecase的类型,根据AudioPolicy中output的类型获得

3 Audio Hal的结构图

在这里插入图片描述

  • 12
    点赞
  • 98
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
如果您想使用WS2812 RGB LED的PWM HAL库,并且使用RGB结构体来表示颜色,可以参考以下示例代码: ```c #include "main.h" #define NUM_LEDS 8 typedef struct { uint8_t red; uint8_t green; uint8_t blue; } RGB_Color; TIM_HandleTypeDef htim; void WS2812_Init(void) { // 初始化PWM定时器 htim.Instance = TIM2; htim.Init.Prescaler = 0; htim.Init.CounterMode = TIM_COUNTERMODE_UP; htim.Init.Period = 89; // 对应WS2812的周期 htim.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; HAL_TIM_PWM_Init(&htim); TIM_OC_InitTypeDef sConfigOC; sConfigOC.OCMode = TIM_OCMODE_PWM1; sConfigOC.Pulse = 0; sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH; sConfigOC.OCFastMode = TIM_OCFAST_ENABLE; HAL_TIM_PWM_ConfigChannel(&htim, &sConfigOC, TIM_CHANNEL_1); HAL_TIM_PWM_Start(&htim, TIM_CHANNEL_1); } void WS2812_SetColor(RGB_Color color) { // 设置PWM占空比 __HAL_TIM_SET_COMPARE(&htim, TIM_CHANNEL_1, color.green); HAL_Delay(1); // 调整延时以适应WS2812的时序要求 __HAL_TIM_SET_COMPARE(&htim, TIM_CHANNEL_1, color.red); HAL_Delay(1); // 调整延时以适应WS2812的时序要求 __HAL_TIM_SET_COMPARE(&htim, TIM_CHANNEL_1, color.blue); HAL_Delay(1); // 调整延时以适应WS2812的时序要求 } void WS2812_SetAll(RGB_Color color) { for (int i = 0; i < NUM_LEDS; i++) { WS2812_SetColor(color); } } int main(void) { HAL_Init(); WS2812_Init(); RGB_Color red = {255, 0, 0}; RGB_Color green = {0, 255, 0}; RGB_Color blue = {0, 0, 255}; while (1) { WS2812_SetAll(red); // 设置所有LED为红色 HAL_Delay(1000); WS2812_SetAll(green); // 设置所有LED为绿色 HAL_Delay(1000); WS2812_SetAll(blue); // 设置所有LED为蓝色 HAL_Delay(1000); } } ``` 在以上示例代码中,使用了PWM定时器来控制WS2812 LED的颜色。RGB_Color结构体用于表示颜色值,可以根据需要进行修改。请确保根据实际硬件进行适当的配置和修改。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值