Use the SNDCTL_DSP_SETTRIGGER interface to start/stop the device, this

allows the "onmove" callback to be called whenever the DMA actually
starts (and not on the first write). This also removes the need for
sio_osee_setpar() call every time the device is stopped.
This commit is contained in:
Alexandre Ratchov 2016-11-04 14:09:42 +01:00
parent 9be2c65600
commit db20298468
1 changed files with 49 additions and 20 deletions

View File

@ -89,6 +89,8 @@ struct sio_oss_hdl {
unsigned int chan;
unsigned int appbufsz;
unsigned int round;
int filling;
};
static struct sio_hdl *sio_oss_fdopen(const char *, int, unsigned int, int);
@ -280,7 +282,7 @@ sio_oss_fdopen(const char *str, int fd, unsigned int mode, int nbio)
hdl->chan = 2;
hdl->round = 960;
hdl->appbufsz = 8 * 960;
hdl->filling = 0;
hdl->fd = fd;
return (struct sio_hdl *)hdl;
@ -320,17 +322,33 @@ static int
sio_oss_start(struct sio_hdl *sh)
{
struct sio_oss_hdl *hdl = (struct sio_oss_hdl *)sh;
int trig;
hdl->isamples = 0;
hdl->osamples = 0;
hdl->idelta = 0;
hdl->odelta = 0;
/* Nothing else to do here. OSS starts playing/recording
* on first write/read.
*/
_sio_onmove_cb(&hdl->sio, 0);
if (hdl->sio.mode & SIO_PLAY) {
/*
* keep the device paused and let sio_oss_pollfd() trigger the
* start later, to avoid buffer underruns
*/
hdl->filling = 1;
trig = 0;
} else {
/*
* no play buffers to fill, start now!
*/
trig = PCM_ENABLE_INPUT;
_sio_onmove_cb(&hdl->sio, 0);
}
DPRINTF("trig = 0x%x\n", trig);
if (ioctl(hdl->fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) {
DPERROR("sio_oss_start: SETTRIGGER");
hdl->sio.eof = 1;
return 0;
}
return 1;
}
@ -338,23 +356,19 @@ static int
sio_oss_stop(struct sio_hdl *sh)
{
struct sio_oss_hdl *hdl = (struct sio_oss_hdl*)sh;
int trig;
if (ioctl(hdl->fd, SNDCTL_DSP_SYNC, NULL) < 0) {
DPERROR("sio_oss_stop: SYNC");
if (hdl->filling) {
hdl->filling = 0;
return 1;
}
trig = 0;
if (ioctl(hdl->fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) {
DPERROR("sio_oss_stop: SETTRIGGER");
hdl->sio.eof = 1;
return 0;
}
if (ioctl(hdl->fd, SNDCTL_DSP_HALT, NULL) < 0) {
DPERROR("sio_oss_stop: HALT");
hdl->sio.eof = 1;
return 0;
}
/* Reset device parameters. When we do not do this, resuming
* playback/recording will trigger poll with revents=POLLIN
* too often, which leads to sndiod using 100 % CPU.
*/
return sio_oss_setpar(sh, &hdl->sio.par);
return 1;
}
static int
@ -575,10 +589,25 @@ static int
sio_oss_pollfd(struct sio_hdl *sh, struct pollfd *pfd, int events)
{
struct sio_oss_hdl *hdl = (struct sio_oss_hdl *)sh;
int trig;
pfd->fd = hdl->fd;
pfd->events = events;
if (hdl->filling && hdl->sio.wused == hdl->sio.par.bufsz *
hdl->sio.par.pchan * hdl->sio.par.bps) {
hdl->filling = 0;
trig = 0;
if (hdl->sio.mode & SIO_PLAY)
trig |= PCM_ENABLE_OUTPUT;
if (hdl->sio.mode & SIO_REC)
trig |= PCM_ENABLE_INPUT;
if (ioctl(hdl->fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) {
DPERROR("sio_oss_pollfd: SETTRIGGER");
hdl->sio.eof = 1;
return 0;
}
_sio_onmove_cb(&hdl->sio, 0);
}
return 1;
}