这里使用了transcode-1.1.7对wav文件进行解码,然后使用opensl es进行播放
transcode-1.1.7是比较好的对wav进行解码的第三方库,这里会把它作为WAVLib NDK导入模块
transcode-1.1.7是比较好的对wav进行解码的第三方库,这里会把它作为WAVLib NDK导入模块
包含WAVLib导入模块的Android.mk构建模块
LOCAL_PATH:=$(call my-dir)
#
#转码WAVLib
#
#源文件
MY_WAVLIB_SRC_FILES:= wavlib.c platform_posix.c
#包含导出路径
MY_WAVLIB_C_INCLUDES := $(LOCAL_PATH)
#
#WVILib静态
#
include $(CLEAR_VARS)
#模块名称
LOCAL_MODULE := wavlib_static
#源文件
LOCAL_SRC_FILES := $(MY_WAVLIB_SRC_FILES)
#包含导入路径
LOCAL_EXPORT_C_INCLUDES := $(MY_WAVLIB_C_INCLUDES)
#构建静态库
include $(BUILD_STATIC_LIBRARY)
#
#WAVLib共享
#
include $(CLEAR_VARS)
#模块名称
LOCAL_MODULE := wavlib_shared
#源文件
LOCAL_SRC_FILES := $(MY_WAVLIB_SRC_FILES)
#包含导出路径
LOCAL_EXPORT_C_INCLUDES := $(MY_WAVLIB_C_INCLUDES)
#构建共享库
include $(BUILD_SHARED_LIBRARY)
打开关闭wav文件
/**
* Close the given WAVE file.
* 关闭Wav文件
* @param wav WAV file.
* @throws IOException
*/
static void CloseWaveFile(
WAV wav)
{
if (0 != wav)
{
wav_close(wav);
}
}
/**
* Open the given WAVE file.
* 打开WAV文件
* @param env JNIEnv interface.
* @param fileName file name.
* @return WAV file.
* @throws IOException
*/
static WAV OpenWaveFile(
JNIEnv* env,
jstring fileName)
{
WAVError error = WAV_SUCCESS;
WAV wav = 0;
// Get the file name as a C string
const char* cFileName = env->GetStringUTFChars(fileName, 0);
if (0 == cFileName)
goto exit;
// Open the WAVE file
wav = wav_open(cFileName, WAV_READ, &error);
// Release the file name
env->ReleaseStringUTFChars(fileName, cFileName);
// Check error
if (0 == wav)
{
ThrowException(env,
JAVA_LANG_IOEXCEPTION,
wav_strerror(error));
}
exit:
return wav;
创建引擎对象的CreateEngine函数
/**
* Creates an OpenGL ES engine.
*
* @param env JNIEnv interface.
* @param engineObject object to hold engine. [OUT]
* @throws IOException
*/
static void CreateEngine(
JNIEnv* env,
SLObjectItf& engineObject)
{
// OpenSL ES for Android is designed to be thread-safe,
// so this option request will be ignored, but it will
// make the source code portable to other platforms.
SLEngineOption engineOptions[] = {
{ (SLuint32) SL_ENGINEOPTION_THREADSAFE, (SLuint32) SL_BOOLEAN_TRUE }
};
// Create the OpenSL ES engine object
SLresult result = slCreateEngine(
&engineObject,
ARRAY_LEN(engineOptions),
engineOptions,
0, // no interfaces
0, // no interfaces
0); // no required
// Check error
CheckError(env, result);
}
获取Engine Interface的 GetEngineInterface函数
/**
* Gets the engine interface from the given engine object
* in order to create other objects from the engine.
*
* @param env JNIEnv interface.
* @param engineObject engine object.
* @param engineEngine engine interface. [OUT]
* @throws IOException
*/
static void GetEngineInterface(
JNIEnv* env,
SLObjectItf& engineObject,
SLEngineItf& engineEngine)
{
// Get the engine interface
SLresult result = (*engineObject)->GetInterface(
engineObject,
SL_IID_ENGINE,
&engineEngine);
// Check error
CheckError(env, result);
}
创建Output Mixer的CreateOutputMix函数
/**
* 创建输出混音器
*
* @param env JNIEnv interface.
* @param engineEngine engine engine.
* @param outputMixObject object to hold the output mix. [OUT]
* @throws IOException
*/
static void CreateOutputMix(
JNIEnv* env,
SLEngineItf engineEngine,
SLObjectItf& outputMixObject)
{
// 创建输出混音器对象
SLresult result = (*engineEngine)->CreateOutputMix(
engineEngine,
&outputMixObject,
0, // no interfaces
0, // no interfaces
0); // no required
// Check error
CheckError(env, result);
}
初始化缓冲区
static void InitPlayerBuffer(
JNIEnv* env,
WAV wav,
unsigned char*& buffer,
size_t& bufferSize)
{
// Calculate the buffer size
bufferSize = wav_get_channels(wav) * wav_get_rate(wav) * wav_get_bits(wav);
// Initialize buffer
buffer = new unsigned char[bufferSize];
if (0 == buffer)
{
ThrowException(env,
JAVA_LANG_OUTOFMEMORYERROR,
"buffer");
}
}
创建带有缓存区队列的音频播放器
static void CreateBufferQueueAudioPlayer(
WAV wav,
SLEngineItf engineEngine,
SLObjectItf outputMixObject,
SLObjectItf& audioPlayerObject)
{
// Android 针对数据源的简单缓存区队列定位器
SLDataLocator_AndroidSimpleBufferQueue dataSourceLocator = {
SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, // 定位器类型
1 //缓存区数量 };
SLDataFormat_PCM dataSourceFormat = { // PCM 数据源格式
SL_DATAFORMAT_PCM, // 格式类型
wav_get_channels(wav), // 通道数
wav_get_rate(wav) * 1000, // 毫赫兹/秒的样本数
wav_get_bits(wav), // 样本位数
wav_get_bits(wav), // 容器大小
SL_SPEAKER_FRONT_CENTER, // 通道屏蔽
SL_BYTEORDER_LITTLEENDIAN // 字节顺序
};
SLDataSource dataSource = // 数据源是含有PCM格式的简单缓存区队列
&dataSourceLocator, // 数据定位器
&dataSourceFormat // 数据格式
};
// 针对数据接收器的混音定位器
SLDataLocator_OutputMix dataSinkLocator = {
SL_DATALOCATOR_OUTPUTMIX, // 定位器类型
outputMixObject // 输出混音
};
SLDataSink dataSink = {
&dataSinkLocator, // locator
0 // format
};
SLInterfaceID interfaceIds[] = {
SL_IID_BUFFERQUEUE
};
SLboolean requiredInterfaces[] = {
SL_BOOLEAN_TRUE // for SL_IID_BUFFERQUEUE
};
// 创建音频播放对象
SLresult result = (*engineEngine)->CreateAudioPlayer(
engineEngine,
&audioPlayerObject,
&dataSource,
&dataSink,
ARRAY_LEN(interfaceIds),
interfaceIds,
requiredInterfaces);
}
注册播放回调
/**
* @param env JNIEnv interface.
* @param audioPlayerBufferQueue audio player buffer queue.
* @param ctx player context.
* @throws IOException
*/
static void RegisterPlayerCallback(
JNIEnv* env,
SLAndroidSimpleBufferQueueItf audioPlayerBufferQueue,
PlayerContext* ctx)
{
// 注册播放回调
SLresult result = (*audioPlayerBufferQueue)->RegisterCallback(
audioPlayerBufferQueue,
PlayerCallback,
ctx); // player context
}
/**
* 当一个缓存区完成播放是获得调用
*
* @param audioPlayerBufferQueue audio player buffer queue.
* @param context player context.
*/
static void PlayerCallback(
SLAndroidSimpleBufferQueueItf audioPlayerBufferQueue,
void* context)
{
// Get the player context
PlayerContext* ctx = (PlayerContext*) context;
// Read data
ssize_t readSize = wav_read_data(
ctx->wav,
ctx->buffer,
ctx->bufferSize);
// If data is read
if (0 < readSize)
{
(*audioPlayerBufferQueue)->Enqueue(
audioPlayerBufferQueue,
ctx->buffer,
readSize);
}
else
{
DestroyContext(ctx);
}
}
启动播放音频
static void SetAudioPlayerStatePlaying(
JNIEnv* env,
SLPlayItf audioPlayerPlay)
{
// 把音频设置为播放
SLresult result = (*audioPlayerPlay)->SetPlayState(
audioPlayerPlay,
SL_PLAYSTATE_PLAYING);
// Check error
CheckError(env, result);
}