Blame src/libout123/modules/pulse.c

Packit c32a2d
/*
Packit c32a2d
	pulse: audio output using PulseAudio server
Packit c32a2d
Packit c32a2d
	copyright 2006-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 Nicholas J. Humfrey
Packit c32a2d
*/
Packit c32a2d
Packit c32a2d
#include "out123_int.h"
Packit c32a2d
Packit c32a2d
#include <stdlib.h>
Packit c32a2d
#include <stdio.h>
Packit c32a2d
#include <math.h>
Packit c32a2d
Packit c32a2d
#include <pulse/simple.h>
Packit c32a2d
#include <pulse/error.h>
Packit c32a2d
Packit c32a2d
#include "debug.h"
Packit c32a2d
Packit c32a2d
static int open_pulse(out123_handle *ao)
Packit c32a2d
{
Packit c32a2d
	int err;
Packit c32a2d
	pa_simple* pas = NULL;
Packit c32a2d
	pa_sample_spec ss;
Packit c32a2d
	/* Check if already open ? */
Packit c32a2d
	if (ao->userptr) {
Packit c32a2d
		if(!AOQUIET)
Packit c32a2d
			error("Pulse audio output is already open.");
Packit c32a2d
		return -1;
Packit c32a2d
	}
Packit c32a2d
Packit c32a2d
	/* Open an audio I/O stream. */
Packit c32a2d
	/* When they are < 0, I shall set some default. */
Packit c32a2d
	if(ao->rate < 0 || ao->format < 0 || ao->channels < 0)
Packit c32a2d
	{
Packit c32a2d
		ao->rate     = 44100;
Packit c32a2d
		ao->channels = 2;
Packit c32a2d
		ao->format   = MPG123_ENC_SIGNED_16;
Packit c32a2d
	}
Packit c32a2d
Packit c32a2d
	/* Fill out pulse audio's data structure */
Packit c32a2d
	ss.channels = ao->channels;
Packit c32a2d
	ss.rate = ao->rate;
Packit c32a2d
Packit c32a2d
	switch(ao->format) {
Packit c32a2d
		case MPG123_ENC_SIGNED_16:
Packit c32a2d
#ifdef WORDS_BIGENDIAN
Packit c32a2d
			ss.format=PA_SAMPLE_S16BE;
Packit c32a2d
#else
Packit c32a2d
			ss.format=PA_SAMPLE_S16LE;
Packit c32a2d
#endif
Packit c32a2d
		break;
Packit c32a2d
		case MPG123_ENC_SIGNED_24:
Packit c32a2d
#ifdef WORDS_BIGENDIAN
Packit c32a2d
			ss.format=PA_SAMPLE_S24BE;
Packit c32a2d
#else
Packit c32a2d
			ss.format=PA_SAMPLE_S24LE;
Packit c32a2d
#endif
Packit c32a2d
		break;
Packit c32a2d
		case MPG123_ENC_SIGNED_32:
Packit c32a2d
#ifdef WORDS_BIGENDIAN
Packit c32a2d
			ss.format=PA_SAMPLE_S32BE;
Packit c32a2d
#else
Packit c32a2d
			ss.format=PA_SAMPLE_S32LE;
Packit c32a2d
#endif
Packit c32a2d
		break;
Packit c32a2d
		case MPG123_ENC_FLOAT_32:
Packit c32a2d
#ifdef WORDS_BIGENDIAN
Packit c32a2d
			ss.format=PA_SAMPLE_FLOAT32BE;
Packit c32a2d
#else
Packit c32a2d
			ss.format=PA_SAMPLE_FLOAT32LE;
Packit c32a2d
#endif
Packit c32a2d
		break;
Packit c32a2d
		case MPG123_ENC_ALAW_8:
Packit c32a2d
			ss.format=PA_SAMPLE_ALAW;
Packit c32a2d
		break;
Packit c32a2d
		case MPG123_ENC_ULAW_8:
Packit c32a2d
			ss.format=PA_SAMPLE_ULAW;
Packit c32a2d
		break;
Packit c32a2d
		case MPG123_ENC_UNSIGNED_8:
Packit c32a2d
			ss.format=PA_SAMPLE_U8;
Packit c32a2d
		break;
Packit c32a2d
		default:
Packit c32a2d
			if(!AOQUIET)
Packit c32a2d
				error1("Unsupported audio format: 0x%x", ao->format);
Packit c32a2d
			return -1;
Packit c32a2d
		break;
Packit c32a2d
	}
Packit c32a2d
Packit c32a2d
Packit c32a2d
	/* Perform the open */
Packit c32a2d
	pas = pa_simple_new(
Packit c32a2d
			NULL,				/* Use the default server */
Packit c32a2d
			ao->name,		/* Our application's name */
Packit c32a2d
			PA_STREAM_PLAYBACK,
Packit c32a2d
			ao->device,			/* Use the default device if NULL */
Packit c32a2d
			"via out123",		/* Description of our stream */
Packit c32a2d
			&ss,				/* Our sample format */
Packit c32a2d
			NULL,				/* Use default channel map */
Packit c32a2d
			NULL,				/* Use default buffering attributes */
Packit c32a2d
			&err				/* Error result code */
Packit c32a2d
	);
Packit c32a2d
Packit c32a2d
	if(pas == NULL)
Packit c32a2d
	{
Packit c32a2d
		if(!AOQUIET)
Packit c32a2d
			error1("Failed to open pulse audio output: %s", pa_strerror(err));
Packit c32a2d
		return -1;
Packit c32a2d
	}
Packit c32a2d
Packit c32a2d
	/* Store the pointer */
Packit c32a2d
	ao->userptr = (void*)pas;
Packit c32a2d
	return 0;
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
Packit c32a2d
static int get_formats_pulse(out123_handle *ao)
Packit c32a2d
{
Packit c32a2d
	/* Only implemented Signed 16-bit audio for now */
Packit c32a2d
	return MPG123_ENC_SIGNED_16;
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
Packit c32a2d
static int write_pulse(out123_handle *ao, unsigned char *buf, int len)
Packit c32a2d
{
Packit c32a2d
	pa_simple *pas = (pa_simple*)ao->userptr;
Packit c32a2d
	int ret, err;
Packit c32a2d
	/* Doesn't return number of bytes but just success or not. */
Packit c32a2d
	ret = pa_simple_write( pas, buf, len, &err );
Packit c32a2d
	if(ret<0)
Packit c32a2d
	{
Packit c32a2d
		if(!AOQUIET)
Packit c32a2d
			error1("Failed to write audio: %s", pa_strerror(err));
Packit c32a2d
		return -1;
Packit c32a2d
	}
Packit c32a2d
	return len; /* If successful, everything has been written. */
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
static int close_pulse(out123_handle *ao)
Packit c32a2d
{
Packit c32a2d
	pa_simple *pas = (pa_simple*)ao->userptr;
Packit c32a2d
Packit c32a2d
	if (pas) {
Packit c32a2d
		int err; /* Do we really want to handle errors here? End is the end. */
Packit c32a2d
		pa_simple_drain(pas, &err;;
Packit c32a2d
		pa_simple_free(pas);
Packit c32a2d
		ao->userptr = NULL;
Packit c32a2d
	}
Packit c32a2d
	
Packit c32a2d
	return 0;
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
static void flush_pulse(out123_handle *ao)
Packit c32a2d
{
Packit c32a2d
	pa_simple *pas = (pa_simple*)ao->userptr;
Packit c32a2d
	
Packit c32a2d
	if (pas) {
Packit c32a2d
		int err;
Packit c32a2d
		pa_simple_flush( pas, &err );	
Packit c32a2d
		if(err && !AOQUIET)
Packit c32a2d
			error1("Failed to flush audio: %s", pa_strerror(err));
Packit c32a2d
	}
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
Packit c32a2d
static int init_pulse(out123_handle* ao)
Packit c32a2d
{
Packit c32a2d
	if (ao==NULL) return -1;
Packit c32a2d
Packit c32a2d
	/* Set callbacks */
Packit c32a2d
	ao->open = open_pulse;
Packit c32a2d
	ao->flush = flush_pulse;
Packit c32a2d
	ao->write = write_pulse;
Packit c32a2d
	ao->get_formats = get_formats_pulse;
Packit c32a2d
	ao->close = close_pulse;
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 */			"pulse",						
Packit c32a2d
	/* description */	"Output audio using PulseAudio Server",
Packit c32a2d
	/* revision */		"$Rev:$",						
Packit c32a2d
	/* handle */		NULL,
Packit c32a2d
	
Packit c32a2d
	/* init_output */	init_pulse,						
Packit c32a2d
};
Packit c32a2d