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.mzph.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;不同的培训来源使用相同的术语来谈论不同的事情&#…

制造业包括哪些?需要堡垒机吗?

制造业-国民经济的主体&#xff0c;是立国之本、兴国之器、强国之基&#xff0c;一个关系着大家吃穿住行的行业&#xff0c;一个与大家息息相关的行业。但大家对于制造业还有很多不了解&#xff0c;有小伙伴在问&#xff0c;制造业包括哪些&#xff1f;需要堡垒机吗&#xff1f…

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…

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…

Docker 从入门到精通(大全)

一、概述 1.1 基本概念 Docker 是一个开源的应用容器引擎&#xff0c;基于 Go 语言 并遵从 Apache2.0 协议开源。 Docker 可以让开发者打包他们的应用以及依赖包到一个轻量级、可移植的容器中&#xff0c;然后发布到任何流行的 Linux 机器上&#xff0c;也可以实现虚拟化。…

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将数据存储在文件系统中的存…

会声会影2024永久激活码序列号注册机分享

大家好呀&#xff0c;今天我想给大家安利一款我最近超级喜欢的软件——会声会影2024&#xff01;&#x1f31f; 作为一个视频编辑爱好者&#xff0c;我尝试过很多视频编辑软件&#xff0c;但总感觉少了那么一点点“火花”。直到我遇到了会声会影2024&#xff0c;它完全改变了我…

环境科学SCI期刊,IF=3+,易录用,几乎不退稿

一、期刊名称 International Journal of Environmental Science and Technology 二、期刊简介概况 期刊类型&#xff1a;SCI 学科领域&#xff1a;环境科学 影响因子&#xff1a;3.1 中科院分区&#xff1a;4区 三、期刊简介 International Journal of Environmental Sci…

深入理解计算机系统 CSAPP 家庭作业6.45

CS:APP3e, Bryant and OHallaron 可以参考这里 void bijk(array A, array B, array C, int n, int bsize) {int i, j, k, kk, jj;double sum;int en bsize*(n/bsize);for (i 0; i < n; i)for (j 0; j < n; j)C[i][j] 0.0;for (kk 0; kk < en; kk bsize) {for (j…

QT拖放事件之八:通过全局剪切板中的接口QClipboard::mimeData()来获取MIME类型数据

1、演示效果 首先向剪切板写入数据,然后点击paste按钮进行从全局剪切板中 获取 MIME数据。。。 2、核心代码 void Widget::on_pasteBtn_clicked() {const QClipboard* clipBoard = QGuiApplication::clipboard()

算法07 深度优先搜索及相关问题详解

深搜与广搜是搜索算法中最常用的两种算法&#xff0c;通过深度优先搜索解决问题还会用到回溯和剪枝&#xff0c;让我们一起进入本章&#xff0c;了解深搜的基本概念和模板&#xff0c;并学会解决一些常见问题。 目录 问题导入 走迷宫问题 如何走&#xff1f; 问题建模 如何…