134 lines
4.4 KiB
C
134 lines
4.4 KiB
C
|
#include <kinc/audio2/audio.h>
|
||
|
|
||
|
#include <SLES/OpenSLES.h>
|
||
|
#include <SLES/OpenSLES_Android.h>
|
||
|
|
||
|
#include <stdlib.h>
|
||
|
#include <string.h>
|
||
|
|
||
|
static kinc_a2_buffer_t a2_buffer;
|
||
|
|
||
|
static SLObjectItf engineObject;
|
||
|
static SLEngineItf engineEngine;
|
||
|
static SLObjectItf outputMixObject;
|
||
|
static SLObjectItf bqPlayerObject;
|
||
|
static SLPlayItf bqPlayerPlay = NULL;
|
||
|
static SLAndroidSimpleBufferQueueItf bqPlayerBufferQueue;
|
||
|
#define AUDIO_BUFFER_SIZE 1 * 1024
|
||
|
static int16_t tempBuffer[AUDIO_BUFFER_SIZE];
|
||
|
|
||
|
static void copySample(void *buffer) {
|
||
|
float left_value = *(float *)&a2_buffer.channels[0][a2_buffer.read_location];
|
||
|
float right_value = *(float *)&a2_buffer.channels[1][a2_buffer.read_location];
|
||
|
a2_buffer.read_location += 1;
|
||
|
if (a2_buffer.read_location >= a2_buffer.data_size) {
|
||
|
a2_buffer.read_location = 0;
|
||
|
}
|
||
|
((int16_t *)buffer)[0] = (int16_t)(left_value * 32767);
|
||
|
((int16_t *)buffer)[1] = (int16_t)(right_value * 32767);
|
||
|
}
|
||
|
|
||
|
static void bqPlayerCallback(SLAndroidSimpleBufferQueueItf caller, void *context) {
|
||
|
if (kinc_a2_internal_callback(&a2_buffer, AUDIO_BUFFER_SIZE / 2)) {
|
||
|
for (int i = 0; i < AUDIO_BUFFER_SIZE; i += 2) {
|
||
|
copySample(&tempBuffer[i]);
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
memset(tempBuffer, 0, sizeof(tempBuffer));
|
||
|
}
|
||
|
SLresult result = (*bqPlayerBufferQueue)->Enqueue(bqPlayerBufferQueue, tempBuffer, AUDIO_BUFFER_SIZE * 2);
|
||
|
}
|
||
|
|
||
|
static bool initialized = false;
|
||
|
|
||
|
void kinc_a2_init() {
|
||
|
if (initialized) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
kinc_a2_internal_init();
|
||
|
initialized = true;
|
||
|
|
||
|
a2_buffer.read_location = 0;
|
||
|
a2_buffer.write_location = 0;
|
||
|
a2_buffer.data_size = 128 * 1024;
|
||
|
a2_buffer.channel_count = 2;
|
||
|
a2_buffer.channels[0] = (float*)malloc(a2_buffer.data_size * sizeof(float));
|
||
|
a2_buffer.channels[1] = (float*)malloc(a2_buffer.data_size * sizeof(float));
|
||
|
|
||
|
SLresult result;
|
||
|
result = slCreateEngine(&engineObject, 0, NULL, 0, NULL, NULL);
|
||
|
result = (*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE);
|
||
|
result = (*engineObject)->GetInterface(engineObject, SL_IID_ENGINE, &engineEngine);
|
||
|
|
||
|
const SLInterfaceID ids[] = {SL_IID_VOLUME};
|
||
|
const SLboolean req[] = {SL_BOOLEAN_FALSE};
|
||
|
result = (*engineEngine)->CreateOutputMix(engineEngine, &outputMixObject, 1, ids, req);
|
||
|
result = (*outputMixObject)->Realize(outputMixObject, SL_BOOLEAN_FALSE);
|
||
|
|
||
|
SLDataLocator_AndroidSimpleBufferQueue loc_bufq = {SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, 2};
|
||
|
SLDataFormat_PCM format_pcm = {SL_DATAFORMAT_PCM, 2,
|
||
|
SL_SAMPLINGRATE_44_1, 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};
|
||
|
|
||
|
SLDataLocator_OutputMix loc_outmix = {SL_DATALOCATOR_OUTPUTMIX, outputMixObject};
|
||
|
SLDataSink audioSnk = {&loc_outmix, NULL};
|
||
|
|
||
|
const SLInterfaceID ids1[] = {SL_IID_ANDROIDSIMPLEBUFFERQUEUE};
|
||
|
const SLboolean req1[] = {SL_BOOLEAN_TRUE};
|
||
|
result = (*engineEngine)->CreateAudioPlayer(engineEngine, &(bqPlayerObject), &audioSrc, &audioSnk, 1, ids1, req1);
|
||
|
result = (*bqPlayerObject)->Realize(bqPlayerObject, SL_BOOLEAN_FALSE);
|
||
|
|
||
|
result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_PLAY, &(bqPlayerPlay));
|
||
|
|
||
|
result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_ANDROIDSIMPLEBUFFERQUEUE, &(bqPlayerBufferQueue));
|
||
|
|
||
|
result = (*bqPlayerBufferQueue)->RegisterCallback(bqPlayerBufferQueue, bqPlayerCallback, NULL);
|
||
|
|
||
|
result = (*bqPlayerPlay)->SetPlayState(bqPlayerPlay, SL_PLAYSTATE_PLAYING);
|
||
|
|
||
|
memset(tempBuffer, 0, sizeof(tempBuffer));
|
||
|
result = (*bqPlayerBufferQueue)->Enqueue(bqPlayerBufferQueue, tempBuffer, AUDIO_BUFFER_SIZE * 2);
|
||
|
}
|
||
|
|
||
|
void pauseAudio() {
|
||
|
if (bqPlayerPlay == NULL) {
|
||
|
return;
|
||
|
}
|
||
|
SLresult result = (*bqPlayerPlay)->SetPlayState(bqPlayerPlay, SL_PLAYSTATE_PAUSED);
|
||
|
}
|
||
|
|
||
|
void resumeAudio() {
|
||
|
if (bqPlayerPlay == NULL) {
|
||
|
return;
|
||
|
}
|
||
|
SLresult result = (*bqPlayerPlay)->SetPlayState(bqPlayerPlay, SL_PLAYSTATE_PLAYING);
|
||
|
}
|
||
|
|
||
|
void kinc_a2_update() {}
|
||
|
|
||
|
void kinc_a2_shutdown() {
|
||
|
if (bqPlayerObject != NULL) {
|
||
|
(*bqPlayerObject)->Destroy(bqPlayerObject);
|
||
|
bqPlayerObject = NULL;
|
||
|
bqPlayerPlay = NULL;
|
||
|
bqPlayerBufferQueue = NULL;
|
||
|
}
|
||
|
if (outputMixObject != NULL) {
|
||
|
(*outputMixObject)->Destroy(outputMixObject);
|
||
|
outputMixObject = NULL;
|
||
|
}
|
||
|
if (engineObject != NULL) {
|
||
|
(*engineObject)->Destroy(engineObject);
|
||
|
engineObject = NULL;
|
||
|
engineEngine = NULL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
uint32_t kinc_a2_samples_per_second(void) {
|
||
|
return 44100;
|
||
|
}
|