首页/新闻资讯/正文详情

基于 OpenSL ES 与 JNI 的 Android Native Audio 示例深度解析

发布时间:2026/9/24 16:21:47 来源:云帆数科 栏目:资讯中心
基于 OpenSL ES 与 JNI 的 Android Native Audio 示例深度解析
示例工程移动开发【免费下载链接】ndk-samplesAndroid NDK samples with Android Studio项目地址https://gitcode.com/gh_mirrors/nd/ndk-samples点击查看免费下载Native Audio 是 ndk-samples 仓库中一个以 C OpenSL ES 音频 API 为核心、通过 JNI 与 Java 层交互的完整音频示例覆盖了播放Buffer Queue / URI / Asset FD 三种数据源与录音两大能力。阅读本文后你将掌握 OpenSL ES 引擎与输出混音器的搭建流程、三种音频播放器与录音器的完整创建范式、采样率重采样与线程互斥的实战写法并了解为何 Android 11 起官方推荐迁移到 Oboe 库。示例定位与技术选型根据 native-audio/README.md 的说明该示例通过 JNI 在 C 侧调用 OpenSL ES API 完成声音的播放与录制其创建的录音器与播放器并不走 fast audio path快速音频路径。这意味着它是一个侧重功能完整性而非最低延迟的教学示例适合用来理解 OpenSL ES 的完整对象模型。示例同时展示了 Android Studio 的 CMake 插件 C 支持的工作流源码位于 native-audio/app/src/main/cpp/native-audio-jni.c构建配置见 native-audio/app/src/main/cpp/CMakeLists.txt。重要的弃用警告README 特别强调OpenSL ES 自 Android 11 起已被弃用deprecated官方推荐开发者改用 Oboe 库。这是阅读本示例时必须牢记的前提OpenSL ES 的 API 形态与对象模型仍有很强的学习价值但新项目应优先采用 hello-oboe 示例所展示的 Oboe 方案。前置条件与运行步骤README 给出的运行环境要求为Android Studio 2.2 并随附 NDK仓库当前配置对构建系统版本要求更高实际以工程内 gradle/libs.versions.toml 与各模块 Gradle 配置为准。完整启动流程下载并启动 Android Studio打开示例目录即仓库中的native-audio目录打开File/Project Structure...点击Download或Select NDK location配置 NDK 路径点击Tools/Android/Sync Project with Gradle Files同步 Gradle点击Run/Run app部署到设备。运行后界面包含 Hello / Android / Sawtooth 三个短音效按钮、内嵌 soundtrack背景音乐、混音器控制Reverb、Mute、URI 播放控制组播放/暂停/循环/声道/音量/声像、录音与回放按钮布局定义见 native-audio/app/src/main/res/layout/main.xml。应用整体架构引擎、输出混音器与三类播放器从 native-audio-jni.c 的全局对象可以看出 OpenSL ES 典型的对象层次Engine引擎engineObject/engineEngine一切对象的创建入口Output Mix输出混音器outputMixObject所有播放器的音频汇聚目标并挂载可选的环境混响Environmental Reverb接口三类播放器Buffer Queue PlayerbqPlayerObject播放内存中的 PCM 短音效URI PlayeruriPlayerObject播放网络/本地 URIAsset FD PlayerfdPlayerObject通过文件描述符播放 APK 内嵌资源Recorder录音器recorderObject通过SLAndroidSimpleBufferQueue接收 PCM 数据。引擎与输出混音器创建流程Java_com_example_nativeaudio_NativeAudio_createEngine展示了标准三步法// 创建引擎 result slCreateEngine(engineObject, 0, NULL, 0, NULL, NULL); // Realize 后才可用 result (*engineObject)-Realize(engineObject, SL_BOOLEAN_FALSE); // 获取 ENGINE 接口用于创建其他对象 result (*engineObject)-GetInterface(engineObject, SL_IID_ENGINE, engineEngine);随后通过CreateOutputMix创建输出混音器并将环境混响声明为非必需接口SL_BOOLEAN_FALSEconst SLInterfaceID ids[1] {SL_IID_ENVIRONMENTALREVERB}; const SLboolean req[1] {SL_BOOLEAN_FALSE}; result (*engineEngine)-CreateOutputMix(engineEngine, outputMixObject, 1, ids, req);取混响接口后用SL_I3DL2_ENVIRONMENT_PRESET_STONECORRIDOR预设石质走廊设置属性源码注释明确指出该接口可能因特性缺失、CPU 负载过高或未申请/授予MODIFY_AUDIO_SETTINGS权限而失败因此示例对失败结果选择忽略——这正是 AndroidManifest.xml 声明MODIFY_AUDIO_SETTINGS权限的原因。权限声明一览AndroidManifest.xml 声明了三个权限与功能一一对应权限用途对应功能RECORD_AUDIO创建音频录音器录音按钮MODIFY_AUDIO_SETTINGS使用环境混响等音频效果Reverb 按钮INTERNETURI 播放器访问网络资源URI soundtrackJava 侧NativeAudio.java对RECORD_AUDIO使用了运行时权限申请ActivityCompat.requestPermissionsonRequestPermissionsResult回调拒绝时会弹出 Toast 提示并允许用户重试。Buffer Queue 播放器内存 PCM 播放与重采样Buffer Queue 播放器用于播放三份内置 PCM 数据hello、android两份预录音频由 hello_clip.h 与 android_clip.h 以 C 字符串数组形式内嵌均为8 kHz 单声道 16 位有符号小端PCM以及运行时合成的锯齿波sawtoothBuffer8000 帧由__attribute__((constructor))在加载时生成。数据源配置createBufferQueueAudioPlayer中音频源配置如下SLDataLocator_AndroidSimpleBufferQueue loc_bufq { SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, 2}; // 最多 2 个 buffer SLDataFormat_PCM format_pcm { SL_DATAFORMAT_PCM, 1, // 单声道 SL_SAMPLINGRATE_8, SL_PCMSAMPLEFORMAT_FIXED_16, SL_PCMSAMPLEFORMAT_FIXED_16, SL_SPEAKER_FRONT_CENTER, SL_BYTEORDER_LITTLEENDIAN};Java 侧在onCreate中通过AudioManager.getProperty(PROPERTY_OUTPUT_SAMPLE_RATE)与PROPERTY_OUTPUT_FRAMES_PER_BUFFER查询设备原生采样率与每缓冲帧数仅 API 17传入原生层。当sampleRate 0时if (bqPlayerSampleRate) { format_pcm.samplesPerSec bqPlayerSampleRate; // 采样率单位毫赫兹(milliHz) }源码注释指出一旦采样率设置为原生采样率将触发 fast audio path同时为兼容 fast path创建播放器时动态裁剪接口数量——fast path 不支持SL_IID_EFFECTSEND因此CreateAudioPlayer的接口个数在bqPlayerSampleRate ? 2 : 3间切换。简易重采样实现由于内置剪辑为 8 kHz、录音为 16 kHz而播放器可能以设备原生采样率运行createResampledBuf实现了一个仅支持整数倍上采样的朴素重采样器要求bqPlayerSampleRate % srcRate 0即目标采样率必须能被源采样率整除否则返回 NULL 回退到原始 8 kHz 播放采用样本复制sample-and-hold方式将每个源样本重复upSampleRate次播放录音回放CLIP_PLAYBACK时若无法重采样则退化为简单降采样每两个 16 kHz 样本取一个将 16 kHz 数据折半为 8 kHz。for (int sample 0; sample srcSampleCount; sample) { for (int dup 0; dup upSampleRate; dup) { *workBuf src[sample]; } }播放回调与多缓冲bqPlayerCallback是缓冲队列播放完成回调每次一个 buffer 播完若nextCount 0且数据有效则Enqueue下一块数据继续播放否则释放重采样缓冲并解锁互斥锁。注释明确说明流式播放时应至少预入队 2 个 buffer而本示例只入队一个巨型 buffer以简化逻辑。URI 播放器与 Asset FD 播放器URI 播放器createUriAudioPlayer使用SLDataLocator_URI定位数据源格式声明为SL_CONTAINERTYPE_UNSPECIFIED的 MIME 流。源码注释指出无效 URI 在 Android 上并非在创建时被检测而是在 prepare/prefetch 阶段报错因此创建后需检查Realize返回值失败时调用Destroy并返回JNI_FALSE。该播放器还演示了完整的控制接口获取SL_IID_PLAY播放/暂停、SL_IID_SEEK循环、SL_IID_MUTESOLO声道静音/独奏、SL_IID_VOLUME音量。Java 界面上的静音/独奏/音量/声像控制均通过一组getMuteSolo()/getVolume()辅助函数选择当前可用的播放器来路由其中音量以millibel千分之一贝尔为单位——SeekBar 从 100 递减时衰减量millibel (100 - progress) * -50。已知问题URI 流式播放损坏README 的 Known Issues 明确记录URI Player 流式播放存在缺陷broken对应 upstream issue #229。Java 代码中同样可见其影响——onCreate末尾对 SDK 19 的设备禁用了全部 URI 相关控件uri_soundtrack、pause_uri、loop_uri、声道、音量、声像等并注释内部 bug idb/29321867等待后续系统版本修复后重新开放。因此该部分代码在当前 Android 版本上主要用于演示 API 形态。Asset FD 播放器createAssetAudioPlayer演示了如何播放 APK 内嵌资源// 通过 JNI 获取 AAssetManager AAssetManager* mgr AAssetManager_fromJava(env, assetManager); AAsset* asset AAssetManager_open(mgr, utf8, AASSET_MODE_UNKNOWN); // 将 asset 打开为文件描述符 off_t start, length; int fd AAsset_openFileDescriptor(asset, start, length); AAsset_close(asset); // 以 SL_DATALOCATOR_ANDROIDFD 作为数据源创建播放器 SLDataLocator_AndroidFD loc_fd {SL_DATALOCATOR_ANDROIDFD, fd, start, length};这是嵌入式 soundtrack按钮的实现路径Java 侧传入AssetManager与文件名background.mp3其版权信息见 native-audio/app/src/main/assets/README.txt原生层打开文件描述符后创建播放器并默认开启整文件循环SetLoop(SL_BOOLEAN_TRUE, 0, SL_TIME_UNKNOWN)。录音器单缓冲采集与互斥保护createAudioRecorder的音频源为SL_IODEVICE_AUDIOINPUT输入设备数据接收端为SLAndroidSimpleBufferQueuePCM 格式固定为16 kHz 单声道 16 位小端。录音缓冲为recorderBuffer[16000 * 5]约 5 秒。SLDataLocator_IODevice loc_dev {SL_DATALOCATOR_IODEVICE, SL_IODEVICE_AUDIOINPUT, SL_DEFAULTDEVICEID_AUDIOINPUT, NULL};startRecording的核心动作是先停止上一次录音并Clear缓冲队列 → 入队一个空 buffer →SetRecordState(SL_RECORDSTATE_RECORDING)启动采集。bqRecorderCallback在缓冲填满时停止录音SL_RECORDSTATE_STOPPED并将recorderSize置为有效长度播放回放CLIP_PLAYBACK则把这段 16 kHz 数据重采样或降采样到 8 kHz 后送入 Buffer Queue 播放器完成录-放闭环。并发保护音频引擎互斥锁示例用pthread_mutex_t实现录音与播放的互斥audioEngineLock源码注释说明了设计动机防止录音尚未结束又发起第二次录音/播放导致崩溃。所有入口selectClip、startRecording均使用pthread_mutex_trylock非阻塞尝试加锁失败即返回JNI_FALSE让上层稍后重试锁的释放分散在播放/录音回调与入队失败分支中shutdown时统一pthread_mutex_destroy。这种trylock 回调解锁的模式虽然在回调路径中手工管理锁较为繁琐但清晰演示了音频回调线程与 UI 线程之间的同步边界是理解原生音频引擎线程模型的良好切入点。JNI 绑定与 CMake 构建Java 侧通过System.loadLibrary(native-audio-jni)加载动态库见 NativeAudio.java 的静态初始化块并以public static native声明了createEngine、createBufferQueueAudioPlayer、createUriAudioPlayer、createAssetAudioPlayer、selectClip、enableReverb、createAudioRecorder、startRecording、shutdown等 18 个原生方法C 侧以Java_com_example_nativeaudio_NativeAudio_前缀逐一实现。构建配置 native-audio/app/src/main/cpp/CMakeLists.txt 非常精简cmake_minimum_required(VERSION 3.22.1) set(CMAKE_C_FLAGS ${CMAKE_C_FLAGS} -Wall) add_library(native-audio-jni SHARED native-audio-jni.c) target_link_libraries(native-audio-jni android log OpenSLES)三个链接库各司其职androidAAssetManager 等原生接口、log日志输出、OpenSLESOpenSL ES 音频 API。小结与迁移建议本示例完整覆盖了 OpenSL ES 的核心编程范式引擎 → 输出混音器 →播放器/录音器的对象层次、Buffer Queue / URI / AndroidFD 三种数据源、回调驱动的缓冲管理、以及 JNI 与 CMake 的集成方式。需要再次强调 README 中的结论OpenSL ES 已从 Android 11 起弃用新项目应使用 hello-oboe 中演示的 Oboe 库若需更低延迟的音频路径可参考本仓库 audio-echo 示例对 Oboe 的实际应用。对于学习目的本示例依然是理解 Android 原生音频对象模型的经典教材。赞分享示例工程移动开发【免费下载链接】ndk-samplesAndroid NDK samples with Android Studio项目地址https://gitcode.com/gh_mirrors/nd/ndk-samples点击查看免费下载相关推荐ndk-samples 之 Audio-Echo基于 OpenSL ES 低延迟音频路径的回声示例全解析ndk samples 之 Audio Echo基于 OpenSL ES 低延迟音频路径的回声示例全解析 本篇技术指南以 Android NDK 官方示例仓库示例工程移动开发Android NDK音频回声示例解析OpenSL ES低延迟实现Android NDK音频回声示例解析OpenSL ES低延迟实现 项目概述 这个Android NDK音频回声示例展示了如何利用OpenSL ES API在示例工程移动开发Android Native音频完全指南OpenSL ES、Native Audio与Oboe库3个样本对比ndk-samplesAndroid Native音频完全指南OpenSL ES、Native Audio与Oboe库3个样本对比ndk samples 在 Android 官示例工程移动开发上一篇如何快速掌握麻雀AI助手5分钟上手指南与实用技巧下一篇wvp-GB28181-pro 从部署到接入第一台摄像机3 步搭起自己的国标视频平台创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关推荐

