Android音頻系統

最近在做UAC的項目,大概就是接收內核UAC的事件,也就是聲音相關事件。然后就是pcm_read和AudioTrackr->write之間互傳。感覺略微有點奇怪,所以簡單總結一下。

1 UAC的簡要流程

open_netlink_socket 打開內核窗口,類似于ioctl。

recvfrom 接收數據。

UAC_CAP_START 處理開始播放事件。
?? ?host_to_device
?? ??? ?tracker_data_thread 播放線程。
?? ??? ??? ?pcm_read->(AudioTrackr->write)
?? ??? ?pcm_open
?? ??? ?pcm_read
?? ??? ?pcm_close
?? ??? ?
UAC_CAP_STOP?處理停止播放事件。
?? ?
UAC_PLAY_START?處理開始錄音事件。
?? ?device_to_host
?? ??? ?recorder_data_thread
?? ??? ??? ?(AudioRecord->read)<-pcm_write
?? ??? ?pcm_open
?? ??? ?pcm_write
?? ??? ?pcm_close
?? ?
UAC_PLAY_STOP?處理停止錄音事件。

2 安卓音頻系統

https://source.android.com/docs/core/audio?hl=zh-cn

關于UAC的內容,居然也有說:

https://source.android.com/docs/core/audio/usb?hl=zh-cn

不過下面這兩個圖我覺得直觀一丟丟。

下面這個都包漿了。。。

大致就是幾層:

1 Java App層,這一層封裝最完善,但是只有最常規的操作,給開發app的帥哥做傻瓜式操作的。使用android.media.MediaPlayer。

2 Framework層,這一層可以使用AudioTracker和AudioRecorder,這一層接口比較底層一點,提供的功能比較多。可以實現實時處理和一些特效。Java和C++都可以用。下面還有個AudioFlinger,是用來做混音的。也是上下層的分隔。所以繞過Framework層,直接用HAL的接口,可能就有問題。

3 HAL接口。有HIDL和AIDL的,這一層理論上可以用,但是貌似比較少,起碼我們公司的大神都不在這層搞事。

4 ALSA接口,這一層是標準Linux的,花樣也是非常多。

3 App接口

沒啥好說的,這部分我也不是太熟悉,直接懟media.MediaPlayer即可。代碼說明一切吧。

package com.example.audioplayer;import android.media.MediaPlayer;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import androidx.appcompat.app.AppCompatActivity;public class MainActivity extends AppCompatActivity {private MediaPlayer mediaPlayer;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);Button playButton = findViewById(R.id.play_button);Button stopButton = findViewById(R.id.stop_button);// 播放本地音頻文件mediaPlayer = MediaPlayer.create(this, R.raw.example_audio);// 如果你想播放網絡音頻流,可以使用下面的代碼// mediaPlayer = new MediaPlayer();// try {//     mediaPlayer.setDataSource("http://your-audio-url.com/audio.mp3");//     mediaPlayer.prepare(); // 同步準備,可能會阻塞主線程,建議使用異步準備// } catch (IOException e) {//     e.printStackTrace();// }playButton.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {if (mediaPlayer != null && !mediaPlayer.isPlaying()) {mediaPlayer.start();}}});stopButton.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {if (mediaPlayer != null && mediaPlayer.isPlaying()) {mediaPlayer.stop();// 重新準備MediaPlayermediaPlayer.prepareAsync();}}});}@Overrideprotected void onDestroy() {super.onDestroy();if (mediaPlayer != null) {mediaPlayer.release();mediaPlayer = null;}}
}

4 AudioTracker和AudioRecorder

我這次項目用的就是這兩個,其實還是挺簡單,看個例子就夠了。。。

