Blame src/libout123/modules/tinyalsa.c

Packit c32a2d
/*
Packit c32a2d
	tinyalsa: sound output with TINY Advanced Linux Sound Architecture
Packit c32a2d
Packit c32a2d
	copyright 2006-8 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
Packit c32a2d
	initially written by Jarno Lehtinen <lehtinen@sci.fi>
Packit c32a2d
*/
Packit c32a2d
Packit c32a2d
#include "out123_int.h"
Packit c32a2d
#include <errno.h>
Packit c32a2d
Packit c32a2d
#include <tinyalsa/asoundlib.h>
Packit c32a2d
Packit c32a2d
#include "debug.h"
Packit c32a2d
Packit c32a2d
Packit c32a2d
typedef struct
Packit c32a2d
{
Packit c32a2d
	struct pcm *pcm;
Packit c32a2d
	struct pcm_params *params;
Packit c32a2d
	struct pcm_config config;
Packit c32a2d
Packit c32a2d
	unsigned int device;
Packit c32a2d
	unsigned int card;
Packit c32a2d
} mpg123_tinyalsa_t;
Packit c32a2d
Packit c32a2d
Packit c32a2d
static int initialize_device(out123_handle *ao)
Packit c32a2d
{
Packit c32a2d
	mpg123_tinyalsa_t* ta = (mpg123_tinyalsa_t*)ao->userptr;
Packit c32a2d
Packit c32a2d
	ta->config.channels = ao->channels;
Packit c32a2d
	ta->config.rate = ao->rate;
Packit c32a2d
    	ta->config.period_size = 1024;
Packit c32a2d
    	ta->config.period_count = 4;
Packit c32a2d
       	ta->config.format = PCM_FORMAT_S16_LE;
Packit c32a2d
    	ta->config.start_threshold = 0;
Packit c32a2d
    	ta->config.stop_threshold = 0;
Packit c32a2d
	ta->config.silence_threshold = 0;
Packit c32a2d
Packit c32a2d
	ta->pcm = pcm_open(ta->card, ta->device, PCM_OUT, &ta->config);
Packit c32a2d
	if (!ta->pcm || !pcm_is_ready(ta->pcm))
Packit c32a2d
	{
Packit c32a2d
		if(!AOQUIET)
Packit c32a2d
			error3( "(open) Unable to open card %u PCM device %u (%s)\n"
Packit c32a2d
			,	ta->card, ta->device, pcm_get_error(ta->pcm) );
Packit c32a2d
		return -1;
Packit c32a2d
	}
Packit c32a2d
Packit c32a2d
	return 0;
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
Packit c32a2d
static int open_tinyalsa(out123_handle *ao)
Packit c32a2d
{
Packit c32a2d
        debug("open_tinyalsa()");
Packit c32a2d
Packit c32a2d
	mpg123_tinyalsa_t* ta = (mpg123_tinyalsa_t*)ao->userptr;
Packit c32a2d
Packit c32a2d
        if (ao->format != -1)
Packit c32a2d
	{
Packit c32a2d
                /* we're going to play: initalize sample format */
Packit c32a2d
                return initialize_device(ao);
Packit c32a2d
        }
Packit c32a2d
	else
Packit c32a2d
	{
Packit c32a2d
                /* query mode; sample format will be set for each query */
Packit c32a2d
                return 0;
Packit c32a2d
        }
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
Packit c32a2d
static int get_formats_tinyalsa(out123_handle *ao)
Packit c32a2d
{
Packit c32a2d
        debug("get_formats_tinyalsa()");
Packit c32a2d
Packit c32a2d
	mpg123_tinyalsa_t* ta = (mpg123_tinyalsa_t*)ao->userptr;
Packit c32a2d
Packit c32a2d
	if ( ao->rate >= pcm_params_get_min(ta->params, PCM_PARAM_RATE) && ao->rate <= pcm_params_get_max(ta->params, PCM_PARAM_RATE) && ao->channels >= pcm_params_get_min(ta->params, PCM_PARAM_CHANNELS) && ao->channels <= pcm_params_get_max(ta->params, PCM_PARAM_CHANNELS) ) 
Packit c32a2d
	{
Packit c32a2d
        	return MPG123_ENC_SIGNED_16;
Packit c32a2d
	}
Packit c32a2d
	else
Packit c32a2d
	{
Packit c32a2d
		return 0;
Packit c32a2d
	}
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
Packit c32a2d
static int write_tinyalsa(out123_handle *ao, unsigned char *buf, int bytes)
Packit c32a2d
{
Packit c32a2d
	mpg123_tinyalsa_t* ta = (mpg123_tinyalsa_t*)ao->userptr;
Packit c32a2d
Packit c32a2d
	if (ta->pcm)
Packit c32a2d
	{
Packit c32a2d
		if(pcm_write(ta->pcm, buf, bytes))
Packit c32a2d
		{
Packit c32a2d
			if(!AOQUIET)
Packit c32a2d
				error("Error playing sample\n");
Packit c32a2d
			return -1;
Packit c32a2d
		}
Packit c32a2d
	}
Packit c32a2d
	return bytes;
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
Packit c32a2d
static void flush_tinyalsa(out123_handle *ao)
Packit c32a2d
{
Packit c32a2d
        debug("flush_tinyalsa()");
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
Packit c32a2d
static int close_tinyalsa(out123_handle *ao)
Packit c32a2d
{
Packit c32a2d
        debug("close_tinyalsa()");
Packit c32a2d
Packit c32a2d
	mpg123_tinyalsa_t* ta = (mpg123_tinyalsa_t*)ao->userptr;
Packit c32a2d
Packit c32a2d
	if (ta->pcm)
Packit c32a2d
	{
Packit c32a2d
		pcm_close(ta->pcm);
Packit c32a2d
	}
Packit c32a2d
Packit c32a2d
	return 0;
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
Packit c32a2d
static int deinit_tinyalsa(out123_handle* ao)
Packit c32a2d
{
Packit c32a2d
	mpg123_tinyalsa_t* ta = (mpg123_tinyalsa_t*)ao->userptr;
Packit c32a2d
Packit c32a2d
	/* Free up card/device parameters */
Packit c32a2d
	pcm_params_free(ta->params);
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
Packit c32a2d
static int init_tinyalsa(out123_handle* ao)
Packit c32a2d
{
Packit c32a2d
	if (ao==NULL) return -1;
Packit c32a2d
Packit c32a2d
	/* Set callbacks */
Packit c32a2d
	ao->open = open_tinyalsa;
Packit c32a2d
	ao->flush = flush_tinyalsa;
Packit c32a2d
	ao->write = write_tinyalsa;
Packit c32a2d
	ao->get_formats = get_formats_tinyalsa;
Packit c32a2d
	ao->close = close_tinyalsa;
Packit c32a2d
	ao->deinit = deinit_tinyalsa;
Packit c32a2d
Packit c32a2d
	/* Allocate memory for data structure */
Packit c32a2d
	ao->userptr = malloc( sizeof( mpg123_tinyalsa_t ) );
Packit c32a2d
	if(ao->userptr==NULL)
Packit c32a2d
	{
Packit c32a2d
		if(!AOQUIET)
Packit c32a2d
			error("failed to malloc memory for 'mpg123_tinyalsa_t'");
Packit c32a2d
		return -1;
Packit c32a2d
	}
Packit c32a2d
	memset( ao->userptr, 0, sizeof(mpg123_tinyalsa_t) );
Packit c32a2d
Packit c32a2d
	/* Set card and device */
Packit c32a2d
	mpg123_tinyalsa_t* ta = (mpg123_tinyalsa_t*)ao->userptr;
Packit c32a2d
Packit c32a2d
	ta->card = 0;
Packit c32a2d
	ta->device = 0;
Packit c32a2d
Packit c32a2d
	if (ao->device)
Packit c32a2d
	{
Packit c32a2d
		char *ptr = ao->device;
Packit c32a2d
		ta->card = (unsigned int)strtol(ptr, &ptr, 10);
Packit c32a2d
		if (strlen(ptr) > 0)
Packit c32a2d
		{
Packit c32a2d
	    		ta->device = (unsigned int)strtol(++ptr, &ptr, 10);
Packit c32a2d
	  	}
Packit c32a2d
	}
Packit c32a2d
Packit c32a2d
	/* Get card/device parameters */
Packit c32a2d
	ta->params = pcm_params_get(ta->card, ta->device, PCM_OUT);
Packit c32a2d
	if (ta->params == NULL)
Packit c32a2d
	{
Packit c32a2d
		if(!AOQUIET)
Packit c32a2d
			error2( "(params) Unable to open card %u PCM device %u.\n"
Packit c32a2d
			,	ta->card, ta->device );
Packit c32a2d
		return -1;
Packit c32a2d
	}
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 */		"tinyalsa",
Packit c32a2d
	/* description */	"Output audio using TINY Advanced Linux Sound Architecture (TINYALSA).",
Packit c32a2d
	/* revision */		"$Rev:$",
Packit c32a2d
	/* handle */		NULL,
Packit c32a2d
Packit c32a2d
	/* init_output */	init_tinyalsa,
Packit c32a2d
};
Packit c32a2d