如何构建与部署tree-sitter-cangjie:Makefile、CMake与npm三种构建路径实战对比
如何构建与部署tree-sitter-cangjie:Makefile、CMake与npm三种构建路径实战对比

如何构建与部署tree-sitter-cangjie:Makefile、CMake与npm三种构建路径实战对比 【免费下载链接】tree-sitter-cangjie 项目地址: https://gitcode.com/Cangjie-SIG/tree-sitter-cangjie tree-sitter-cangjie 是专为仓颉编程语言打造的 Tree-sitter 语法解析… · 2026/9/24 16:21:47

【Dv2Admin】页面保存增加保存预警提示信息
【Dv2Admin】页面保存增加保存预警提示信息

在现代Web应用开发中,用户体验的提升不仅依赖于流畅的交互设计和美观的界面,还需要通过及时反馈让用户了解当前操作的状态。在表单更新操作场景中,用户需要实时知道他们的操作是否成功或需要采取额外步骤。通过引入弹窗提示等反馈机制,可以有效地提升用户体验。 本文将通过… · 2026/9/24 16:21:40

【Dv2Admin】列表翻页解决数据存储的交互问题
【Dv2Admin】列表翻页解决数据存储的交互问题

在现代的动态网页应用中,交互和数据的无缝连接是用户体验的核心。在浏览购物网页或管理系统时,选择项的即时响应、数据的自动保存、分页数据的处理以及多项选择后的提交等功能都无形中提升了用户体验。然而,这一切背后的技术实现却并不简单。 本文将通过一个学生书籍管理系… · 2026/9/24 16:21:40