#include <android/media/AudioTrack.h>// 假設audioBuffer是一個已經加載好的音頻數據的short數組
short audioBuffer[]; // 音頻數據填充到這個數組中
int bufferSize = audioTrack->frameCount() * audioTrack->channelCount(); // 計算緩沖區大小// 創建一個AudioTrack實例
auto audioTrack = new android::media::AudioTrack(android::media::AudioTrack::STREAM_MUSIC, // 音頻流類型44100, // 采樣率44.1kHzandroid::media::AudioTrack::CHANNEL_OUT_STEREO, // 立體聲輸出android::media::AudioTrack::TRANSFER_MODE_STATIC, // 靜態模式bufferSize, // 緩沖區大小android::media::AudioTrack::MODE_STATIC // 靜態播放模式
);// 開始播放音頻
audioTrack->start();// 寫入數據到AudioTrack緩沖區
audioTrack->write(audioBuffer, bufferSize);// 播放完畢,暫停并釋放資源
audioTrack->stop();
delete audioTrack;

5 HAL

這部分位于vendor,上面的是位于system,所以還是區別很大。如果要在vendor搞事情,還是要用這個部分。

定義是在這個地方:https://android.googlesource.com/platform/hardware/interfaces/+/refs/heads/master/audio/

但是比較疑惑的一點是單位有大神說直接調用Hal,會碰壞系統。。。存疑中。。。

用的話直接用hardware/audio.h就可以。

#include <jni.h>
#include <string>
#include <android/log.h>
#include <hardware/hardware.h>
#include <hardware/audio.h>#define LOG_TAG "NativeAudio"
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)extern "C" JNIEXPORT void JNICALL
Java_com_example_audioplayer_MainActivity_nativeInitAudio(JNIEnv *env, jobject thiz) {LOGD("Initializing Audio HAL");hw_module_t *module = nullptr;hw_device_t *device = nullptr;// Load the audio hardware moduleif (hw_get_module(AUDIO_HARDWARE_MODULE_ID, (const hw_module_t **)&module) == 0) {LOGD("Audio module loaded");// Open the audio hardware deviceif (module->methods->open(module, AUDIO_HARDWARE_INTERFACE, &device) == 0) {LOGD("Audio device opened");audio_hw_device_t *audioDevice = (audio_hw_device_t *)device;if (audioDevice && audioDevice->init_check(audioDevice) == 0) {LOGD("Audio device initialized");// Set up and start playback using audio_stream_outaudio_stream_out_t *streamOut = nullptr;audioDevice->open_output_stream(audioDevice, 0, AUDIO_DEVICE_OUT_SPEAKER,AUDIO_OUTPUT_FLAG_NONE, nullptr, &streamOut, nullptr);if (streamOut) {LOGD("Audio stream out opened");// Simplified example to play a buffer (should use actual audio data)size_t bufferSize = streamOut->common.get_buffer_size(&streamOut->common);uint8_t *buffer = new uint8_t[bufferSize];memset(buffer, 0, bufferSize);  // Fill buffer with silence or actual audio datastreamOut->write(streamOut, buffer, bufferSize);delete[] buffer;audioDevice->close_output_stream(audioDevice, streamOut);} else {LOGD("Failed to open audio stream out");}} else {LOGD("Audio device initialization failed");}device->close(device);} else {LOGD("Failed to open audio device");}} else {LOGD("Failed to load audio module");}
}

6 ALSA

這個部分有點略大,看看下次寫吧。。。還有一個OMX,以后有心情再寫吧。。。

最后回到一開始說的UAC,應該是新生成了音頻的節點,然后可以從這個節點讀取音頻數據,但是最后要將聲音從Android的接口放出去,所以那么搞。之前調試的時候,在UAC的模式下,好像也確實是生成了兩張聲卡。這部分感覺內容也挺多了,下次再總結。

參考:

https://source.android.com/docs/core/audio?hl=zh-cn

Android系統Audio框架介紹_android audio-CSDN博客

Android系統Audio框架介紹_android audio-CSDN博客

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

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

相關文章

[leetcode]valid-triangle-number. 有效三角形的個數

. - 力扣&#xff08;LeetCode&#xff09; class Solution { public:int triangleNumber(vector<int>& nums) {int n nums.size();sort(nums.begin(), nums.end());int ans 0;for (int i 0; i < n; i) {for (int j i 1; j < n; j) {int left j 1, righ…

