diff options
| author | Jules Blok <jules.blok@gmail.com> | 2015-06-10 00:00:12 +0200 |
|---|---|---|
| committer | Jules Blok <jules.blok@gmail.com> | 2015-06-10 00:00:12 +0200 |
| commit | 7dfced21a2e5aac7195e0e1ad76468e30306766b (patch) | |
| tree | bd671b639d3d911460b767caabad8fc8a759a6bf /Source/Core/AudioCommon/OpenSLESStream.cpp | |
| parent | c25be031fc1031d795157d8344b87b7841145197 (diff) | |
| parent | 7b0a65e295c784f9d573f2ef52d4e2a7b9bb2889 (diff) | |
Merge branch 'master' into stable
Diffstat (limited to 'Source/Core/AudioCommon/OpenSLESStream.cpp')
| -rw-r--r-- | Source/Core/AudioCommon/OpenSLESStream.cpp | 139 |
1 files changed, 139 insertions, 0 deletions
diff --git a/Source/Core/AudioCommon/OpenSLESStream.cpp b/Source/Core/AudioCommon/OpenSLESStream.cpp new file mode 100644 index 0000000000..2f44ef25f0 --- /dev/null +++ b/Source/Core/AudioCommon/OpenSLESStream.cpp @@ -0,0 +1,139 @@ +// Copyright 2013 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#ifdef ANDROID +#include <assert.h> + +#include <SLES/OpenSLES.h> +#include <SLES/OpenSLES_Android.h> + +#include "AudioCommon/OpenSLESStream.h" +#include "Common/CommonTypes.h" + +// engine interfaces +static SLObjectItf engineObject; +static SLEngineItf engineEngine; +static SLObjectItf outputMixObject; + +// buffer queue player interfaces +static SLObjectItf bqPlayerObject = nullptr; +static SLPlayItf bqPlayerPlay; +static SLAndroidSimpleBufferQueueItf bqPlayerBufferQueue; +static SLMuteSoloItf bqPlayerMuteSolo; +static SLVolumeItf bqPlayerVolume; +static CMixer *g_mixer; +#define BUFFER_SIZE 512 +#define BUFFER_SIZE_IN_SAMPLES (BUFFER_SIZE / 2) + +// Double buffering. +static short buffer[2][BUFFER_SIZE]; +static int curBuffer = 0; + +static void bqPlayerCallback(SLAndroidSimpleBufferQueueItf bq, void *context) +{ + assert(bq == bqPlayerBufferQueue); + assert(nullptr == context); + + 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 + _assert_msg_(AUDIO, SL_RESULT_SUCCESS == result, "Couldn't enqueue audio stream."); + + curBuffer ^= 1; // Switch buffer + // Render to the fresh buffer + g_mixer->Mix(reinterpret_cast<short *>(buffer[curBuffer]), BUFFER_SIZE_IN_SAMPLES); +} + +bool OpenSLESStream::Start() +{ + 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; +} + +void OpenSLESStream::Stop() +{ + 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; + } +} +#endif |
