609 lines · 13.8 KB · C
RawDownload
#include "dat.h"#include "fns.h"#include "error.h"#include "audio.h"#include <sys/ioctl.h>#include <linux/soundcard.h>#include <SLES/OpenSLES.h>#include <SLES/OpenSLES_Android.h> #define 	Audio_Mic_Val		SOUND_MIXER_MIC#define 	Audio_Linein_Val	SOUND_MIXER_LINE #define		Audio_Speaker_Val	SOUND_MIXER_PCM // SOUND_MIXER_VOLUME#define		Audio_Headphone_Val	SOUND_MIXER_ALTPCM#define		Audio_Lineout_Val	SOUND_MIXER_CD #define 	Audio_Pcm_Val		AFMT_S16_LE#define 	Audio_Ulaw_Val		AFMT_MU_LAW#define 	Audio_Alaw_Val		AFMT_A_LAW #include "audio-tbls.c"#define	min(a,b)	((a) < (b) ? (a) : (b)) #define DEVAUDIO	"/dev/snd/pcmC0D0p"#define DEVMIXER	"/dev/snd/controlC0" #define DPRINT if(1)print enum {	A_Pause,	A_UnPause,	A_In,	A_Out,}; static struct {	int data;	/* dsp data fd */	int ctl;	/* mixer fd */	int pause;	QLock lk;} afd = {.data = -1, .ctl = -1, .pause =A_UnPause }; static Audio_t av;static QLock inlock;static QLock outlock; static int audio_open(int);static int audio_pause(int, int);static int audio_set_info(int, Audio_d*, int); // SLES stuff// engine interfacesstatic SLObjectItf engineObject = NULL;static SLEngineItf engineEngine; // output mix interfacesstatic SLObjectItf outputMixObject = NULL;static SLEnvironmentalReverbItf outputMixVolume = NULL; // buffer queue player interfacesstatic SLObjectItf bqPlayerObject = NULL;static SLPlayItf bqPlayerPlay;static SLAndroidSimpleBufferQueueItf bqPlayerBufferQueue;//static SLEffectSendItf bqPlayerEffectSend; // recorder interfacesstatic SLObjectItf recorderObject = NULL;static SLRecordItf recorderRecord;static SLAndroidSimpleBufferQueueItf recorderBufferQueue;  Audio_t*getaudiodev(void){	return &av;} void audio_file_init(void){	/* Let's try this SLES junk */	SLresult result; 	/* Create engine */	SLEngineOption eo[] = {(SLuint32) SL_ENGINEOPTION_THREADSAFE, (SLuint32) SL_BOOLEAN_TRUE};	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 volume specified as a required interface	const SLInterfaceID ids[1] = {SL_IID_VOLUME};	const SLboolean req[1] = {SL_BOOLEAN_FALSE};	result = (*engineEngine)->CreateOutputMix(engineEngine, &outputMixObject, 1, ids, req);	assert(SL_RESULT_SUCCESS == result); 	// realize the output mix	result = (*outputMixObject)->Realize(outputMixObject, SL_BOOLEAN_FALSE);	assert(SL_RESULT_SUCCESS == result); 	// get the volume interface	result = (*outputMixObject)->GetInterface(outputMixObject, SL_IID_VOLUME,			&outputMixVolume); 	audio_info_init(&av);}  voidaudio_file_open(Chan *c, int omode){	SLresult result; //	DPRINT("opened mode %o\n", omode); 	if (omode == OWRITE || omode == ORDWR) {		// configure audio source		SLDataLocator_AndroidSimpleBufferQueue loc_bufq = {SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, 2};		SLDataFormat_PCM format_pcm = {SL_DATAFORMAT_PCM, 1, SL_SAMPLINGRATE_44_1,			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[1] = {SL_IID_BUFFERQUEUE};		const SLboolean req[1] = {SL_BOOLEAN_TRUE};		result = (*engineEngine)->CreateAudioPlayer(engineEngine, &bqPlayerObject, &audioSrc, &audioSnk,				1, 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);	} else if (omode == OREAD || omode == ORDWR) {		// configure audio source		SLDataLocator_IODevice loc_dev = {SL_DATALOCATOR_IODEVICE, SL_IODEVICE_AUDIOINPUT,				SL_DEFAULTDEVICEID_AUDIOINPUT, NULL};		SLDataSource audioSrc = {&loc_dev, NULL};			// configure audio sink		SLDataLocator_AndroidSimpleBufferQueue loc_bq = {SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, 1};		SLDataFormat_PCM format_pcm = {SL_DATAFORMAT_PCM, 1, SL_SAMPLINGRATE_16,			SL_PCMSAMPLEFORMAT_FIXED_16, SL_PCMSAMPLEFORMAT_FIXED_16,			SL_SPEAKER_FRONT_CENTER, SL_BYTEORDER_LITTLEENDIAN};		SLDataSink audioSnk = {&loc_bq, &format_pcm};			// create audio recorder		// (requires the RECORD_AUDIO permission)		const SLInterfaceID id[1] = {SL_IID_ANDROIDSIMPLEBUFFERQUEUE};		const SLboolean req[1] = {SL_BOOLEAN_TRUE};		result = (*engineEngine)->CreateAudioRecorder(engineEngine, &recorderObject, &audioSrc,				&audioSnk, 1, id, req);		if (SL_RESULT_SUCCESS != result) {			return;		}			// realize the audio recorder		result = (*recorderObject)->Realize(recorderObject, SL_BOOLEAN_FALSE);		if (SL_RESULT_SUCCESS != result) {			return;		}			// get the record interface		result = (*recorderObject)->GetInterface(recorderObject, SL_IID_RECORD, &recorderRecord);		assert(SL_RESULT_SUCCESS == result);			// get the buffer queue interface		result = (*recorderObject)->GetInterface(recorderObject, SL_IID_ANDROIDSIMPLEBUFFERQUEUE,				&recorderBufferQueue);		assert(SL_RESULT_SUCCESS == result);	}} void    audio_file_close(Chan *c){	// Destroy the buffer queue object	if (bqPlayerObject != NULL) {		(*bqPlayerObject)->Destroy(bqPlayerObject);		bqPlayerObject = NULL;		bqPlayerPlay = NULL;		bqPlayerBufferQueue = NULL;		//bqPlayerEffectSend = NULL;	}} longaudio_file_read(Chan *c, void *va, long count, vlong offset){	SLresult result;	SLBufferQueueState state; 	//DPRINT("in audio_file_read, count = %d\n", count); 	// in case already recording, stop recording and clear buffer queue	result = (*recorderRecord)->SetRecordState(recorderRecord, SL_RECORDSTATE_STOPPED);	assert(SL_RESULT_SUCCESS == result);	result = (*recorderBufferQueue)->Clear(recorderBufferQueue);	assert(SL_RESULT_SUCCESS == result); 	// the buffer is not valid for playback yet	//recorderSize = 0; 	// enqueue an empty buffer to be filled by the recorder	// (for streaming recording, we would enqueue at least 2 empty buffers to start things off)	result = (*recorderBufferQueue)->Enqueue(recorderBufferQueue, va,			count);	// 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); 	// start recording	result = (*recorderRecord)->SetRecordState(recorderRecord, SL_RECORDSTATE_RECORDING);	assert(SL_RESULT_SUCCESS == result); 	result = (*recorderBufferQueue)->GetState(recorderBufferQueue, &state); 	//DPRINT("state.count = %d\n", state.count); 	while (state.count)	{		(*recorderBufferQueue)->GetState(recorderBufferQueue, &state);		//DPRINT("state.count = %d\n", state.count);	} 	result = (*recorderRecord)->SetRecordState(recorderRecord, SL_RECORDSTATE_STOPPED); 	return count;	//	long ba, status, chunk, total;////	USED(c);//	USED(offset);//	DPRINT("audio_file_read %d %d\n", afd.data, afd.ctl);//	qlock(&inlock);//	if(waserror()){//		qunlock(&inlock);//		nexterror();//	}////	if(afd.data < 0)//		error(Eperm);////	/* check block alignment *///	ba = av.in.bits * av.in.chan / Bits_Per_Byte;////	if(count % ba)//		error(Ebadarg);//		//	if(!audio_pause(afd.data, A_UnPause))//		error(Eio);//	//	total = 0;//	while(total < count){//		chunk = count - total;//		status = read (afd.data, va + total, chunk);//		if(status < 0)//			error(Eio);//		total += status;//	}//	//	if(total != count)//		error(Eio);////	poperror();//	qunlock(&inlock);//	//	return count;} long                                            audio_file_write(Chan *c, void *va, long count, vlong offset){	SLresult result;	SLBufferQueueState state; //	DPRINT("count = %d, offset = %d\n", count, offset); 	result = (*bqPlayerBufferQueue)->Enqueue(bqPlayerBufferQueue, va, count); 	// set the player's state to playing	result = (*bqPlayerPlay)->SetPlayState(bqPlayerPlay, SL_PLAYSTATE_PLAYING);	assert(SL_RESULT_SUCCESS == result); 	result = (*bqPlayerBufferQueue)->GetState(bqPlayerBufferQueue, &state); 	while (state.count)	{		(*bqPlayerBufferQueue)->GetState(bqPlayerBufferQueue, &state);	} 	result = (*bqPlayerPlay)->SetPlayState(bqPlayerPlay, SL_PLAYSTATE_STOPPED); 	return count; //	long status = -1;//	long ba, total, chunk, bufsz;//	//	USED(c);//	USED(offset);//	DPRINT("audio_file_write %d %d\n", afd.data, afd.ctl);//	qlock(&outlock);//	if(waserror()){//		qunlock(&outlock);//		nexterror();//	}//	//	if(afd.data < 0)//		error(Eperm);//	//	/* check block alignment *///	ba = av.out.bits * av.out.chan / Bits_Per_Byte;////	if(count % ba)//		error(Ebadarg);////	total = 0;//	bufsz = av.out.buf * Audio_Max_Buf / Audio_Max_Val;////	if(bufsz == 0)//		error(Ebadarg);////	while(total < count){//		chunk = min(bufsz, count - total);//		status = write(afd.data, va, chunk);//		if(status <= 0)//			error(Eio);//		total += status;//	}////	poperror();//	qunlock(&outlock);////	return count;	} longaudio_ctl_write(Chan *c, void *va, long count, vlong offset){	Audio_t tmpav = av;	int tfd; 	USED(c);	USED(offset);	tmpav.in.flags = 0;	tmpav.out.flags = 0;		DPRINT ("audio_ctl_write %X %X\n", afd.data, afd.ctl);	if(!audioparse(va, count, &tmpav))		error(Ebadarg); 	if(!canqlock(&inlock))		error("device busy");	if(waserror()){		qunlock(&inlock);		nexterror();	}	if(!canqlock(&outlock))		error("device busy");	if(waserror()){		qunlock(&outlock);		nexterror();	} 	/* DEVAUDIO needs to be open to issue an ioctl */	tfd = afd.data;	if(tfd < 0){		tfd = open(DEVAUDIO, O_RDONLY|O_NONBLOCK);		if(tfd < 0)			oserror();	}	if(waserror()){		if(tfd != afd.data)			close(tfd);		nexterror();	} 	if(tmpav.in.flags & AUDIO_MOD_FLAG){		if(!audio_pause(tfd, A_Pause))			error(Ebadarg);		if(!audio_set_info(tfd, &tmpav.in, A_In))			error(Ebadarg);	} 	poperror();	if(tfd != afd.data)		close(tfd); 	tmpav.in.flags = 0;	av = tmpav; 	poperror();	qunlock(&outlock);	poperror();	qunlock(&inlock);	return count;} /* Linux/OSS specific stuff */ static intchoosefmt(Audio_d *i){	switch(i->bits){	case 8:		switch(i->enc){		case Audio_Alaw_Val:			return AFMT_A_LAW;		case Audio_Ulaw_Val:			return AFMT_MU_LAW;		case Audio_Pcm_Val:			return AFMT_U8;		}		break;	case 16:		if(i->enc == Audio_Pcm_Val)			return AFMT_S16_LE;		break;	}	return -1;} static intsetvolume(int fd, int what, int left, int right){	int can, v;		if(ioctl(fd, SOUND_MIXER_READ_DEVMASK, &can) < 0)		can = ~0; 	DPRINT("setvolume fd%d %X can mix 0x%X (mask %X)\n", fd, what, (can & (1<<what)), can);	if(!(can & (1<<what)))		return 0;	v = left | (right<<8);	if(ioctl(afd.ctl, MIXER_WRITE(what), &v) < 0)		return 0;	return 1;} static intaudio_set_info(int fd, Audio_d *i, int d){	int status, arg;	int oldfmt, newfmt; 	USED(d);	DPRINT("audio_set_info (%d) %d %d\n", fd, afd.data, afd.ctl);	if(fd < 0)		return 0; 	/* sample rate */	if(i->flags & AUDIO_RATE_FLAG){		arg = i->rate;		if(ioctl(fd, SNDCTL_DSP_SPEED, &arg) < 0)			return 0;	}		/* channels */	if(i->flags & AUDIO_CHAN_FLAG){		arg = i->chan;		if(ioctl(fd, SNDCTL_DSP_CHANNELS, &arg) < 0)			return 0;	} 	/* precision */	if(i->flags & AUDIO_BITS_FLAG){		arg = i->bits;		if(ioctl(fd, SNDCTL_DSP_SAMPLESIZE, &arg) < 0)			return 0;	}		/* encoding */	if(i->flags & AUDIO_ENC_FLAG){		ioctl(fd, SNDCTL_DSP_GETFMTS, &oldfmt); 		newfmt = choosefmt(i);		if(newfmt < 0)			return 0;		if(newfmt != oldfmt){			status = ioctl(fd, SNDCTL_DSP_SETFMT, &arg);			DPRINT ("enc oldfmt newfmt %x status %d\n", oldfmt, newfmt, status);

Lines 1–500 of 609.