Android Native层音频采集与播放实战:AudioTrack与AudioRecord

发布时间:2026/9/23 10:33:06

Android Native层音频采集与播放实战:AudioTrack与AudioRecord 1. 项目概述在Android音视频开发领域音频采集与播放是最基础也是最重要的功能之一。作为一名长期从事Android底层开发的工程师我经常需要处理各种音频相关的需求。今天要分享的是如何在Native层直接使用AudioTrack和AudioRecord这两个核心类来实现低延迟的音频采集与播放。与Java层的实现相比Native层的AudioTrack和AudioRecord能够提供更低的延迟和更高的性能。这对于需要实时音频处理的应用场景如语音通话、音频直播、游戏音效等尤为重要。在本文中我将详细介绍如何在C代码中初始化这两个类并实现边录音边播放的功能。2. 环境准备与依赖配置2.1 开发环境要求要开发Native层的音频功能需要准备以下环境Android NDK开发环境建议使用最新稳定版Android源码环境至少需要包含frameworks/av目录支持C17的编译器Android设备或模拟器建议使用真机测试模拟器可能存在音频延迟问题2.2 项目依赖配置在Android.bp文件中需要添加以下依赖shared_libs: [ framework-permission-aidl-cpp, libaudioclient, libutils, libcutils, liblog, libbinder, ],这些依赖项分别提供了libaudioclient包含AudioTrack和AudioRecord的核心实现libutils提供Android基础工具类libcutils提供底层C工具函数liblog用于日志输出libbinder用于进程间通信framework-permission-aidl-cpp提供权限相关的AIDL接口3. AudioRecord初始化与配置3.1 AudioRecord核心参数解析AudioRecord的初始化需要配置以下关键参数音频源Audio SourceAUDIO_SOURCE_DEFAULT默认音频源AUDIO_SOURCE_MIC麦克风AUDIO_SOURCE_VOICE_COMMUNICATION语音通话专用AUDIO_SOURCE_VOICE_RECOGNITION语音识别专用采样率Sample Rate常用值8000Hz、16000Hz、44100Hz、48000Hz选择依据根据应用场景和硬件支持情况决定音频格式Audio FormatAUDIO_FORMAT_PCM_16_BIT16位PCMAUDIO_FORMAT_PCM_8_BIT8位PCMAUDIO_FORMAT_PCM_FLOAT浮点PCM声道配置Channel ConfigAUDIO_CHANNEL_IN_MONO单声道AUDIO_CHANNEL_IN_STEREO立体声缓冲区大小Buffer Size必须大于等于getMinBufferSize()返回的最小值过小会导致音频数据丢失过大会增加延迟3.2 初始化代码实现以下是完整的AudioRecord初始化代码#include media/AudioRecord.h #include utils/Log.h spAudioRecord AudioTest::initRecord() { // 获取最小帧数 size_t minFrameCount; status_t status AudioRecord::getMinFrameCount(minFrameCount, 16000, AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_IN_MONO); if (status ! NO_ERROR) { ALOGE(Failed to get min frame count, using default); minFrameCount 480 * 4; // 默认值 } // 创建AttributionSourceState std::string packageName{AudioCapture}; AttributionSourceState attributionSource; attributionSource.packageName packageName; attributionSource.token spBBinder::make(); // 创建AudioRecord实例 spAudioRecord audioRecord new AudioRecord(attributionSource); // 配置AudioRecord参数 status audioRecord-set(AUDIO_SOURCE_DEFAULT, 16000, AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_IN_MONO, minFrameCount); // 检查初始化状态 if (audioRecord-initCheck() ! NO_ERROR) { ALOGE(AudioRecord initialization failed); return nullptr; } // 开始录音 status audioRecord-start(); if (status ! NO_ERROR) { ALOGE(Failed to start AudioRecord); return nullptr; } return audioRecord; }3.3 注意事项与常见问题权限问题必须确保应用有RECORD_AUDIO权限在Android 10及以上版本还需要在AndroidManifest.xml中声明FOREGROUND_SERVICE权限缓冲区大小计算音频帧与字节数的转换公式字节数 帧数 × 声道数 × 每样本字节数例如单声道16位PCM每帧1×22字节采样率选择语音通话8000Hz或16000Hz足够音乐录制建议44100Hz或48000Hz注意不是所有设备都支持所有采样率4. AudioTrack初始化与配置4.1 AudioTrack核心参数解析AudioTrack的初始化需要配置以下关键参数流类型Stream TypeAUDIO_STREAM_MUSIC音乐播放AUDIO_STREAM_VOICE_CALL语音通话AUDIO_STREAM_SYSTEM系统声音采样率Sample Rate必须与AudioRecord的采样率一致否则会导致播放速度异常音频格式Audio Format必须与AudioRecord的格式一致否则会导致播放声音失真声道配置Channel ConfigAUDIO_CHANNEL_OUT_MONO单声道输出AUDIO_CHANNEL_OUT_STEREO立体声输出输出标志Output FlagsAUDIO_OUTPUT_FLAG_PRIMARY主输出设备AUDIO_OUTPUT_FLAG_FAST低延迟模式AUDIO_OUTPUT_FLAG_DEEP_BUFFER大缓冲区模式4.2 初始化代码实现以下是完整的AudioTrack初始化代码#include media/AudioTrack.h #include utils/Log.h spAudioTrack AudioTest::initPlayback() { // 创建AudioTrack实例 spAudioTrack audioTrack new AudioTrack( AUDIO_STREAM_MUSIC, 16000, AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_OUT_MONO, AUDIO_OUTPUT_FLAG_PRIMARY); // 检查初始化状态 if (audioTrack-initCheck() ! NO_ERROR) { ALOGE(AudioTrack initialization failed); return nullptr; } // 设置缓冲区大小与AudioRecord一致 audioTrack-setBufferSizeInFrames(minFrameCount); // 开始播放 status_t status audioTrack-start(); if (status ! NO_ERROR) { ALOGE(Failed to start AudioTrack); return nullptr; } return audioTrack; }4.3 输出模式选择建议低延迟场景如游戏音效使用AUDIO_OUTPUT_FLAG_FAST配合AUDIO_STREAM_VOICE_CALL流类型缓冲区大小尽可能小高质量音乐播放使用AUDIO_OUTPUT_FLAG_DEEP_BUFFER配合AUDIO_STREAM_MUSIC流类型缓冲区大小可以适当增大语音通话场景使用AUDIO_OUTPUT_FLAG_PRIMARY配合AUDIO_STREAM_VOICE_CALL流类型缓冲区大小适中5. 音频采集与播放实现5.1 核心流程设计边录音边播放的流程如下初始化AudioRecord和AudioTrack创建音频数据缓冲区循环读取音频数据并写入AudioTrack处理停止信号释放资源5.2 完整实现代码void AudioTest::startRecordAndPlay() { // 初始化AudioRecord spAudioRecord audioRecord initRecord(); if (audioRecord nullptr) { ALOGE(Failed to initialize AudioRecord); return; } // 初始化AudioTrack spAudioTrack audioTrack initPlayback(); if (audioTrack nullptr) { ALOGE(Failed to initialize AudioTrack); audioRecord-stop(); return; } // 计算缓冲区大小字节 size_t bufferSize minFrameCount * 2; // 单声道16位PCM // 创建音频缓冲区 std::unique_ptruint8_t[] audioBuffer(new uint8_t[bufferSize]); // 设置运行标志 mProcessRunningFlag true; // 主循环 while (mProcessRunningFlag) { // 读取音频数据 ssize_t readSize audioRecord-read(audioBuffer.get(), bufferSize); if (readSize 0) { // 写入AudioTrack ssize_t written audioTrack-write(audioBuffer.get(), readSize); // 日志记录 ALOGV(Read %zd bytes, wrote %zd bytes, readSize, written); // 处理写入不完整的情况 if (written readSize) { ALOGW(Partial write: %zd/%zd bytes, written, readSize); } } else if (readSize 0) { ALOGE(Error reading from AudioRecord: %zd, readSize); break; } } // 停止并释放资源 audioRecord-stop(); audioTrack-stop(); } void AudioTest::stopRecordAndPlay() { // 设置停止标志 mProcessRunningFlag false; }5.3 性能优化技巧缓冲区管理使用智能指针管理内存避免内存泄漏缓冲区大小应根据实际需求调整线程优先级音频处理线程应设置为高优先级可以使用pthread_setschedparam设置实时性保障减少循环内的非音频处理逻辑避免在音频线程中进行IO操作错误处理检查每次read/write的返回值处理部分写入的情况6. 常见问题与解决方案6.1 音频延迟问题症状录音和播放之间存在明显延迟解决方案检查AudioRecord和AudioTrack的缓冲区大小是否一致尝试使用更小的缓冲区使用AUDIO_OUTPUT_FLAG_FAST标志确保音频处理线程有足够的CPU资源6.2 音频失真问题症状播放的声音有杂音或失真解决方案检查AudioRecord和AudioTrack的采样率、格式是否匹配确保缓冲区大小足够大检查音频源质量尝试不同的音频格式如改用PCM_FLOAT6.3 权限相关问题症状录音功能无法正常工作解决方案检查是否声明了RECORD_AUDIO权限在运行时检查权限对于Android 10确保有前台服务权限检查音频源是否可用6.4 内存泄漏问题症状长时间运行后内存占用持续增加解决方案使用智能指针管理资源确保所有资源都被正确释放使用Android Studio的内存分析工具检查泄漏点7. 高级应用与扩展7.1 音频数据处理可以在读取和写入之间添加音频处理逻辑如回声消除噪声抑制音频编码/解码音效处理7.2 多线程设计对于复杂的音频应用建议采用多线程设计单独的线程负责音频采集单独的线程负责音频处理单独的线程负责音频播放使用线程安全队列传递数据7.3 低延迟优化要实现极低延迟的音频处理使用AAudio APIAndroid O及以上设置合适的线程优先级使用高性能音频路径如FastMixer优化缓冲区大小在实际项目中我发现Native层的AudioTrack和AudioRecord虽然性能更好但也更加复杂。特别是在处理不同Android版本的兼容性问题时需要做大量的测试和适配工作。建议在关键音频应用中加入详细的日志和性能监控以便及时发现和解决问题。
延伸阅读

