Blame src/libout123/modules/openal.c

Packit c32a2d
/*
Packit c32a2d
	openal.c: audio output on OpenAL
Packit c32a2d
Packit c32a2d
	copyright 1995-2016 by the mpg123 project - free software under the terms of the LGPL 2.1
Packit c32a2d
	see COPYING and AUTHORS files in distribution or http://mpg123.org
Packit c32a2d
	initially written by Taihei Monma
Packit c32a2d
*/
Packit c32a2d
Packit c32a2d
/* Need usleep(). */
Packit c32a2d
#define _DEFAULT_SOURCE
Packit c32a2d
#define _BSD_SOURCE
Packit c32a2d
Packit c32a2d
#include "out123_int.h"
Packit c32a2d
Packit c32a2d
#ifdef OPENAL_SUBDIR_OPENAL
Packit c32a2d
	#include <OpenAL/al.h>
Packit c32a2d
	#include <OpenAL/alc.h>
Packit c32a2d
#elif defined(OPENAL_SUBDIR_AL)
Packit c32a2d
	#include <AL/al.h>
Packit c32a2d
	#include <AL/alc.h>
Packit c32a2d
#else
Packit c32a2d
	#include <al.h>
Packit c32a2d
	#include <alc.h>
Packit c32a2d
#endif
Packit c32a2d
#include <errno.h>
Packit c32a2d
#include <unistd.h>
Packit c32a2d
Packit c32a2d
#include "debug.h"
Packit c32a2d
Packit c32a2d
#define NUM_BUFFERS 16
Packit c32a2d
Packit c32a2d
#ifndef AL_FORMAT_MONO_FLOAT32
Packit c32a2d
#define AL_FORMAT_MONO_FLOAT32 0x10010
Packit c32a2d
#endif
Packit c32a2d
#ifndef AL_FORMAT_STEREO_FLOAT32
Packit c32a2d
#define AL_FORMAT_STEREO_FLOAT32 0x10011
Packit c32a2d
#endif
Packit c32a2d
Packit c32a2d
typedef struct
Packit c32a2d
{
Packit c32a2d
	ALCdevice *device;
Packit c32a2d
	ALCcontext *context;
Packit c32a2d
	ALuint source, buffer;
Packit c32a2d
	ALenum format;
Packit c32a2d
	ALsizei rate;
Packit c32a2d
} mpg123_openal_t;
Packit c32a2d
Packit c32a2d
Packit c32a2d
static int open_openal(out123_handle *ao)
Packit c32a2d
{
Packit c32a2d
	mpg123_openal_t* al = (mpg123_openal_t*)ao->userptr;
Packit c32a2d
Packit c32a2d
	al->device = alcOpenDevice(NULL);
Packit c32a2d
	al->context = alcCreateContext(al->device, NULL);
Packit c32a2d
	alcMakeContextCurrent(al->context);
Packit c32a2d
	alGenSources(1, &al->source);
Packit c32a2d
Packit c32a2d
	al->rate = ao->rate;
Packit c32a2d
	if(ao->format == MPG123_ENC_SIGNED_16 && ao->channels == 2) al->format = AL_FORMAT_STEREO16;
Packit c32a2d
	else if(ao->format == MPG123_ENC_SIGNED_16 && ao->channels == 1) al->format = AL_FORMAT_MONO16;
Packit c32a2d
	else if(ao->format == MPG123_ENC_UNSIGNED_8 && ao->channels == 2) al->format = AL_FORMAT_STEREO8;
Packit c32a2d
	else if(ao->format == MPG123_ENC_UNSIGNED_8 && ao->channels == 1) al->format = AL_FORMAT_MONO8;
Packit c32a2d
	else if(ao->format == MPG123_ENC_FLOAT_32 && ao->channels == 2) al->format = AL_FORMAT_STEREO_FLOAT32;
Packit c32a2d
	else if(ao->format == MPG123_ENC_FLOAT_32 && ao->channels == 1) al->format = AL_FORMAT_MONO_FLOAT32;
Packit c32a2d
	
Packit c32a2d
	return 0;
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
static int get_formats_openal(out123_handle *ao)
Packit c32a2d
{
Packit c32a2d
	return MPG123_ENC_SIGNED_16|MPG123_ENC_UNSIGNED_8|((alIsExtensionPresent((ALubyte*)"AL_EXT_float32") == AL_TRUE) ? MPG123_ENC_FLOAT_32 : 0);
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
static int write_openal(out123_handle *ao, unsigned char *buf, int len)
Packit c32a2d
{
Packit c32a2d
	ALint state, n;
Packit c32a2d
	mpg123_openal_t* al = (mpg123_openal_t*)ao->userptr;
Packit c32a2d
Packit c32a2d
	alGetSourcei(al->source, AL_BUFFERS_QUEUED, &n);
Packit c32a2d
	if(n < NUM_BUFFERS)
Packit c32a2d
	{
Packit c32a2d
		alGenBuffers(1, &al->buffer);
Packit c32a2d
	}
Packit c32a2d
	else
Packit c32a2d
	{
Packit c32a2d
		alGetSourcei(al->source, AL_SOURCE_STATE, &state);
Packit c32a2d
		if(state != AL_PLAYING)
Packit c32a2d
		{
Packit c32a2d
			alSourcePlay(al->source);
Packit c32a2d
		}
Packit c32a2d
		while(alGetSourcei(al->source, AL_BUFFERS_PROCESSED, &n), n == 0)
Packit c32a2d
		{	
Packit c32a2d
			usleep(10000);
Packit c32a2d
		}
Packit c32a2d
		alSourceUnqueueBuffers(al->source, 1, &al->buffer);
Packit c32a2d
	}
Packit c32a2d
	
Packit c32a2d
	alBufferData(al->buffer, al->format, buf, len, al->rate);
Packit c32a2d
	alSourceQueueBuffers(al->source, 1, &al->buffer);
Packit c32a2d
	
Packit c32a2d
	return len;
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
static int close_openal(out123_handle *ao)
Packit c32a2d
{
Packit c32a2d
	ALint state, n;
Packit c32a2d
	mpg123_openal_t* al = (mpg123_openal_t*)ao->userptr;
Packit c32a2d
Packit c32a2d
	if (al)
Packit c32a2d
	{
Packit c32a2d
		/* wait until all buffers are consumed */
Packit c32a2d
		while(alGetSourcei(al->source, AL_SOURCE_STATE, &state), state == AL_PLAYING)
Packit c32a2d
		{
Packit c32a2d
			usleep(10000);
Packit c32a2d
		}
Packit c32a2d
		/* free all processed buffers */
Packit c32a2d
		while(alGetSourcei(al->source, AL_BUFFERS_PROCESSED, &n), n > 0)
Packit c32a2d
		{
Packit c32a2d
			alSourceUnqueueBuffers(al->source, 1, &al->buffer);
Packit c32a2d
			alDeleteBuffers(1, &al->buffer);
Packit c32a2d
		}
Packit c32a2d
		alDeleteSources(1, &al->source);
Packit c32a2d
		alcMakeContextCurrent(NULL);
Packit c32a2d
		alcDestroyContext(al->context);
Packit c32a2d
		alcCloseDevice(al->device);
Packit c32a2d
	}
Packit c32a2d
	
Packit c32a2d
	return 0;
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
static void flush_openal(out123_handle *ao)
Packit c32a2d
{
Packit c32a2d
	ALint n;
Packit c32a2d
	mpg123_openal_t* al = (mpg123_openal_t*)ao->userptr;
Packit c32a2d
Packit c32a2d
	if (al)
Packit c32a2d
	{
Packit c32a2d
		/* stop playing and flush all buffers */
Packit c32a2d
		alSourceStop(al->source);
Packit c32a2d
		while(alGetSourcei(al->source, AL_BUFFERS_PROCESSED, &n), n > 0)
Packit c32a2d
		{
Packit c32a2d
			alSourceUnqueueBuffers(al->source, 1, &al->buffer);
Packit c32a2d
			alDeleteBuffers(1, &al->buffer);
Packit c32a2d
		}
Packit c32a2d
	}
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
static int deinit_openal(out123_handle* ao)
Packit c32a2d
{
Packit c32a2d
	/* Free up memory */
Packit c32a2d
	if(ao->userptr)
Packit c32a2d
	{
Packit c32a2d
		free( ao->userptr );
Packit c32a2d
		ao->userptr = NULL;
Packit c32a2d
	}
Packit c32a2d
Packit c32a2d
	/* Success */
Packit c32a2d
	return 0;
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
static int init_openal(out123_handle* ao)
Packit c32a2d
{
Packit c32a2d
	if (ao==NULL) return -1;
Packit c32a2d
Packit c32a2d
	/* Set callbacks */
Packit c32a2d
	ao->open = open_openal;
Packit c32a2d
	ao->flush = flush_openal;
Packit c32a2d
	ao->write = write_openal;
Packit c32a2d
	ao->get_formats = get_formats_openal;
Packit c32a2d
	ao->close = close_openal;
Packit c32a2d
	ao->deinit = deinit_openal;
Packit c32a2d
Packit c32a2d
	/* Allocate memory for data structure */
Packit c32a2d
	ao->userptr = malloc( sizeof( mpg123_openal_t ) );
Packit c32a2d
	if(ao->userptr==NULL)
Packit c32a2d
	{
Packit c32a2d
		if(!AOQUIET)
Packit c32a2d
			error("failed to malloc memory for 'mpg123_openal_t'");
Packit c32a2d
		return -1;
Packit c32a2d
	}
Packit c32a2d
	memset( ao->userptr, 0, sizeof(mpg123_openal_t) );
Packit c32a2d
Packit c32a2d
	/* Success */
Packit c32a2d
	return 0;
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
Packit c32a2d
/* 
Packit c32a2d
	Module information data structure
Packit c32a2d
*/
Packit c32a2d
mpg123_module_t mpg123_output_module_info = {
Packit c32a2d
	/* api_version */	MPG123_MODULE_API_VERSION,
Packit c32a2d
	/* name */			"openal",
Packit c32a2d
	/* description */	"Output audio using OpenAL.",
Packit c32a2d
	/* revision */		"$Rev:$",
Packit c32a2d
	/* handle */		NULL,
Packit c32a2d
	
Packit c32a2d
	/* init_output */	init_openal,
Packit c32a2d
};
Packit c32a2d
Packit c32a2d