Android OpenSL ES 开发:使用 OpenSL 播放 PCM 数据
OpenSL ES 是基于NDK也就是c语言的底层开发音频的公开API,通过使用它能够做到标准化, 高性能,低响应时间的音频功能实现方法。
这次是使用OpenSL ES来做一个音乐播放器,它能够播放m4a、mp3文件,并能够暂停和调整音量。
播放音乐需要做一些步骤:
1.创建声音引擎
首先创建声音引擎的对象接口
result = slCreateEngine(&engineObject, , NULL, , NULL, NULL);
然后实现它
result = (*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE);
从声音引擎的对象中抓取声音引擎
result = (*engineObject)->GetInterface(engineObject, SL_IID_ENGINE, &engineEngine);
创建"输出混音器"
result = (*engineEngine)->CreateOutputMix(engineEngine, &outputMixObject, , ids, req);
实现输出混合音
result = (*outputMixObject)->Realize(outputMixObject, SL_BOOLEAN_FALSE);
2.创建声音播放器
创建和实现播放器
// realize the player
result = (*bqPlayerObject)->Realize(bqPlayerObject, SL_BOOLEAN_FALSE);
assert(SL_RESULT_SUCCESS == result);
(void)result; // get the play interface
result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_PLAY, &bqPlayerPlay);
assert(SL_RESULT_SUCCESS == result);
(void)result;
3.设置播放缓冲
数据格式配置
SLDataFormat_PCM format_pcm = {SL_DATAFORMAT_PCM, , SL_SAMPLINGRATE_8,
SL_PCMSAMPLEFORMAT_FIXED_16, SL_PCMSAMPLEFORMAT_FIXED_16,
SL_SPEAKER_FRONT_CENTER, SL_BYTEORDER_LITTLEENDIAN};
数据定位器 就是定位要播放声音数据的存放位置,分为4种:内存位置,输入/输出设备位置,缓冲区队列位置,和midi缓冲区队列位置。
数据定位器配置
SLDataLocator_AndroidSimpleBufferQueue loc_bufq = {SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, };
得到了缓存队列接口,并注册
// get the buffer queue interface
result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_BUFFERQUEUE,
&bqPlayerBufferQueue);
assert(SL_RESULT_SUCCESS == result);
(void)result; // register callback on the buffer queue
result = (*bqPlayerBufferQueue)->RegisterCallback(bqPlayerBufferQueue, bqPlayerCallback, NULL);
assert(SL_RESULT_SUCCESS == result);
(void)result;
4.获得其他接口用来控制播放
得到声音特效接口
// get the effect send interface
result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_EFFECTSEND,
&bqPlayerEffectSend);
assert(SL_RESULT_SUCCESS == result);
(void)result;
得到音量接口
// get the volume interface
result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_VOLUME, &bqPlayerVolume);
assert(SL_RESULT_SUCCESS == result);
(void)result; // set the player's state to playing
result = (*bqPlayerPlay)->SetPlayState(bqPlayerPlay, SL_PLAYSTATE_PLAYING);
assert(SL_RESULT_SUCCESS == result);
(void)result;
5.提供播放数据
打开音乐文件
// convert Java string to UTF-8
const char *utf8 = (*env)->GetStringUTFChars(env, filename, NULL);
assert(NULL != utf8); // use asset manager to open asset by filename
AAssetManager* mgr = AAssetManager_fromJava(env, assetManager);
assert(NULL != mgr);
AAsset* asset = AAssetManager_open(mgr, utf8, AASSET_MODE_UNKNOWN); // release the Java string and UTF-8
(*env)->ReleaseStringUTFChars(env, filename, utf8); // the asset might not be found
if (NULL == asset) {
return JNI_FALSE;
} // open asset as file descriptor
off_t start, length;
int fd = AAsset_openFileDescriptor(asset, &start, &length);
assert( <= 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};
6.播放音乐
播放音乐只需要通过播放接口改变播放状态就可以了,暂停也是,停止也是,但是暂停必须之前的播放缓存做了才行,否则那暂停就相当于停止了
result = (*fdPlayerPlay)->SetPlayState(fdPlayerPlay, isPlaying ? SL_PLAYSTATE_PLAYING : SL_PLAYSTATE_PAUSED);
7.调解音量
SLVolumeItf getVolume()
{
if (fdPlayerVolume != NULL)
return fdPlayerVolume;
else
return bqPlayerVolume;
} void Java_com_renhui_openslaudio_MainActivity_setVolumeAudioPlayer(JNIEnv env, jclass clazz,
jint millibel)
{
SLresult result;
SLVolumeItf volumeItf = getVolume();
if (NULL != volumeItf) {
result = (volumeItf)->SetVolumeLevel(volumeItf, millibel);
assert(SL_RESULT_SUCCESS == result);
(void)result;
}
}
8.释放资源
关闭app时释放占用资源
void Java_com_renhui_openslaudio_MainActivity_shutdown(JNIEnv* env, jclass clazz)
{ // destroy buffer queue audio player object, and invalidate all associated interfaces
if (bqPlayerObject != NULL) {
(*bqPlayerObject)->Destroy(bqPlayerObject);
bqPlayerObject = NULL;
bqPlayerPlay = NULL;
bqPlayerBufferQueue = NULL;
bqPlayerEffectSend = NULL;
bqPlayerMuteSolo = NULL;
bqPlayerVolume = NULL;
} // destroy file descriptor audio player object, and invalidate all associated interfaces
if (fdPlayerObject != NULL) {
(*fdPlayerObject)->Destroy(fdPlayerObject);
fdPlayerObject = NULL;
fdPlayerPlay = NULL;
fdPlayerSeek = NULL;
fdPlayerMuteSolo = NULL;
fdPlayerVolume = NULL;
} // destroy output mix object, and invalidate all associated interfaces
if (outputMixObject != NULL) {
(*outputMixObject)->Destroy(outputMixObject);
outputMixObject = NULL;
outputMixEnvironmentalReverb = NULL;
} // destroy engine object, and invalidate all associated interfaces
if (engineObject != NULL) {
(*engineObject)->Destroy(engineObject);
engineObject = NULL;
engineEngine = NULL;
}
}
参考文章
http://blog.csdn.net/u013898698/article/details/72822595
http://blog.csdn.net/ywl5320/article/details/78503768
参考源码
https://github.com/renhui/OpenSL_Audio
Android OpenSL ES 开发:使用 OpenSL 播放 PCM 数据的更多相关文章
- Android OpenSL ES 开发:OpenSL ES利用SoundTouch实现PCM音频的变速和变调
缘由 OpenSL ES 学习到现在已经知道 OpenSL ES 不仅能播放和录制PCM音频数据,还能改变声音大小.设置左声道或右声道播放.还能变速播放,可谓是播放音频的王者.但是变速有一点不好的就是 ...
- Android OpenSL ES 开发:Android OpenSL 介绍和开发流程说明
一.Android OpenSL ES 介绍 OpenSL ES (Open Sound Library for Embedded Systems)是无授权费.跨平台.针对嵌入式系统精心优化的硬件音频 ...
- Android OpenSL ES 开发:Android OpenSL 录制 PCM 音频数据
一.实现说明 OpenSL ES的录音要比播放简单一些,在创建好引擎后,再创建好录音接口基本就可以录音了.在这里我们做的是流式录音,所以需要用至少2个buffer来缓存录制好的PCM数据,这里我们可以 ...
- Android OpenGL ES 开发教程 从入门到精通
感谢,摘自:http://blog.csdn.net/mapdigit/article/details/7526556 Android OpenGL ES 简明开发教程 Android OpenGL ...
- Android OpenGL ES 开发(三): OpenGL ES 定义形状
在上篇文章,我们能够配置好基本的Android OpenGL 使用的环境.但是如果我们不了解OpenGL ES如何定义图像的一些基本知识就使用OpenGL ES进行绘图还是有点棘手的.所以能够在Ope ...
- Android 音视频深入 二 AudioTrack播放pcm(附源码下载)
本篇项目地址,名字是录音和播放PCM,求starhttps://github.com/979451341/Audio-and-video-learning-materials 1.AudioTrack ...
- ffplay代码播放pcm数据
摘抄雷兄 http://blog.csdn.net/leixiaohua1020/article/details/46890259 /** * 最简单的SDL2播放音频的例子(SDL2播放PCM) * ...
- FFMPEG学习----使用SDL播放PCM数据
参考雷神的代码: /** * 最简单的SDL2播放音频的例子(SDL2播放PCM) * Simplest Audio Play SDL2 (SDL2 play PCM) * * 本程序使用SDL2播放 ...
- Android OpenGL ES 开发(N): OpenGL ES 2.0 机型兼容问题整理
在使用OpenGL ES做开发的时候,发现不是所有机型对OpenGL的代码都兼容的那么好,同样的代码在某些机型上总是会出现问题,但是在其他手机上就是好的.下面是本人总结的OpengGL 兼容问题: 一 ...
随机推荐
- Microsoft Graph API -----起题 Graph API
最近因为工作需要,接触学习使用了Microsoft Graph API.在看完Microsoft的Graph官方文档之后,也做了一些简单的案例,在Stack Overflow上做过一些回答.整体来说, ...
- 第一阶段——CentOS6_Python3.6.1笔记(尚学堂-Python基础快速入门)+ 【补充】麦子-Python程序入门与进阶
虚拟机环境: 设置网络 .修改网络地址 .设置网卡为nat模式 .确保物理机启动dhcp.net服务 .编辑文件:vim /etc/sysconfig/network-scripts/ifcfg-et ...
- 【Linux】在Win10上搭建WSL(适用于Linux的Windows子系统)
1.打开WSL ,控制面板 -- 程序 -- 程序和功能 -- 打开或关闭Windows功能 - 选中[适用于Linux的Windows子系统] 2.开启后重启电脑 3.在Win10自带的Micro ...
- 自己动手写Redis客户端(C#实现)3 - GET请求和批量回复
实现代码(C#) 1.发送GET指令 string keyGet = "SetKeyTest"; // 设置 的key StringBuilder sbSendGet = new ...
- python tensorflow model
step01_formula # -*- coding: utf-8 -*- """ 단순 선형회귀방정식 : x(1) -> y - y = a*X + b (a ...
- zabbix4.0监控Mysql数据库
#wget http://repo.zabbix.com/zabbix/3.4/rhel/7/x86_64/zabbix-agent-3.4.11-1.el7.x86_64.rpm #rpm -ivh ...
- Excel—数学函数
ROUND(四舍五入函数)就是说把一个小数点后多位的数四舍五入小数点位数的函数 函数语法:ROUND(哪个数,要四舍五入到小数点后几位) ROUNDUP(保留小数点几位后进位的函数)就是说要保留一个小 ...
- Python解析XML文件
XML与JSON的互相转化详见:XML模块 https://www.cnblogs.com/shengyang17/p/8606223.html <?xml version="1.0& ...
- ISP PIPLINE (十二) Sharpening
什么是sharpening? 不解释,从左到右为sharpen , 从右到左为blur. 简单理解为边缘增强,使得轮廓清晰.增强对比度. 如何进行sharpening? 下面是实际sharpen的过程 ...
- PBRT笔记(7)——反射模型
基础术语 表面反射可以分为4大类: diffuse 漫反射 glossy specular 镜面反射高光 perfect specular 完美反射高光 retro-reflective distri ...