From af89cefd99133aabaaa20a436eab25f7dd8501fd Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Tue, 11 Feb 2003 18:14:43 +0000 Subject: [PATCH] More changes for dmix plugin: - added poll_events to main pcm structure - added poll_revents callback to pcm->ops structure - fixed snd_pcm_wait() - call revents function and enhanced error code reporting DMIX plugin: - more complete code (works at least for one instance) - still no "mix" code (it's silent) --- src/pcm/pcm.c | 14 ++- src/pcm/pcm_adpcm.c | 2 + src/pcm/pcm_alaw.c | 2 + src/pcm/pcm_copy.c | 1 + src/pcm/pcm_dmix.c | 282 +++++++++++++++++++++++++++++++++++-------- src/pcm/pcm_file.c | 1 + src/pcm/pcm_hooks.c | 1 + src/pcm/pcm_hw.c | 1 + src/pcm/pcm_ladspa.c | 2 + src/pcm/pcm_lfloat.c | 2 + src/pcm/pcm_linear.c | 2 + src/pcm/pcm_local.h | 2 + src/pcm/pcm_meter.c | 1 + src/pcm/pcm_mulaw.c | 2 + src/pcm/pcm_multi.c | 1 + src/pcm/pcm_null.c | 1 + src/pcm/pcm_params.c | 15 +++ src/pcm/pcm_plug.c | 8 ++ src/pcm/pcm_plugin.c | 6 + src/pcm/pcm_plugin.h | 1 + src/pcm/pcm_rate.c | 32 ++++- src/pcm/pcm_route.c | 2 + src/pcm/pcm_share.c | 1 + src/pcm/pcm_shm.c | 1 + 24 files changed, 330 insertions(+), 53 deletions(-) diff --git a/src/pcm/pcm.c b/src/pcm/pcm.c index 7894994a..525fd2f6 100644 --- a/src/pcm/pcm.c +++ b/src/pcm/pcm.c @@ -812,6 +812,7 @@ int snd_pcm_hw_free(snd_pcm_t *pcm) int snd_pcm_sw_params(snd_pcm_t *pcm, snd_pcm_sw_params_t *params) { int err; + assert(pcm->setup); /* the hw_params must be set at first!!! */ err = pcm->ops->sw_params(pcm->op_arg, params); if (err < 0) return err; @@ -1169,9 +1170,10 @@ int snd_pcm_poll_descriptors(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int s assert(pcm && pfds); if (space >= 1 && pfds) { pfds->fd = pcm->poll_fd; - pfds->events = pcm->stream == SND_PCM_STREAM_PLAYBACK ? (POLLOUT|POLLERR|POLLNVAL) : (POLLIN|POLLERR|POLLNVAL); - } else + pfds->events = pcm->poll_events | POLLERR | POLLNVAL; + } else { return 0; + } return 1; } @@ -1186,6 +1188,8 @@ int snd_pcm_poll_descriptors(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int s int snd_pcm_poll_descriptors_revents(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int nfds, unsigned short *revents) { assert(pcm && pfds && revents); + if (pcm->ops->poll_revents) + return pcm->ops->poll_revents(pcm, pfds, nfds, revents); if (nfds == 1) { *revents = pfds->revents; return 0; @@ -1903,12 +1907,18 @@ int snd_pcm_open_slave(snd_pcm_t **pcmp, snd_config_t *root, int snd_pcm_wait(snd_pcm_t *pcm, int timeout) { struct pollfd pfd; + unsigned short revents; int err; err = snd_pcm_poll_descriptors(pcm, &pfd, 1); assert(err == 1); err = poll(&pfd, 1, timeout); if (err < 0) return -errno; + err = snd_pcm_poll_descriptors_revents(pcm, &pfd, 1, &revents); + if (err < 0) + return err; + if (revents & (POLLERR | POLLNVAL)) + return -EIO; return err > 0 ? 1 : 0; } diff --git a/src/pcm/pcm_adpcm.c b/src/pcm/pcm_adpcm.c index 85fbfe5d..5b112cef 100644 --- a/src/pcm/pcm_adpcm.c +++ b/src/pcm/pcm_adpcm.c @@ -527,6 +527,7 @@ static snd_pcm_ops_t snd_pcm_adpcm_ops = { dump: snd_pcm_adpcm_dump, nonblock: snd_pcm_plugin_nonblock, async: snd_pcm_plugin_async, + poll_revents: snd_pcm_plugin_poll_revents, mmap: snd_pcm_plugin_mmap, munmap: snd_pcm_plugin_munmap, }; @@ -573,6 +574,7 @@ int snd_pcm_adpcm_open(snd_pcm_t **pcmp, const char *name, snd_pcm_format_t sfor pcm->fast_ops = &snd_pcm_plugin_fast_ops; pcm->private_data = adpcm; pcm->poll_fd = slave->poll_fd; + pcm->poll_events = slave->poll_events; snd_pcm_set_hw_ptr(pcm, &adpcm->plug.hw_ptr, -1, 0); snd_pcm_set_appl_ptr(pcm, &adpcm->plug.appl_ptr, -1, 0); *pcmp = pcm; diff --git a/src/pcm/pcm_alaw.c b/src/pcm/pcm_alaw.c index 4ade3424..1bb3f5d9 100644 --- a/src/pcm/pcm_alaw.c +++ b/src/pcm/pcm_alaw.c @@ -400,6 +400,7 @@ static snd_pcm_ops_t snd_pcm_alaw_ops = { dump: snd_pcm_alaw_dump, nonblock: snd_pcm_plugin_nonblock, async: snd_pcm_plugin_async, + poll_revents: snd_pcm_plugin_poll_revents, mmap: snd_pcm_plugin_mmap, munmap: snd_pcm_plugin_munmap, }; @@ -447,6 +448,7 @@ int snd_pcm_alaw_open(snd_pcm_t **pcmp, const char *name, snd_pcm_format_t sform pcm->fast_ops = &snd_pcm_plugin_fast_ops; pcm->private_data = alaw; pcm->poll_fd = slave->poll_fd; + pcm->poll_events = slave->poll_events; snd_pcm_set_hw_ptr(pcm, &alaw->plug.hw_ptr, -1, 0); snd_pcm_set_appl_ptr(pcm, &alaw->plug.appl_ptr, -1, 0); *pcmp = pcm; diff --git a/src/pcm/pcm_copy.c b/src/pcm/pcm_copy.c index e27cd937..2bca627b 100644 --- a/src/pcm/pcm_copy.c +++ b/src/pcm/pcm_copy.c @@ -163,6 +163,7 @@ static snd_pcm_ops_t snd_pcm_copy_ops = { dump: snd_pcm_copy_dump, nonblock: snd_pcm_plugin_nonblock, async: snd_pcm_plugin_async, + poll_revents: snd_pcm_plugin_poll_revents, mmap: snd_pcm_plugin_mmap, munmap: snd_pcm_plugin_munmap, }; diff --git a/src/pcm/pcm_dmix.c b/src/pcm/pcm_dmix.c index 0b47dc2d..40200ad0 100644 --- a/src/pcm/pcm_dmix.c +++ b/src/pcm/pcm_dmix.c @@ -48,6 +48,18 @@ const char *_snd_module_pcm_dmix = ""; #endif +/* + * + */ + + +/* + * FIXME: + * add possibility to use futexes here + */ +#define DMIX_IPC_SEMS 1 +#define DMIX_IPC_SEM_CLIENT 0 + /* * */ @@ -80,12 +92,16 @@ typedef struct { typedef struct { key_t ipc_key; /* IPC key for semaphore and memory */ int semid; /* IPC global semaphore identification */ - int semlock; /* locked with our process? */ int shmid; /* IPC global shared memory identification */ snd_pcm_dmix_share_t *shmptr; /* pointer to shared memory area */ snd_pcm_t *spcm; /* slave PCM handle */ snd_pcm_uframes_t appl_ptr; snd_pcm_uframes_t hw_ptr; + snd_pcm_uframes_t avail_max; + snd_pcm_uframes_t slave_appl_ptr; + snd_pcm_uframes_t slave_hw_ptr; + snd_pcm_state_t state; + snd_timestamp_t trigger_tstamp; int server, client; int comm_fd; /* communication file descriptor (socket) */ int hw_fd; /* hardware file descriptor */ @@ -109,7 +125,7 @@ struct sembuf { static int semaphore_create_or_connect(snd_pcm_dmix_t *dmix) { - dmix->semid = semget(dmix->ipc_key, 1, IPC_CREAT | 0666); + dmix->semid = semget(dmix->ipc_key, DMIX_IPC_SEMS, IPC_CREAT | 0666); if (dmix->semid < 0) return -errno; return 0; @@ -121,28 +137,28 @@ static int semaphore_discard(snd_pcm_dmix_t *dmix) return -EINVAL; if (semctl(dmix->semid, 0, IPC_RMID, NULL) < 0) return -errno; - dmix->semlock = 0; dmix->semid = -1; return 0; } -static int semaphore_down(snd_pcm_dmix_t *dmix) +static int semaphore_down(snd_pcm_dmix_t *dmix, int sem_num) { - static struct sembuf op[2] = { { 0, 0, SEM_UNDO }, { 0, 1, SEM_UNDO | IPC_NOWAIT } }; + struct sembuf op[2] = { { 0, 0, SEM_UNDO }, { 0, 1, SEM_UNDO | IPC_NOWAIT } }; assert(dmix->semid >= 0); - if (semop(dmix->semid, op, 1) < 0) + op[0].sem_num = sem_num; + op[1].sem_num = sem_num; + if (semop(dmix->semid, op, 2) < 0) return -errno; - dmix->semlock = 1; return 0; } -static int semaphore_up(snd_pcm_dmix_t *dmix) +static int semaphore_up(snd_pcm_dmix_t *dmix, int sem_num) { - static struct sembuf op = { 0, -1, SEM_UNDO | IPC_NOWAIT }; + struct sembuf op = { 0, -1, SEM_UNDO | IPC_NOWAIT }; assert(dmix->semid >= 0); + op.sem_num = sem_num; if (semop(dmix->semid, &op, 1) < 0) return -errno; - dmix->semlock = 0; return 0; } @@ -279,6 +295,12 @@ static int send_fd(int sock, void *data, size_t len, int fd) return ret; } +#if 0 +#define server_printf(fmt, args...) printf(fmt, ##args) +#else +#define server_printf(fmt, args...) /* nothing */ +#endif + static void server_job(snd_pcm_dmix_t *dmix) { int ret, sck, i; @@ -287,7 +309,7 @@ static void server_job(snd_pcm_dmix_t *dmix) /* close all files to free resources */ i = sysconf(_SC_OPEN_MAX); - while (--i >= 0) { + while (--i >= 3) { if (i != dmix->server_fd && i != dmix->hw_fd) close(i); } @@ -298,22 +320,27 @@ static void server_job(snd_pcm_dmix_t *dmix) pfds[0].fd = dmix->server_fd; pfds[0].events = POLLIN | POLLERR | POLLHUP; + server_printf("DMIX SERVER STARTED\n"); while (1) { ret = poll(pfds, current + 1, 500); + server_printf("DMIX SERVER: poll ret = %i, revents[0] = 0x%x\n", ret, pfds[0].revents); if (ret < 0) /* some error */ break; - if (ret == 0) { /* timeout */ + if (ret == 0 || pfds[0].revents & (POLLERR | POLLHUP)) { /* timeout or error? */ struct shmid_ds buf; + semaphore_down(dmix, DMIX_IPC_SEM_CLIENT); if (shmctl(dmix->shmid, IPC_STAT, &buf) < 0) { shm_discard(dmix); continue; } - if (buf.shm_nattch == 0) /* server is the last user, exit */ + server_printf("DMIX SERVER: nattch = %i\n", (int)buf.shm_nattch); + if (buf.shm_nattch == 1) /* server is the last user, exit */ break; + semaphore_up(dmix, DMIX_IPC_SEM_CLIENT); + continue; } - if (pfds[0].revents & (POLLERR | POLLHUP)) - break; if (pfds[0].revents & POLLIN) { + ret--; sck = accept(dmix->server_fd, 0, 0); if (sck >= 0) { if (current == max) { @@ -327,20 +354,22 @@ static void server_job(snd_pcm_dmix_t *dmix) } } } - for (i = 0; i < max; i++) { + for (i = 0; i < max && ret > 0; i++) { struct pollfd *pfd = &pfds[i+1]; unsigned char cmd; if (pfd->revents & (POLLERR | POLLHUP)) { + ret--; close(pfd->fd); pfd->fd = -1; continue; } if (!(pfd->revents & POLLIN)) continue; + ret--; if (read(pfd->fd, &cmd, 1) == 1) cmd = 0 /*process command */; } - for (i = 0; i < max; i++) { + for (i = 0; i < max && ret > 0; i++) { if (pfds[i+1].fd < 0) { if (i + 1 != max) memcpy(&pfds[i+1], &pfds[i+2], sizeof(struct pollfd) * (max - i - 1)); @@ -349,8 +378,10 @@ static void server_job(snd_pcm_dmix_t *dmix) } } close(dmix->server_fd); - close(dmix->poll_fd); + close(dmix->hw_fd); shm_discard(dmix); + semaphore_discard(dmix); + server_printf("DMIX SERVER EXIT\n"); exit(EXIT_SUCCESS); } @@ -390,8 +421,8 @@ static int server_create(snd_pcm_dmix_t *dmix) static int server_discard(snd_pcm_dmix_t *dmix) { if (dmix->server) { - kill(dmix->server_pid, SIGTERM); - waitpid(dmix->server_pid, NULL, 0); + //kill(dmix->server_pid, SIGTERM); + //waitpid(dmix->server_pid, NULL, 0); dmix->server_pid = (pid_t)-1; } if (dmix->server_fd > 0) { @@ -445,7 +476,7 @@ static int client_discard(snd_pcm_dmix_t *dmix) /* * synchronize shm ring buffer with hardware */ -static void snd_pcm_dmix_sync_ptr(snd_pcm_t *pcm, snd_pcm_uframes_t size) +static void snd_pcm_dmix_sync_area(snd_pcm_t *pcm, snd_pcm_uframes_t size) { snd_pcm_dmix_t *dmix = pcm->private_data; snd_pcm_uframes_t appl_ptr; @@ -454,13 +485,47 @@ static void snd_pcm_dmix_sync_ptr(snd_pcm_t *pcm, snd_pcm_uframes_t size) appl_ptr = dmix->appl_ptr - size; if (appl_ptr > pcm->boundary) appl_ptr += pcm->boundary; + /* add sample areas here */ +} + +/* + * synchronize hardware pointer (hw_ptr) with ours + */ +static int snd_pcm_dmix_sync_ptr(snd_pcm_t *pcm) +{ + snd_pcm_dmix_t *dmix = pcm->private_data; + snd_pcm_uframes_t slave_hw_ptr, old_slave_hw_ptr, avail; + snd_pcm_sframes_t diff; + + old_slave_hw_ptr = dmix->slave_hw_ptr; + slave_hw_ptr = dmix->slave_hw_ptr = *dmix->spcm->hw.ptr; + diff = slave_hw_ptr - old_slave_hw_ptr; + if (diff == 0) /* fast path */ + return 0; + if (diff < 0) { + slave_hw_ptr += dmix->spcm->boundary; + diff = slave_hw_ptr - old_slave_hw_ptr; + } + dmix->hw_ptr += diff; + dmix->hw_ptr %= pcm->boundary; + // printf("sync ptr diff = %li\n", diff); + if (pcm->stop_threshold >= pcm->boundary) /* don't care */ + return 0; + if ((avail = snd_pcm_mmap_playback_avail(pcm)) >= pcm->stop_threshold) { + dmix->state = SND_PCM_STATE_XRUN; + dmix->avail_max = avail; + return -EPIPE; + } + if (avail > dmix->avail_max) + dmix->avail_max = avail; + return 0; } /* * plugin implementation */ -static int snd_pcm_dmix_nonblock(snd_pcm_t *pcm, int nonblock ATTRIBUTE_UNUSED) +static int snd_pcm_dmix_nonblock(snd_pcm_t *pcm ATTRIBUTE_UNUSED, int nonblock ATTRIBUTE_UNUSED) { /* value is cached for us in pcm->mode (SND_PCM_NONBLOCK flag) */ return 0; @@ -472,9 +537,28 @@ static int snd_pcm_dmix_async(snd_pcm_t *pcm, int sig, pid_t pid) return snd_timer_async(dmix->timer, sig, pid); } -static int snd_pcm_dmix_info(snd_pcm_t *pcm, snd_pcm_info_t * info) +static int snd_pcm_dmix_poll_revents(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int nfds, unsigned short *revents) { snd_pcm_dmix_t *dmix = pcm->private_data; + unsigned short events; + static snd_timer_read_t rbuf[5]; /* can be overwriten by multiple plugins, we don't need the value */ + + assert(pfds && nfds == 1 && revents); + events = pfds[0].revents; + if (events & POLLIN) { + events |= POLLOUT; + events &= ~POLLIN; + /* empty the timer read queue */ + while (snd_timer_read(dmix->timer, &rbuf, sizeof(rbuf)) == sizeof(rbuf)) ; + } + *revents = events; + return 0; +} + +static int snd_pcm_dmix_info(snd_pcm_t *pcm, snd_pcm_info_t * info) +{ + // snd_pcm_dmix_t *dmix = pcm->private_data; + memset(info, 0, sizeof(*info)); info->stream = pcm->stream; info->card = -1; @@ -584,21 +668,22 @@ static int snd_pcm_dmix_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) return 0; } -static int snd_pcm_dmix_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params) +static int snd_pcm_dmix_hw_params(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_hw_params_t * params ATTRIBUTE_UNUSED) { - // snd_pcm_dmix_t *dmix = pcm->private_data; + /* values are cached in the pcm structure */ + return 0; } -static int snd_pcm_dmix_hw_free(snd_pcm_t *pcm) +static int snd_pcm_dmix_hw_free(snd_pcm_t *pcm ATTRIBUTE_UNUSED) { - // snd_pcm_dmix_t *dmix = pcm->private_data; + /* values are cached in the pcm structure */ return 0; } -static int snd_pcm_dmix_sw_params(snd_pcm_t *pcm, snd_pcm_sw_params_t * params) +static int snd_pcm_dmix_sw_params(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_sw_params_t * params ATTRIBUTE_UNUSED) { - // snd_pcm_dmix_t *dmix = pcm->private_data; + /* values are cached in the pcm structure */ return 0; } @@ -610,72 +695,143 @@ static int snd_pcm_dmix_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t * in static int snd_pcm_dmix_status(snd_pcm_t *pcm, snd_pcm_status_t * status) { snd_pcm_dmix_t *dmix = pcm->private_data; + + memset(status, 0, sizeof(*status)); + status->state = dmix->state; + status->trigger_tstamp = dmix->trigger_tstamp; + gettimeofday(&status->tstamp, 0); + status->avail = snd_pcm_mmap_playback_avail(pcm); + status->avail_max = status->avail > dmix->avail_max ? status->avail : dmix->avail_max; + dmix->avail_max = 0; return 0; } static snd_pcm_state_t snd_pcm_dmix_state(snd_pcm_t *pcm) { snd_pcm_dmix_t *dmix = pcm->private_data; - return 0; + return dmix->state; } static int snd_pcm_dmix_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp) { snd_pcm_dmix_t *dmix = pcm->private_data; - return 0; + int err; + + assert(pcm && delayp); + switch(dmix->state) { + case SNDRV_PCM_STATE_DRAINING: + case SNDRV_PCM_STATE_RUNNING: + err = snd_pcm_dmix_sync_ptr(pcm); + if (err < 0) + return err; + case SNDRV_PCM_STATE_PREPARED: + case SNDRV_PCM_STATE_SUSPENDED: + *delayp = snd_pcm_mmap_playback_hw_avail(pcm); + return 0; + case SNDRV_PCM_STATE_XRUN: + return -EPIPE; + default: + return -EBADFD; + } } static int snd_pcm_dmix_hwsync(snd_pcm_t *pcm) { snd_pcm_dmix_t *dmix = pcm->private_data; - return 0; + + switch(dmix->state) { + case SNDRV_PCM_STATE_DRAINING: + case SNDRV_PCM_STATE_RUNNING: + return snd_pcm_dmix_sync_ptr(pcm); + case SNDRV_PCM_STATE_PREPARED: + case SNDRV_PCM_STATE_SUSPENDED: + return 0; + case SNDRV_PCM_STATE_XRUN: + return -EPIPE; + default: + return -EBADFD; + } } static int snd_pcm_dmix_prepare(snd_pcm_t *pcm) { snd_pcm_dmix_t *dmix = pcm->private_data; + + assert(pcm->boundary == dmix->spcm->boundary); /* for sure */ + dmix->state = SND_PCM_STATE_PREPARED; + dmix->appl_ptr = 0; + dmix->hw_ptr = 0; return 0; } static int snd_pcm_dmix_reset(snd_pcm_t *pcm) { snd_pcm_dmix_t *dmix = pcm->private_data; + dmix->hw_ptr %= pcm->period_size; + dmix->appl_ptr = dmix->hw_ptr; return 0; } static int snd_pcm_dmix_start(snd_pcm_t *pcm) { snd_pcm_dmix_t *dmix = pcm->private_data; + int err; + + if (dmix->state != SND_PCM_STATE_PREPARED) + return -EBADFD; + err = snd_timer_start(dmix->timer); + if (err < 0) + return err; + dmix->state = SND_PCM_STATE_RUNNING; + dmix->slave_hw_ptr = *dmix->spcm->hw.ptr; + snd_pcm_dmix_sync_area(pcm, dmix->appl_ptr < pcm->buffer_size ? dmix->appl_ptr : pcm->buffer_size); return 0; } static int snd_pcm_dmix_drop(snd_pcm_t *pcm) { snd_pcm_dmix_t *dmix = pcm->private_data; + if (dmix->state == SND_PCM_STATE_OPEN) + return -EBADFD; + dmix->state = SND_PCM_STATE_SETUP; return 0; } static int snd_pcm_dmix_drain(snd_pcm_t *pcm) { snd_pcm_dmix_t *dmix = pcm->private_data; + if (dmix->state == SND_PCM_STATE_OPEN) + return -EBADFD; + dmix->state = SND_PCM_STATE_SETUP; return 0; } static int snd_pcm_dmix_pause(snd_pcm_t *pcm, int enable) { snd_pcm_dmix_t *dmix = pcm->private_data; + if (enable) { + if (dmix->state != SND_PCM_STATE_RUNNING) + return -EBADFD; + dmix->state = SND_PCM_STATE_PAUSED; + } else { + if (dmix->state != SND_PCM_STATE_PAUSED) + return -EBADFD; + dmix->state = SND_PCM_STATE_RUNNING; + } return 0; } static snd_pcm_sframes_t snd_pcm_dmix_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t frames) { - snd_pcm_dmix_t *dmix = pcm->private_data; + /* FIXME: substract samples from the mix ring buffer, too? */ + snd_pcm_mmap_appl_backward(pcm, frames); return frames; } -static int snd_pcm_dmix_resume(snd_pcm_t *pcm) +static int snd_pcm_dmix_resume(snd_pcm_t *pcm ATTRIBUTE_UNUSED) { - snd_pcm_dmix_t *dmix = pcm->private_data; + // snd_pcm_dmix_t *dmix = pcm->private_data; + // FIXME return 0; } @@ -705,7 +861,7 @@ static int snd_pcm_dmix_close(snd_pcm_t *pcm) if (dmix->timer) snd_timer_close(dmix->timer); - semaphore_down(dmix); + semaphore_down(dmix, DMIX_IPC_SEM_CLIENT); snd_pcm_close(dmix->spcm); if (dmix->server) server_discard(dmix); @@ -713,9 +869,10 @@ static int snd_pcm_dmix_close(snd_pcm_t *pcm) client_discard(dmix); if (shm_discard(dmix) > 0) { if (semaphore_discard(dmix) < 0) - semaphore_up(dmix); - } - semaphore_up(dmix); + semaphore_up(dmix, DMIX_IPC_SEM_CLIENT); + } else { + semaphore_up(dmix, DMIX_IPC_SEM_CLIENT); + } pcm->private_data = NULL; free(dmix); return 0; @@ -725,25 +882,38 @@ static snd_pcm_sframes_t snd_pcm_dmix_mmap_commit(snd_pcm_t *pcm, snd_pcm_uframes_t offset ATTRIBUTE_UNUSED, snd_pcm_uframes_t size) { + int err; + snd_pcm_mmap_appl_forward(pcm, size); - snd_pcm_dmix_sync_ptr(pcm, size); + err = snd_pcm_dmix_sync_ptr(pcm); + if (err < 0) + return err; + /* ok, we commit the changes after the validation of area */ + /* it's intended, although the result might be crappy */ + snd_pcm_dmix_sync_area(pcm, size); return size; } static snd_pcm_sframes_t snd_pcm_dmix_avail_update(snd_pcm_t *pcm ATTRIBUTE_UNUSED) { - //snd_pcm_dmix_t *dmix = pcm->private_data; - return 0; + int err; + + err = snd_pcm_dmix_sync_ptr(pcm); + if (err < 0) + return err; + return snd_pcm_mmap_playback_avail(pcm); } static void snd_pcm_dmix_dump(snd_pcm_t *pcm, snd_output_t *out) { - // snd_pcm_dmix_t *dmix = pcm->private_data; + snd_pcm_dmix_t *dmix = pcm->private_data; snd_output_printf(out, "Direct Stream Mixing PCM\n"); if (pcm->setup) { snd_output_printf(out, "\nIts setup is:\n"); snd_pcm_dump_setup(pcm, out); } + if (dmix->spcm) + snd_pcm_dump(dmix->spcm, out); } static snd_pcm_ops_t snd_pcm_dmix_ops = { @@ -757,6 +927,7 @@ static snd_pcm_ops_t snd_pcm_dmix_ops = { dump: snd_pcm_dmix_dump, nonblock: snd_pcm_dmix_nonblock, async: snd_pcm_dmix_async, + poll_revents: snd_pcm_dmix_poll_revents, mmap: snd_pcm_dmix_mmap, munmap: snd_pcm_dmix_munmap, }; @@ -792,7 +963,7 @@ static int snd_pcm_dmix_initialize_slave(snd_pcm_dmix_t *dmix, snd_pcm_t *spcm, snd_pcm_hw_params_t *hw_params; snd_pcm_sw_params_t *sw_params; int ret, buffer_is_not_initialized; - snd_pcm_uframes_t boundary, buffer_size; + snd_pcm_uframes_t boundary; hw_params = &dmix->shmptr->hw_params; sw_params = &dmix->shmptr->sw_params; @@ -887,14 +1058,14 @@ static int snd_pcm_dmix_initialize_slave(snd_pcm_dmix_t *dmix, snd_pcm_t *spcm, SNDERR("unable to set stop threshold\n"); return ret; } - ret = INTERNAL(snd_pcm_hw_params_get_buffer_size)(hw_params, &buffer_size); + ret = snd_pcm_sw_params_set_silence_threshold(spcm, sw_params, 0); if (ret < 0) { - SNDERR("unable to get buffer size\n"); + SNDERR("unable to set silence threshold\n"); return ret; } - ret = snd_pcm_sw_params_set_silence_threshold(spcm, sw_params, buffer_size); + ret = snd_pcm_sw_params_set_silence_size(spcm, sw_params, boundary); if (ret < 0) { - SNDERR("unable to set silence threshold\n"); + SNDERR("unable to set silence threshold (please upgrade to 0.9.0rc8+ driver)\n"); return ret; } @@ -924,6 +1095,7 @@ static int snd_pcm_dmix_initialize_poll_fd(snd_pcm_dmix_t *dmix) snd_pcm_info_t *info; snd_timer_params_t *params; char name[128]; + struct pollfd fd; snd_pcm_info_alloca(&info); snd_timer_params_alloca(¶ms); @@ -949,6 +1121,12 @@ static int snd_pcm_dmix_initialize_poll_fd(snd_pcm_dmix_t *dmix) SNDERR("unable to set timer parameters\n", name); return ret; } + if (snd_timer_poll_descriptors_count(dmix->timer) != 1) { + SNDERR("unable to use timer with fd more than one!!!\n", name); + return ret; + } + snd_timer_poll_descriptors(dmix->timer, &fd, 1); + dmix->poll_fd = fd.fd; return 0; } @@ -1002,7 +1180,7 @@ int snd_pcm_dmix_open(snd_pcm_t **pcmp, const char *name, goto _err; } - ret = semaphore_down(dmix); + ret = semaphore_down(dmix, DMIX_IPC_SEM_CLIENT); if (ret < 0) { semaphore_discard(dmix); goto _err; @@ -1017,6 +1195,7 @@ int snd_pcm_dmix_open(snd_pcm_t **pcmp, const char *name, pcm->ops = &snd_pcm_dmix_ops; pcm->fast_ops = &snd_pcm_dmix_fast_ops; pcm->private_data = dmix; + dmix->state = SND_PCM_STATE_OPEN; if (first_instance) { ret = snd_pcm_open_slave(&spcm, root, sconf, stream, mode); @@ -1064,12 +1243,15 @@ int snd_pcm_dmix_open(snd_pcm_t **pcmp, const char *name, } pcm->poll_fd = dmix->poll_fd; + pcm->poll_events = POLLIN; /* it's different than other plugins */ dmix->shmptr->type = spcm->type; snd_pcm_set_hw_ptr(pcm, &dmix->hw_ptr, -1, 0); snd_pcm_set_appl_ptr(pcm, &dmix->appl_ptr, -1, 0); + semaphore_up(dmix, DMIX_IPC_SEM_CLIENT); + *pcmp = pcm; return 0; @@ -1086,7 +1268,7 @@ int snd_pcm_dmix_open(snd_pcm_t **pcmp, const char *name, if (shm_discard(dmix) > 0) { if (dmix->semid >= 0) { if (semaphore_discard(dmix) < 0) - semaphore_up(dmix); + semaphore_up(dmix, DMIX_IPC_SEM_CLIENT); } } } diff --git a/src/pcm/pcm_file.c b/src/pcm/pcm_file.c index 0eee4c32..e14217c8 100644 --- a/src/pcm/pcm_file.c +++ b/src/pcm/pcm_file.c @@ -492,6 +492,7 @@ int snd_pcm_file_open(snd_pcm_t **pcmp, const char *name, pcm->fast_ops = &snd_pcm_file_fast_ops; pcm->private_data = file; pcm->poll_fd = slave->poll_fd; + pcm->poll_events = slave->poll_events; snd_pcm_link_hw_ptr(pcm, slave); snd_pcm_link_appl_ptr(pcm, slave); *pcmp = pcm; diff --git a/src/pcm/pcm_hooks.c b/src/pcm/pcm_hooks.c index cd0b9618..6f9cf98c 100644 --- a/src/pcm/pcm_hooks.c +++ b/src/pcm/pcm_hooks.c @@ -351,6 +351,7 @@ int snd_pcm_hooks_open(snd_pcm_t **pcmp, const char *name, snd_pcm_t *slave, int pcm->fast_ops = &snd_pcm_hooks_fast_ops; pcm->private_data = h; pcm->poll_fd = slave->poll_fd; + pcm->poll_events = slave->poll_events; snd_pcm_link_hw_ptr(pcm, slave); snd_pcm_link_appl_ptr(pcm, slave); *pcmp = pcm; diff --git a/src/pcm/pcm_hw.c b/src/pcm/pcm_hw.c index 85f9892c..d4b58b8e 100644 --- a/src/pcm/pcm_hw.c +++ b/src/pcm/pcm_hw.c @@ -898,6 +898,7 @@ int snd_pcm_hw_open_fd(snd_pcm_t **pcmp, const char *name, pcm->fast_ops = &snd_pcm_hw_fast_ops; pcm->private_data = hw; pcm->poll_fd = fd; + pcm->poll_events = info.stream == SND_PCM_STREAM_PLAYBACK ? POLLOUT : POLLIN; *pcmp = pcm; diff --git a/src/pcm/pcm_ladspa.c b/src/pcm/pcm_ladspa.c index 696203b6..7d24eddb 100644 --- a/src/pcm/pcm_ladspa.c +++ b/src/pcm/pcm_ladspa.c @@ -706,6 +706,7 @@ static snd_pcm_ops_t snd_pcm_ladspa_ops = { dump: snd_pcm_ladspa_dump, nonblock: snd_pcm_plugin_nonblock, async: snd_pcm_plugin_async, + poll_revents: snd_pcm_plugin_poll_revents, mmap: snd_pcm_plugin_mmap, munmap: snd_pcm_plugin_munmap, }; @@ -1173,6 +1174,7 @@ int snd_pcm_ladspa_open(snd_pcm_t **pcmp, const char *name, pcm->fast_ops = &snd_pcm_plugin_fast_ops; pcm->private_data = ladspa; pcm->poll_fd = slave->poll_fd; + pcm->poll_events = slave->poll_events; snd_pcm_set_hw_ptr(pcm, &ladspa->plug.hw_ptr, -1, 0); snd_pcm_set_appl_ptr(pcm, &ladspa->plug.appl_ptr, -1, 0); *pcmp = pcm; diff --git a/src/pcm/pcm_lfloat.c b/src/pcm/pcm_lfloat.c index 1280db42..b49b4ae6 100644 --- a/src/pcm/pcm_lfloat.c +++ b/src/pcm/pcm_lfloat.c @@ -360,6 +360,7 @@ static snd_pcm_ops_t snd_pcm_lfloat_ops = { dump: snd_pcm_lfloat_dump, nonblock: snd_pcm_plugin_nonblock, async: snd_pcm_plugin_async, + poll_revents: snd_pcm_plugin_poll_revents, mmap: snd_pcm_plugin_mmap, munmap: snd_pcm_plugin_munmap, }; @@ -407,6 +408,7 @@ int snd_pcm_lfloat_open(snd_pcm_t **pcmp, const char *name, snd_pcm_format_t sfo pcm->fast_ops = &snd_pcm_plugin_fast_ops; pcm->private_data = lfloat; pcm->poll_fd = slave->poll_fd; + pcm->poll_events = slave->poll_events; snd_pcm_set_hw_ptr(pcm, &lfloat->plug.hw_ptr, -1, 0); snd_pcm_set_appl_ptr(pcm, &lfloat->plug.appl_ptr, -1, 0); *pcmp = pcm; diff --git a/src/pcm/pcm_linear.c b/src/pcm/pcm_linear.c index 4a4e4291..437d01e3 100644 --- a/src/pcm/pcm_linear.c +++ b/src/pcm/pcm_linear.c @@ -416,6 +416,7 @@ static snd_pcm_ops_t snd_pcm_linear_ops = { dump: snd_pcm_linear_dump, nonblock: snd_pcm_plugin_nonblock, async: snd_pcm_plugin_async, + poll_revents: snd_pcm_plugin_poll_revents, mmap: snd_pcm_plugin_mmap, munmap: snd_pcm_plugin_munmap, }; @@ -463,6 +464,7 @@ int snd_pcm_linear_open(snd_pcm_t **pcmp, const char *name, snd_pcm_format_t sfo pcm->fast_ops = &snd_pcm_plugin_fast_ops; pcm->private_data = linear; pcm->poll_fd = slave->poll_fd; + pcm->poll_events = slave->poll_events; snd_pcm_set_hw_ptr(pcm, &linear->plug.hw_ptr, -1, 0); snd_pcm_set_appl_ptr(pcm, &linear->plug.appl_ptr, -1, 0); *pcmp = pcm; diff --git a/src/pcm/pcm_local.h b/src/pcm/pcm_local.h index a2be05ea..14de711e 100644 --- a/src/pcm/pcm_local.h +++ b/src/pcm/pcm_local.h @@ -125,6 +125,7 @@ typedef struct { int (*close)(snd_pcm_t *pcm); int (*nonblock)(snd_pcm_t *pcm, int nonblock); int (*async)(snd_pcm_t *pcm, int sig, pid_t pid); + int (*poll_revents)(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int nfds, unsigned short *revents); int (*info)(snd_pcm_t *pcm, snd_pcm_info_t *info); int (*hw_refine)(snd_pcm_t *pcm, snd_pcm_hw_params_t *params); int (*hw_params)(snd_pcm_t *pcm, snd_pcm_hw_params_t *params); @@ -164,6 +165,7 @@ struct _snd_pcm { snd_pcm_stream_t stream; int mode; int poll_fd; + unsigned short poll_events; int setup; snd_pcm_access_t access; /* access mode */ snd_pcm_format_t format; /* SND_PCM_FORMAT_* */ diff --git a/src/pcm/pcm_meter.c b/src/pcm/pcm_meter.c index 26e169b7..0eb6a07e 100644 --- a/src/pcm/pcm_meter.c +++ b/src/pcm/pcm_meter.c @@ -655,6 +655,7 @@ int snd_pcm_meter_open(snd_pcm_t **pcmp, const char *name, unsigned int frequenc pcm->fast_ops = &snd_pcm_meter_fast_ops; pcm->private_data = meter; pcm->poll_fd = slave->poll_fd; + pcm->poll_events = slave->poll_events; snd_pcm_link_hw_ptr(pcm, slave); snd_pcm_link_appl_ptr(pcm, slave); *pcmp = pcm; diff --git a/src/pcm/pcm_mulaw.c b/src/pcm/pcm_mulaw.c index 6534f84e..16a389d6 100644 --- a/src/pcm/pcm_mulaw.c +++ b/src/pcm/pcm_mulaw.c @@ -415,6 +415,7 @@ static snd_pcm_ops_t snd_pcm_mulaw_ops = { dump: snd_pcm_mulaw_dump, nonblock: snd_pcm_plugin_nonblock, async: snd_pcm_plugin_async, + poll_revents: snd_pcm_plugin_poll_revents, mmap: snd_pcm_plugin_mmap, munmap: snd_pcm_plugin_munmap, }; @@ -462,6 +463,7 @@ int snd_pcm_mulaw_open(snd_pcm_t **pcmp, const char *name, snd_pcm_format_t sfor pcm->fast_ops = &snd_pcm_plugin_fast_ops; pcm->private_data = mulaw; pcm->poll_fd = slave->poll_fd; + pcm->poll_events = slave->poll_events; snd_pcm_set_hw_ptr(pcm, &mulaw->plug.hw_ptr, -1, 0); snd_pcm_set_appl_ptr(pcm, &mulaw->plug.appl_ptr, -1, 0); *pcmp = pcm; diff --git a/src/pcm/pcm_multi.c b/src/pcm/pcm_multi.c index c52f094e..0be87165 100644 --- a/src/pcm/pcm_multi.c +++ b/src/pcm/pcm_multi.c @@ -698,6 +698,7 @@ int snd_pcm_multi_open(snd_pcm_t **pcmp, const char *name, pcm->fast_ops = &snd_pcm_multi_fast_ops; pcm->private_data = multi; pcm->poll_fd = multi->slaves[master_slave].pcm->poll_fd; + pcm->poll_events = multi->slaves[master_slave].pcm->poll_events; snd_pcm_link_hw_ptr(pcm, multi->slaves[master_slave].pcm); snd_pcm_link_appl_ptr(pcm, multi->slaves[master_slave].pcm); *pcmp = pcm; diff --git a/src/pcm/pcm_null.c b/src/pcm/pcm_null.c index c7703850..a727f2b1 100644 --- a/src/pcm/pcm_null.c +++ b/src/pcm/pcm_null.c @@ -378,6 +378,7 @@ int snd_pcm_null_open(snd_pcm_t **pcmp, const char *name, snd_pcm_stream_t strea pcm->fast_ops = &snd_pcm_null_fast_ops; pcm->private_data = null; pcm->poll_fd = fd; + pcm->poll_events = stream == SND_PCM_STREAM_PLAYBACK ? POLLOUT : POLLIN; snd_pcm_set_hw_ptr(pcm, &null->hw_ptr, -1, 0); snd_pcm_set_appl_ptr(pcm, &null->appl_ptr, -1, 0); *pcmp = pcm; diff --git a/src/pcm/pcm_params.c b/src/pcm/pcm_params.c index 0648faf0..8d4d255b 100644 --- a/src/pcm/pcm_params.c +++ b/src/pcm/pcm_params.c @@ -1020,6 +1020,9 @@ int snd_pcm_hw_param_never_eq(const snd_pcm_hw_params_t *params, return -EINVAL; } +#if 0 +#define CHOOSE_DEBUG +#endif /* Choose one configuration from configuration space defined by PARAMS The configuration chosen is that obtained fixing in this order: @@ -1035,6 +1038,12 @@ int snd_pcm_hw_param_never_eq(const snd_pcm_hw_params_t *params, static int snd_pcm_hw_params_choose(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) { int err; +#ifdef CHOOSE_DEBUG + snd_output_t *log; + snd_output_stdio_attach(&log, stderr, 0); + snd_output_printf(log, "CHOOSE called:\n"); + snd_pcm_hw_params_dump(params, log); +#endif err = snd_pcm_hw_param_set_first(pcm, params, SND_PCM_HW_PARAM_ACCESS, NULL, 0); if (err < 0) @@ -1063,6 +1072,11 @@ static int snd_pcm_hw_params_choose(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) err = snd_pcm_hw_param_set_first(pcm, params, SND_PCM_HW_PARAM_TICK_TIME, NULL, 0); if (err < 0) return err; +#ifdef CHOOSE_DEBUG + snd_output_printf(log, "choose done\n"); + snd_pcm_hw_params_dump(params, log); + snd_output_close(log); +#endif return 0; } @@ -2204,6 +2218,7 @@ int snd_pcm_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) res = pcm->ops->hw_refine(pcm->op_arg, params); #ifdef REFINE_DEBUG snd_output_printf(log, "refine done - result = %i\n", res); + snd_pcm_hw_params_dump(params, log); snd_output_close(log); #endif return res; diff --git a/src/pcm/pcm_plug.c b/src/pcm/pcm_plug.c index e0c05faa..6328d147 100644 --- a/src/pcm/pcm_plug.c +++ b/src/pcm/pcm_plug.c @@ -92,6 +92,12 @@ static int snd_pcm_plug_async(snd_pcm_t *pcm, int sig, pid_t pid) return snd_pcm_async(plug->slave, sig, pid); } +static int snd_pcm_plug_poll_revents(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int nfds, unsigned short *revents) +{ + snd_pcm_plug_t *plug = pcm->private_data; + return snd_pcm_poll_descriptors_revents(plug->slave, pfds, nfds, revents); +} + static int snd_pcm_plug_info(snd_pcm_t *pcm, snd_pcm_info_t *info) { snd_pcm_plug_t *plug = pcm->private_data; @@ -959,6 +965,7 @@ static snd_pcm_ops_t snd_pcm_plug_ops = { dump: snd_pcm_plug_dump, nonblock: snd_pcm_plug_nonblock, async: snd_pcm_plug_async, + poll_revents: snd_pcm_plug_poll_revents, mmap: snd_pcm_plug_mmap, munmap: snd_pcm_plug_munmap, }; @@ -1013,6 +1020,7 @@ int snd_pcm_plug_open(snd_pcm_t **pcmp, pcm->fast_op_arg = slave->fast_op_arg; pcm->private_data = plug; pcm->poll_fd = slave->poll_fd; + pcm->poll_events = slave->poll_events; snd_pcm_link_hw_ptr(pcm, slave); snd_pcm_link_appl_ptr(pcm, slave); *pcmp = pcm; diff --git a/src/pcm/pcm_plugin.c b/src/pcm/pcm_plugin.c index 858fdd26..b01d30f8 100644 --- a/src/pcm/pcm_plugin.c +++ b/src/pcm/pcm_plugin.c @@ -158,6 +158,12 @@ int snd_pcm_plugin_async(snd_pcm_t *pcm, int sig, pid_t pid) return snd_pcm_async(plugin->slave, sig, pid); } +int snd_pcm_plugin_poll_revents(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int nfds, unsigned short *revents) +{ + snd_pcm_plugin_t *plugin = pcm->private_data; + return snd_pcm_poll_descriptors_revents(plugin->slave, pfds, nfds, revents); +} + int snd_pcm_plugin_info(snd_pcm_t *pcm, snd_pcm_info_t * info) { snd_pcm_plugin_t *plugin = pcm->private_data; diff --git a/src/pcm/pcm_plugin.h b/src/pcm/pcm_plugin.h index df8f9c4d..a4353c51 100644 --- a/src/pcm/pcm_plugin.h +++ b/src/pcm/pcm_plugin.h @@ -56,6 +56,7 @@ int snd_pcm_plugin_close(snd_pcm_t *pcm); int snd_pcm_plugin_card(snd_pcm_t *pcm); int snd_pcm_plugin_nonblock(snd_pcm_t *pcm, int nonblock); int snd_pcm_plugin_async(snd_pcm_t *pcm, int sig, pid_t pid); +int snd_pcm_plugin_poll_revents(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int nfds, unsigned short *revents); int snd_pcm_plugin_info(snd_pcm_t *pcm, snd_pcm_info_t * info); int snd_pcm_plugin_hw_free(snd_pcm_t *pcm); int snd_pcm_plugin_sw_refine(snd_pcm_t *pcm, snd_pcm_sw_params_t *params); diff --git a/src/pcm/pcm_rate.c b/src/pcm/pcm_rate.c index f2270c8c..395f5b67 100644 --- a/src/pcm/pcm_rate.c +++ b/src/pcm/pcm_rate.c @@ -438,11 +438,39 @@ static int snd_pcm_rate_sw_params(snd_pcm_t *pcm, snd_pcm_sw_params_t * params) snd_pcm_rate_t *rate = pcm->private_data; snd_pcm_t *slave = rate->plug.slave; snd_pcm_sw_params_t sparams; + snd_pcm_uframes_t boundary1, boundary2; + sparams = *params; + if ((rate->pitch >= DIV ? 1 : 0) ^ (pcm->stream == SND_PCM_STREAM_CAPTURE ? 1 : 0)) { + boundary1 = pcm->buffer_size; + boundary2 = slave->buffer_size; + while (boundary2 * 2 <= LONG_MAX - slave->buffer_size) { + boundary1 *= 2; + boundary2 *= 2; + } + } else { + boundary1 = pcm->buffer_size; + boundary2 = slave->buffer_size; + while (boundary1 * 2 <= LONG_MAX - pcm->buffer_size) { + boundary1 *= 2; + boundary2 *= 2; + } + } + params->boundary = boundary1; + sparams.boundary = boundary2; + if (pcm->stream == SND_PCM_STREAM_PLAYBACK) { + rate->pitch = (((u_int64_t)boundary2 * DIV) + boundary1 / 2) / boundary1; + } else { + rate->pitch = (((u_int64_t)boundary1 * DIV) + boundary2 / 2) / boundary2; + } recalc(pcm, &sparams.avail_min); recalc(pcm, &sparams.xfer_align); recalc(pcm, &sparams.start_threshold); - recalc(pcm, &sparams.stop_threshold); + if (sparams.stop_threshold >= sparams.boundary) { + sparams.stop_threshold = sparams.boundary; + } else { + recalc(pcm, &sparams.stop_threshold); + } recalc(pcm, &sparams.silence_threshold); recalc(pcm, &sparams.silence_size); return snd_pcm_sw_params(slave, &sparams); @@ -548,6 +576,7 @@ static snd_pcm_ops_t snd_pcm_rate_ops = { dump: snd_pcm_rate_dump, nonblock: snd_pcm_plugin_nonblock, async: snd_pcm_plugin_async, + poll_revents: snd_pcm_plugin_poll_revents, mmap: snd_pcm_plugin_mmap, munmap: snd_pcm_plugin_munmap, }; @@ -599,6 +628,7 @@ int snd_pcm_rate_open(snd_pcm_t **pcmp, const char *name, snd_pcm_format_t sform pcm->fast_ops = &snd_pcm_plugin_fast_ops; pcm->private_data = rate; pcm->poll_fd = slave->poll_fd; + pcm->poll_events = slave->poll_events; snd_pcm_set_hw_ptr(pcm, &rate->plug.hw_ptr, -1, 0); snd_pcm_set_appl_ptr(pcm, &rate->plug.appl_ptr, -1, 0); *pcmp = pcm; diff --git a/src/pcm/pcm_route.c b/src/pcm/pcm_route.c index 73530bc5..72faae07 100644 --- a/src/pcm/pcm_route.c +++ b/src/pcm/pcm_route.c @@ -732,6 +732,7 @@ static snd_pcm_ops_t snd_pcm_route_ops = { dump: snd_pcm_route_dump, nonblock: snd_pcm_plugin_nonblock, async: snd_pcm_plugin_async, + poll_revents: snd_pcm_plugin_poll_revents, mmap: snd_pcm_plugin_mmap, munmap: snd_pcm_plugin_munmap, }; @@ -864,6 +865,7 @@ int snd_pcm_route_open(snd_pcm_t **pcmp, const char *name, pcm->fast_ops = &snd_pcm_plugin_fast_ops; pcm->private_data = route; pcm->poll_fd = slave->poll_fd; + pcm->poll_events = slave->poll_events; snd_pcm_set_hw_ptr(pcm, &route->plug.hw_ptr, -1, 0); snd_pcm_set_appl_ptr(pcm, &route->plug.appl_ptr, -1, 0); err = route_load_ttable(&route->params, pcm->stream, tt_ssize, ttable, tt_cused, tt_sused); diff --git a/src/pcm/pcm_share.c b/src/pcm/pcm_share.c index 04a9a681..7b82296c 100644 --- a/src/pcm/pcm_share.c +++ b/src/pcm/pcm_share.c @@ -1431,6 +1431,7 @@ int snd_pcm_share_open(snd_pcm_t **pcmp, const char *name, const char *sname, pcm->fast_ops = &snd_pcm_share_fast_ops; pcm->private_data = share; pcm->poll_fd = share->client_socket; + pcm->poll_events = stream == SND_PCM_STREAM_PLAYBACK ? POLLOUT : POLLIN; snd_pcm_set_hw_ptr(pcm, &share->hw_ptr, -1, 0); snd_pcm_set_appl_ptr(pcm, &share->appl_ptr, -1, 0); diff --git a/src/pcm/pcm_shm.c b/src/pcm/pcm_shm.c index a9558e36..68786326 100644 --- a/src/pcm/pcm_shm.c +++ b/src/pcm/pcm_shm.c @@ -788,6 +788,7 @@ int snd_pcm_shm_open(snd_pcm_t **pcmp, const char *name, return err; } pcm->poll_fd = err; + pcm->poll_events = stream == SND_PCM_STREAM_PLAYBACK ? POLLOUT : POLLIN; snd_pcm_set_hw_ptr(pcm, &ctrl->hw.ptr, -1, 0); snd_pcm_set_appl_ptr(pcm, &ctrl->appl.ptr, -1, 0); *pcmp = pcm; -- 2.47.1