Blame channels/audin/client/opensles/opensl_io.c

Packit Service fa4841
/*
Packit Service fa4841
opensl_io.c:
Packit Service fa4841
Android OpenSL input/output module
Packit Service fa4841
Copyright (c) 2012, Victor Lazzarini
Packit Service fa4841
All rights reserved.
Packit Service fa4841
Packit Service fa4841
Redistribution and use in source and binary forms, with or without
Packit Service fa4841
modification, are permitted provided that the following conditions are met:
Packit Service fa4841
    * Redistributions of source code must retain the above copyright
Packit Service fa4841
      notice, this list of conditions and the following disclaimer.
Packit Service fa4841
    * Redistributions in binary form must reproduce the above copyright
Packit Service fa4841
      notice, this list of conditions and the following disclaimer in the
Packit Service fa4841
      documentation and/or other materials provided with the distribution.
Packit Service fa4841
    * Neither the name of the <organization> nor the
Packit Service fa4841
      names of its contributors may be used to endorse or promote products
Packit Service fa4841
      derived from this software without specific prior written permission.
Packit Service fa4841
Packit Service fa4841
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
Packit Service fa4841
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
Packit Service fa4841
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
Packit Service fa4841
DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
Packit Service fa4841
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
Packit Service fa4841
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
Packit Service fa4841
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
Packit Service fa4841
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
Packit Service fa4841
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
Packit Service fa4841
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Packit Service fa4841
*/
Packit Service fa4841
Packit Service fa4841
#include <assert.h>
Packit Service fa4841
Packit Service fa4841
#include "audin_main.h"
Packit Service fa4841
#include "opensl_io.h"
Packit Service fa4841
#define CONV16BIT 32768
Packit Service fa4841
#define CONVMYFLT (1. / 32768.)
Packit Service fa4841
Packit Service fa4841
typedef struct
Packit Service fa4841
{
Packit Service fa4841
	size_t size;
Packit Service fa4841
	void* data;
Packit Service fa4841
} queue_element;
Packit Service fa4841
Packit Service fa4841
struct opensl_stream
Packit Service fa4841
{
Packit Service fa4841
	// engine interfaces
Packit Service fa4841
	SLObjectItf engineObject;
Packit Service fa4841
	SLEngineItf engineEngine;
Packit Service fa4841
Packit Service fa4841
	// device interfaces
Packit Service fa4841
	SLDeviceVolumeItf deviceVolume;
Packit Service fa4841
Packit Service fa4841
	// recorder interfaces
Packit Service fa4841
	SLObjectItf recorderObject;
Packit Service fa4841
	SLRecordItf recorderRecord;
Packit Service fa4841
	SLAndroidSimpleBufferQueueItf recorderBufferQueue;
Packit Service fa4841
Packit Service fa4841
	unsigned int inchannels;
Packit Service fa4841
	unsigned int sr;
Packit Service fa4841
	unsigned int buffersize;
Packit Service fa4841
	unsigned int bits_per_sample;
Packit Service fa4841
Packit Service fa4841
	queue_element* prep;
Packit Service fa4841
	queue_element* next;
Packit Service fa4841
Packit Service fa4841
	void* context;
Packit Service fa4841
	opensl_receive_t receive;
Packit Service fa4841
};
Packit Service fa4841
Packit Service fa4841
static void bqRecorderCallback(SLAndroidSimpleBufferQueueItf bq, void* context);
Packit Service fa4841
Packit Service fa4841
// creates the OpenSL ES audio engine
Packit Service fa4841
static SLresult openSLCreateEngine(OPENSL_STREAM* p)
Packit Service fa4841
{
Packit Service fa4841
	SLresult result;
Packit Service fa4841
	// create engine
Packit Service fa4841
	result = slCreateEngine(&(p->engineObject), 0, NULL, 0, NULL, NULL);
Packit Service fa4841
Packit Service fa4841
	if (result != SL_RESULT_SUCCESS)
Packit Service fa4841
		goto engine_end;
Packit Service fa4841
Packit Service fa4841
	// realize the engine
Packit Service fa4841
	result = (*p->engineObject)->Realize(p->engineObject, SL_BOOLEAN_FALSE);
Packit Service fa4841
Packit Service fa4841
	if (result != SL_RESULT_SUCCESS)
Packit Service fa4841
		goto engine_end;
Packit Service fa4841
Packit Service fa4841
	// get the engine interface, which is needed in order to create other objects
Packit Service fa4841
	result = (*p->engineObject)->GetInterface(p->engineObject, SL_IID_ENGINE, &(p->engineEngine));
Packit Service fa4841
Packit Service fa4841
	if (result != SL_RESULT_SUCCESS)
Packit Service fa4841
		goto engine_end;
Packit Service fa4841
Packit Service fa4841
	// get the volume interface - important, this is optional!
Packit Service fa4841
	result =
Packit Service fa4841
	    (*p->engineObject)->GetInterface(p->engineObject, SL_IID_DEVICEVOLUME, &(p->deviceVolume));
Packit Service fa4841
Packit Service fa4841
	if (result != SL_RESULT_SUCCESS)
Packit Service fa4841
	{
Packit Service fa4841
		p->deviceVolume = NULL;
Packit Service fa4841
		result = SL_RESULT_SUCCESS;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
engine_end:
Packit Service fa4841
	assert(SL_RESULT_SUCCESS == result);
Packit Service fa4841
	return result;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
// Open the OpenSL ES device for input
Packit Service fa4841
static SLresult openSLRecOpen(OPENSL_STREAM* p)
Packit Service fa4841
{
Packit Service fa4841
	SLresult result;
Packit Service fa4841
	SLuint32 sr = p->sr;
Packit Service fa4841
	SLuint32 channels = p->inchannels;
Packit Service fa4841
	assert(!p->recorderObject);
Packit Service fa4841
Packit Service fa4841
	if (channels)
Packit Service fa4841
	{
Packit Service fa4841
		switch (sr)
Packit Service fa4841
		{
Packit Service fa4841
			case 8000:
Packit Service fa4841
				sr = SL_SAMPLINGRATE_8;
Packit Service fa4841
				break;
Packit Service fa4841
Packit Service fa4841
			case 11025:
Packit Service fa4841
				sr = SL_SAMPLINGRATE_11_025;
Packit Service fa4841
				break;
Packit Service fa4841
Packit Service fa4841
			case 16000:
Packit Service fa4841
				sr = SL_SAMPLINGRATE_16;
Packit Service fa4841
				break;
Packit Service fa4841
Packit Service fa4841
			case 22050:
Packit Service fa4841
				sr = SL_SAMPLINGRATE_22_05;
Packit Service fa4841
				break;
Packit Service fa4841
Packit Service fa4841
			case 24000:
Packit Service fa4841
				sr = SL_SAMPLINGRATE_24;
Packit Service fa4841
				break;
Packit Service fa4841
Packit Service fa4841
			case 32000:
Packit Service fa4841
				sr = SL_SAMPLINGRATE_32;
Packit Service fa4841
				break;
Packit Service fa4841
Packit Service fa4841
			case 44100:
Packit Service fa4841
				sr = SL_SAMPLINGRATE_44_1;
Packit Service fa4841
				break;
Packit Service fa4841
Packit Service fa4841
			case 48000:
Packit Service fa4841
				sr = SL_SAMPLINGRATE_48;
Packit Service fa4841
				break;
Packit Service fa4841
Packit Service fa4841
			case 64000:
Packit Service fa4841
				sr = SL_SAMPLINGRATE_64;
Packit Service fa4841
				break;
Packit Service fa4841
Packit Service fa4841
			case 88200:
Packit Service fa4841
				sr = SL_SAMPLINGRATE_88_2;
Packit Service fa4841
				break;
Packit Service fa4841
Packit Service fa4841
			case 96000:
Packit Service fa4841
				sr = SL_SAMPLINGRATE_96;
Packit Service fa4841
				break;
Packit Service fa4841
Packit Service fa4841
			case 192000:
Packit Service fa4841
				sr = SL_SAMPLINGRATE_192;
Packit Service fa4841
				break;
Packit Service fa4841
Packit Service fa4841
			default:
Packit Service fa4841
				return -1;
Packit Service fa4841
		}
Packit Service fa4841
Packit Service fa4841
		// configure audio source
Packit Service fa4841
		SLDataLocator_IODevice loc_dev = { SL_DATALOCATOR_IODEVICE, SL_IODEVICE_AUDIOINPUT,
Packit Service fa4841
			                               SL_DEFAULTDEVICEID_AUDIOINPUT, NULL };
Packit Service fa4841
		SLDataSource audioSrc = { &loc_dev, NULL };
Packit Service fa4841
		// configure audio sink
Packit Service fa4841
		int speakers;
Packit Service fa4841
Packit Service fa4841
		if (channels > 1)
Packit Service fa4841
			speakers = SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT;
Packit Service fa4841
		else
Packit Service fa4841
			speakers = SL_SPEAKER_FRONT_CENTER;
Packit Service fa4841
Packit Service fa4841
		SLDataLocator_AndroidSimpleBufferQueue loc_bq = { SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE,
Packit Service fa4841
			                                              2 };
Packit Service fa4841
		SLDataFormat_PCM format_pcm;
Packit Service fa4841
		format_pcm.formatType = SL_DATAFORMAT_PCM;
Packit Service fa4841
		format_pcm.numChannels = channels;
Packit Service fa4841
		format_pcm.samplesPerSec = sr;
Packit Service fa4841
		format_pcm.channelMask = speakers;
Packit Service fa4841
		format_pcm.endianness = SL_BYTEORDER_LITTLEENDIAN;
Packit Service fa4841
Packit Service fa4841
		if (16 == p->bits_per_sample)
Packit Service fa4841
		{
Packit Service fa4841
			format_pcm.bitsPerSample = SL_PCMSAMPLEFORMAT_FIXED_16;
Packit Service fa4841
			format_pcm.containerSize = 16;
Packit Service fa4841
		}
Packit Service fa4841
		else if (8 == p->bits_per_sample)
Packit Service fa4841
		{
Packit Service fa4841
			format_pcm.bitsPerSample = SL_PCMSAMPLEFORMAT_FIXED_8;
Packit Service fa4841
			format_pcm.containerSize = 8;
Packit Service fa4841
		}
Packit Service fa4841
		else
Packit Service fa4841
			assert(0);
Packit Service fa4841
Packit Service fa4841
		SLDataSink audioSnk = { &loc_bq, &format_pcm };
Packit Service fa4841
		// create audio recorder
Packit Service fa4841
		// (requires the RECORD_AUDIO permission)
Packit Service fa4841
		const SLInterfaceID id[] = { SL_IID_ANDROIDSIMPLEBUFFERQUEUE };
Packit Service fa4841
		const SLboolean req[] = { SL_BOOLEAN_TRUE };
Packit Service fa4841
		result = (*p->engineEngine)
Packit Service fa4841
		             ->CreateAudioRecorder(p->engineEngine, &(p->recorderObject), &audioSrc,
Packit Service fa4841
		                                   &audioSnk, 1, id, req);
Packit Service fa4841
		assert(!result);
Packit Service fa4841
Packit Service fa4841
		if (SL_RESULT_SUCCESS != result)
Packit Service fa4841
			goto end_recopen;
Packit Service fa4841
Packit Service fa4841
		// realize the audio recorder
Packit Service fa4841
		result = (*p->recorderObject)->Realize(p->recorderObject, SL_BOOLEAN_FALSE);
Packit Service fa4841
		assert(!result);
Packit Service fa4841
Packit Service fa4841
		if (SL_RESULT_SUCCESS != result)
Packit Service fa4841
			goto end_recopen;
Packit Service fa4841
Packit Service fa4841
		// get the record interface
Packit Service fa4841
		result = (*p->recorderObject)
Packit Service fa4841
		             ->GetInterface(p->recorderObject, SL_IID_RECORD, &(p->recorderRecord));
Packit Service fa4841
		assert(!result);
Packit Service fa4841
Packit Service fa4841
		if (SL_RESULT_SUCCESS != result)
Packit Service fa4841
			goto end_recopen;
Packit Service fa4841
Packit Service fa4841
		// get the buffer queue interface
Packit Service fa4841
		result = (*p->recorderObject)
Packit Service fa4841
		             ->GetInterface(p->recorderObject, SL_IID_ANDROIDSIMPLEBUFFERQUEUE,
Packit Service fa4841
		                            &(p->recorderBufferQueue));
Packit Service fa4841
		assert(!result);
Packit Service fa4841
Packit Service fa4841
		if (SL_RESULT_SUCCESS != result)
Packit Service fa4841
			goto end_recopen;
Packit Service fa4841
Packit Service fa4841
		// register callback on the buffer queue
Packit Service fa4841
		result = (*p->recorderBufferQueue)
Packit Service fa4841
		             ->RegisterCallback(p->recorderBufferQueue, bqRecorderCallback, p);
Packit Service fa4841
		assert(!result);
Packit Service fa4841
Packit Service fa4841
		if (SL_RESULT_SUCCESS != result)
Packit Service fa4841
			goto end_recopen;
Packit Service fa4841
Packit Service fa4841
	end_recopen:
Packit Service fa4841
		return result;
Packit Service fa4841
	}
Packit Service fa4841
	else
Packit Service fa4841
		return SL_RESULT_SUCCESS;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
// close the OpenSL IO and destroy the audio engine
Packit Service fa4841
static void openSLDestroyEngine(OPENSL_STREAM* p)
Packit Service fa4841
{
Packit Service fa4841
	// destroy audio recorder object, and invalidate all associated interfaces
Packit Service fa4841
	if (p->recorderObject != NULL)
Packit Service fa4841
	{
Packit Service fa4841
		(*p->recorderObject)->Destroy(p->recorderObject);
Packit Service fa4841
		p->recorderObject = NULL;
Packit Service fa4841
		p->recorderRecord = NULL;
Packit Service fa4841
		p->recorderBufferQueue = NULL;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	// destroy engine object, and invalidate all associated interfaces
Packit Service fa4841
	if (p->engineObject != NULL)
Packit Service fa4841
	{
Packit Service fa4841
		(*p->engineObject)->Destroy(p->engineObject);
Packit Service fa4841
		p->engineObject = NULL;
Packit Service fa4841
		p->engineEngine = NULL;
Packit Service fa4841
	}
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
static queue_element* opensles_queue_element_new(size_t size)
Packit Service fa4841
{
Packit Service fa4841
	queue_element* q = calloc(1, sizeof(queue_element));
Packit Service fa4841
Packit Service fa4841
	if (!q)
Packit Service fa4841
		goto fail;
Packit Service fa4841
Packit Service fa4841
	q->size = size;
Packit Service fa4841
	q->data = malloc(size);
Packit Service fa4841
Packit Service fa4841
	if (!q->data)
Packit Service fa4841
		goto fail;
Packit Service fa4841
Packit Service fa4841
	return q;
Packit Service fa4841
fail:
Packit Service fa4841
	free(q);
Packit Service fa4841
	return NULL;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
static void opensles_queue_element_free(void* obj)
Packit Service fa4841
{
Packit Service fa4841
	queue_element* e = (queue_element*)obj;
Packit Service fa4841
Packit Service fa4841
	if (e)
Packit Service fa4841
		free(e->data);
Packit Service fa4841
Packit Service fa4841
	free(e);
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
// open the android audio device for input
Packit Service fa4841
OPENSL_STREAM* android_OpenRecDevice(void* context, opensl_receive_t receive, int sr,
Packit Service fa4841
                                     int inchannels, int bufferframes, int bits_per_sample)
Packit Service fa4841
{
Packit Service fa4841
	OPENSL_STREAM* p;
Packit Service fa4841
Packit Service fa4841
	if (!context || !receive)
Packit Service fa4841
		return NULL;
Packit Service fa4841
Packit Service fa4841
	p = (OPENSL_STREAM*)calloc(1, sizeof(OPENSL_STREAM));
Packit Service fa4841
Packit Service fa4841
	if (!p)
Packit Service fa4841
		return NULL;
Packit Service fa4841
Packit Service fa4841
	p->context = context;
Packit Service fa4841
	p->receive = receive;
Packit Service fa4841
	p->inchannels = inchannels;
Packit Service fa4841
	p->sr = sr;
Packit Service fa4841
	p->buffersize = bufferframes;
Packit Service fa4841
	p->bits_per_sample = bits_per_sample;
Packit Service fa4841
Packit Service fa4841
	if ((p->bits_per_sample != 8) && (p->bits_per_sample != 16))
Packit Service fa4841
		goto fail;
Packit Service fa4841
Packit Service fa4841
	if (openSLCreateEngine(p) != SL_RESULT_SUCCESS)
Packit Service fa4841
		goto fail;
Packit Service fa4841
Packit Service fa4841
	if (openSLRecOpen(p) != SL_RESULT_SUCCESS)
Packit Service fa4841
		goto fail;
Packit Service fa4841
Packit Service fa4841
	/* Create receive buffers, prepare them and start recording */
Packit Service fa4841
	p->prep = opensles_queue_element_new(p->buffersize * p->bits_per_sample / 8);
Packit Service fa4841
	p->next = opensles_queue_element_new(p->buffersize * p->bits_per_sample / 8);
Packit Service fa4841
Packit Service fa4841
	if (!p->prep || !p->next)
Packit Service fa4841
		goto fail;
Packit Service fa4841
Packit Service fa4841
	(*p->recorderBufferQueue)->Enqueue(p->recorderBufferQueue, p->next->data, p->next->size);
Packit Service fa4841
	(*p->recorderBufferQueue)->Enqueue(p->recorderBufferQueue, p->prep->data, p->prep->size);
Packit Service fa4841
	(*p->recorderRecord)->SetRecordState(p->recorderRecord, SL_RECORDSTATE_RECORDING);
Packit Service fa4841
	return p;
Packit Service fa4841
fail:
Packit Service fa4841
	android_CloseRecDevice(p);
Packit Service fa4841
	return NULL;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
// close the android audio device
Packit Service fa4841
void android_CloseRecDevice(OPENSL_STREAM* p)
Packit Service fa4841
{
Packit Service fa4841
	if (p == NULL)
Packit Service fa4841
		return;
Packit Service fa4841
Packit Service fa4841
	opensles_queue_element_free(p->next);
Packit Service fa4841
	opensles_queue_element_free(p->prep);
Packit Service fa4841
	openSLDestroyEngine(p);
Packit Service fa4841
	free(p);
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
// this callback handler is called every time a buffer finishes recording
Packit Service fa4841
static void bqRecorderCallback(SLAndroidSimpleBufferQueueItf bq, void* context)
Packit Service fa4841
{
Packit Service fa4841
	OPENSL_STREAM* p = (OPENSL_STREAM*)context;
Packit Service fa4841
	queue_element* e;
Packit Service fa4841
Packit Service fa4841
	if (!p)
Packit Service fa4841
		return;
Packit Service fa4841
Packit Service fa4841
	e = p->next;
Packit Service fa4841
Packit Service fa4841
	if (!e)
Packit Service fa4841
		return;
Packit Service fa4841
Packit Service fa4841
	if (!p->context || !p->receive)
Packit Service fa4841
		WLog_WARN(TAG, "Missing receive callback=%p, context=%p", p->receive, p->context);
Packit Service fa4841
	else
Packit Service fa4841
		p->receive(p->context, e->data, e->size);
Packit Service fa4841
Packit Service fa4841
	p->next = p->prep;
Packit Service fa4841
	p->prep = e;
Packit Service fa4841
	(*p->recorderBufferQueue)->Enqueue(p->recorderBufferQueue, e->data, e->size);
Packit Service fa4841
}