diff options
Diffstat (limited to 'modules/alsa/alsa_play.c')
-rw-r--r-- | modules/alsa/alsa_play.c | 40 |
1 files changed, 37 insertions, 3 deletions
diff --git a/modules/alsa/alsa_play.c b/modules/alsa/alsa_play.c index b21ce3d..327acf4 100644 --- a/modules/alsa/alsa_play.c +++ b/modules/alsa/alsa_play.c @@ -22,11 +22,13 @@ struct auplay_st { bool run; snd_pcm_t *write; int16_t *sampv; + void *xsampv; size_t sampc; auplay_write_h *wh; void *arg; struct auplay_prm prm; char *device; + enum aufmt aufmt; }; @@ -45,6 +47,7 @@ static void auplay_destructor(void *arg) snd_pcm_close(st->write); mem_deref(st->sampv); + mem_deref(st->xsampv); mem_deref(st->device); } @@ -59,14 +62,25 @@ static void *write_thread(void *arg) while (st->run) { const int samples = num_frames; + void *sampv; st->wh(st->sampv, st->sampc, st->arg); - n = snd_pcm_writei(st->write, st->sampv, samples); + if (st->aufmt == AUFMT_S16LE) { + sampv = st->sampv; + } + else { + sampv = st->xsampv; + auconv_from_s16(st->aufmt, st->xsampv, + st->sampv, st->sampc); + } + + n = snd_pcm_writei(st->write, sampv, samples); + if (-EPIPE == n) { snd_pcm_prepare(st->write); - n = snd_pcm_writei(st->write, st->sampv, samples); + n = snd_pcm_writei(st->write, st->xsampv, samples); if (n != samples) { warning("alsa: write error: %s\n", snd_strerror(n)); @@ -90,6 +104,7 @@ int alsa_play_alloc(struct auplay_st **stp, const struct auplay *ap, auplay_write_h *wh, void *arg) { struct auplay_st *st; + snd_pcm_format_t pcmfmt; int num_frames; int err; @@ -111,6 +126,7 @@ int alsa_play_alloc(struct auplay_st **stp, const struct auplay *ap, st->ap = ap; st->wh = wh; st->arg = arg; + st->aufmt = alsa_sample_format; st->sampc = prm->srate * prm->ch * prm->ptime / 1000; num_frames = st->prm.srate * st->prm.ptime / 1000; @@ -121,6 +137,15 @@ int alsa_play_alloc(struct auplay_st **stp, const struct auplay *ap, goto out; } + if (st->aufmt != AUFMT_S16LE) { + size_t sz = aufmt_sample_size(st->aufmt) * st->sampc; + st->xsampv = mem_alloc(sz, NULL); + if (!st->xsampv) { + err = ENOMEM; + goto out; + } + } + err = snd_pcm_open(&st->write, st->device, SND_PCM_STREAM_PLAYBACK, 0); if (err < 0) { warning("alsa: could not open auplay device '%s' (%s)\n", @@ -128,7 +153,16 @@ int alsa_play_alloc(struct auplay_st **stp, const struct auplay *ap, goto out; } - err = alsa_reset(st->write, st->prm.srate, st->prm.ch, num_frames); + pcmfmt = aufmt_to_alsaformat(st->aufmt); + if (pcmfmt == SND_PCM_FORMAT_UNKNOWN) { + warning("alsa: unknown sample format '%s'\n", + aufmt_name(st->aufmt)); + err = EINVAL; + goto out; + } + + err = alsa_reset(st->write, st->prm.srate, st->prm.ch, num_frames, + pcmfmt); if (err) { warning("alsa: could not reset player '%s' (%s)\n", st->device, snd_strerror(err)); |