更多相关文章

2026/9/23 10:33:06

渲染管线全解析:从三维场景到屏幕像素的完整链路

1. 渲染管线到底在解决什么问题很多人第一次接触计算机图形学,看到“渲染管线”这四个字,脑子里浮现的是一根管子,里面流着各种颜色。这个直觉其实不算错,但不够精确。渲染管线本质上是一条从三维场景数据到二维屏幕像素的流水线&…

2026/9/23 10:33:06

YOLOv8室内家具数据集训练:2416张图像从解压到部署全攻略

简介:这份室内家具目标检测数据集以YOLO格式标注,共包含2416张图像及对应标签,覆盖常见室内家具类别,适合使用YOLOv3、v4、v5等系列算法训练与验证,面向目标检测方向的研究人员、算法学习者及开发者,可有效…

2026/9/23 10:33:06

JavaWeb超市订单管理系统源码解析:结构、运行与答辩指南

简介:一套完整可运行的JavaWeb超市订单管理系统源码与数据库打包资源,面向正在完成JavaWeb课程设计的高校学生,也适合需要参考完整管理系统的入门开发者,可用于课程设计提交、项目实训或毕业设计前期参考。压缩包内共162个文件&am…

2026/9/23 11:23:17

电商数据分析驱动跨界合作:从用户重叠到增量评估的实战方法论

