高通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的結構圖

在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章