| 
									
										
										
										
											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"
 | 
					
						
							| 
									
										
										
										
											2015-09-26 17:13:07 -04:00
										 |  |  | #include "Common/Assert.h"
 | 
					
						
							| 
									
										
										
										
											2014-09-07 20:06:58 -05:00
										 |  |  | #include "Common/CommonTypes.h"
 | 
					
						
							| 
									
										
										
										
											2015-09-26 17:13:07 -04:00
										 |  |  | #include "Common/Logging/Log.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; | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02: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; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  | static void bqPlayerCallback(SLAndroidSimpleBufferQueueItf bq, void* context) | 
					
						
							| 
									
										
										
										
											2014-08-30 16:29:15 -04:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   assert(bq == bqPlayerBufferQueue); | 
					
						
							|  |  |  |   assert(nullptr == context); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Render to the fresh buffer
 | 
					
						
							|  |  |  |   g_mixer->Mix(reinterpret_cast<short*>(buffer[curBuffer]), BUFFER_SIZE_IN_SAMPLES); | 
					
						
							|  |  |  |   SLresult result = | 
					
						
							|  |  |  |       (*bqPlayerBufferQueue)->Enqueue(bqPlayerBufferQueue, buffer[curBuffer], sizeof(buffer[0])); | 
					
						
							|  |  |  |   curBuffer ^= 1;  // Switch buffer
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Comment from sample code:
 | 
					
						
							|  |  |  |   // the most likely other result is SL_RESULT_BUFFER_INSUFFICIENT,
 | 
					
						
							|  |  |  |   // which for this code example would indicate a programming error
 | 
					
						
							|  |  |  |   _assert_msg_(AUDIO, SL_RESULT_SUCCESS == result, "Couldn't enqueue audio stream."); | 
					
						
							| 
									
										
										
										
											2013-02-26 13:49:00 -06:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2014-08-30 16:29:15 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-26 13:49:00 -06:00
										 |  |  | bool OpenSLESStream::Start() | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   SLresult result; | 
					
						
							|  |  |  |   // create engine
 | 
					
						
							|  |  |  |   result = slCreateEngine(&engineObject, 0, nullptr, 0, nullptr, nullptr); | 
					
						
							|  |  |  |   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, | 
					
						
							|  |  |  |                                  m_mixer->GetSampleRate() * 1000, | 
					
						
							|  |  |  |                                  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}; | 
					
						
							|  |  |  |   SLDataSink audioSnk = {&loc_outmix, nullptr}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // 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); | 
					
						
							|  |  |  |   result = (*bqPlayerBufferQueue)->RegisterCallback(bqPlayerBufferQueue, bqPlayerCallback, nullptr); | 
					
						
							|  |  |  |   assert(SL_RESULT_SUCCESS == result); | 
					
						
							|  |  |  |   result = (*bqPlayerPlay)->SetPlayState(bqPlayerPlay, SL_PLAYSTATE_PLAYING); | 
					
						
							|  |  |  |   assert(SL_RESULT_SUCCESS == result); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Render and enqueue a first buffer.
 | 
					
						
							|  |  |  |   curBuffer ^= 1; | 
					
						
							|  |  |  |   g_mixer = m_mixer.get(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   result = (*bqPlayerBufferQueue)->Enqueue(bqPlayerBufferQueue, buffer[0], sizeof(buffer[0])); | 
					
						
							|  |  |  |   if (SL_RESULT_SUCCESS != result) | 
					
						
							|  |  |  |     return false; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return true; | 
					
						
							| 
									
										
										
										
											2013-02-26 13:49:00 -06:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void OpenSLESStream::Stop() | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   if (bqPlayerObject != nullptr) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     (*bqPlayerObject)->Destroy(bqPlayerObject); | 
					
						
							|  |  |  |     bqPlayerObject = nullptr; | 
					
						
							|  |  |  |     bqPlayerPlay = nullptr; | 
					
						
							|  |  |  |     bqPlayerBufferQueue = nullptr; | 
					
						
							|  |  |  |     bqPlayerMuteSolo = nullptr; | 
					
						
							|  |  |  |     bqPlayerVolume = nullptr; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (outputMixObject != nullptr) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     (*outputMixObject)->Destroy(outputMixObject); | 
					
						
							|  |  |  |     outputMixObject = nullptr; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (engineObject != nullptr) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     (*engineObject)->Destroy(engineObject); | 
					
						
							|  |  |  |     engineObject = nullptr; | 
					
						
							|  |  |  |     engineEngine = nullptr; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2013-02-26 13:49:00 -06:00
										 |  |  | } | 
					
						
							|  |  |  | #endif
 |