大模型RAG技術:構建高效、可信賴的知識檢索系統

前言 LLM 問題 幻覺&#xff1a;在沒有答案的情況下提供虛假信息。 過時&#xff1a;當用戶需要特定的當前響應時&#xff0c;提供過時或通用的信息。 來源&#xff1a;從非權威來源創建響應。由于術語混淆&#xff0c;不同的培訓來源使用相同的術語來談論不同的事情&#…

網絡構建和設計方法_1.網絡需求分析

1.網絡需求分析 網絡需求分析是網絡構建及開發過程的起始環節&#xff0c;也是極其重要的階段。在該階段&#xff0c;可盡早明確客戶使用網絡的真實用途或痛點&#xff0c;以便為后續能夠構建和設計出更貼近客戶真實訴求的網絡打下堅實基礎&#xff0c;前期的網絡需求分析至關…

制造業包括哪些?需要堡壘機嗎?

制造業-國民經濟的主體&#xff0c;是立國之本、興國之器、強國之基&#xff0c;一個關系著大家吃穿住行的行業&#xff0c;一個與大家息息相關的行業。但大家對于制造業還有很多不了解&#xff0c;有小伙伴在問&#xff0c;制造業包括哪些&#xff1f;需要堡壘機嗎&#xff1f…

深入探索npm依賴:掌握查看與管理包依賴的藝術

深入探索npm依賴&#xff1a;掌握查看與管理包依賴的藝術 在JavaScript和Node.js的世界中&#xff0c;npm&#xff08;Node Package Manager&#xff09;不僅是一個包管理器&#xff0c;更是一個強大的工具&#xff0c;用于管理項目依賴。理解并掌握如何查看和管理npm包的依賴…

k8s使用Endpoint將信息存儲到集群外部數據庫

https://mp.csdn.net/mp_blog/creation/editor/139864305 上一篇文章

引領AI新時代:深度學習與大模型的關鍵技術

文章目錄 &#x1f4d1;前言一、內容概述二、作者簡介三、書籍特色四、學習平臺與資源 &#x1f4d1;前言 在數字化浪潮席卷全球的今天&#xff0c;人工智能&#xff08;AI&#xff09;和深度學習技術已經滲透到我們生活的方方面面。從智能手機中的智能語音助手&#xff0c;到…

20.流入門

學習知識&#xff1a;輸入流和輸出流讀文件的簡單使用 test.txt&#xff1a; iloveu是我愛你的意思。 Main.java import java.io.*;public class Main {public static void main(String[] args) {// 1.利用輸入流讀文件//讀取test.txt并輸出文件內容try{FileInputStream in…

分類預測 | Matlab實現GA-XGBoost遺傳算法優化XGBoost的多特征分類預測

分類預測 | Matlab實現GA-XGBoost遺傳算法優化XGBoost的多特征分類預測 目錄 分類預測 | Matlab實現GA-XGBoost遺傳算法優化XGBoost的多特征分類預測效果一覽基本介紹程序設計參考資料 效果一覽 基本介紹 Matlab實現GA-XGBoost遺傳算法優化XGBoost的多特征分類預測&#xff0c;…

【Hadoop集群搭建】集群崩潰處理及啟動時常見報錯解決辦法

目錄 1. 集群崩潰處理 1.1 殺死進程 1.2 刪除目錄&#xff08;logs/和hadoopdata/&#xff09; 1.3 重新初始化集群 1.4 重新啟動集群 2. 啟動時常見報錯 2.1 報錯如下 2.2 在運行程序測試 MapReduce 計算框架時報錯如下 2.3 報錯如下 1. 集群崩潰處理 1.1 殺死進程 sbin/st…

Clickhouse的基本sql語句

1&#xff0c;建庫語句 create database if not exists mytestdb on cluster default_cluster;注意&#xff1a;用戶在集群中創建數據庫或者表時使用ON CLUSTER語句&#xff0c;保證各個ClickHouse節點上數據庫、表的元信息相同。 2&#xff0c;建表 -- 創建復制表 create t…