前期工作小结
前期工作小结

从暑假开始到目前,主要做的工作是:阅读学姐的增量学习的论文,以及对论文内的数据进行复现。论文阅读:读完学姐的论文,主要理解 LAUR 增量学习框架——用贝叶斯参数建模缓解灾难性遗忘,BERT/BGE 做特征编码&… · 2026/9/24 17:04:05

video-use 技能实战指南:用对话式 Agent 完成视频剪辑、调色、字幕与动画合成
video-use 技能实战指南:用对话式 Agent 完成视频剪辑、调色、字幕与动画合成

AI 技能/插件音视频视频处理人工智能 【免费下载链接】video-use Edit videos with coding agents 项目地址: https://gitcode.com/GitHub_Trending/vid/video-use 点击查看 免费下载 导读 video-use 是一个开源、基于对话驱动的视频编辑技能(Skill&am… · 2026/9/24 17:03:59

基于SpringBoot+Vue的美妆产品推荐系统(源代码+文档+PPT+调试+讲解)
基于SpringBoot+Vue的美妆产品推荐系统(源代码+文档+PPT+调试+讲解)

温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台… · 2026/9/24 17:03:47

openFrameworks 视频播放实战:基于 ofVideoPlayer 的加载、速度控制与像素可视化
openFrameworks 视频播放实战:基于 ofVideoPlayer 的加载、速度控制与像素可视化

