|
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 |
|