Android14音頻子系統-Audio HAL分析

文章目錄

      • 1)概述
      • 2)HAL的打開流程
      • 3)HAL庫的實現(Qualcomm)
      • 4)tinyalsa
      • 5)數據結構
      • 6)代碼流程

1)概述

1、回顧HAL、tinyalsa與linux driver的關系

2、與AudioFlinger的關系

3、

1、如何判斷當前平臺用的是哪個庫?
android\hardware\libhardware\modules\audio
android\hardware\libhardware_legacy\audio\audio_hw_hal.cpp
可嘗試注入錯誤代碼,單編 驗證一下 > 但編了也不一定會用!2、hal的作用?隱藏了什么細節,還是說只是為了符合Android框架而寫?
>>播放數據之前的,設置的步驟和參數就是廠家要保護的內容3、HAL如何對接tinyalsa?
把tinyalsa當做一個庫接口使用即可

2)HAL的打開流程

1、由AudioFlinger負責加載
android\frameworks\av\services\audioflinger\AudioFlinger.cpp
audio_module_handle_t AudioFlinger::loadHwModule(const char *name) //name為動態庫的名字2、數據結構:
/android/frameworks/av/media/libaudiohal/include/media/audiohal/DeviceHalInterface.h 
//接口與audio_hw_hal.cpp一一對應android\frameworks\av\services\audioflinger\AudioHwDevice.h //存放device
class AudioHwDevice {
private:const audio_module_handle_t mHandle;const char * const          mModuleName;sp<DeviceHalInterface>      mHwDevice;const Flags                 mFlags;
};3、以aidl / hidl為例,傳統hal實現則直接使用hw_get_module得到對應的庫
AudioHwDevice* AudioFlinger::loadHwModule_l(const char *name)
mDevicesFactoryHal = DevicesFactoryHalInterface::create(); //根據版本選擇aidl / hidl進程4、
android\frameworks\av\media\libaudiohal\FactoryHal.cpp
void *createPreferredImpl(bool isDevice) {
if (createHalService(std::max(*ifaceVersionIt, *siblingVersionIt), isDevice,&rawInterface)) {return rawInterface;}
}mDevicesFactoryHal->openDevice(name, &dev);
--AServiceManager_waitForService(serviceName.c_str()); 5、廠商實現的Audio aidl hal service在哪里?
android\hardware\interfaces\audio\aidl\default\main.cpp
原本傳統hal庫由audio policy解析audio_policy_config而來,Audio aidl hal service也要去解析audio_policy_config去dlopen庫?按理來說是的

3)HAL庫的實現(Qualcomm)

