|
|
* get either the default device name or something the | * get either the default device name or something the |
* user specified | * user specified |
*/ | */ |
void get_device_name(char *retref, int retsize); |
static void get_in_device_name(char *retref, int retsize); |
|
static void get_out_device_name(char *retref, int retsize); |
| |
struct alsa_info | struct alsa_info |
{ | { |
|
|
unsigned int periods; | unsigned int periods; |
snd_pcm_uframes_t bufframesize; | snd_pcm_uframes_t bufframesize; |
fd_set fd_set; | fd_set fd_set; |
|
int setup_read, setup_write; |
}; | }; |
| |
void *release_alsa(void *handle) | void *release_alsa(void *handle) |
|
|
| |
void *grab_read_alsa( void ) | void *grab_read_alsa( void ) |
{ | { |
/* no capture support */ |
struct alsa_info *retval; |
return NULL; |
snd_pcm_t *handle; |
|
char card_name[256]; |
|
int err; |
|
|
|
get_in_device_name(card_name, 256); |
|
|
|
err = snd_pcm_open(&handle, card_name, SND_PCM_STREAM_CAPTURE, 0); |
|
if(err < 0) |
|
{ |
|
const char *serr = snd_strerror(err); |
|
|
|
_alDebug(ALD_MAXIMUS, __FILE__, __LINE__, |
|
"grab_alsa: init failed: %s\n", serr); |
|
|
|
return NULL; |
|
} |
|
|
|
retval = malloc(sizeof *retval); |
|
retval->handle = handle; |
|
retval->format = 0; |
|
retval->channels = 0; |
|
retval->speed = 0; |
|
retval->framesize = 0; |
|
retval->bufframesize= 0; |
|
retval->periods = 0; |
|
retval->setup_read = 0; |
|
retval->setup_write = 0; |
|
|
|
_alDebug(ALD_MAXIMUS, __FILE__, __LINE__, |
|
"grab_alsa: init ok, using %s\n", card_name); |
|
|
|
return retval; |
|
} |
|
|
|
static void get_out_device_name(char *retref, int retsize) |
|
{ |
|
Rcvar rcv; |
|
|
|
assert(retref); |
|
|
|
if (!(rcv = rc_lookup("alsa-device"))) |
|
rcv = rc_lookup("alsa-out-device"); |
|
if (rcv != NULL) |
|
{ |
|
if(rc_type(rcv) == ALRC_STRING) |
|
{ |
|
rc_tostr0(rcv, retref, retsize); |
|
return; |
|
|
|
} |
|
} |
|
|
|
assert((int) strlen(DEFAULT_DEVICE) < retsize); |
|
strcpy(retref, DEFAULT_DEVICE); |
|
|
|
return; |
} | } |
| |
void get_device_name(char *retref, int retsize) |
static void get_in_device_name(char *retref, int retsize) |
{ | { |
Rcvar rcv; | Rcvar rcv; |
| |
assert(retref); | assert(retref); |
| |
rcv = rc_lookup("alsa-device"); |
if (!(rcv = rc_lookup("alsa-in-device"))) |
|
rcv = rc_lookup("alsa-device"); |
if(rcv != NULL) | if(rcv != NULL) |
{ | { |
if(rc_type(rcv) == ALRC_STRING) | if(rc_type(rcv) == ALRC_STRING) |
|
|
char card_name[256]; | char card_name[256]; |
int err; | int err; |
| |
get_device_name(card_name, 256); |
get_out_device_name(card_name, 256); |
| |
err = snd_pcm_open(&handle, card_name, 0, SND_PCM_STREAM_PLAYBACK); |
err = snd_pcm_open(&handle, card_name, SND_PCM_STREAM_PLAYBACK, 0); |
if(err < 0) | if(err < 0) |
{ | { |
const char *serr = snd_strerror(err); | const char *serr = snd_strerror(err); |
|
|
retval->speed = 0; | retval->speed = 0; |
retval->framesize = 0; | retval->framesize = 0; |
retval->bufframesize= 0; | retval->bufframesize= 0; |
retval->periods = 0; |
retval->periods = 0; |
|
retval->setup_read = 0; |
|
retval->setup_write = 0; |
| |
_alBlitBuffer = alsa_blitbuffer; | _alBlitBuffer = alsa_blitbuffer; |
| |
|
|
return retval; | return retval; |
} | } |
| |
ALboolean set_read_alsa( UNUSED(void *handle), |
ALboolean set_read_alsa( void *handle, |
UNUSED(ALuint *bufsiz), |
ALuint *bufsiz, |
UNUSED(ALenum *fmt), |
ALenum *fmt, |
UNUSED(ALuint *speed)) |
ALuint *speed) |
{ | { |
/* no capture support */ |
struct alsa_info *ai = handle; |
return AL_FALSE; |
snd_pcm_hw_params_t *setup; |
|
snd_pcm_uframes_t buffer_size, period_size; |
|
snd_pcm_t *phandle = 0; |
|
int err, dir; |
|
snd_output_t *out; |
|
|
|
if( (ai == NULL) || (ai->handle == NULL) ) |
|
return AL_FALSE; |
|
|
|
|
|
if (*fmt == AL_FORMAT_QUAD8_LOKI) |
|
*fmt = AL_FORMAT_STEREO8; |
|
if (*fmt == AL_FORMAT_QUAD16_LOKI) |
|
*fmt = AL_FORMAT_STEREO16; |
|
|
|
ai->channels = (unsigned int) _al_ALCHANNELS(*fmt); |
|
ai->format = (unsigned int) AL2ALSAFMT(*fmt); |
|
ai->speed = (unsigned int) *speed; |
|
ai->framesize = (unsigned int) FRAMESIZE(ai->format, ai->channels); |
|
ai->bufframesize= (snd_pcm_uframes_t) *bufsiz / ai->framesize * 4; |
|
ai->periods = 2; |
|
|
|
_alDebug(ALD_MAXIMUS, __FILE__, __LINE__, |
|
"alsa info (read):\n"\ |
|
" channels: %u\n"\ |
|
" format: %u\n"\ |
|
" speed: %u\n"\ |
|
" framesize: %u\n"\ |
|
" bufframesize: %u\n"\ |
|
" periods: %u", |
|
ai->channels, ai->format, ai->speed, ai->framesize, ai->bufframesize, ai->periods); |
|
|
|
phandle = ai->handle; |
|
snd_output_stdio_attach (&out, stderr, 0); |
|
|
|
snd_pcm_hw_params_alloca(&setup); |
|
err = snd_pcm_hw_params_any(phandle, setup); |
|
if(err < 0) |
|
{ |
|
_alDebug(ALD_MAXIMUS, __FILE__, __LINE__, |
|
"set_read_alsa: Could not query parameters: %s",snd_strerror(err)); |
|
|
|
return AL_FALSE; |
|
} |
|
|
|
/* set the interleaved read format */ |
|
err = snd_pcm_hw_params_set_access(phandle, setup, SND_PCM_ACCESS_RW_INTERLEAVED); |
|
if (err < 0) { |
|
_alDebug(ALD_MAXIMUS, __FILE__, __LINE__, |
|
"set_read_alsa: Could not set access type: %s",snd_strerror(err)); |
|
return AL_FALSE; |
|
} |
|
|
|
/* set format */ |
|
err = snd_pcm_hw_params_set_format(phandle, setup, ai->format); |
|
if(err < 0) |
|
{ |
|
_alDebug(ALD_MAXIMUS, __FILE__, __LINE__, |
|
"set_read_alsa: could not set format: %s",snd_strerror(err)); |
|
|
|
return AL_FALSE; |
|
} |
|
|
|
|
|
/* channels */ |
|
err = snd_pcm_hw_params_set_channels(phandle, setup, ai->channels); |
|
if(err < 0) |
|
{ |
|
#if (SND_LIB_MAJOR == 0) |
|
err = snd_pcm_hw_params_get_channels(setup); |
|
#else |
|
snd_pcm_hw_params_get_channels(setup, &err); |
|
#endif |
|
|
|
if (err != (int) (ai->channels)) { |
|
_alDebug(ALD_MAXIMUS, __FILE__, __LINE__, |
|
"set_read_alsa: could not set channels: %s",snd_strerror(err)); |
|
|
|
return AL_FALSE; |
|
} |
|
} |
|
|
|
|
|
/* sampling rate */ |
|
err = snd_pcm_hw_params_set_rate_near(phandle, setup, &ai->speed, NULL); |
|
if(err < 0) |
|
{ |
|
_alDebug(ALD_MAXIMUS, __FILE__, __LINE__, |
|
"set_read_alsa: could not set speed: %s",snd_strerror(err)); |
|
|
|
return AL_FALSE; |
|
} else if (err > 0) /* err is sampling rate if > 0 */ |
|
ai->speed = (unsigned int) err; |
|
|
|
|
|
/* Set number of periods. Periods used to be called fragments. */ |
|
err = snd_pcm_hw_params_set_periods(phandle, setup, ai->periods, 0); |
|
if (err < 0) { |
|
_alDebug(ALD_MAXIMUS, __FILE__, __LINE__, |
|
"set_read_alsa: %s\n", snd_strerror(err)); |
|
return AL_FALSE; |
|
} |
|
|
|
snd_pcm_hw_params_dump (setup, out); |
|
err = snd_pcm_hw_params_set_buffer_size(phandle, setup, ai->bufframesize); |
|
snd_pcm_hw_params_dump (setup, out); |
|
if (err < 0) { |
|
_alDebug(ALD_MAXIMUS, __FILE__, __LINE__, |
|
"set_read_alsa: %s, size: %d, speed: %d\n", |
|
snd_strerror(err), ai->bufframesize, ai->speed); |
|
return AL_FALSE; |
|
} |
|
|
|
#if (SND_LIB_MAJOR == 0) |
|
buffer_size = snd_pcm_hw_params_get_buffer_size(setup); |
|
period_size = snd_pcm_hw_params_get_period_size(setup, &dir); |
|
#else |
|
snd_pcm_hw_params_get_buffer_size(setup, &buffer_size); |
|
snd_pcm_hw_params_get_period_size(setup, &period_size, &dir); |
|
#endif |
|
|
|
_alDebug(ALD_MAXIMUS, __FILE__, __LINE__, |
|
"set_read_alsa (info): Buffersize = %i (%i)",buffer_size, *bufsiz); |
|
_alDebug(ALD_MAXIMUS, __FILE__, __LINE__, |
|
"set_read_alsa (info): Periodsize = %i", period_size); |
|
|
|
err = snd_pcm_hw_params(phandle, setup); |
|
if(err < 0) |
|
{ |
|
_alDebug(ALD_MAXIMUS, __FILE__, __LINE__, |
|
"set_read_alsa: %s\n", snd_strerror(err)); |
|
return AL_FALSE; |
|
} |
|
|
|
err = snd_pcm_prepare(phandle); |
|
if(err < 0) |
|
{ |
|
_alDebug(ALD_MAXIMUS, __FILE__, __LINE__, |
|
"set_read_alsa %s\n", snd_strerror(err)); |
|
return AL_FALSE; |
|
} |
|
|
|
_alDebug(ALD_MAXIMUS, __FILE__, __LINE__, |
|
"set_read_alsa: handle: %p, phandle: %p\n", handle, phandle); |
|
snd_output_close (out); |
|
ai->setup_read = 1; |
|
|
|
return AL_TRUE; |
} | } |
| |
ALboolean set_write_alsa(void *handle, | ALboolean set_write_alsa(void *handle, |
|
|
snd_pcm_uframes_t buffer_size, period_size; | snd_pcm_uframes_t buffer_size, period_size; |
snd_pcm_t *phandle = 0; | snd_pcm_t *phandle = 0; |
int err, dir; | int err, dir; |
|
snd_output_t *out; |
| |
if( (ai == NULL) || (ai->handle == NULL) ) | if( (ai == NULL) || (ai->handle == NULL) ) |
return AL_FALSE; |
return AL_FALSE; |
| |
| |
ai->channels = (unsigned int) _al_ALCHANNELS(*fmt); |
ai->channels = (unsigned int) _al_ALCHANNELS(*fmt); |
ai->format = (unsigned int) AL2ALSAFMT(*fmt); |
ai->format = (unsigned int) AL2ALSAFMT(*fmt); |
ai->speed = (unsigned int) *speed; |
ai->speed = (unsigned int) *speed; |
ai->framesize = (unsigned int) FRAMESIZE(ai->format, ai->channels); |
ai->framesize = (unsigned int) FRAMESIZE(ai->format, ai->channels); |
ai->bufframesize= (snd_pcm_uframes_t) *bufsiz / ai->framesize * 4; | ai->bufframesize= (snd_pcm_uframes_t) *bufsiz / ai->framesize * 4; |
ai->periods = 2; |
ai->periods = 2; |
| |
_alDebug(ALD_MAXIMUS, __FILE__, __LINE__, |
_alDebug(ALD_MAXIMUS, __FILE__, __LINE__, |
"alsa info:\n"\ |
"alsa info (write):\n"\ |
" channels: %u\n"\ |
" channels: %u\n"\ |
" format: %u\n"\ |
" format: %u\n"\ |
" speed: %u\n"\ |
" speed: %u\n"\ |
" framesize: %u\n"\ |
" framesize: %u\n"\ |
" bufframesize: %u\n"\ |
" bufframesize: %u\n"\ |
" periods: %u", |
" periods: %u", |
ai->channels, ai->format, ai->speed, ai->framesize, ai->bufframesize, ai->periods); |
ai->channels, ai->format, ai->speed, ai->framesize, ai->bufframesize, ai->periods); |
| |
phandle = ai->handle; |
phandle = ai->handle; |
|
snd_output_stdio_attach (&out, stderr, 0); |
| |
snd_pcm_hw_params_alloca(&setup); | snd_pcm_hw_params_alloca(&setup); |
err = snd_pcm_hw_params_any(phandle, setup); | err = snd_pcm_hw_params_any(phandle, setup); |
if(err < 0) | if(err < 0) |
{ | { |
_alDebug(ALD_MAXIMUS, __FILE__, __LINE__, | _alDebug(ALD_MAXIMUS, __FILE__, __LINE__, |
"set_write_alsa: Could not query parameters: %s",snd_strerror(err)); |
"set_write_alsa: Could not query parameters: %s",snd_strerror(err)); |
| |
return AL_FALSE; | return AL_FALSE; |
} | } |
| |
/* set the interleaved read format */ |
/* set the interleaved write format */ |
err = snd_pcm_hw_params_set_access(phandle, setup, SND_PCM_ACCESS_RW_INTERLEAVED); |
err = snd_pcm_hw_params_set_access(phandle, setup, SND_PCM_ACCESS_RW_INTERLEAVED); |
if (err < 0) { |
if (err < 0) { |
_alDebug(ALD_MAXIMUS, __FILE__, __LINE__, |
_alDebug(ALD_MAXIMUS, __FILE__, __LINE__, |
"set_write_alsa: Could not set access type: %s",snd_strerror(err)); |
"set_write_alsa: Could not set access type: %s",snd_strerror(err)); |
return AL_FALSE; |
return AL_FALSE; |
} |
} |
| |
/* set format */ | /* set format */ |
err = snd_pcm_hw_params_set_format(phandle, setup, ai->format); | err = snd_pcm_hw_params_set_format(phandle, setup, ai->format); |
if(err < 0) | if(err < 0) |
{ | { |
_alDebug(ALD_MAXIMUS, __FILE__, __LINE__, | _alDebug(ALD_MAXIMUS, __FILE__, __LINE__, |
"set_write_alsa: could not set format: %s",snd_strerror(err)); |
"set_write_alsa: could not set format: %s",snd_strerror(err)); |
| |
return AL_FALSE; | return AL_FALSE; |
} | } |
|
|
err = snd_pcm_hw_params_set_channels(phandle, setup, ai->channels); | err = snd_pcm_hw_params_set_channels(phandle, setup, ai->channels); |
if(err < 0) | if(err < 0) |
{ | { |
|
#if (SND_LIB_MAJOR == 0) |
|
err = snd_pcm_hw_params_get_channels(setup); |
|
#else |
|
snd_pcm_hw_params_get_channels(setup, &err); |
|
#endif |
| |
#if (SND_LIB_MAJOR == 0) |
if (err!= (int) (ai->channels)) { |
err = snd_pcm_hw_params_get_channels(setup); |
|
#else |
|
snd_pcm_hw_params_get_channels(setup, &err); |
|
#endif |
|
|
|
if(err!= (int) (ai->channels)) { |
|
_alDebug(ALD_MAXIMUS, __FILE__, __LINE__, | _alDebug(ALD_MAXIMUS, __FILE__, __LINE__, |
"set_write_alsa: could not set channels: %s",snd_strerror(err)); |
"set_write_alsa: could not set channels: %s",snd_strerror(err)); |
| |
return AL_FALSE; | return AL_FALSE; |
} | } |
|
|
| |
| |
/* sampling rate */ | /* sampling rate */ |
err = snd_pcm_hw_params_set_rate_near(phandle, setup, ai->speed, NULL); |
err = snd_pcm_hw_params_set_rate_near(phandle, setup, &ai->speed, NULL); |
if(err < 0) | if(err < 0) |
{ | { |
_alDebug(ALD_MAXIMUS, __FILE__, __LINE__, | _alDebug(ALD_MAXIMUS, __FILE__, __LINE__, |
"set_write_alsa: could not set speed: %s",snd_strerror(err)); |
"set_write_alsa: could not set speed: %s",snd_strerror(err)); |
| |
return AL_FALSE; | return AL_FALSE; |
} |
} else if (err > 0) /* err is sampling rate if > 0 */ |
/* err is sampling rate if >= 0 */ |
ai->speed = (unsigned int) err; |
ai->speed = (unsigned int) err; |
|
| |
| |
/* Set number of periods. Periods used to be called fragments. */ |
/* Set number of periods. Periods used to be called fragments. */ |
err = snd_pcm_hw_params_set_periods(phandle, setup, ai->periods, 0); |
err = snd_pcm_hw_params_set_periods(phandle, setup, ai->periods, 0); |
if (err < 0) { |
if (err < 0) { |
_alDebug(ALD_MAXIMUS, __FILE__, __LINE__, |
_alDebug(ALD_MAXIMUS, __FILE__, __LINE__, |
"set_write_alsa: %s\n", snd_strerror(err)); |
"set_write_alsa: %s\n", snd_strerror(err)); |
return AL_FALSE; | return AL_FALSE; |
} |
} |
| |
err = snd_pcm_hw_params_set_buffer_size(phandle, setup, ai->bufframesize); |
snd_pcm_hw_params_dump (setup, out); |
if (err < 0) { |
err = snd_pcm_hw_params_set_buffer_size(phandle, setup, ai->bufframesize); |
_alDebug(ALD_MAXIMUS, __FILE__, __LINE__, |
snd_pcm_hw_params_dump (setup, out); |
"set_write_alsa: %s\n", snd_strerror(err)); |
if (err < 0) { |
|
_alDebug(ALD_MAXIMUS, __FILE__, __LINE__, |
|
"set_write_alsa: %s, size: %d, speed: %d\n", |
|
snd_strerror(err), ai->bufframesize, ai->speed); |
return AL_FALSE; | return AL_FALSE; |
} |
} |
|
|
|
#if (SND_LIB_MAJOR == 0) |
|
buffer_size = snd_pcm_hw_params_get_buffer_size(setup); |
|
period_size = snd_pcm_hw_params_get_period_size(setup, &dir); |
|
#else |
|
snd_pcm_hw_params_get_buffer_size(setup, &buffer_size); |
|
snd_pcm_hw_params_get_period_size(setup, &period_size, &dir); |
|
#endif |
| |
#if (SND_LIB_MAJOR == 0) |
|
buffer_size = snd_pcm_hw_params_get_buffer_size(setup); |
|
period_size = snd_pcm_hw_params_get_period_size(setup, &dir); |
|
#else |
|
snd_pcm_hw_params_get_buffer_size(setup, &buffer_size); |
|
snd_pcm_hw_params_get_period_size(setup, &period_size, &dir); |
|
#endif |
|
|
|
_alDebug(ALD_MAXIMUS, __FILE__, __LINE__, | _alDebug(ALD_MAXIMUS, __FILE__, __LINE__, |
"set_write_alsa (info): Buffersize = %i (%i)",buffer_size, *bufsiz); |
"set_write_alsa (info): Buffersize = %i (%i)",buffer_size, *bufsiz); |
_alDebug(ALD_MAXIMUS, __FILE__, __LINE__, | _alDebug(ALD_MAXIMUS, __FILE__, __LINE__, |
"set_write_alsa (info): Periodsize = %i", period_size); |
"set_write_alsa (info): Periodsize = %i", period_size); |
| |
err = snd_pcm_hw_params(phandle, setup); | err = snd_pcm_hw_params(phandle, setup); |
if(err < 0) | if(err < 0) |
{ | { |
_alDebug(ALD_MAXIMUS, __FILE__, __LINE__, | _alDebug(ALD_MAXIMUS, __FILE__, __LINE__, |
"set_alsa: %s\n", snd_strerror(err)); |
"set_alsa: %s\n", snd_strerror(err)); |
return AL_FALSE; | return AL_FALSE; |
} | } |
| |
|
|
if(err < 0) | if(err < 0) |
{ | { |
_alDebug(ALD_MAXIMUS, __FILE__, __LINE__, | _alDebug(ALD_MAXIMUS, __FILE__, __LINE__, |
"set_alsa %s\n", snd_strerror(err)); |
"set_alsa %s\n", snd_strerror(err)); |
return AL_FALSE; | return AL_FALSE; |
} | } |
| |
|
_alDebug(ALD_MAXIMUS, __FILE__, __LINE__, |
|
"set_write_alsa: handle: %p, phandle: %p\n", handle, phandle); |
|
snd_output_close (out); |
|
ai->setup_write = 1; |
|
|
return AL_TRUE; | return AL_TRUE; |
} | } |
| |
|
|
int data_len = bytes; | int data_len = bytes; |
int channels = 0; | int channels = 0; |
int err; | int err; |
snd_pcm_uframes_t frames; |
snd_pcm_uframes_t frames; |
| |
if((ai == NULL) || (ai->handle == NULL)) |
if((ai == NULL) || (ai->handle == NULL) || (!ai->setup_write)) |
{ | { |
return; | return; |
} | } |
| |
phandle = ai->handle; | phandle = ai->handle; |
channels= ai->channels; |
channels= ai->channels; |
frames = (snd_pcm_uframes_t) bytes / ai->framesize; |
frames = (snd_pcm_uframes_t) bytes / ai->framesize; |
| |
while(data_len > 0) | while(data_len > 0) |
{ | { |
|
|
| |
return; | return; |
} | } |
|
|
|
/* capture data from the audio device */ |
|
ALsizei capture_alsa(void *handle, |
|
void *capture_buffer, |
|
int bufsize) |
|
{ |
|
struct alsa_info *ai = handle; |
|
snd_pcm_t *phandle = 0; |
|
char *pdata = capture_buffer; |
|
int ret; |
|
snd_pcm_uframes_t frames; |
|
|
|
if ((ai == NULL) || (ai->handle == NULL) || (!ai->setup_read)) |
|
return 0; |
|
|
|
phandle = ai->handle; |
|
frames = (snd_pcm_uframes_t) bufsize / ai->framesize; |
|
grab: |
|
|
|
_alDebug(ALD_MAXIMUS, __FILE__, __LINE__, |
|
"set_read_alsa: handle: %p, phandle: %p\n", handle, phandle); |
|
ret = snd_pcm_readi (phandle, pdata, frames); |
|
if (ret < 0) { |
|
fprintf(stderr, "Error, overrun: %d, trying to recover.\n", ret); |
|
ret = snd_pcm_prepare(phandle); |
|
if (ret < 0) |
|
fprintf(stderr, "Unable to recover: %d\n", ret); |
|
else |
|
goto grab; |
|
return 0; |
|
} else |
|
return ret * ai->framesize; |
|
} |
|
|
| |
static int AL2ALSAFMT(ALenum format) { | static int AL2ALSAFMT(ALenum format) { |
switch(format) { | switch(format) { |