【Android音视频】OpenSL ES音频播放示例一

article/2025/7/4 4:15:44

本文将实现一个使用OpenSL ES来播放assets目录下mp3歌曲的demo(实际推荐大家使用oboe库)。

Android NDK之高性能音频https://developer.android.google.cn/ndk/guides/audio/opensl/getting-started

Oboe is a C++ library that makes it easy to build high-performance audio apps on Android.icon-default.png?t=M666https://github.com/google/oboe NDK 软件包中包括 Khronos Group 开发的 OpenSL ES™ 1.0.1 API 规范的 Android 专用实现。利用这个库,不论您是编写合成器、数字音频工作站、卡拉 OK 应用、游戏还是其他实时应用,都可以使用 C 或 C++ 实现高性能、低延迟的音频。

OpenSL ES™ 标准与 Android Java 框架中的 MediaPlayer 和 MediaRecorder API 提供类似的音频功能。

OpenSL ES API 可以帮助您开发和提升应用的音频性能。

标准 OpenSL ES 头文件 <SLES/OpenSLES.h> 和 <SLES/OpenSLES_Platform.h> 允许音频输入和输出。<SLES/OpenSLES_Android.h> 和 <SLES/OpenSLES_AndroidConfiguration.h> 中提供了其他 Android 专用功能。

OpenSL ES编程简述icon-default.png?t=M666https://developer.android.google.cn/ndk/guides/audio/opensl/opensl-prog-notes


PlayerX.c

#include <stdlib.h>
#include <assert.h>
#include <jni.h>
#include <string.h>#include <SLES/OpenSLES.h>
#include <SLES/OpenSLES_Android.h>#include <sys/types.h>
#include <android/asset_manager.h>
#include <android/asset_manager_jni.h>

该示例将包含4个简单的接口

  • 引擎初始化(学习 SLObjectItf,SLEngineItf)
  • 创建播放器(学习 SLPlayItf)
  • 切换播放状态
  • 回收资源
static SLObjectItf engineObject = NULL;
static SLEngineItf engineEngine = NULL;static SLObjectItf outputMixObject = NULL;
static SLEnvironmentalReverbItf outputMixEnvironmentalReverb = NULL;JNIEXPORT void JNICALL
Java_tao_h_playerx_MainActivity_createEngine(JNIEnv *env, jclass clazz) {SLresult result = slCreateEngine(&engineObject, 0, NULL, 0, NULL, NULL);assert(SL_RESULT_SUCCESS == result);(void) result;result = (*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE);assert(SL_RESULT_SUCCESS == result);(void) result;result = (*engineObject)->GetInterface(engineObject, SL_IID_ENGINE, &engineEngine);assert(SL_RESULT_SUCCESS == result);(void) result;const SLInterfaceID ids[1] = {SL_IID_ENVIRONMENTALREVERB};const SLboolean req[1] = {SL_BOOLEAN_FALSE};result = (*engineEngine)->CreateOutputMix(engineEngine, &outputMixObject, 1, ids, req);assert(SL_RESULT_SUCCESS == result);(void) result;result = (*outputMixObject)->Realize(outputMixObject, SL_BOOLEAN_FALSE);assert(SL_RESULT_SUCCESS == result);(void) result;result = (*outputMixObject)->GetInterface(outputMixObject, SL_IID_ENVIRONMENTALREVERB,&outputMixEnvironmentalReverb);const SLEnvironmentalReverbSettings reverbSettings = SL_I3DL2_ENVIRONMENT_PRESET_STONECORRIDOR;if (result == SL_RESULT_SUCCESS) {result = (*outputMixEnvironmentalReverb)->SetEnvironmentalReverbProperties(outputMixEnvironmentalReverb, &reverbSettings);(void) result;}
}

 (void)result 只是用于忽略编译警告


创建基于FD的音频播放器

static SLObjectItf fdPlayerObject = NULL;
static SLPlayItf fdPlayerPlay = NULL;
static SLSeekItf fdPlayerSeek = NULL;JNIEXPORT jboolean JNICALL
Java_tao_h_playerx_MainActivity_createAssetAudioPlayer(JNIEnv *env, jclass clazz,jobject asset_manager, jstring file_name) {SLresult result;const char *utf8 = (*env)->GetStringUTFChars(env, file_name, NULL);assert(NULL != utf8);AAssetManager *mgr = AAssetManager_fromJava(env, asset_manager);assert(NULL != mgr);AAsset *asset = AAssetManager_open(mgr, utf8, AASSET_MODE_UNKNOWN);(*env)->ReleaseStringUTFChars(env, file_name, utf8);if (asset == NULL) {return JNI_FALSE;}off_t start, length;int fd = AAsset_openFileDescriptor(asset, &start, &length);assert(0 <= fd);AAsset_close(asset);SLDataLocator_AndroidFD loc_fd = {SL_DATALOCATOR_ANDROIDFD, fd, start, length};SLDataFormat_MIME format_mime = {SL_DATAFORMAT_MIME, NULL, SL_CONTAINERTYPE_UNSPECIFIED};SLDataSource audioSrc = {&loc_fd, &format_mime};SLDataLocator_OutputMix loc_output_mix = {SL_DATALOCATOR_OUTPUTMIX, outputMixObject};SLDataSink audioSink = {&loc_output_mix, NULL};const SLInterfaceID ids[3] = {SL_IID_SEEK, SL_IID_MUTESOLO, SL_IID_VOLUME};const SLboolean req[3] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE};result = (*engineEngine)->CreateAudioPlayer(engineEngine, &fdPlayerObject, &audioSrc,&audioSink, 3, ids, req);assert(SL_RESULT_SUCCESS == result);(void) result;result = (*fdPlayerObject)->Realize(fdPlayerObject, SL_BOOLEAN_FALSE);assert(SL_RESULT_SUCCESS == result);(void) result;result = (*fdPlayerObject)->GetInterface(fdPlayerObject, SL_IID_PLAY, &fdPlayerPlay);assert(SL_RESULT_SUCCESS == result);(void) result;result = (*fdPlayerObject)->GetInterface(fdPlayerObject, SL_IID_SEEK, &fdPlayerSeek);assert(SL_RESULT_SUCCESS == result);(void) result;result = (*fdPlayerSeek)->SetLoop(fdPlayerSeek, SL_BOOLEAN_TRUE, 0, SL_TIME_UNKNOWN);assert(SL_RESULT_SUCCESS == result);(void) result;return JNI_TRUE;
}

设置播放状态

JNIEXPORT void JNICALL
Java_tao_h_playerx_MainActivity_setPlayingAssetAudioPlayer(JNIEnv *env, jclass clazz,jboolean is_playing) {SLresult result;if (NULL != fdPlayerPlay) {result = (*fdPlayerPlay)->SetPlayState(fdPlayerPlay, is_playing ? SL_PLAYSTATE_PLAYING: SL_PLAYSTATE_PAUSED);assert(SL_RESULT_SUCCESS == result);(void) result;}
}

 回收资源(务必按照与创建时相反的顺序进行资源释放)

JNIEXPORT void JNICALL
Java_tao_h_playerx_MainActivity_shutdown(JNIEnv *env, jclass clazz) {if (fdPlayerObject != NULL) {(*fdPlayerObject)->Destroy(fdPlayerObject);fdPlayerPlay = NULL;fdPlayerSeek = NULL;}if (outputMixObject != NULL) {(*outputMixObject)->Destroy(outputMixObject);outputMixObject = NULL;outputMixEnvironmentalReverb = NULL;}if (engineObject != NULL) {(*engineObject)->Destroy(engineObject);engineObject = NULL;engineEngine = NULL;}
}

 创建简单的页面来进行播放,布局就不放上来了

public class MainActivity extends AppCompatActivity {static {System.loadLibrary("PlayerX");}private AssetManager mAssetManager;private boolean isPlayingAsset = false;public static native void createEngine();public static native boolean createAssetAudioPlayer(AssetManager assetManager, String fileName);public static native void setPlayingAssetAudioPlayer(boolean isPlaying);public static native void shutdown();@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);mAssetManager = getAssets();createEngine();findViewById(R.id.asset_song).setOnClickListener(new View.OnClickListener() {boolean created = false;@Overridepublic void onClick(View v) {if (!created) {created = createAssetAudioPlayer(mAssetManager, "Legend Of Heroes.mp3");}if (created) {isPlayingAsset = !isPlayingAsset;setPlayingAssetAudioPlayer(isPlayingAsset);}}});}@Overrideprotected void onDestroy() {shutdown();super.onDestroy();}
}

CMakeLists.txt

cmake_minimum_required(VERSION 3.4.1)project("PlayerX")set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99 -Wall")add_library(PlayerXSHAREDPlayerX.c)target_link_libraries(PlayerXandroidlogOpenSLES)


http://chatgpt.dhexx.cn/article/NJOHrQlD.shtml

相关文章

OpenSL ES总结

OpenSL ES - 嵌入式音频加速标准。OpenSL ES™ 是无授权费、跨平台、针对嵌入式系统精心优化的硬件音频加速API。它为嵌入式移动多媒体设备上的本地应用程序开发者提供标准化, 高性能,低响应时间的音频功能实现方法&#xff0c;并实现软/硬件音频性能的直接跨平台部署&#xff…

最简单的OpenSL播放PCM实时音频

这里是c语言写的给android用的&#xff0c;可以拿到其他平台使用。既然是最简单的&#xff0c;肯定使用起来就是超级简单如回调方法就一句代码。这里简单说一下使用要注意的地方: 1.如果想要使用opensl的一些功能如音量控制&#xff1a; 只是这样是不可以的&#xff0c;拿到…

Android12之OpenSL ES通路hidl flag与hal flag转换原理(十八)

简介: CSDN博客专家,专注Android/Linux系统,分享多mic语音方案、音视频、编解码等技术,与大家一起成长! 优质专栏:Audio工程师进阶系列【原创干货持续更新中……】🚀 人生格言: 人生从来没有捷径,只有行动才是治疗恐惧和懒惰的唯一良药. 更多原创,欢迎关注:Android…

分析OpenSL回声Demo

分析OpenSL回声Demo 前言 回声App是google的一个使用openSL的示例。 代码地址: https://github.com/android/ndk-samples/tree/main/audio-echo 通过代码可以学习到如何简单使用OpenSL采集音频&#xff0c;播放音频。 Demo的设计图 流程 App的大致流程为&#xff1a; 使用…

Android音视频【十三】OpenSL ES介绍基于OpenSL ES实现音频采集

人间观察 勿再别人的心中修行自己&#xff0c; 勿再自己的心中强求别人。 前言 最近写文章有点偷懒了&#xff0c;离上次写文章大概一个月了。 一般Android音频的采集在java层使用AudioRecord类进行采集。 但是为什么要学OpenSL呢?除了C/C的性能优势(不过其实java的效率也不…

Harmony Native开发-我的OpenSL ES录音机

零、写在前面 最早我是在Android上开发的OpenSL ES。但最近看了下鸿蒙的文档&#xff0c;发现它的底层库也支持OpenSL ES&#xff0c;这我的兴致就来了。简单了解了一下鸿蒙的Native开发&#xff0c;就着手开发起来。移植过程中发现其实对Android程序员还是相当友好的&#xf…

Android中opensl架构,Android OpenSL ES详解

简介 NDK开发OpenSL ES跨平台高效音频解决方案.png OpenSL ES全称为Open Sound Library for Embedded Systems,即嵌入式音频加速标准。OpenSL ES是无授权费、跨平台、针对嵌入式系统精心优化的硬件音频加速 API。它为嵌入式移动多媒体设备上的本地 应用程序开发者提供了标准化…

音视频学习 AudioTrack、OpenSL ES 音频渲染

前言 在讲解音频渲染之前&#xff0c;需要对音频的基础知识有所了解&#xff0c;所以该篇分为基础概念和AudioTrack 以及 OpenSL ES Demo 实例讲解&#xff0c;这样有助于更好的理解 Android 中音频渲染。 音频的基础概念涉及的知识点比较多&#xff0c;该篇文章的上半部分会…

OpenSL ES技术分析

背景简介 OpenSL ES是一种针对嵌入式系统特别优化过的硬件音频加速API&#xff0c;无授权费并且可以跨平台使用。它提供的高性能、标准化、低延迟的特性实现为嵌入式媒体开发提供了标准&#xff0c;嵌入式开发者在开发本地音频应用也将变得更为简便&#xff0c;利用该API能够实…

使用MediaCodec+OpenSL编写简单的音频播放器

使用MediaCodecOpenSL编写简单的音频播放器 前言 通过MediaCodec Native API 和OpenSL编写一个简单的音频播放器。可以解码并播放一个mp3文件. 流程 初始化 使用AMediaExtractor解析Mp3文件&#xff0c;它可以得到音频文件的格式、以及帧&#xff08;未解码&#xff09;。…

使用Android高性能音频--OpenSL ES和AAudio

AAudio的概念介绍: AAudio 是作为 OpenSL ES 库的轻量级原生 Android 替代项而开发。 与 OpenSL ES 相比&#xff0c;AAudio API 不仅较小&#xff0c;而且容易使用。 AAudio 是在 Android O 版本中引入的全新 Android C API。 因此 API 是专为需要低延迟的高性能音频应用而设…

opensl学习笔记

这个是看opensl文档看到的一个简单的使用示例图&#xff0c;单纯看代码的话很难理解opensl播放和采集的原理&#xff0c;可以结合图来理解。使用Audio Player来播放音频&#xff0c;DataSource类型为SLDataSource&#xff0c;例如安卓设备就是SL_DATALOCATOR_ANDROIDSIMPLEBUFF…

使用OpenSL直接播放mp3

使用OpenSL直接播放mp3 前言 通过使用OpenSL来播放一个mp3文件来学习openSL的使用方式。 设计 在android平台播放mp3方式有多种方式入使用MediaPlayer、AudioTrack、OpenSL、oboe等。根据使用MediaPlayer,AudioTrack的经验一个播放器需要有的基础功能有加载数据、开始、暂停…

音视频开发之旅(36) -FFmpeg +OpenSL ES实现音频解码和播放

目录 OpenSL ES基本介绍OpenSL ES播放音频流程代码实现遇到的问题资料收获 上一篇我们通过AudioTrack实现了FFmpeg解码后的PCM音频数据的播放&#xff0c;在Android上还有一种播放音频的方式即OpenSL ES, 什么是OpenSL ES&#xff0c;这个我们平时接触的很少&#xff0c;原因…

Android OpenSL ES 开发:Android OpenSL 介绍和开发流程说明

一、Android OpenSL ES 介绍 OpenSL ES (Open Sound Library for Embedded Systems)是无授权费、跨平台、针对嵌入式系统精心优化的硬件音频加速API。它为嵌入式移动多媒体设备上的本地应用程序开发者提供标准化, 高性能,低响应时间的音频功能实现方法&#xff0c;并实现软/硬件…

Xcode7 网络请求报错:The resource could not be loaded because the App Transport Security policy requir...

Google后查证&#xff0c;iOS9引入了新特性App Transport Security (ATS)。详情&#xff1a;App Transport Security (ATS)新特性要求App内访问的网络必须使用HTTPS协议。但是现在公司的项目使用的是HTTP协议&#xff0c;使用私有加密方式保证数据安全。现在也不能马上改成HTTP…

【用户自定义气象站】

自定义气象站系统由数据采集器、传感器、总线模块、网络模块、供电模块等组成&#xff0c;可实现野外无人看守的情况下长期监测。用户可根据自己的需求&#xff0c;自定义测量指标&#xff0c;以达到观测目的。 自定义气象站测量指标 自定义气象站测量参数指标 总辐射、光合…

自动气象站设备的防雷要点

自动气象站设备&#xff0c;其工作场所几乎都是在户外&#xff0c;雨打风吹、电闪雷鸣、日晒雨淋&#xff0c;由于是雷雨天气&#xff0c;气象站也要连续工作。如何科学防雷&#xff0c;直接影响到气象站的运行与使用寿命。 自动气象站设备的工作要点是获取气象环境参数&#x…

12,桥接模式-露娜的召唤师技能

一,前言 7种结构型设计模式:桥接模式,适配器模式,装饰模式,组合模式,享元模式,外观模式,代理模式上篇我们说了装饰模式:动态地将责任附加到对象上,在不修改任何底层代码的情况下,为对象赋予新的职责开发中,我们经常会遇到一个类有两个或两个以上的维度经常在变化 如果我们使用…

浮标水质监测站是什么

浮标水质监测站是设立在河流、湖泊、水库、近岸海域等流域内进行现场水质自动监测的监测仪器&#xff0c;是以水质监测仪为核心&#xff0c;运用传感器技术&#xff0c;结合浮标体、电源供电系统、数据传输设备组成的放置于水域内的小型水质监测系统。用于连续自动监测被测水体…