You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
118 lines
2.6 KiB
118 lines
2.6 KiB
|
|
#include <alsa/asoundlib.h> |
|
#include <alsa/pcm.h> |
|
#include "sound.h" |
|
|
|
static snd_pcm_t *pcm_handle; |
|
|
|
static int init(int *rate, int *format, char **parm) |
|
{ |
|
snd_pcm_hw_params_t *hwparams; |
|
int ret; |
|
unsigned int channels, fmt; |
|
unsigned int btime = 250000; /* 250ms */ |
|
unsigned int ptime = 50000; /* 50ms */ |
|
char *card_name = "default"; |
|
|
|
parm_init(); |
|
chkparm1("buffer", btime = 1000 * strtoul(token, NULL, 0)); |
|
chkparm1("period", btime = 1000 * strtoul(token, NULL, 0)); |
|
chkparm1("card", card_name = token); |
|
parm_end(); |
|
|
|
if ((ret = snd_pcm_open(&pcm_handle, card_name, |
|
SND_PCM_STREAM_PLAYBACK, 0)) < 0) { |
|
fprintf(stderr, "Unable to initialize ALSA pcm device: %s\n", |
|
snd_strerror(ret)); |
|
return -1; |
|
} |
|
|
|
channels = *format & XMP_FORMAT_MONO ? 1 : 2; |
|
if (*format & XMP_FORMAT_UNSIGNED) { |
|
fmt = *format & XMP_FORMAT_8BIT ? |
|
SND_PCM_FORMAT_U8 : SND_PCM_FORMAT_U16; |
|
} else { |
|
fmt = *format & XMP_FORMAT_8BIT ? |
|
SND_PCM_FORMAT_S8 : SND_PCM_FORMAT_S16; |
|
} |
|
|
|
snd_pcm_hw_params_alloca(&hwparams); |
|
snd_pcm_hw_params_any(pcm_handle, hwparams); |
|
snd_pcm_hw_params_set_access(pcm_handle, hwparams, |
|
SND_PCM_ACCESS_RW_INTERLEAVED); |
|
snd_pcm_hw_params_set_format(pcm_handle, hwparams, fmt); |
|
snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, |
|
(unsigned int *)rate, 0); |
|
snd_pcm_hw_params_set_channels_near(pcm_handle, hwparams, &channels); |
|
snd_pcm_hw_params_set_buffer_time_near(pcm_handle, hwparams, &btime, 0); |
|
snd_pcm_hw_params_set_period_time_near(pcm_handle, hwparams, &ptime, 0); |
|
snd_pcm_nonblock(pcm_handle, 0); |
|
|
|
if ((ret = snd_pcm_hw_params(pcm_handle, hwparams)) < 0) { |
|
fprintf(stderr, "Unable to set ALSA output parameters: %s\n", |
|
snd_strerror(ret)); |
|
return -1; |
|
} |
|
|
|
if ((ret = snd_pcm_prepare(pcm_handle)) < 0) { |
|
fprintf(stderr, "Unable to prepare ALSA: %s\n", |
|
snd_strerror(ret)); |
|
return -1; |
|
} |
|
|
|
if (channels == 1) { |
|
*format |= XMP_FORMAT_MONO; |
|
} else { |
|
*format &= ~XMP_FORMAT_MONO; |
|
} |
|
|
|
return 0; |
|
} |
|
|
|
static void play(void *b, int i) |
|
{ |
|
int frames; |
|
|
|
frames = snd_pcm_bytes_to_frames(pcm_handle, i); |
|
if (snd_pcm_writei(pcm_handle, b, frames) < 0) { |
|
snd_pcm_prepare(pcm_handle); |
|
} |
|
} |
|
|
|
static void deinit() |
|
{ |
|
snd_pcm_close(pcm_handle); |
|
} |
|
|
|
static void flush() |
|
{ |
|
snd_pcm_drain(pcm_handle); |
|
} |
|
|
|
static void onpause() |
|
{ |
|
} |
|
|
|
static void onresume() |
|
{ |
|
} |
|
|
|
|
|
static char *help[] = { |
|
"buffer=num", "Set the ALSA buffer time in milliseconds", |
|
"period=num", "Set the ALSA period time in milliseconds", |
|
"card <name>", "Select sound card to use", |
|
NULL |
|
}; |
|
|
|
struct sound_driver sound_alsa = { |
|
"alsa", |
|
"ALSA PCM audio", |
|
help, |
|
init, |
|
deinit, |
|
play, |
|
flush, |
|
onpause, |
|
onresume |
|
};
|
|
|