1、目錄介紹:
Qualcomm開源的hal實現
android\hardware\qcom\audio\hal //HAL新架構
android\hardware\qcom\audio\legacy\alsa_sound //HAL舊架構
android\hardware\qcom\audio\legacy\libalsa-intf //alsa-lib2、由于Android系統的發展變化(這些混合的代碼 實在讓人看著難受,還費時間去對比篩選),存在多種架構
1)hal實現分為舊架構和新架構,官方實現的demo代碼對應路徑,廠商需要根據這個去填充自家代碼實現
舊架構:android\hardware\libhardware_legacy
新架構:android\hardware\libhardware\modules\audio2)alsa-lib與tinyalsa
在Android 4.0之前是使用這alsa-lib接口,之后簡化演變成現在的tinyalsa
qcom實現的alsa-lib : android\hardware\qcom\audio\legacy\libalsa-intf
tinyalsa :android\external\tinyalsa本文以HAL舊架構 + tinyalsa為例子分析hal實現3、通信模型大致如下
AudioFlinger -> aidl -> hal -> hal庫(qualcomm)  -> tinyalsa -> linux driver4、常見音效:
音質:acoustics
音頻后處理效果:Post Processing Effects
強化低頻響應:Bass Boost
動態范圍壓縮:Dynamic Range Compression
虛擬環繞聲:Virtualizer
均衡器:EQ5、submix
虛擬設備,實現內部音頻流混合與重定向,支持屏幕錄制、音頻轉發等高級功能
AudioUsbALSA.cpp -> 外接USB聲卡6、基本代碼分析
1)HAL入口函數 - 誰來調用?AudioFlinger
static int legacy_adev_open(const hw_module_t* module, const char* name,hw_device_t** device)
2)
static struct hw_module_methods_t legacy_audio_module_methods = {open: legacy_adev_open
};struct legacy_audio_module HAL_MODULE_INFO_SYM = {module: {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: "LEGACY Audio HW HAL",author: "The Android Open Source Project",methods: &legacy_audio_module_methods,dso : NULL,reserved : {0},},},
};3)hwif 即廠商實現的 對接hal接口
struct legacy_stream_out {struct audio_stream_out stream;AudioStreamOut *legacy_out;
};struct legacy_stream_in {struct audio_stream_in stream;AudioStreamIn *legacy_in;
};static int adev_open_output_stream()
{out->legacy_out = ladev->hwif->openOutputStreamWithFlags(devices, flags,(int *) &config->format,&raw_channel_mask,&config->sample_rate, &status);
}4)AudioHardwareALSA()構造函數中
打開庫ro.hardware.alsa.default
AudioHardwareALSA()
{hw_device_t* device;err = module->methods->open(module, ALSA_HARDWARE_NAME, &device);if (err == 0) {mALSADevice = (alsa_device_t *)device;mALSADevice->init(mALSADevice, mDeviceList);}
}ssize_t AudioStreamOutALSA::write(const void *buffer, size_t bytes)
{n = pcm_write(mHandle->handle, (char *)buffer + sent, period_size);
}5)
#define HAL_MODULE_INFO_SYM HWI  //hal module info
#define HAL_MODULE_INFO_SYM_AS_STR "HMI" //#define ALSA_HARDWARE_MODULE_ID "alsa"
#define ALSA_HARDWARE_NAME      "alsa"6)alsa_handle_t
typedef List < alsa_handle_t > ALSAHandleList;struct alsa_handle_t {alsa_device_t *module;uint32_t devices;strcut pcm *handle;snd_pcm_format_t format;
}struct alsa_device_t {hw_device_t common;status_t (*init)(alsa_device_t *, ALSAHandleList &);status_t (*open)(alsa_handle_t *);...void (*setVoiceVolume)(int);
}typedef struct hw_deivce_t {struct hw_module_t* module;int (*close)(struct hw_device_t* device);
} hw_device_t;

4)tinyalsa

1、tinyalsa這套框架帶來了什么?
>>操作linux driver需要open/read/write,tinyalsa根據asoc協議封裝對應的操作,提供統一接口給到hal,hal只需少量參數即可操作pcm設備節點,實現功能2、測試工具tinyplay/tinycap/tinymix
源碼位置:
android\external\tinyalsa\tinyplay.c
板卡位置
/system/bin/tinyplay  //播放工具
/system/bin/tinycap //錄音工具
/system/bin/tinymix //控制工具(設置音量等操作),注意不是mix混音示例:tinyplay /data/M1F1-int16WE-AFsp.wav -D 1 -d 13、音頻格式:
1)PCM與RAW介紹 : https://blog.csdn.net/weixin_42654603/article/details/143757958
2)tiny只支持wav格式?> 僅支持 PCM(原始數據格式)/ RAW(直接從音頻源-如MIC,不經過編碼和壓縮的原始數據)格式
3)*.wav :Waveform audio File Format (windows系統的標準音頻格式之一) - 不涉及加解密,是PCM流 儲存的文件格式(在PCM流的基礎上加一些控制信息)
4)常說的DOlby音效是什么格式?一般采用AC-3編碼技術
5)WACE Sample Files下載 : https://blog.csdn.net/touzani/article/details/16553284、在TV上,digital output選擇PCM和RAW 又分別代表什么?
PCM:會將音頻數據 轉換 PCM流,兼容絕大多數音頻設備;
RAM:不會處理,直接輸出給音頻設備,音頻設備要求很高;5、tinymix的使用
1)查看tinymix可控的寄存器列表
root@# tinymix
Mixer name: 'audiocodec'
Number of controls: 16
ctl type num name          value
1   INT  1  "digital volume" 0
2   INT  1  "LINEIN to output mixer gain control" 3
3   BOOL 1  "LINEOUT Switch" On
...2)設置音量
tinymix "LINEOUT volume" "2"

