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 数据的更多相关文章

  1. Android OpenSL ES 开发:OpenSL ES利用SoundTouch实现PCM音频的变速和变调

    缘由 OpenSL ES 学习到现在已经知道 OpenSL ES 不仅能播放和录制PCM音频数据,还能改变声音大小.设置左声道或右声道播放.还能变速播放,可谓是播放音频的王者.但是变速有一点不好的就是 ...

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

    一.Android OpenSL ES 介绍 OpenSL ES (Open Sound Library for Embedded Systems)是无授权费.跨平台.针对嵌入式系统精心优化的硬件音频 ...

  3. Android OpenSL ES 开发:Android OpenSL 录制 PCM 音频数据

    一.实现说明 OpenSL ES的录音要比播放简单一些,在创建好引擎后,再创建好录音接口基本就可以录音了.在这里我们做的是流式录音,所以需要用至少2个buffer来缓存录制好的PCM数据,这里我们可以 ...

  4. Android OpenGL ES 开发教程 从入门到精通

    感谢,摘自:http://blog.csdn.net/mapdigit/article/details/7526556 Android OpenGL ES 简明开发教程 Android OpenGL ...

  5. Android OpenGL ES 开发(三): OpenGL ES 定义形状

    在上篇文章,我们能够配置好基本的Android OpenGL 使用的环境.但是如果我们不了解OpenGL ES如何定义图像的一些基本知识就使用OpenGL ES进行绘图还是有点棘手的.所以能够在Ope ...

  6. Android 音视频深入 二 AudioTrack播放pcm(附源码下载)

    本篇项目地址,名字是录音和播放PCM,求starhttps://github.com/979451341/Audio-and-video-learning-materials 1.AudioTrack ...

  7. ffplay代码播放pcm数据

    摘抄雷兄 http://blog.csdn.net/leixiaohua1020/article/details/46890259 /** * 最简单的SDL2播放音频的例子(SDL2播放PCM) * ...

  8. FFMPEG学习----使用SDL播放PCM数据

    参考雷神的代码: /** * 最简单的SDL2播放音频的例子(SDL2播放PCM) * Simplest Audio Play SDL2 (SDL2 play PCM) * * 本程序使用SDL2播放 ...

  9. Android OpenGL ES 开发(N): OpenGL ES 2.0 机型兼容问题整理

    在使用OpenGL ES做开发的时候,发现不是所有机型对OpenGL的代码都兼容的那么好,同样的代码在某些机型上总是会出现问题,但是在其他手机上就是好的.下面是本人总结的OpengGL 兼容问题: 一 ...

随机推荐

  1. Angular动画——路由动画及高阶动画函数

    一.路由动画 路由动画需要在host元数据中指定触发器.动画注意不要过多,否则适得其反. 内容优先,引导用户去注意到某个内容.动画只是辅助手段. 定义一个进场动画,一个离场动画. 因为进场动画和离场动 ...

  2. Mac Segmentation fault: 11

    同样一份代码,在windows10编译运行都没问题.但在mac上运行报Segmentation fault: 11错误. 原因是有指针被定义但是没有分配空间便传入函数,如 double *x; 因为M ...

  3. java文件过滤器的使用

    前言: java.io.FileFilter(过滤器接口)boolean accept(File pathname) File类提供了如下方法使用过滤器:public File[] listFiles ...

  4. vue小白必看的生命钩子函数图解

    还有3个钩子并未出现在图上: 1.activated生命周期钩子函数在keep-alive 组件激活时调用,该钩子在服务器端渲染期间不被调用. 2.deactivated生命周期钩子函数在keep-a ...

  5. list学习内容总结

    list定义:list[]或者[]内任意类型的内容,多个用逗号分开 name1 = list(['Cyberpunk2077', 'Jim', 2077]) name2 = list('Cyberpu ...

  6. CloseableHttpClient获取https请求不验证证书

    创建---调用 CloseableHttpClient httpclient = getHttpsClient(); /** * 获取https连接(不验证证书) * * @return */ pri ...

  7. 操作系统PV编程题目总结一

    1.今有一个文件F供进程共享,现把这些进程分为A.B两组,规定同组的进程可以同时读文件F:但当有A组(或B组)的进程在读文件F时就不允许B组(或A组)的进程读文件F.试用P.V操作(记录型信号量)来进 ...

  8. 英语词汇—V01

    今日词汇 1, wash [wɒʃ] n. 洗涤:洗的衣服:化妆水:冲积物 vt. 洗涤:洗刷:冲走:拍打 vi. 洗澡:被冲蚀 2, dust [dʌst] n. 灰尘:尘埃:尘土 vt. 撒:拂去 ...

  9. DW1000 用户手册中文版 附录3:双向测距(Two-Way Ranging)

    由于已经在wode中排版无法直接复制到博客中,故本节博客发布使用了图片. 论坛可下载PDF  http://bphero.com.cn/forum.php?mod=viewthread&tid ...

  10. Numpy 基础运算2

    # -*- encoding:utf-8 -*- # Copyright (c) 2015 Shiye Inc. # All rights reserved. # # Author: ldq < ...