使用OpenSL ES 进行wav音频解码播放

这里使用了transcode-1.1.7对wav文件进行解码,然后使用opensl es进行播放

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);
}












发布了18 篇原创文章 · 获赞 10 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/LIANGJIANGLI/article/details/78989007