Android音頻系統

来源:https://www.cnblogs.com/linhaostudy/archive/2018/09/24/9694078.html
-Advertisement-
Play Games

1 分析思路 1. Thread如何創建? AudioPolicyService是策略的制定者,AudioFlinger是策略的執行者, 所以: AudioPolicyService根據配置文件使喚AudioFlinger來創建Thread 2. Thread對應output, output對應哪些 ...


1 分析思路

  1. Thread如何創建?
    AudioPolicyService是策略的制定者,AudioFlinger是策略的執行者,
    所以: AudioPolicyService根據配置文件使喚AudioFlinger來創建Thread

  2. Thread對應output, output對應哪些設備節點?

  3. AudioTrack和Track的創建過程: AudioTrack對應哪一個Thread, 對應哪一個output?

  4. AudioTrack如何傳輸數據給Thread?

  5. AudioTrack如何播放、暫停、關閉?

2 以例子說明幾個重要概念

stream type, strategy, device, output, profile, module : policy

out flag : 比如對於某個專業APP, 它只從HDMI播放聲音, 這時就可以指定out flag為AUDIO_OUTPUT_FLAG_DIRECT,這會導致最終的聲音無需混音即直接輸出到對應的device

Android系統里使用hardware module來訪問硬體, 比如音效卡
音效卡上有喇叭、耳機等等,稱為device
為了便於管理, 把一個設備上具有相同參數的一組device稱為output,
一個module能支持哪些output,一個output能支持哪些device,使用配置文件/system/etc/audio_policy.conf來描述

app要播放聲音, 要指定聲音類型: stream type有那麼多的類型, 來來來, 先看它屬於哪一類(策略): strategy

根據strategy確定要用什麼設備播放: device, 喇叭、耳機還是藍牙?
根據device確定output, 進而知道對應的playbackthread,
把聲音數據傳給這個thread

一個stream如何最終選擇到一個device,這些stream如何互相影響(一個高優先順序的聲音會使得其他聲音靜音),等等等, 統稱為policy (政策)

輸出、輸入設備:
https://blog.csdn.net/zzqhost/article/details/7711935

3 所涉及文件形象講解

系統服務APP:

frameworks/av/media/mediaserver/main_mediaserver.cpp

AudioFlinger :

AudioFlinger.cpp
(frameworks/av/services/audioflinger/AudioFlinger.cpp)

Threads.cpp (frameworks/av/services/audioflinger/Threads.cpp)

Tracks.cpp (frameworks/av/services/audioflinger/Tracks.cpp)

audio_hw_hal.cpp (hardware/libhardware_legacy/audio/Audio_hw_hal.cpp)

AudioHardware.cpp (device/friendly-arm/common/libaudio/AudioHardware.cpp)

AudioPolicyService:

AudioPolicyService.cpp (frameworks/av/services/audiopolicy/AudioPolicyService.cpp)

AudioPolicyClientImpl.cpp (frameworks/av/services/audiopolicy/AudioPolicyClientImpl.cpp)

AudioPolicyInterfaceImpl.cpp(frameworks/av/services/audiopolicy/AudioPolicyInterfaceImpl.cpp)

AudioPolicyManager.cpp (device/friendly-arm/common/libaudio/AudioPolicyManager.cpp)

AudioPolicyManager.h (device/friendly-arm/common/libaudio/AudioPolicyManager.h)

AudioPolicyManagerBase.cpp (hardware/libhardware_legacy/audio/AudioPolicyManagerBase.cpp)

堪誤: 上面3個文件被以下文件替代
AudioPolicyManager.cpp (frameworks/av/services/audiopolicy/AudioPolicyManager.cpp)

應用程式APP所用文件:

AudioTrack.java (frameworks/base/media/java/android/media/AudioTrack.java)

android_media_AudioTrack.cpp (frameworks/base/core/jni/android_media_AudioTrack.cpp)

AudioTrack.cpp (frameworks/av/media/libmedia/AudioTrack.cpp)

AudioSystem.cpp (frameworks/av/media/libmedia/AudioSystem.cpp)

4 AudioPolicyService啟動過程分析

