mirror of
https://github.com/alsa-project/alsa-lib.git
synced 2025-10-29 05:40:25 -04:00
direct plugins (dmix) - suspend/resume fixes
- this patch adds support for suspend & result for dmix and other direct plugins - the timer detection / initialization (TREAD support) was redesigned and the check for proper driver version was moved to the timer_hw.c
This commit is contained in:
parent
7450dbcf36
commit
bac9a7de83
8 changed files with 70 additions and 36 deletions
|
|
@ -693,7 +693,7 @@ enum sndrv_timer_event {
|
|||
SNDRV_TIMER_EVENT_PAUSE, /* val = 0 */
|
||||
SNDRV_TIMER_EVENT_EARLY, /* val = 0, early event */
|
||||
SNDRV_TIMER_EVENT_SUSPEND, /* val = 0 */
|
||||
SNDRV_TIMER_EVENT_RESUME, /* val = 0 */
|
||||
SNDRV_TIMER_EVENT_RESUME, /* val = resolution in ns */
|
||||
/* master timer events for slave timer instances */
|
||||
SNDRV_TIMER_EVENT_MSTART = SNDRV_TIMER_EVENT_START + 10,
|
||||
SNDRV_TIMER_EVENT_MSTOP = SNDRV_TIMER_EVENT_STOP + 10,
|
||||
|
|
|
|||
|
|
@ -85,11 +85,15 @@ typedef enum _snd_timer_event {
|
|||
SND_TIMER_EVENT_CONTINUE, /* val = resolution in ns */
|
||||
SND_TIMER_EVENT_PAUSE, /* val = 0 */
|
||||
SND_TIMER_EVENT_EARLY, /* val = 0 */
|
||||
SND_TIMER_EVENT_SUSPEND, /* val = 0 */
|
||||
SND_TIMER_EVENT_RESUME, /* val = resolution in ns */
|
||||
/* master timer events for slave timer instances */
|
||||
SND_TIMER_EVENT_MSTART = SND_TIMER_EVENT_START + 10,
|
||||
SND_TIMER_EVENT_MSTOP = SND_TIMER_EVENT_STOP + 10,
|
||||
SND_TIMER_EVENT_MCONTINUE = SND_TIMER_EVENT_CONTINUE + 10,
|
||||
SND_TIMER_EVENT_MPAUSE = SND_TIMER_EVENT_PAUSE + 10,
|
||||
SND_TIMER_EVENT_MSUSPEND = SND_TIMER_EVENT_SUSPEND + 10,
|
||||
SND_TIMER_EVENT_MRESUME = SND_TIMER_EVENT_RESUME + 10
|
||||
} snd_timer_event_t;
|
||||
|
||||
/** timer read structure */
|
||||
|
|
|
|||
|
|
@ -431,6 +431,13 @@ int snd_pcm_direct_async(snd_pcm_t *pcm, int sig, pid_t pid)
|
|||
return snd_timer_async(dmix->timer, sig, pid);
|
||||
}
|
||||
|
||||
static inline void process_timer_event(snd_pcm_direct_t *dmix, snd_timer_tread_t *te)
|
||||
{
|
||||
#if 0
|
||||
printf("te->event = %i\n", te->event);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* empty the timer read queue */
|
||||
void snd_pcm_direct_clear_timer_queue(snd_pcm_direct_t *dmix)
|
||||
{
|
||||
|
|
@ -440,6 +447,7 @@ void snd_pcm_direct_clear_timer_queue(snd_pcm_direct_t *dmix)
|
|||
if (dmix->tread) {
|
||||
snd_timer_tread_t rbuf;
|
||||
snd_timer_read(dmix->timer, &rbuf, sizeof(rbuf));
|
||||
process_timer_event(dmix, &rbuf);
|
||||
} else {
|
||||
snd_timer_read_t rbuf;
|
||||
snd_timer_read(dmix->timer, &rbuf, sizeof(rbuf));
|
||||
|
|
@ -449,7 +457,7 @@ void snd_pcm_direct_clear_timer_queue(snd_pcm_direct_t *dmix)
|
|||
if (dmix->tread) {
|
||||
snd_timer_tread_t rbuf;
|
||||
while (snd_timer_read(dmix->timer, &rbuf, sizeof(rbuf)) > 0)
|
||||
;
|
||||
process_timer_event(dmix, &rbuf);
|
||||
} else {
|
||||
snd_timer_read_t rbuf;
|
||||
while (snd_timer_read(dmix->timer, &rbuf, sizeof(rbuf)) > 0)
|
||||
|
|
@ -666,6 +674,23 @@ int snd_pcm_direct_munmap(snd_pcm_t *pcm ATTRIBUTE_UNUSED)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int snd_pcm_direct_resume(snd_pcm_t *pcm)
|
||||
{
|
||||
snd_pcm_direct_t *dmix = pcm->private_data;
|
||||
int err;
|
||||
|
||||
snd_pcm_direct_semaphore_down(dmix, DIRECT_IPC_SEM_CLIENT);
|
||||
err = snd_pcm_resume(dmix->spcm);
|
||||
if (err == -ENOSYS) {
|
||||
/* FIXME: error handling? */
|
||||
snd_pcm_prepare(dmix->spcm);
|
||||
snd_pcm_start(dmix->spcm);
|
||||
err = 0;
|
||||
}
|
||||
snd_pcm_direct_semaphore_up(dmix, DIRECT_IPC_SEM_CLIENT);
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* this function initializes hardware and starts playback operation with
|
||||
* no stop threshold (it operates all time without xrun checking)
|
||||
|
|
@ -909,8 +934,8 @@ int snd_pcm_direct_initialize_poll_fd(snd_pcm_direct_t *dmix)
|
|||
snd_pcm_info_t *info;
|
||||
char name[128];
|
||||
int capture = dmix->type == SND_PCM_TYPE_DSNOOP ? 1 : 0;
|
||||
|
||||
dmix->tread = 0;
|
||||
|
||||
dmix->tread = 1;
|
||||
dmix->timer_need_poll = 0;
|
||||
snd_pcm_info_alloca(&info);
|
||||
ret = snd_pcm_info(dmix->spcm, info);
|
||||
|
|
@ -923,11 +948,14 @@ int snd_pcm_direct_initialize_poll_fd(snd_pcm_direct_t *dmix)
|
|||
snd_pcm_info_get_card(info),
|
||||
snd_pcm_info_get_device(info),
|
||||
snd_pcm_info_get_subdevice(info) * 2 + capture);
|
||||
ret = snd_timer_open(&dmix->timer, name, SND_TIMER_OPEN_NONBLOCK
|
||||
/*| SND_TIMER_OPEN_TREAD*/); /* XXX: TREAD is set later */
|
||||
ret = snd_timer_open(&dmix->timer, name, SND_TIMER_OPEN_NONBLOCK | SND_TIMER_OPEN_TREAD);
|
||||
if (ret < 0) {
|
||||
SNDERR("unable to open timer '%s'", name);
|
||||
return ret;
|
||||
dmix->tread = 1;
|
||||
ret = snd_timer_open(&dmix->timer, name, SND_TIMER_OPEN_NONBLOCK);
|
||||
if (ret < 0) {
|
||||
SNDERR("unable to open timer '%s'", name);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
if (snd_timer_poll_descriptors_count(dmix->timer) != 1) {
|
||||
|
|
@ -937,27 +965,30 @@ int snd_pcm_direct_initialize_poll_fd(snd_pcm_direct_t *dmix)
|
|||
snd_timer_poll_descriptors(dmix->timer, &dmix->timer_fd, 1);
|
||||
dmix->poll_fd = dmix->timer_fd.fd;
|
||||
|
||||
dmix->timer_event_suspend = 1<<SND_TIMER_EVENT_MSUSPEND;
|
||||
dmix->timer_event_resume = 1<<SND_TIMER_EVENT_MRESUME;
|
||||
|
||||
/*
|
||||
* A hack to avoid Oops in the older kernel
|
||||
*
|
||||
* Enable TREAD mode only when protocl is newer than 2.0.2.
|
||||
* Some hacks for older kernel drivers
|
||||
*/
|
||||
{
|
||||
int ver = 0;
|
||||
ioctl(dmix->poll_fd, SNDRV_TIMER_IOCTL_PVERSION, &ver);
|
||||
if (ver >= SNDRV_PROTOCOL_VERSION(2, 0, 3)) {
|
||||
dmix->tread = 1;
|
||||
if (ioctl(dmix->poll_fd, SNDRV_TIMER_IOCTL_TREAD, &dmix->tread) < 0)
|
||||
dmix->tread = 0;
|
||||
}
|
||||
/* In older versions, check via poll before read() is needed
|
||||
* because of the confliction between TIMER_START and
|
||||
* FIONBIO ioctls.
|
||||
*/
|
||||
if (ver < SNDRV_PROTOCOL_VERSION(2, 0, 4))
|
||||
dmix->timer_need_poll = 1;
|
||||
/*
|
||||
* In older versions, timer uses pause events instead
|
||||
* suspend/resume events.
|
||||
*/
|
||||
if (ver < SNDRV_PROTOCOL_VERSION(2, 0, 5)) {
|
||||
dmix->timer_event_suspend = 1<<SND_TIMER_EVENT_MPAUSE;
|
||||
dmix->timer_event_resume = 1<<SND_TIMER_EVENT_MCONTINUE;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -1012,6 +1043,7 @@ int snd_pcm_direct_open_secondary_client(snd_pcm_t **spcmp, snd_pcm_direct_t *dm
|
|||
int snd_pcm_direct_set_timer_params(snd_pcm_direct_t *dmix)
|
||||
{
|
||||
snd_timer_params_t *params;
|
||||
unsigned int filter;
|
||||
int ret;
|
||||
|
||||
snd_timer_params_alloca(¶ms);
|
||||
|
|
@ -1019,8 +1051,12 @@ int snd_pcm_direct_set_timer_params(snd_pcm_direct_t *dmix)
|
|||
if (dmix->type != SND_PCM_TYPE_DSNOOP)
|
||||
snd_timer_params_set_early_event(params, 1);
|
||||
snd_timer_params_set_ticks(params, 1);
|
||||
if (dmix->tread)
|
||||
snd_timer_params_set_filter(params, (1<<SND_TIMER_EVENT_TICK)|(1<<SND_TIMER_EVENT_MPAUSE));
|
||||
if (dmix->tread) {
|
||||
filter = (1<<SND_TIMER_EVENT_TICK) |
|
||||
dmix->timer_event_suspend |
|
||||
dmix->timer_event_resume;
|
||||
snd_timer_params_set_filter(params, filter);
|
||||
}
|
||||
ret = snd_timer_params(dmix->timer, params);
|
||||
if (ret < 0) {
|
||||
SNDERR("unable to set timer parameters");
|
||||
|
|
|
|||
|
|
@ -105,6 +105,8 @@ struct snd_pcm_direct {
|
|||
int poll_fd;
|
||||
int tread;
|
||||
int timer_need_poll;
|
||||
unsigned int timer_event_suspend;
|
||||
unsigned int timer_event_resume;
|
||||
int server_fd;
|
||||
pid_t server_pid;
|
||||
snd_timer_t *timer; /* timer used as poll_fd */
|
||||
|
|
@ -153,6 +155,7 @@ int snd_pcm_direct_sw_params(snd_pcm_t *pcm, snd_pcm_sw_params_t * params);
|
|||
int snd_pcm_direct_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t * info);
|
||||
int snd_pcm_direct_mmap(snd_pcm_t *pcm);
|
||||
int snd_pcm_direct_munmap(snd_pcm_t *pcm);
|
||||
int snd_pcm_direct_resume(snd_pcm_t *pcm);
|
||||
int snd_pcm_direct_timer_stop(snd_pcm_direct_t *dmix);
|
||||
void snd_pcm_direct_clear_timer_queue(snd_pcm_direct_t *dmix);
|
||||
int snd_pcm_direct_set_timer_params(snd_pcm_direct_t *dmix);
|
||||
|
|
|
|||
|
|
@ -580,13 +580,6 @@ static snd_pcm_sframes_t snd_pcm_dmix_forward(snd_pcm_t *pcm, snd_pcm_uframes_t
|
|||
return frames;
|
||||
}
|
||||
|
||||
static int snd_pcm_dmix_resume(snd_pcm_t *pcm)
|
||||
{
|
||||
snd_pcm_direct_t *dmix = pcm->private_data;
|
||||
snd_pcm_resume(dmix->spcm);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static snd_pcm_sframes_t snd_pcm_dmix_readi(snd_pcm_t *pcm ATTRIBUTE_UNUSED, void *buffer ATTRIBUTE_UNUSED, snd_pcm_uframes_t size ATTRIBUTE_UNUSED)
|
||||
{
|
||||
return -ENODEV;
|
||||
|
|
@ -715,7 +708,7 @@ static snd_pcm_fast_ops_t snd_pcm_dmix_fast_ops = {
|
|||
.pause = snd_pcm_dmix_pause,
|
||||
.rewind = snd_pcm_dmix_rewind,
|
||||
.forward = snd_pcm_dmix_forward,
|
||||
.resume = snd_pcm_dmix_resume,
|
||||
.resume = snd_pcm_direct_resume,
|
||||
.link_fd = NULL,
|
||||
.link = NULL,
|
||||
.unlink = NULL,
|
||||
|
|
|
|||
|
|
@ -434,13 +434,6 @@ static snd_pcm_sframes_t snd_pcm_dshare_forward(snd_pcm_t *pcm, snd_pcm_uframes_
|
|||
return frames;
|
||||
}
|
||||
|
||||
static int snd_pcm_dshare_resume(snd_pcm_t *pcm)
|
||||
{
|
||||
snd_pcm_direct_t *dshare = pcm->private_data;
|
||||
snd_pcm_resume(dshare->spcm);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static snd_pcm_sframes_t snd_pcm_dshare_readi(snd_pcm_t *pcm ATTRIBUTE_UNUSED, void *buffer ATTRIBUTE_UNUSED, snd_pcm_uframes_t size ATTRIBUTE_UNUSED)
|
||||
{
|
||||
return -ENODEV;
|
||||
|
|
@ -561,7 +554,7 @@ static snd_pcm_fast_ops_t snd_pcm_dshare_fast_ops = {
|
|||
.pause = snd_pcm_dshare_pause,
|
||||
.rewind = snd_pcm_dshare_rewind,
|
||||
.forward = snd_pcm_dshare_forward,
|
||||
.resume = snd_pcm_dshare_resume,
|
||||
.resume = snd_pcm_direct_resume,
|
||||
.link_fd = NULL,
|
||||
.link = NULL,
|
||||
.unlink = NULL,
|
||||
|
|
|
|||
|
|
@ -457,7 +457,7 @@ static snd_pcm_fast_ops_t snd_pcm_dsnoop_fast_ops = {
|
|||
.pause = snd_pcm_dsnoop_pause,
|
||||
.rewind = snd_pcm_dsnoop_rewind,
|
||||
.forward = snd_pcm_dsnoop_forward,
|
||||
.resume = snd_pcm_dsnoop_resume,
|
||||
.resume = snd_pcm_direct_resume,
|
||||
.link_fd = NULL,
|
||||
.link = NULL,
|
||||
.unlink = NULL,
|
||||
|
|
|
|||
|
|
@ -258,9 +258,14 @@ int snd_timer_hw_open(snd_timer_t **handle, const char *name, int dev_class, int
|
|||
}
|
||||
if (mode & SND_TIMER_OPEN_TREAD) {
|
||||
int arg = 1;
|
||||
if (ver < SNDRV_PROTOCOL_VERSION(2, 0, 3)) {
|
||||
ret = -ENOTTY;
|
||||
goto __no_tread;
|
||||
}
|
||||
if (ioctl(fd, SNDRV_TIMER_IOCTL_TREAD, &arg) < 0) {
|
||||
ret = -errno;
|
||||
close(fd);
|
||||
__no_tread:
|
||||
SNDERR("extended read is not supported (SNDRV_TIMER_IOCTL_TREAD)");
|
||||
return ret;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue