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

article/2025/7/29 2:11:23

这里是c语言写的给android用的,可以拿到其他平台使用。既然是最简单的,肯定使用起来就是超级简单如回调方法就一句代码。这里简单说一下使用要注意的地方:
1.如果想要使用opensl的一些功能如音量控制:
这里写图片描述
只是这样是不可以的,拿到的bqPlayerVolume为空值,还需要在这个地方打开一下:
这里写图片描述
这是我碰到的坑,帮助大家直接跳过。
2. opensl播放音频速率是一定的,那么给opensl更新数据的速率也是一定的,opensl跟openal一样也是有播放缓存的,每播放完毕缓存中一个pcm音频数据包就会有回调,回调方法就是:

// this callback handler is called every time a buffer finishes playing
void bqPlayerCallback(SLAndroidSimpleBufferQueueItf bq, void *context)
{p->inputDataCount --;
}

我这里处理超简单,就是一个数据包计数,传进去一个pcm数据包就计数加一,这个回调就计数减一,这个计数就表示音频播放器里面将要播放的pcm音频数据包的数量。就根据这个计数来控制pcm数据的更新速率就可以了。如果缓存中播放完毕再更新数据会断片,就是计数为零时。
3.这里处理不好会有内存泄漏,就是传给opensl的数据包地址要用数组或者链表存起来,播放完毕再释放掉。

完整播放器demo:
http://blog.csdn.net/m0_37677536/article/details/78775007

Opensl_io.h

//
// Created by huizai on 2017/12/4.
//#ifndef FFMPEG_DEMO_OPENSL_IO_H
#define FFMPEG_DEMO_OPENSL_IO_H#include <SLES/OpenSLES.h>
#include <SLES/OpenSLES_Android.h>typedef struct opensl_stream {// engine interfacesSLObjectItf engineObject;SLEngineItf engineEngine;// output mix interfacesSLObjectItf outputMixObject;// buffer queue player interfacesSLObjectItf bqPlayerObject;SLPlayItf bqPlayerPlay;SLAndroidSimpleBufferQueueItf bqPlayerBufferQueue;SLObjectItf pitchObject;SLPitchItf bqPitchEngne;SLPlaybackRateItf bqPlayerRate;SLPitchItf bqPlayerVolume;// buffer indexesint      inputDataCount;double time;uint32_t outchannels; //输出的声道数量uint32_t sampleRate; //采样率} OPENSL_STREAM;int android_SetPlayRate(OPENSL_STREAM *p,int playRate);/*Open the audio device with a given sampling rate (sr), input and output channels and IO buffer sizein frames. Returns a handle to the OpenSL stream
*/
OPENSL_STREAM* android_OpenAudioDevice(uint32_t sr, uint32_t inchannels, uint32_t outchannels, uint32_t bufferframes);/*Close the audio device
*/
void android_CloseAudioDevice(OPENSL_STREAM *p);/*Write a buffer to the OpenSL stream *p, of size samples. Returns the number of samples written.
*/
uint32_t android_AudioOut(OPENSL_STREAM *p, uint16_t *buffer,uint32_t size);#endif //FFMPEG_DEMO_OPENSL_IO_H

Opensl_io.c

//
// Created by huizai on 2017/12/4.
//#include "Opensl_io.h"static void bqPlayerCallback(SLAndroidSimpleBufferQueueItf bq, void *context);// creates the OpenSL ES audio engine
static SLresult openSLCreateEngine(OPENSL_STREAM *p)
{SLresult result;// create engineresult = slCreateEngine(&(p->engineObject), 0, NULL, 0, NULL, NULL);if(result != SL_RESULT_SUCCESS) goto  engine_end;// realize the engineresult = (*p->engineObject)->Realize(p->engineObject, SL_BOOLEAN_FALSE);if(result != SL_RESULT_SUCCESS) goto engine_end;// get the engine interface, which is needed in order to create other objectsresult = (*p->engineObject)->GetInterface(p->engineObject, SL_IID_ENGINE, &(p->engineEngine));if(result != SL_RESULT_SUCCESS) goto  engine_end;engine_end:return result;
}// opens the OpenSL ES device for output
static SLresult openSLPlayOpen(OPENSL_STREAM *p)
{SLresult result;SLuint32 sr = p->sampleRate;SLuint32  channels = p->outchannels;if(channels) {// configure audio sourceSLDataLocator_AndroidSimpleBufferQueue loc_bufq = {SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, 2};switch(sr){case 8000:sr = SL_SAMPLINGRATE_8;break;case 11025:sr = SL_SAMPLINGRATE_11_025;break;case 16000:sr = SL_SAMPLINGRATE_16;break;case 22050:sr = SL_SAMPLINGRATE_22_05;break;case 24000:sr = SL_SAMPLINGRATE_24;break;case 32000:sr = SL_SAMPLINGRATE_32;break;case 44100:sr = SL_SAMPLINGRATE_44_1;break;case 48000:sr = SL_SAMPLINGRATE_48;break;case 64000:sr = SL_SAMPLINGRATE_64;break;case 88200:sr = SL_SAMPLINGRATE_88_2;break;case 96000:sr = SL_SAMPLINGRATE_96;break;case 192000:sr = SL_SAMPLINGRATE_192;break;default:break;return -1;}const SLInterfaceID ids[] = {SL_IID_VOLUME};const SLboolean req[] = {SL_BOOLEAN_FALSE};result = (*p->engineEngine)->CreateOutputMix(p->engineEngine, &(p->outputMixObject), 1, ids, req);if(result != SL_RESULT_SUCCESS) return result;// realize the output mixresult = (*p->outputMixObject)->Realize(p->outputMixObject, SL_BOOLEAN_FALSE);int speakers;if(channels > 1)speakers = SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT;else speakers = SL_SPEAKER_FRONT_CENTER;SLDataFormat_PCM format_pcm = {SL_DATAFORMAT_PCM,channels, sr,SL_PCMSAMPLEFORMAT_FIXED_16, SL_PCMSAMPLEFORMAT_FIXED_16,(SLuint32)speakers, SL_BYTEORDER_LITTLEENDIAN};SLDataSource audioSrc = {&loc_bufq, &format_pcm};// configure audio sinkSLDataLocator_OutputMix loc_outmix = {SL_DATALOCATOR_OUTPUTMIX, p->outputMixObject};SLDataSink audioSnk = {&loc_outmix, NULL};// create audio playerconst SLInterfaceID ids1[] = {SL_IID_ANDROIDSIMPLEBUFFERQUEUE,SL_IID_PLAYBACKRATE,SL_IID_VOLUME};const SLboolean req1[] = {SL_BOOLEAN_TRUE,SL_BOOLEAN_TRUE,SL_BOOLEAN_TRUE};result = (*p->engineEngine)->CreateAudioPlayer(p->engineEngine, &(p->bqPlayerObject), &audioSrc, &audioSnk,3, ids1, req1);if(result != SL_RESULT_SUCCESS) return result;// realize the playerresult = (*p->bqPlayerObject)->Realize(p->bqPlayerObject, SL_BOOLEAN_FALSE);if(result != SL_RESULT_SUCCESS) return result;// get the play interfaceresult = (*p->bqPlayerObject)->GetInterface(p->bqPlayerObject, SL_IID_PLAY, &(p->bqPlayerPlay));if(result != SL_RESULT_SUCCESS) return result;// get the play rateresult = (*p->bqPlayerObject)->GetInterface(p->bqPlayerObject, SL_IID_VOLUME, &(p->bqPlayerVolume));if(result != SL_RESULT_SUCCESS) return result;// get the play volumeresult = (*p->bqPlayerObject)->GetInterface(p->bqPlayerObject, SL_IID_PLAYBACKRATE, &(p->bqPlayerRate));if(result != SL_RESULT_SUCCESS) return result;// get the buffer queue interfaceresult = (*p->bqPlayerObject)->GetInterface(p->bqPlayerObject, SL_IID_ANDROIDSIMPLEBUFFERQUEUE,&(p->bqPlayerBufferQueue));if(result != SL_RESULT_SUCCESS) return result;// register callback on the buffer queueresult = (*p->bqPlayerBufferQueue)->RegisterCallback(p->bqPlayerBufferQueue, bqPlayerCallback, p);if(result != SL_RESULT_SUCCESS) return result;// set the player's state to playingresult = (*p->bqPlayerPlay)->SetPlayState(p->bqPlayerPlay, SL_PLAYSTATE_PLAYING);return result;}return SL_RESULT_SUCCESS;
}// close the OpenSL IO and destroy the audio engine
static void openSLDestroyEngine(OPENSL_STREAM *p)
{// destroy buffer queue audio player object, and invalidate all associated interfacesif (p->bqPlayerObject != NULL) {(*p->bqPlayerObject)->Destroy(p->bqPlayerObject);p->bqPlayerObject = NULL;p->bqPlayerPlay = NULL;p->bqPlayerBufferQueue = NULL;}// destroy output mix object, and invalidate all associated interfacesif (p->outputMixObject != NULL) {(*p->outputMixObject)->Destroy(p->outputMixObject);p->outputMixObject = NULL;}// destroy engine object, and invalidate all associated interfacesif (p->engineObject != NULL) {(*p->engineObject)->Destroy(p->engineObject);p->engineObject = NULL;p->engineEngine = NULL;}
}// open the android audio device for input and/or output
OPENSL_STREAM *android_OpenAudioDevice(uint32_t sr, uint32_t inchannels, uint32_t outchannels, uint32_t bufferframes)
{OPENSL_STREAM *p;//分配内存空间并初始化p = (OPENSL_STREAM *) calloc(1,sizeof(OPENSL_STREAM));//采样率p->sampleRate = sr;//创建引擎对象及接口if(openSLCreateEngine(p) != SL_RESULT_SUCCESS) {android_CloseAudioDevice(p);return NULL;}p->inputDataCount = 0;//输出声道数p->outchannels = outchannels;if(openSLPlayOpen(p) != SL_RESULT_SUCCESS) {android_CloseAudioDevice(p);return NULL;}return p;
}// close the android audio device
void android_CloseAudioDevice(OPENSL_STREAM *p)
{if (p == NULL)return;openSLDestroyEngine(p);free(p);
}// returns timestamp of the processed stream
double android_GetTimestamp(OPENSL_STREAM *p)
{return p->time;
}// this callback handler is called every time a buffer finishes playing
void bqPlayerCallback(SLAndroidSimpleBufferQueueItf bq, void *context)
{OPENSL_STREAM *p = (OPENSL_STREAM *) context;p->inputDataCount --;// free(p->inputBuffer);
}// puts a buffer of size samples to the device
uint32_t android_AudioOut(OPENSL_STREAM *p, uint16_t *buffer,uint32_t size)
{(*p->bqPlayerBufferQueue)->Enqueue(p->bqPlayerBufferQueue,buffer, size);p->inputDataCount ++;return 0;
}int android_SetPlayRate(OPENSL_STREAM *p,int rateChange){SLmillibel value;SLresult result;if (!p) return -1;if (!p->bqPlayerRate) return -1;result = (*p->bqPlayerRate)->GetRate(p->bqPlayerRate,&value);if (result != SL_RESULT_SUCCESS)return -1;if (rateChange<0){value -= 100;} elsevalue += 100;if (value < 500) value = 500;if (value > 2000) value = 2000;result = (*p->bqPlayerRate)->SetRate(p->bqPlayerRate,value);if (result == SL_RESULT_SUCCESS){return 0;} elsereturn -1;
}

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

相关文章

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;结合浮标体、电源供电系统、数据传输设备组成的放置于水域内的小型水质监测系统。用于连续自动监测被测水体…

【赛纳斯】EC Raman电化学拉曼光谱检测系统推动科研新突破

【前言】   近日,Angew在线发表了厦门大学李剑锋教授团队在设计用于氧还原反应的先进材料及改进催化剂的设计最 新综述文章。该论文综述了双金属纳米催化剂有序度对氧还原反应的影响。论文第 一作者为&#xff1a;Heng-Quan Chen,Huajie Ze,Mu-Fei Yue,论文共同通讯作者为&am…

Ethercat学习-从站源码移植

文章目录 简介移植源码1.源码结构2.GD32硬件接口准备1.SPI接口2.PDI中断配置3.Sync0中断配置4.Sync1中断配置5.定时器中断配置 3.移植准备4.源码移植1.修改头文件名2.ecatport.c文件修改1.SPI部分修改2.中断部分3.修改HW_Init()4.报错修改 3.myapp.c文件修改 5.其他 简介 移植…