5)數據結構

1、module與device
在這里插入圖片描述

1)qcom_audio_device與audio_hw_device的"繼承"用法

這樣設計的目的是什么?為什么轉換來轉換去?
struct qcom_audio_device {struct audio_hw_device device; //向上層提供標準接口struct AudioHardwareInterface *hwif; //向下是指向廠商實現的接口
};先來看看如何使用
static int qcom_adev_open(const hw_module_t* module, const char* name,hw_device_t** device)
{...qadev->device.init_check = adev_init_check;qadev->hwif = createAudioHardware();...*device = &qadev->device.common; //將構造好的device返回給上層調用者保存
}static int adev_init_check(const struct audio_hw_device *dev)
{const struct qcom_audio_device *qadev = to_cladev(dev); //將上層傳遞下來的device轉換一下,相當于父子指針轉換return qadev->hwif->initCheck(); //調用廠家實現的接口
}小結:向上提供的接口需要是穩定的,具體的實現則由廠商自行設計,這樣是靈活的
1)父子對象可以互相轉換,對于上層和hal可以用同一個指針地址,不用額外設計對應關系;
2)如果不分開audio_hw_device、AudioHardwareInterface兩個結構體,則廠商的靈活性會差些,反之廠商可以根據實際情況去調整,更加靈活;

2、stream音頻流

在這里插入圖片描述

1)HAL庫的qcom_stream_out和qcom_stream_in類設計

struct qcom_stream_out {struct audio_stream_out stream; //向上提供接口AudioStreamOut *qcom_out; //指向廠家的接口 AudioStreamOutALSA
};struct qcom_stream_in {struct audio_stream_in stream; //向上提供接口AudioStreamIn *qcom_in; //指向廠家的接口 AudioStreamInALSA
};設計目的與qcom_audio_device同理

2)qcom_stream_out與AudioStreamOutALSA的繼承""用法

1、out->qcom_out = qadev->hwif->openOutputStream(devices,..);
2、AudioStreamOut * AudioHardwareALSA::openOutputStream(){
AudioStreamOutALSA *out = 0;
...
return out;
}
先把父類"繼承"過來,再將其它子類獨有成員一一 賦值

3)類的層級關系設計如下
handle(module的容器) -> module -> device -> stream
device //代表一個音頻設備
stream //由于音頻流操作頗多,抽象出單獨的類,負責控制音頻流,播放,暫停等

3、AlSAMixer與ALSAControl
在這里插入圖片描述

1)主要作用是讀寫設備節點“controlC0”,設置聲卡參數

6)代碼流程

在這里插入圖片描述

2、上層三個步驟使用聲卡播放

qcom_adev_open() //hal層的open,分配資源
adev_open_output_session() // 打開聲卡設備,構造stream方法
qcom_stream_out->stream.write() //寫聲卡數據

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/86139.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/86139.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/86139.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

前端與 Spring Boot 后端無感 Token 刷新 - 從原理到全棧實踐

&#x1f337; 古之立大事者&#xff0c;不惟有超世之才&#xff0c;亦必有堅忍不拔之志 &#x1f390; 個人CSND主頁——Micro麥可樂的博客 &#x1f425;《Docker實操教程》專欄以最新的Centos版本為基礎進行Docker實操教程&#xff0c;入門到實戰 &#x1f33a;《RabbitMQ》…

【AI智能體】新手教程-通過 Chat SDK 搭建網頁在線客服

通過扣子搭建的智能體可以一鍵發布為 Chat SDK&#xff0c;快速部署到你的自建網站中&#xff0c;作為在線智能客服面向網站的用戶提供 AI 答疑服務。本文檔介紹通過 Chat SDK 搭建網頁版在線客服的詳細操作步驟。 場景說明 網站作為企業和組織與用戶互動的重要平臺&#xff…