做了这么多年电商数据分析,我最深的一个感受是:这个岗位的价值早就不该只停留在“日报、周报、活动复盘”上了。你花一整晚跑出来的转化漏斗,老板看完点点头,第二天晨会该干嘛还干嘛。但有一天我换了个思路,把分析视角…

2026/9/23 11:23:17

3个核心算法手写实现,搞定迅雷快传资源搜索面试难题

3个核心算法手写实现,搞定迅雷快传资源搜索面试难题 面试被问原理答不上来,那种尴尬感真的让人头皮发麻。很多候选人面对“迅雷快传资源搜索”这类高频场景,只能背八股文,一旦追问底层逻辑,立马哑火。今天不整虚的,直接带你 手写实现…

2026/9/23 11:23:17

大学生个人小结一文搞懂:转岗微服务避坑指南

大学生个人小结一文搞懂:转岗微服务避坑指南 很多应届生盯着语法书看了三个月,闭着眼都能敲出 for 循环,可一让搭个能跑通的项目就卡壳。这种“会写代码却不会做系统”的割裂感,是转岗大厂最痛的点。今天这篇大学生个人小结,不灌鸡汤,直接拆解微服…

2026/9/23 11:23:17

整机与单板硬件测试方案拆解:电源、时钟、信号与降额实战