SpringBoot優點達項目實戰:項目基本配置(二)

SpringBoot優點達項目實戰&#xff1a;項目基本配置&#xff08;二&#xff09; 文章目錄 SpringBoot優點達項目實戰&#xff1a;項目基本配置&#xff08;二&#xff09;1、項目初始化配置2、MyBatisPlus配置3、Knife配置4、定義統一返回數據結構 1、項目初始化配置 創建appli…

學習筆記——動態路由——RIP(RIP工作原理/防環機制)

三、RIP工作原理/防環機制 1、工作原理 配置好RIP的路由器會每隔30s,向鄰居路由器自動發送RIP路由更新報文。報文里面攜帶了其所知道的所有路由。 通過發送數據包進行路由信息的交互&#xff0c;路由器啟動RIP協議&#xff0c;向周圍鄰居路由器傳遞request(請求)response(響…

克隆網站的風險

克隆網站的風險 隨著互聯網的快速發展&#xff0c;克隆網站也變得越來越常見。克隆網站是指復制原始網站的外觀和功能&#xff0c;并偽裝成原始網站。雖然克隆網站可以提供與原始網站相似的服務和體驗&#xff0c;但它們也帶來了一系列風險。本文將探討克隆網站的風險&#xff…

我的故事與思考

在24年的高考帷幕落下之后&#xff0c;我們站在了一個新的起點&#xff0c;面對著即將開始的大學新生活&#xff0c;我們面臨著一道重要的選擇題&#xff1a;是選擇一個心儀的專業&#xff0c;還是選擇一個知名度更高的學校&#xff1f;這是一個困擾了眾多考生和家長的長期難題…

Docker 從入門到精通(大全)

一、概述 1.1 基本概念 Docker 是一個開源的應用容器引擎&#xff0c;基于 Go 語言 并遵從 Apache2.0 協議開源。 Docker 可以讓開發者打包他們的應用以及依賴包到一個輕量級、可移植的容器中&#xff0c;然后發布到任何流行的 Linux 機器上&#xff0c;也可以實現虛擬化。…

使用QtGui顯示QImage的幾種方法

問題描述 我是一名剛學習Qt的新手,正在嘗試創建一個簡單的GUI應用程序。當點擊一個按鈕時,顯示一張圖片。我可以使用QImage對象讀取圖片,但是否有簡單的方法調用一個Qt函數,將QImage作為輸入并顯示它? 方法一:使用QLabel顯示QImage 最簡單的方式是將QImage添加到QLabe…

bigtop gradle 任務依賴關系

./gradlew deb 會編譯ubuntu的所有deb包 任務deb會依賴17個任務&#xff0c;它們會按字母排序執行&#xff0c;如下&#xff1a; alluxio-deb bigtop-groovy-deb bigtop-jsvc-deb bigtop-utils-deb flink-deb hadoop-deb hbase-deb hive-deb kafka-deb livy-deb phoenix-deb …

這5款國內可用的寶藏AI視頻工具,不允許有人還不知道!(建議收藏)

文章首發于公眾號&#xff1a;X小鹿AI副業 大家好&#xff0c;我是程序員X小鹿&#xff0c;前互聯網大廠程序員&#xff0c;自由職業2年&#xff0c;也一名 AIGC 愛好者&#xff0c;持續分享更多前沿的「AI 工具」和「AI副業玩法」&#xff0c;歡迎一起交流~ 前幾天一位粉絲說給…

【MySQL】數據庫——存儲引擎

一、存儲引擎概述 1.概念 MySQL中的數據用各種不同的技術存儲在文件中&#xff0c;每一種技術都使用不同的存儲機制、索引技巧、鎖定水平并最終提供不同的功能和能力&#xff0c;這些不同的技術以及配套的功能在MySQL中稱為存儲引擎存儲引擎是MySQL將數據存儲在文件系統中的存…