比如一部典型的手機,它既有聽筒、耳機介面,還有藍牙設備。假設預設情況下播放音樂是通過聽筒喇叭輸出的,那麼當用戶插入耳機時,這個策略就會改變——從耳機輸出,而不再是聽筒;又比如在機器插著耳機時,播放音樂不應該從喇叭輸出,但是當有來電鈴聲時,就需要同時從喇叭和耳機輸出音頻。這些“音頻策略”的制定,主導者就是AudioPolicyService

在AudioFlinger小節,我們反覆強調它只是策略的執行者,而AudioPolicyService則是策略的制定者。這種分離方式有效地降低了整個系統的藕合性,而且為各個模塊獨立擴展功能提供了保障。

  1. 載入解析/vendor/etc/audio_policy.conf/system/etc/audio_policy.conf
    • 對於配置文件里的每一個module項, new HwModule(name), 放入mHwModules數組;
    • 對於module里的每一個output, new IOProfile,放入module的mOutputProfiles
    • 對於module里的每一個input, new IOProfile, 放入module的mInputProfiles
  2. 根據module的name載入廠家提供的so文件(通過AudioFlinger來載入)
  3. 打開對應的output(通過AudioFlinger來open output)

為了讓大家對AudioPolicyService有個感性的認識,我們以下圖來形象地表示它與AudioTrack及AudioFlinger間的關係:

5 AudioFlinger啟動過程分析

  1. 註冊AudioFlinger服務
  2. 被AudioPolicyService調用以打開廠家提供的so文件
    1. 載入哪個so文件? 文件名是什麼? 文件名從何而來?
      名字從/system/etc/audio_policy.conf得到 : primary
      所以so文件就是 : audio.primary.XXX.so, eg. audio.primary.tiny4412.so
    2. 該so文件由什麼源文件組成? 查看Android.mk
    audio.primary.$(TARGET_DEVICE) : device/friendly-arm/common/libaudio/AudioHardware.cpp
    libhardware_legacy
     libhardware_legacy :    hardware/libhardware_legacy/audio/audio_hw_hal.cpp
  3. 對硬體的封裝:
AudioFlinger       : AudioHwDevice (放入mAudioHwDevs數組中)
audio_hw_hal.cpp   : audio_hw_device
廠家               : AudioHardware (派生自: AudioHardwareInterface)

AudioHwDevice是對audio_hw_device的封裝,audio_hw_device中函數的實現要通過AudioHardware類對象

6 AudioTrack創建過程概述

  1. 體驗測試程式: frameworks/base/media/tests/audiotests/shared_mem_test.cpp

frameworks/base/media/tests/mediaframeworktest/src/com/android/mediaframeworktest/functional/audio/MediaAudioTrackTest.java

播放聲音時都要創建AudioTrack對象,java的AudioTrack對象創建時會導致c++的AudioTrack對象被創建;

所以分析的核心是c++的AudioTrack類,創建AudioTrack時涉及一個重要函數: set()函數

  1. 猜測創建過程的主要工作
    1. 使用AudioTrack的屬性, 根據AudioPolicy找到對應的output、playbackThread
    2. 在playbackThread中創建對應的track
    3. APP的AudioTrack 和 playbackThread的mTracks中的track之間建立共用記憶體
  2. 源碼時序圖

7 AudioTrack創建過程_Track和共用記憶體

回顧:

  1. APP創建AudioTrack AudioFlinger中PlaybackThread創建對應的Track

b. APP給AudioTrack提供音頻數據有2種方式: 一次性提供(MODE_STATIC)、邊播放邊提供(MODE_STREAM)

問:

  1. 音頻數據存在buffer中, 這個buffer由誰提供? APP 還是 PlaybackThread ?
  2. APP提供數據, PlaybackThread消耗數據, 如何同步?

8 音頻數據的傳遞

  1. APP創建AudioTrack, playbackThread創建對應的Track
    它們之間通過共用記憶體傳遞音頻數據
  2. APP有2種使用共用記憶體的方式:
    1. MODE_STATIC:
      APP創建共用記憶體, APP一次性填充數據
    2. MODE_STREAM:
      APP使用obtainBuffer獲得空白記憶體, 填充數據後使用releaseBuffer釋放記憶體
  3. playbackThread使用obtainBuffer獲得含有數據的記憶體, 使用數據後使用releaseBuffer釋放記憶體
  4. AudioTrack中含有mProxy, 它被用來管理共用記憶體, 裡面含有obtainBuffer, releaseBuffer函數。Track中含有mServerProxy, 它被用來管理共用記憶體, 裡面含有obtainBuffer, releaseBuffer函數。對於不同的MODE, 這些Proxy指向不同的對象
  5. 對於MODE_STREAM, APP和playbackThread使用環型緩衝區的方式傳遞數據

