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; | ||
|  | } |