flask靜態資源與模板頁面、模板用戶登錄案例

案例代碼 import flask# template_folder 模板文件夾(靜態頁面 html頁面渲染) # static_folder 靜態資源文件夾主要存放的是類似靜態數據、音頻、視頻、圖片等 app flask.Flask(__name__, static_folderstatic, template_foldertemplate)app.route(/) def index():# render_t…

【工具教程】識別PDF中文字內容,批量識別文字并保存到Excel表格中的操作步驟和方法

在日常辦公和文件管理中&#xff0c;我們常常會遇到需要處理大量 PDF 文件的情況。有時&#xff0c;為了更好地管理和查找這些文件&#xff0c;需要根據 PDF 文件中特定區域的文字內容對文件進行重命名。例如&#xff0c;在企業檔案管理中&#xff0c;合同文件可能需要根據合同…

重生學AI第十三集:初識神經網絡之Conv2d

終于該學習神經網絡的搭建了&#xff0c;開心&#xff0c;嘻嘻 學習神經網絡離不開torch.nn&#xff0c;先把他印在腦子里&#xff0c;什么是torch.nn?他是Pytorch的一個模塊&#xff0c;包含了大量構建神經網絡需要的類和方法&#xff0c;就像前面學習的torch.utils&#xf…

學習C++、QT---07(C++的權限、C++的引用)

每日一言 你解決的每一個難題&#xff0c;都是在為未來的自己解鎖新技能。 權限的講解 這邊呢我們利用銀行的一個案例來講解權限的奧秘 權限指的是public、private 、protected 就是這三種權限&#xff0c;因此有這一張表進行分清他們之間的區別和聯系 但是我們在平時的話會因…

全球化短劇平臺全棧技術架構白皮書:多區域部署、智能分發與沉浸式體驗的完整解決方案

一、全球化基礎架構深度設計 全球網絡基礎設施構建 采用多活數據中心部署模式&#xff0c;在北美&#xff08;弗吉尼亞&#xff09;、歐洲&#xff08;法蘭克福&#xff09;、亞太&#xff08;新加坡&#xff09;建立三大核心樞紐節點 構建混合CDN網絡&#xff0c;整合AWS Clo…

深入剖析 LGM—— 開啟高分辨率 3D 內容創作新時代

一、引言 在當今數字化時代&#xff0c;3D 內容創作的需求如井噴般增長&#xff0c;從游戲開發中絢麗多彩的虛擬世界&#xff0c;到影視制作里震撼人心的特效場景&#xff0c;再到工業設計中精準無誤的產品原型&#xff0c;3D 技術無處不在。然而&#xff0c;傳統 3D 內容創作…

從用戶到社區Committer:小米工程師隋亮亮的Apache Fory成長之路

Apache Fory 是一個基于JIT和零拷貝的高性能多語言序列化框架&#xff0c;實現了高效緊湊的序列化協議&#xff0c;提供極致的性能、壓縮率和易用性。在多語言序列化框架技術領域取得了重大突破&#xff0c;推動序列化技術步入高性能易用新篇章&#xff01;這一切&#xff0c;都…

【Koa系列】10min快速入門Koa

簡介 koa是基于node開發的一個服務端框架&#xff0c;功能同express&#xff0c;但更小巧簡單。 官方倉庫地址&#xff1a;https://github.com/koajs/koa 創建項目 創建文件夾nodeKoa&#xff0c;執行以下腳本 npm init -y npm i koa npm i nodemon 基礎示例 創建一個服…

IDEA與通義聯合:智能編程效率革命

IDEA與通義聯合&#xff1a;智能編程效率革命 當最強Java IDE遇上頂尖AI助手&#xff0c;會碰撞出怎樣的生產力火花&#xff1f; 思維導圖解讀&#xff1a;智能編程工作流 #mermaid-svg-uTAcSs1kBBmDwGfM {font-family:"trebuchet ms",verdana,arial,sans-serif;font…

