forked from dolphin-emu/dolphin
		
	Macros should be all upper-cased. This is also kind of a wart that's been sticking out for quite a while now (we avoid prefixing underscores).
		
			
				
	
	
		
			139 lines
		
	
	
		
			4.6 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			139 lines
		
	
	
		
			4.6 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
// 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/Assert.h"
 | 
						|
#include "Common/CommonTypes.h"
 | 
						|
#include "Common/Logging/Log.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 Mixer* 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);
 | 
						|
 | 
						|
  // 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.");
 | 
						|
}
 | 
						|
 | 
						|
bool OpenSLESStream::Init()
 | 
						|
{
 | 
						|
  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;
 | 
						|
}
 | 
						|
 | 
						|
OpenSLESStream::~OpenSLESStream()
 | 
						|
{
 | 
						|
  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
 |