summaryrefslogtreecommitdiff
path: root/Source/Core/AudioCommon/OpenSLESStream.cpp
diff options
context:
space:
mode:
authorJules Blok <jules.blok@gmail.com>2015-06-10 00:00:12 +0200
committerJules Blok <jules.blok@gmail.com>2015-06-10 00:00:12 +0200
commit7dfced21a2e5aac7195e0e1ad76468e30306766b (patch)
treebd671b639d3d911460b767caabad8fc8a759a6bf /Source/Core/AudioCommon/OpenSLESStream.cpp
parentc25be031fc1031d795157d8344b87b7841145197 (diff)
parent7b0a65e295c784f9d573f2ef52d4e2a7b9bb2889 (diff)
Merge branch 'master' into stable
Diffstat (limited to 'Source/Core/AudioCommon/OpenSLESStream.cpp')
-rw-r--r--Source/Core/AudioCommon/OpenSLESStream.cpp139
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