Docker 數據持久化完全指南:Volume、Bind Mount 與匿名卷

Docker 數據持久化完全指南&#xff1a;Volume、Bind Mount 與匿名卷 引言 在 Docker 中&#xff0c;容器的文件系統默認是臨時的&#xff0c;容器刪除后數據也會丟失。為了實現數據持久化&#xff0c;Docker 提供了多種存儲方式&#xff0c;主要包括&#xff1a; docker vo…

OSS跨區域復制災備方案:華東1到華南1的數據同步與故障切換演練

1. 引言 對象存儲服務&#xff08;OSS&#xff09;已成為現代數據架構的核心組件。隨著業務全球化&#xff0c;跨區域數據災備從“可選”變為“必選”。本文以阿里云OSS為實驗環境&#xff0c;實戰演練華東1&#xff08;杭州&#xff09;到華南1&#xff08;深圳&#xff09;的…

前端登錄狀態管理:主流方案對比與安全實踐指南

根據目前業內前端登錄狀態管理的主流設計方案&#xff0c;及其演進趨勢進行匯總&#xff0c;生成主要包括如下內容的報告&#xff1a; 登錄狀態保持的基礎原理&#xff1a;從HTTP無狀態問題出發解析技術需求&#xff0c;使用表格對比核心挑戰。主流技術方案對比&#xff1a;詳…

動手用 Web 實現一個 2048 游戲

文章目錄 為什么選擇 2048&#xff1f;關鍵技術點與算法詳解HTML 結構&#xff1a;搭建游戲界面CSS 樣式&#xff1a;美化游戲界面JavaScript 核心邏輯&#xff1a;驅動游戲運行1&#xff09;數據結構&#xff1a;二維數組表示游戲網格2&#xff09;核心算法&#xff1a;添加隨…

frp v0.62.1內網穿透搭建和使用

官網&#xff1a;https://gofrp.org/zh-cn/ Github&#xff1a;https://github.com/fatedier/frp 開源項目 frp frp 是一種快速反向代理&#xff0c;允許您將位于 NAT 或防火墻后面的本地服務器公開給 Internet。目前支持 TCP 和 UDP&#xff0c;以及 HTTP 和 HTTPS 協議&…

如何使用 USB 數據線將文件從 PC 傳輸到 iPhone

雖然用 USB 數據線將文件從 PC 傳輸到安卓設備非常容易&#xff0c;但對于 iPhone 用戶來說&#xff0c;情況就不同了。不過&#xff0c;幸運的是&#xff0c;我們找到了三種可靠的方法&#xff0c;可以使用 USB 數據線將文件從 PC 傳輸到 iPhone&#xff0c;讓您輕松完成這項任…

【C++高階三】AVL樹深度剖析

【C高階三】AVL樹深度剖析 1.什么是AVL樹2.AVL樹的實現2.1節點類和基本結構2.2插入2.3旋轉處理2.3.1左單旋2.3.2右單旋2.3.3左右雙旋2.3.4右左雙旋 1.什么是AVL樹 AVL樹也叫二叉搜索平衡樹 因為二叉搜索樹如果插入順序是有序的&#xff0c;那么這棵樹的查找效率將會是O(N)&…

LangChain 文本分割器深度解析:從原理到落地應用(上)

食用指南 LangChain 作為大語言模型應用開發框架&#xff0c;文本分割器是其核心組件之一&#xff0c;本文以此作為切入點&#xff0c;詳細介紹文本分割的作用、策略、以及常見的文本切割器應用。考慮到篇幅過長&#xff0c;故拆分為上、中、下三篇&#xff0c;后續會在中篇介…

【Java高頻面試問題】高并發篇

【Java高頻面試問題】高并發篇 Kafka原理核心組件高吞吐核心機制高可用設計 Kafka 如何保證消息不丟失如何解決Kafka重復消費一、生產者端&#xff1a;根源防重二、消費者端&#xff1a;精準控制三、業務層&#xff1a;冪等性設計&#xff08;核心方案&#xff09; 如何解決Kaf…