| 
									
										
										
										
											2013-04-21 02:17:03 -04:00
										 |  |  | // Copyright 2013 Dolphin Emulator Project
 | 
					
						
							| 
									
										
										
										
											2015-05-18 01:08:10 +02:00
										 |  |  | // Licensed under GPLv2+
 | 
					
						
							| 
									
										
										
										
											2013-04-21 02:17:03 -04:00
										 |  |  | // Refer to the license.txt file included.
 | 
					
						
							| 
									
										
										
										
											2013-02-26 13:49:00 -06:00
										 |  |  | 
 | 
					
						
							|  |  |  | #ifdef ANDROID
 | 
					
						
							|  |  |  | #include <assert.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <SLES/OpenSLES.h>
 | 
					
						
							|  |  |  | #include <SLES/OpenSLES_Android.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-17 05:18:15 -05:00
										 |  |  | #include "AudioCommon/OpenSLESStream.h"
 | 
					
						
							| 
									
										
										
										
											2014-09-07 20:06:58 -05:00
										 |  |  | #include "Common/CommonTypes.h"
 | 
					
						
							| 
									
										
										
										
											2014-02-17 05:18:15 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-26 13:49:00 -06:00
										 |  |  | // engine interfaces
 | 
					
						
							|  |  |  | static SLObjectItf engineObject; | 
					
						
							|  |  |  | static SLEngineItf engineEngine; | 
					
						
							|  |  |  | static SLObjectItf outputMixObject; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // buffer queue player interfaces
 | 
					
						
							| 
									
										
										
										
											2014-03-09 21:14:26 +01:00
										 |  |  | static SLObjectItf bqPlayerObject = nullptr; | 
					
						
							| 
									
										
										
										
											2013-02-26 13:49:00 -06:00
										 |  |  | static SLPlayItf bqPlayerPlay; | 
					
						
							|  |  |  | static SLAndroidSimpleBufferQueueItf bqPlayerBufferQueue; | 
					
						
							|  |  |  | static SLMuteSoloItf bqPlayerMuteSolo; | 
					
						
							|  |  |  | static SLVolumeItf bqPlayerVolume; | 
					
						
							| 
									
										
										
										
											2013-10-29 01:23:17 -04:00
										 |  |  | static CMixer *g_mixer; | 
					
						
							| 
									
										
										
										
											2013-02-26 13:49:00 -06:00
										 |  |  | #define BUFFER_SIZE 512
 | 
					
						
							|  |  |  | #define BUFFER_SIZE_IN_SAMPLES (BUFFER_SIZE / 2)
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Double buffering.
 | 
					
						
							|  |  |  | static short buffer[2][BUFFER_SIZE]; | 
					
						
							|  |  |  | static int curBuffer = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-08-30 16:29:15 -04:00
										 |  |  | static void bqPlayerCallback(SLAndroidSimpleBufferQueueItf bq, void *context) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2013-02-26 13:49:00 -06:00
										 |  |  | 	assert(bq == bqPlayerBufferQueue); | 
					
						
							| 
									
										
										
										
											2014-03-09 21:14:26 +01:00
										 |  |  | 	assert(nullptr == context); | 
					
						
							| 
									
										
										
										
											2013-02-26 13:49:00 -06:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	short *nextBuffer = buffer[curBuffer]; | 
					
						
							|  |  |  | 	int nextSize = sizeof(buffer[0]); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	SLresult result = (*bqPlayerBufferQueue)->Enqueue(bqPlayerBufferQueue, nextBuffer, nextSize); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Comment from sample code:
 | 
					
						
							|  |  |  | 	// the most likely other result is SL_RESULT_BUFFER_INSUFFICIENT,
 | 
					
						
							|  |  |  | 	// which for this code example would indicate a programming error
 | 
					
						
							| 
									
										
										
										
											2013-07-05 19:56:15 -05:00
										 |  |  | 	_assert_msg_(AUDIO, SL_RESULT_SUCCESS == result, "Couldn't enqueue audio stream."); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-16 23:51:41 -05:00
										 |  |  | 	curBuffer ^= 1; // Switch buffer
 | 
					
						
							| 
									
										
										
										
											2013-02-26 13:49:00 -06:00
										 |  |  | 	// Render to the fresh buffer
 | 
					
						
							|  |  |  | 	g_mixer->Mix(reinterpret_cast<short *>(buffer[curBuffer]), BUFFER_SIZE_IN_SAMPLES); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2014-08-30 16:29:15 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-26 13:49:00 -06:00
										 |  |  | bool OpenSLESStream::Start() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	SLresult result; | 
					
						
							|  |  |  | 	// create engine
 | 
					
						
							| 
									
										
										
										
											2014-03-09 21:14:26 +01:00
										 |  |  | 	result = slCreateEngine(&engineObject, 0, nullptr, 0, nullptr, nullptr); | 
					
						
							| 
									
										
										
										
											2013-02-26 13:49:00 -06:00
										 |  |  | 	assert(SL_RESULT_SUCCESS == result); | 
					
						
							|  |  |  | 	result = (*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE); | 
					
						
							|  |  |  | 	assert(SL_RESULT_SUCCESS == result); | 
					
						
							|  |  |  | 	result = (*engineObject)->GetInterface(engineObject, SL_IID_ENGINE, &engineEngine); | 
					
						
							|  |  |  | 	assert(SL_RESULT_SUCCESS == result); | 
					
						
							|  |  |  | 	result = (*engineEngine)->CreateOutputMix(engineEngine, &outputMixObject, 0, 0, 0); | 
					
						
							|  |  |  | 	assert(SL_RESULT_SUCCESS == result); | 
					
						
							|  |  |  | 	result = (*outputMixObject)->Realize(outputMixObject, SL_BOOLEAN_FALSE); | 
					
						
							|  |  |  | 	assert(SL_RESULT_SUCCESS == result); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	SLDataLocator_AndroidSimpleBufferQueue loc_bufq = {SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, 2}; | 
					
						
							|  |  |  | 	SLDataFormat_PCM format_pcm = { | 
					
						
							|  |  |  | 		SL_DATAFORMAT_PCM, | 
					
						
							|  |  |  | 		2, | 
					
						
							| 
									
										
										
										
											2014-10-23 11:29:49 -05:00
										 |  |  | 		m_mixer->GetSampleRate() * 1000, | 
					
						
							| 
									
										
										
										
											2013-02-26 13:49:00 -06:00
										 |  |  | 		SL_PCMSAMPLEFORMAT_FIXED_16, | 
					
						
							|  |  |  | 		SL_PCMSAMPLEFORMAT_FIXED_16, | 
					
						
							|  |  |  | 		SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT, | 
					
						
							|  |  |  | 		SL_BYTEORDER_LITTLEENDIAN | 
					
						
							|  |  |  | 	}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	SLDataSource audioSrc = {&loc_bufq, &format_pcm}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// configure audio sink
 | 
					
						
							|  |  |  | 	SLDataLocator_OutputMix loc_outmix = {SL_DATALOCATOR_OUTPUTMIX, outputMixObject}; | 
					
						
							| 
									
										
										
										
											2014-03-09 21:14:26 +01:00
										 |  |  | 	SLDataSink audioSnk = {&loc_outmix, nullptr}; | 
					
						
							| 
									
										
										
										
											2013-02-26 13:49:00 -06:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// create audio player
 | 
					
						
							|  |  |  | 	const SLInterfaceID ids[2] = {SL_IID_BUFFERQUEUE, SL_IID_VOLUME}; | 
					
						
							|  |  |  | 	const SLboolean req[2] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE}; | 
					
						
							|  |  |  | 	result = (*engineEngine)->CreateAudioPlayer(engineEngine, &bqPlayerObject, &audioSrc, &audioSnk, 2, ids, req); | 
					
						
							|  |  |  | 	assert(SL_RESULT_SUCCESS == result); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	result = (*bqPlayerObject)->Realize(bqPlayerObject, SL_BOOLEAN_FALSE); | 
					
						
							|  |  |  | 	assert(SL_RESULT_SUCCESS == result); | 
					
						
							|  |  |  | 	result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_PLAY, &bqPlayerPlay); | 
					
						
							|  |  |  | 	assert(SL_RESULT_SUCCESS == result); | 
					
						
							|  |  |  | 	result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_BUFFERQUEUE, | 
					
						
							|  |  |  | 		&bqPlayerBufferQueue); | 
					
						
							|  |  |  | 	assert(SL_RESULT_SUCCESS == result); | 
					
						
							| 
									
										
										
										
											2014-03-09 21:14:26 +01:00
										 |  |  | 	result = (*bqPlayerBufferQueue)->RegisterCallback(bqPlayerBufferQueue, bqPlayerCallback, nullptr); | 
					
						
							| 
									
										
										
										
											2013-02-26 13:49:00 -06:00
										 |  |  | 	assert(SL_RESULT_SUCCESS == result); | 
					
						
							|  |  |  | 	result = (*bqPlayerPlay)->SetPlayState(bqPlayerPlay, SL_PLAYSTATE_PLAYING); | 
					
						
							|  |  |  | 	assert(SL_RESULT_SUCCESS == result); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-18 08:32:14 -05:00
										 |  |  | 	// Render and enqueue a first buffer.
 | 
					
						
							|  |  |  | 	curBuffer ^= 1; | 
					
						
							| 
									
										
										
										
											2015-05-24 04:13:02 -04:00
										 |  |  | 	g_mixer = m_mixer.get(); | 
					
						
							| 
									
										
										
										
											2013-02-26 13:49:00 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-18 08:32:14 -05:00
										 |  |  | 	result = (*bqPlayerBufferQueue)->Enqueue(bqPlayerBufferQueue, buffer[0], sizeof(buffer[0])); | 
					
						
							| 
									
										
										
										
											2014-08-30 16:29:15 -04:00
										 |  |  | 	if (SL_RESULT_SUCCESS != result) | 
					
						
							| 
									
										
										
										
											2013-02-26 13:49:00 -06:00
										 |  |  | 		return false; | 
					
						
							| 
									
										
										
										
											2014-08-30 16:29:15 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-26 13:49:00 -06:00
										 |  |  | 	return true; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void OpenSLESStream::Stop() | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2014-08-30 16:29:15 -04:00
										 |  |  | 	if (bqPlayerObject != nullptr) | 
					
						
							|  |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2013-02-26 13:49:00 -06:00
										 |  |  | 		(*bqPlayerObject)->Destroy(bqPlayerObject); | 
					
						
							| 
									
										
										
										
											2014-03-09 21:14:26 +01:00
										 |  |  | 		bqPlayerObject = nullptr; | 
					
						
							|  |  |  | 		bqPlayerPlay = nullptr; | 
					
						
							|  |  |  | 		bqPlayerBufferQueue = nullptr; | 
					
						
							|  |  |  | 		bqPlayerMuteSolo = nullptr; | 
					
						
							|  |  |  | 		bqPlayerVolume = nullptr; | 
					
						
							| 
									
										
										
										
											2013-02-26 13:49:00 -06:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2014-08-30 16:29:15 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (outputMixObject != nullptr) | 
					
						
							|  |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2013-02-26 13:49:00 -06:00
										 |  |  | 		(*outputMixObject)->Destroy(outputMixObject); | 
					
						
							| 
									
										
										
										
											2014-03-09 21:14:26 +01:00
										 |  |  | 		outputMixObject = nullptr; | 
					
						
							| 
									
										
										
										
											2013-02-26 13:49:00 -06:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2014-08-30 16:29:15 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (engineObject != nullptr) | 
					
						
							|  |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2013-02-26 13:49:00 -06:00
										 |  |  | 		(*engineObject)->Destroy(engineObject); | 
					
						
							| 
									
										
										
										
											2014-03-09 21:14:26 +01:00
										 |  |  | 		engineObject = nullptr; | 
					
						
							|  |  |  | 		engineEngine = nullptr; | 
					
						
							| 
									
										
										
										
											2013-02-26 13:49:00 -06:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | #endif
 |