1
0
mirror of https://github.com/ericonr/sndio.git synced 2024-02-18 04:45:21 -06:00

handle partial samples in alsa

This commit is contained in:
Alexandre Ratchov 2013-12-10 08:43:45 +01:00
parent 19a9096069
commit e8221ec396

View File

@ -53,6 +53,8 @@ struct sio_alsa_hdl {
int nfds, infds, onfds; int nfds, infds, onfds;
int running; int running;
int events; int events;
int ipartial, opartial;
char *itmpbuf, *otmpbuf;
}; };
static void sio_alsa_onmove(struct sio_alsa_hdl *); static void sio_alsa_onmove(struct sio_alsa_hdl *);
@ -385,6 +387,12 @@ sio_alsa_start(struct sio_hdl *sh)
hdl->sio.eof = 1; hdl->sio.eof = 1;
return 0; return 0;
} }
hdl->otmpbuf = malloc(hdl->obpf);
if (hdl->otmpbuf == NULL) {
hdl->sio.eof = 1;
return 0;
}
hdl->opartial = 0;
} }
if (hdl->sio.mode & SIO_REC) { if (hdl->sio.mode & SIO_REC) {
err = snd_pcm_prepare(hdl->ipcm); err = snd_pcm_prepare(hdl->ipcm);
@ -393,6 +401,12 @@ sio_alsa_start(struct sio_hdl *sh)
hdl->sio.eof = 1; hdl->sio.eof = 1;
return 0; return 0;
} }
hdl->itmpbuf = malloc(hdl->ibpf);
if (hdl->itmpbuf == NULL) {
hdl->sio.eof = 1;
return 0;
}
hdl->ipartial = 0;
} }
if ((hdl->sio.mode & SIO_PLAY) && (hdl->sio.mode & SIO_REC)) { if ((hdl->sio.mode & SIO_PLAY) && (hdl->sio.mode & SIO_REC)) {
err = snd_pcm_link(hdl->ipcm, hdl->opcm); err = snd_pcm_link(hdl->ipcm, hdl->opcm);
@ -426,6 +440,7 @@ sio_alsa_stop(struct sio_hdl *sh)
hdl->sio.eof = 1; hdl->sio.eof = 1;
return 0; return 0;
} }
free(hdl->otmpbuf);
} }
if (hdl->sio.mode & SIO_REC) { if (hdl->sio.mode & SIO_REC) {
err = snd_pcm_drop(hdl->ipcm); err = snd_pcm_drop(hdl->ipcm);
@ -434,6 +449,7 @@ sio_alsa_stop(struct sio_hdl *sh)
hdl->sio.eof = 1; hdl->sio.eof = 1;
return 0; return 0;
} }
free(hdl->itmpbuf);
} }
if ((hdl->sio.mode & SIO_PLAY) && (hdl->sio.mode & SIO_REC)) { if ((hdl->sio.mode & SIO_PLAY) && (hdl->sio.mode & SIO_REC)) {
err = snd_pcm_unlink(hdl->ipcm); err = snd_pcm_unlink(hdl->ipcm);
@ -644,7 +660,6 @@ static int
sio_alsa_getcap(struct sio_hdl *sh, struct sio_cap *cap) sio_alsa_getcap(struct sio_hdl *sh, struct sio_cap *cap)
{ {
struct sio_alsa_hdl *hdl = (struct sio_alsa_hdl *)sh; struct sio_alsa_hdl *hdl = (struct sio_alsa_hdl *)sh;
snd_pcm_hw_params_t *ihwp, *ohwp;
int irates, orates, ifmts, ofmts, ichans, ochans; int irates, orates, ifmts, ofmts, ichans, ochans;
int i; int i;
@ -901,10 +916,22 @@ sio_alsa_read(struct sio_hdl *sh, void *buf, size_t len)
{ {
struct sio_alsa_hdl *hdl = (struct sio_alsa_hdl *)sh; struct sio_alsa_hdl *hdl = (struct sio_alsa_hdl *)sh;
snd_pcm_sframes_t n; snd_pcm_sframes_t n;
snd_pcm_uframes_t todo; size_t todo;
todo = len / hdl->ibpf; if (hdl->ipartial > 0) {
while ((n = snd_pcm_readi(hdl->ipcm, buf, todo)) < 0) { todo = hdl->ipartial;
if (todo > len)
todo = len;
memcpy(buf, hdl->itmpbuf + hdl->ibpf - hdl->ipartial, todo);
hdl->ipartial -= todo;
return todo;
} else {
if (len < hdl->ibpf) {
buf = hdl->itmpbuf;
len = hdl->ibpf;
}
}
while ((n = snd_pcm_readi(hdl->ipcm, buf, len / hdl->ibpf)) < 0) {
if (n == -EINTR) if (n == -EINTR)
continue; continue;
if (n == -EPIPE || n == -ESTRPIPE) { if (n == -EPIPE || n == -ESTRPIPE) {
@ -923,29 +950,33 @@ sio_alsa_read(struct sio_hdl *sh, void *buf, size_t len)
return 0; return 0;
} }
hdl->idelta += n; hdl->idelta += n;
n *= hdl->ibpf; if (buf == hdl->itmpbuf) {
return n; hdl->ipartial = hdl->ibpf;
return 0;
}
return n *= hdl->ibpf;
} }
static size_t static size_t
sio_alsa_write(struct sio_hdl *sh, const void *buf, size_t len) sio_alsa_write(struct sio_hdl *sh, const void *buf, size_t len)
{ {
struct sio_alsa_hdl *hdl = (struct sio_alsa_hdl *)sh; struct sio_alsa_hdl *hdl = (struct sio_alsa_hdl *)sh;
ssize_t n, todo; snd_pcm_sframes_t n;
size_t todo;
if (len < hdl->obpf) { if (len < hdl->obpf || hdl->opartial > 0) {
/* todo = hdl->obpf - hdl->opartial;
* we can't just return, because sio_write() will loop if (todo > 0) {
* forever. Fix this by saving partial samples in a if (todo > len)
* temporary buffer. todo = len;
*/ memcpy(hdl->otmpbuf + hdl->opartial, buf, todo);
DPRINTF("sio_alsa_write: wrong chunk size\n"); hdl->opartial += todo;
hdl->sio.eof = 1; return todo;
return 0; }
len = hdl->obpf;
buf = hdl->otmpbuf;
} }
todo = len / hdl->obpf; while ((n = snd_pcm_writei(hdl->opcm, buf, len / hdl->obpf)) < 0) {
DPRINTFN(2, "sio_alsa_write: len = %zd, todo = %zd\n", len, todo);
while ((n = snd_pcm_writei(hdl->opcm, buf, todo)) < 0) {
if (n == -EINTR) if (n == -EINTR)
continue; continue;
if (n == -ESTRPIPE || n == -EPIPE) { if (n == -ESTRPIPE || n == -EPIPE) {
@ -958,10 +989,13 @@ sio_alsa_write(struct sio_hdl *sh, const void *buf, size_t len)
} }
return 0; return 0;
} }
DPRINTFN(2, "sio_alsa_write: wrote %zd\n", n);
hdl->odelta += n; hdl->odelta += n;
n *= hdl->obpf; if (buf == hdl->otmpbuf) {
return n; if (n > 0)
hdl->opartial = 0;
return 0;
}
return n * hdl->obpf;
} }
void void