简介:这份硬件测试方案文档面向硬件开发、测试工程师及电子相关专业学习者,聚焦整机与单板两类测试场景,帮助读者建立从测试原则到判定准则的完整规范认知。资源包内含1个doc文件,约7.95MB,共76页,内容涵盖…

2026/9/23 11:23:17

GFPGAN源码解析:Python深度学习人脸修复实战指南

简介:本资源为基于Python深度学习框架的GFPGAN图片修复算法实现源码,面向具备一定Python编程与深度学习基础、希望深入研究图像修复与生成对抗网络的开发者及研究人员。项目聚焦面部图像的高质量修复与美化,可应用于老旧照片修复、数字取证及…

2026/9/23 11:18:17

3步搞定电容计算:前端项目避坑速查手册

3步搞定电容计算:前端项目避坑速查手册 很多刚转行做前端或者嵌入式开发的朋友,手里拿着厚厚的电容计算公式,脑子一热就想去写代码。结果呢?语法背得滚瓜烂熟,一到项目现场就抓瞎。为什么?因为你没搞懂电容在真实电路里的脾气,更没学会怎么把物理量变…

2026/9/22 10:02:42

GAMP 5 基于风险的计算机化系统验证:软件分类与审计追踪实践

简介:《A Risk-Based Approach to Compliant GxP Computerized Systems》即业内熟知的GAMP 5指南,面向制药企业质量与IT合规人员、验证工程师及计算机化系统管理者,用于解决GxP法规环境下系统合规性难以科学落地的问题。文档以风险管理为主线…

2026/9/22 9:07:39

安全托管MSSP实战:从静态防御到人机协同的攻防运营与应急响应

简介:这份PPT围绕互联网业务安全托管服务展开,面向企业安全负责人、IT运维人员及关注MSSP/MSS选型的读者,重点回应传统安全过度依赖人工、碎片化静态防御难以对抗产业化攻击等痛点。资源共1个pptx文件,包体约30.63MB,以…

2026/9/23 0:01:54

3个实战技巧搞定形式英语:从看教程到跑通性能优化

3个实战技巧搞定形式英语:从看教程到跑通性能优化 看了一堆教程还是不会写项目?别慌,这种“眼高手低”的困境在开发者圈子里太常见了。很多人以为卡点在语法,其实真正拦路虎是缺乏将知识点串联成完整链路的能力。今天咱们不聊虚的,直接拿【形式英语】这…

2026/9/22 16:34:32

USB Type-C PCB布局分区设计:电源、高速信号与PD协议全攻略

做硬件这行,Type-C接口算是典型的“看着简单,做起来全坑”的东西。光引脚就24个,高低速信号、电源、控制线全部塞在一个小小的连接器里,如果PCB布局不做规划,打样回来基本就是“插上没反应”、“高速掉线”、“静电一打…

2026/9/22 20:01:30

系统编程学习原型如何补齐稳定性边界

系统编程学习原型如何补齐稳定性边界预算有限时&#xff0c;我先优化明显多余的复制&#xff0c;而不是猜测性地换容器。用借用传递只读数据通常就能减少分配&#xff1a; fn parse(line: &str) -> Result<Item, Error> { /* ... */ }用基准确认热点确实在分配&am…

2026/9/22 13:25:41

雨花区哪家财务公司代理记账比较好?

在雨花区&#xff0c;企业处理财税事务常常面临诸多挑战&#xff0c;选择一家靠谱的财务公司至关重要。湖南巨勤财务管理咨询有限公司就是本地正规实体财税服务机构&#xff0c;深耕本地工商财税行业多年&#xff0c;熟悉当地工商局、税务局最新政策与申报流程。主营公司注册、…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
咨询二维码