openFrameworks 视频播放实战:基于 ofVideoPlayer 的加载、速度控制与像素可视化 【免费下载链接】openFrameworks openFrameworks is a community-developed cross platform toolkit for creative coding in C. 项目地址: https://gitcode.com/gh_mirrors/op/ope… · 2026/9/24 17:03:47

30 分钟配好 Continue:JetBrains 插件安装、离线构建与调参指南
30 分钟配好 Continue:JetBrains 插件安装、离线构建与调参指南

30 分钟配好 Continue:JetBrains 插件安装、离线构建与调参指南 【免费下载链接】continue open-source coding agent 项目地址: https://gitcode.com/GitHub_Trending/co/continue 写代码时总要切到网页版 AI 问一句,答完再切回来贴代码&#xf… · 2026/9/24 17:03:47

【Dify】FLUX绘画机器人多模态识别与语音交互自动化
【Dify】FLUX绘画机器人多模态识别与语音交互自动化

以多模态智能交互为核心的自动化创作方式,正推动AI艺术、教育与硬件结合的快速发展。视觉识别、语音播报与机器人控制的结合,为传统绘画和教学带来了新的可能。 本文梳理FLUX绘画机器人结合多模态识别和语音播报的完整工作流,实现从图片输入、内容识别、创意生成到语音解读… · 2026/9/24 17:03:27

