mirror of
https://github.com/hrydgard/ppsspp.git
synced 2025-01-06 04:59:50 +00:00
200 lines
6.3 KiB
C++
200 lines
6.3 KiB
C++
/*
|
|
* Copyright (C) 2010 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*
|
|
*/
|
|
|
|
/* This is a JNI example where we use native methods to play sounds
|
|
* using OpenSL ES. See the corresponding Java source file located at:
|
|
*
|
|
* src/com/example/nativeaudio/NativeAudio/NativeAudio.java
|
|
*/
|
|
|
|
#include <assert.h>
|
|
#include <string.h>
|
|
|
|
// for __android_log_print(ANDROID_LOG_INFO, "YourApp", "formatted message");
|
|
// #include <android/log.h>
|
|
|
|
// for native audio
|
|
#include <SLES/OpenSLES.h>
|
|
#include <SLES/OpenSLES_Android.h>
|
|
|
|
#include "../base/logging.h"
|
|
|
|
// engine interfaces
|
|
static SLObjectItf engineObject = NULL;
|
|
static SLEngineItf engineEngine;
|
|
|
|
// output mix interfaces
|
|
static SLObjectItf outputMixObject = NULL;
|
|
static SLEnvironmentalReverbItf outputMixEnvironmentalReverb = NULL;
|
|
|
|
// buffer queue player interfaces
|
|
static SLObjectItf bqPlayerObject = NULL;
|
|
static SLPlayItf bqPlayerPlay;
|
|
static SLAndroidSimpleBufferQueueItf bqPlayerBufferQueue;
|
|
static SLMuteSoloItf bqPlayerMuteSolo;
|
|
static SLVolumeItf bqPlayerVolume;
|
|
|
|
// synthesized sawtooth clip
|
|
#define SAWTOOTH_FRAMES 8000
|
|
static short sawtoothBuffer[SAWTOOTH_FRAMES];
|
|
|
|
// pointer and size of the next player buffer to enqueue, and number of remaining buffers
|
|
static short *nextBuffer;
|
|
static unsigned nextSize;
|
|
|
|
// synthesize a mono sawtooth wave and place it into a buffer (called automatically on load)
|
|
__attribute__((constructor)) static void onDlOpen(void)
|
|
{
|
|
ILOG("Buffer callback");
|
|
unsigned int i;
|
|
for (i = 0; i < SAWTOOTH_FRAMES; ++i) {
|
|
sawtoothBuffer[i] = 32768 - ((i % 100) * 660);
|
|
}
|
|
}
|
|
|
|
// this callback handler is called every time a buffer finishes playing
|
|
void bqPlayerCallback(SLAndroidSimpleBufferQueueItf bq, void *context)
|
|
{
|
|
assert(bq == bqPlayerBufferQueue);
|
|
assert(NULL == context);
|
|
|
|
|
|
nextBuffer = sawtoothBuffer;
|
|
nextSize = sizeof(sawtoothBuffer);
|
|
SLresult result;
|
|
// enqueue another buffer
|
|
result = (*bqPlayerBufferQueue)->Enqueue(bqPlayerBufferQueue, nextBuffer, nextSize);
|
|
// the most likely other result is SL_RESULT_BUFFER_INSUFFICIENT,
|
|
// which for this code example would indicate a programming error
|
|
assert(SL_RESULT_SUCCESS == result);
|
|
}
|
|
|
|
// create the engine and output mix objects
|
|
extern "C" bool OpenSLWrap_Init()
|
|
{
|
|
SLresult result;
|
|
|
|
// create engine
|
|
result = slCreateEngine(&engineObject, 0, NULL, 0, NULL, NULL);
|
|
assert(SL_RESULT_SUCCESS == result);
|
|
|
|
// realize the engine
|
|
result = (*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE);
|
|
assert(SL_RESULT_SUCCESS == result);
|
|
|
|
// get the engine interface, which is needed in order to create other objects
|
|
result = (*engineObject)->GetInterface(engineObject, SL_IID_ENGINE, &engineEngine);
|
|
assert(SL_RESULT_SUCCESS == result);
|
|
|
|
// create output mix, with environmental reverb specified as a non-required interface
|
|
result = (*engineEngine)->CreateOutputMix(engineEngine, &outputMixObject, 0, 0, 0);
|
|
assert(SL_RESULT_SUCCESS == result);
|
|
|
|
// realize the output mix
|
|
result = (*outputMixObject)->Realize(outputMixObject, SL_BOOLEAN_FALSE);
|
|
assert(SL_RESULT_SUCCESS == result);
|
|
|
|
// create buffer queue audio player
|
|
// ================================
|
|
|
|
// configure audio source
|
|
SLDataLocator_AndroidSimpleBufferQueue loc_bufq = {SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, 2};
|
|
|
|
// TODO: This is all wrong.
|
|
SLDataFormat_PCM format_pcm = {
|
|
SL_DATAFORMAT_PCM,
|
|
1,
|
|
SL_SAMPLINGRATE_8,
|
|
SL_PCMSAMPLEFORMAT_FIXED_16,
|
|
SL_PCMSAMPLEFORMAT_FIXED_16,
|
|
SL_SPEAKER_FRONT_CENTER,
|
|
SL_BYTEORDER_LITTLEENDIAN};
|
|
|
|
SLDataSource audioSrc = {&loc_bufq, &format_pcm};
|
|
|
|
// configure audio sink
|
|
SLDataLocator_OutputMix loc_outmix = {SL_DATALOCATOR_OUTPUTMIX, outputMixObject};
|
|
SLDataSink audioSnk = {&loc_outmix, NULL};
|
|
|
|
// 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);
|
|
|
|
// realize the player
|
|
result = (*bqPlayerObject)->Realize(bqPlayerObject, SL_BOOLEAN_FALSE);
|
|
assert(SL_RESULT_SUCCESS == result);
|
|
|
|
// get the play interface
|
|
result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_PLAY, &bqPlayerPlay);
|
|
assert(SL_RESULT_SUCCESS == result);
|
|
|
|
// get the buffer queue interface
|
|
result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_BUFFERQUEUE,
|
|
&bqPlayerBufferQueue);
|
|
assert(SL_RESULT_SUCCESS == result);
|
|
|
|
// register callback on the buffer queue
|
|
result = (*bqPlayerBufferQueue)->RegisterCallback(bqPlayerBufferQueue, bqPlayerCallback, NULL);
|
|
assert(SL_RESULT_SUCCESS == result);
|
|
|
|
// get the volume interface
|
|
result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_VOLUME, &bqPlayerVolume);
|
|
assert(SL_RESULT_SUCCESS == result);
|
|
|
|
// set the player's state to playing
|
|
result = (*bqPlayerPlay)->SetPlayState(bqPlayerPlay, SL_PLAYSTATE_PLAYING);
|
|
assert(SL_RESULT_SUCCESS == result);
|
|
|
|
// Enqueue a first buffer.
|
|
result = (*bqPlayerBufferQueue)->Enqueue(bqPlayerBufferQueue, sawtoothBuffer, sizeof(sawtoothBuffer));
|
|
if (SL_RESULT_SUCCESS != result) {
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// shut down the native audio system
|
|
extern "C" void OpenSLWrap_Shutdown()
|
|
{
|
|
// destroy buffer queue audio player object, and invalidate all associated interfaces
|
|
if (bqPlayerObject != NULL) {
|
|
(*bqPlayerObject)->Destroy(bqPlayerObject);
|
|
bqPlayerObject = NULL;
|
|
bqPlayerPlay = NULL;
|
|
bqPlayerBufferQueue = NULL;
|
|
bqPlayerMuteSolo = NULL;
|
|
bqPlayerVolume = NULL;
|
|
}
|
|
|
|
// destroy output mix object, and invalidate all associated interfaces
|
|
if (outputMixObject != NULL) {
|
|
(*outputMixObject)->Destroy(outputMixObject);
|
|
outputMixObject = NULL;
|
|
outputMixEnvironmentalReverb = NULL;
|
|
}
|
|
|
|
// destroy engine object, and invalidate all associated interfaces
|
|
if (engineObject != NULL) {
|
|
(*engineObject)->Destroy(engineObject);
|
|
engineObject = NULL;
|
|
engineEngine = NULL;
|
|
}
|
|
}
|