9 PlaybackThread處理流程

  1. prepareTracks_l :
    確定enabled track, disabled track
    對於enabled track, 設置mState.tracks[x]中的參數
  2. threadLoop_mix : 處理數據(比如重採樣)、混音
    確定hook:
    逐個分析mState.tracks[x]的數據, 根據它的格式確定tracks[x].hook
    再確定總的mState.hook

    調用hook:
    調用總的mState.hook即可, 它會再去調用每一個mState.tracks[x].hook

    混音後的數據會放在mState.outputTemp臨時BUFFER中
    然後轉換格式後存入 thread.mMixerBuffer
  3. memcpy_by_audio_format :
    把數據從thread.mMixerBuffer或thread.mEffectBuffer複製到thread.mSinkBuffer
  4. threadLoop_write:
    把thread.mSinkBuffer寫到音效卡上
  5. threadLoop_exit


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 題目:彈飛綿羊 這道題,據說是lct裸題,但是lct那麼高級的數據結構,我並不會,所以採取了學長講過的分塊做法,我們對序列分塊,可以定義兩個數組,其中一個表示從當前位置跳出當前塊需要多少步,另一個數組表示從當前位置跳到下一塊會落在哪個位置,然後新修改就暴力修改當前塊,查詢就直接暴力跑塊外的結果。數組 ...
  • 最近在學習排序演算法的時候,需要利用程式自動生成測試數據,代碼和思路整理在這篇文章裡面。 文章圖片來源於 GitHub,網速不佳的朋友 "請點我看原文" 。 順便軟廣一下個人技術小站: "https://godbmw.com" 。歡迎常來 ♪\(^∇^\ \) 1. 設計思路 因為會被很多排序演算法調用 ...
  • 鄙人最近重新裝完系統之後,在安裝和配置jdk1.8的時候,發現網上許多教程配置jdk環境變數時都還在沿用傳統的方式配置,但是隨著技術的更新,完全沒有必要那麼麻煩了。 下載和安裝jdk的教程,在這裡就不詳細敘述了,網上有好多教程。但是對於新手可能會在安裝過程中彈出兩次選擇安裝目錄感到迷茫,敝人在這裡強 ...
  • 3)為什麼介面能勝任作為和外部系統打交道的合同而抽象類就不行?(見下麵我的山和車,肥皂的例子)【新手可忽略不影響繼續學習】答:馬克-to-win:假設你用抽象類作為合同,(視頻下載) (全部書籍)外部系統有個類A,它本來固有就必須得繼承一個類B,現在還必須得繼承你這個抽象類,語法上不允許。反過來,如 ...
  • 背景:VS2015+MySql+EF6(DB First) 採坑順序:按照以前的記憶,操作依次如下: 1,安裝 MySQL Connector/NET(不用想,裝最新的,8.0.12) 2.安裝 MySQL for Visual Studio (最新1.2.8) 3.在VS2015創建WEB項目 4 ...
  • 飛思卡爾Kinetis MCU屬於ARM Cortex-M系列晶元,因此本文主要介紹的Cortex-M系列晶元調試器,目前市面上Cortex-M調試器種類(這裡主要指的是硬體生產商)非常多,主要分為如下兩大陣營(第三方公司,半導體廠商),本文要講的主角OpenSDA屬於陣營里的後者,其一般不單獨存在... ...
  • Linux基礎學習 一、Linux目錄結構 / : 所有目錄都在/boot : boot 配置文件、內核和其它啟動 時所需的文件/etc : 存放系統配置有關的文件/home : 存放普通用戶目錄/mnt : 硬碟上手動 掛載的文件系統/media : 自動掛載(載入)的硬碟分區以及類似CD、數位相 ...
  • 環境為windows 10系統,vmware 12,centos 7.4。centos安裝了gnome桌面,用裡面的終端來安裝,自帶的firefox瀏覽器。 增加用戶 首先要新建一個用戶來管理gooderpgroupadd gooderpuseradd -g gooderp gooderp之後給這個 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...