基于YOLOv8的渔船作业监控系统:从环境搭建到边缘部署全流程
基于YOLOv8的渔船作业监控系统:从环境搭建到边缘部署全流程

简介:这是一套面向计算机、人工智能、自动化等专业学生与教师的毕业设计级项目资源,围绕YOLOv8实现渔船作业监控系统,可用于毕设、课程设计、大作业或项目立项演示。压缩包共97个文件,约24.21MB,以70个Python源码文件为… · 2026/9/24 0:00:13

1D-CNN时间序列建模实战:从Conv1d原理到工业落地
1D-CNN时间序列建模实战:从Conv1d原理到工业落地

简介:面向时间序列数据建模的一维卷积神经网络完整实现,适合深度学习入门者及需要快速验证时序模型的研究者,能够从音频、文本、传感器或股价等序列中挖掘局部特征与时间依赖。压缩包体积很小,只有3KB,内含3个Python脚… · 2026/9/24 0:00:26

柔软的L:汉语语流中被忽视的舌肌张力控制
柔软的L:汉语语流中被忽视的舌肌张力控制

1. 这个“L”不是字母表里的L,而是舌尖上的L最近在几个方言群和语音教学社群里,反复看到有人发一句:“也说字母L:柔软的长舌”。初看以为是英语发音课笔记,点开才发现全是方言爱好者、播音系学生、语言康复师甚至戏曲演… · 2026/9/24 0:00:44

了解更多?预约专属演示

我们的顾问将为您一对一讲解产品与方案

企业微信二维码