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)
This commit is contained in:
Jaroslav Kysela 2003-02-11 18:14:43 +00:00
parent 06cccc6a78
commit af89cefd99
24 changed files with 332 additions and 55 deletions

View file

@ -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 snd_pcm_sw_params(snd_pcm_t *pcm, snd_pcm_sw_params_t *params)
{ {
int err; int err;
assert(pcm->setup); /* the hw_params must be set at first!!! */
err = pcm->ops->sw_params(pcm->op_arg, params); err = pcm->ops->sw_params(pcm->op_arg, params);
if (err < 0) if (err < 0)
return err; return err;
@ -1169,9 +1170,10 @@ int snd_pcm_poll_descriptors(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int s
assert(pcm && pfds); assert(pcm && pfds);
if (space >= 1 && pfds) { if (space >= 1 && pfds) {
pfds->fd = pcm->poll_fd; pfds->fd = pcm->poll_fd;
pfds->events = pcm->stream == SND_PCM_STREAM_PLAYBACK ? (POLLOUT|POLLERR|POLLNVAL) : (POLLIN|POLLERR|POLLNVAL); pfds->events = pcm->poll_events | POLLERR | POLLNVAL;
} else } else {
return 0; return 0;
}
return 1; 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) int snd_pcm_poll_descriptors_revents(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int nfds, unsigned short *revents)
{ {
assert(pcm && pfds && revents); assert(pcm && pfds && revents);
if (pcm->ops->poll_revents)
return pcm->ops->poll_revents(pcm, pfds, nfds, revents);
if (nfds == 1) { if (nfds == 1) {
*revents = pfds->revents; *revents = pfds->revents;
return 0; 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) int snd_pcm_wait(snd_pcm_t *pcm, int timeout)
{ {
struct pollfd pfd; struct pollfd pfd;
unsigned short revents;
int err; int err;
err = snd_pcm_poll_descriptors(pcm, &pfd, 1); err = snd_pcm_poll_descriptors(pcm, &pfd, 1);
assert(err == 1); assert(err == 1);
err = poll(&pfd, 1, timeout); err = poll(&pfd, 1, timeout);
if (err < 0) if (err < 0)
return -errno; 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; return err > 0 ? 1 : 0;
} }

View file

@ -527,6 +527,7 @@ static snd_pcm_ops_t snd_pcm_adpcm_ops = {
dump: snd_pcm_adpcm_dump, dump: snd_pcm_adpcm_dump,
nonblock: snd_pcm_plugin_nonblock, nonblock: snd_pcm_plugin_nonblock,
async: snd_pcm_plugin_async, async: snd_pcm_plugin_async,
poll_revents: snd_pcm_plugin_poll_revents,
mmap: snd_pcm_plugin_mmap, mmap: snd_pcm_plugin_mmap,
munmap: snd_pcm_plugin_munmap, 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->fast_ops = &snd_pcm_plugin_fast_ops;
pcm->private_data = adpcm; pcm->private_data = adpcm;
pcm->poll_fd = slave->poll_fd; 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_hw_ptr(pcm, &adpcm->plug.hw_ptr, -1, 0);
snd_pcm_set_appl_ptr(pcm, &adpcm->plug.appl_ptr, -1, 0); snd_pcm_set_appl_ptr(pcm, &adpcm->plug.appl_ptr, -1, 0);
*pcmp = pcm; *pcmp = pcm;

View file

@ -400,6 +400,7 @@ static snd_pcm_ops_t snd_pcm_alaw_ops = {
dump: snd_pcm_alaw_dump, dump: snd_pcm_alaw_dump,
nonblock: snd_pcm_plugin_nonblock, nonblock: snd_pcm_plugin_nonblock,
async: snd_pcm_plugin_async, async: snd_pcm_plugin_async,
poll_revents: snd_pcm_plugin_poll_revents,
mmap: snd_pcm_plugin_mmap, mmap: snd_pcm_plugin_mmap,
munmap: snd_pcm_plugin_munmap, 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->fast_ops = &snd_pcm_plugin_fast_ops;
pcm->private_data = alaw; pcm->private_data = alaw;
pcm->poll_fd = slave->poll_fd; 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_hw_ptr(pcm, &alaw->plug.hw_ptr, -1, 0);
snd_pcm_set_appl_ptr(pcm, &alaw->plug.appl_ptr, -1, 0); snd_pcm_set_appl_ptr(pcm, &alaw->plug.appl_ptr, -1, 0);
*pcmp = pcm; *pcmp = pcm;

View file

@ -163,6 +163,7 @@ static snd_pcm_ops_t snd_pcm_copy_ops = {
dump: snd_pcm_copy_dump, dump: snd_pcm_copy_dump,
nonblock: snd_pcm_plugin_nonblock, nonblock: snd_pcm_plugin_nonblock,
async: snd_pcm_plugin_async, async: snd_pcm_plugin_async,
poll_revents: snd_pcm_plugin_poll_revents,
mmap: snd_pcm_plugin_mmap, mmap: snd_pcm_plugin_mmap,
munmap: snd_pcm_plugin_munmap, munmap: snd_pcm_plugin_munmap,
}; };

View file

@ -48,6 +48,18 @@
const char *_snd_module_pcm_dmix = ""; const char *_snd_module_pcm_dmix = "";
#endif #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 { typedef struct {
key_t ipc_key; /* IPC key for semaphore and memory */ key_t ipc_key; /* IPC key for semaphore and memory */
int semid; /* IPC global semaphore identification */ int semid; /* IPC global semaphore identification */
int semlock; /* locked with our process? */
int shmid; /* IPC global shared memory identification */ int shmid; /* IPC global shared memory identification */
snd_pcm_dmix_share_t *shmptr; /* pointer to shared memory area */ snd_pcm_dmix_share_t *shmptr; /* pointer to shared memory area */
snd_pcm_t *spcm; /* slave PCM handle */ snd_pcm_t *spcm; /* slave PCM handle */
snd_pcm_uframes_t appl_ptr; snd_pcm_uframes_t appl_ptr;
snd_pcm_uframes_t hw_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 server, client;
int comm_fd; /* communication file descriptor (socket) */ int comm_fd; /* communication file descriptor (socket) */
int hw_fd; /* hardware file descriptor */ int hw_fd; /* hardware file descriptor */
@ -109,7 +125,7 @@ struct sembuf {
static int semaphore_create_or_connect(snd_pcm_dmix_t *dmix) 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) if (dmix->semid < 0)
return -errno; return -errno;
return 0; return 0;
@ -121,28 +137,28 @@ static int semaphore_discard(snd_pcm_dmix_t *dmix)
return -EINVAL; return -EINVAL;
if (semctl(dmix->semid, 0, IPC_RMID, NULL) < 0) if (semctl(dmix->semid, 0, IPC_RMID, NULL) < 0)
return -errno; return -errno;
dmix->semlock = 0;
dmix->semid = -1; dmix->semid = -1;
return 0; 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); 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; return -errno;
dmix->semlock = 1;
return 0; 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); assert(dmix->semid >= 0);
op.sem_num = sem_num;
if (semop(dmix->semid, &op, 1) < 0) if (semop(dmix->semid, &op, 1) < 0)
return -errno; return -errno;
dmix->semlock = 0;
return 0; return 0;
} }
@ -279,6 +295,12 @@ static int send_fd(int sock, void *data, size_t len, int fd)
return ret; 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) static void server_job(snd_pcm_dmix_t *dmix)
{ {
int ret, sck, i; int ret, sck, i;
@ -287,7 +309,7 @@ static void server_job(snd_pcm_dmix_t *dmix)
/* close all files to free resources */ /* close all files to free resources */
i = sysconf(_SC_OPEN_MAX); i = sysconf(_SC_OPEN_MAX);
while (--i >= 0) { while (--i >= 3) {
if (i != dmix->server_fd && i != dmix->hw_fd) if (i != dmix->server_fd && i != dmix->hw_fd)
close(i); close(i);
} }
@ -298,22 +320,27 @@ static void server_job(snd_pcm_dmix_t *dmix)
pfds[0].fd = dmix->server_fd; pfds[0].fd = dmix->server_fd;
pfds[0].events = POLLIN | POLLERR | POLLHUP; pfds[0].events = POLLIN | POLLERR | POLLHUP;
server_printf("DMIX SERVER STARTED\n");
while (1) { while (1) {
ret = poll(pfds, current + 1, 500); 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 */ if (ret < 0) /* some error */
break; break;
if (ret == 0) { /* timeout */ if (ret == 0 || pfds[0].revents & (POLLERR | POLLHUP)) { /* timeout or error? */
struct shmid_ds buf; struct shmid_ds buf;
semaphore_down(dmix, DMIX_IPC_SEM_CLIENT);
if (shmctl(dmix->shmid, IPC_STAT, &buf) < 0) { if (shmctl(dmix->shmid, IPC_STAT, &buf) < 0) {
shm_discard(dmix); shm_discard(dmix);
continue; 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; break;
semaphore_up(dmix, DMIX_IPC_SEM_CLIENT);
continue;
} }
if (pfds[0].revents & (POLLERR | POLLHUP))
break;
if (pfds[0].revents & POLLIN) { if (pfds[0].revents & POLLIN) {
ret--;
sck = accept(dmix->server_fd, 0, 0); sck = accept(dmix->server_fd, 0, 0);
if (sck >= 0) { if (sck >= 0) {
if (current == max) { 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]; struct pollfd *pfd = &pfds[i+1];
unsigned char cmd; unsigned char cmd;
if (pfd->revents & (POLLERR | POLLHUP)) { if (pfd->revents & (POLLERR | POLLHUP)) {
ret--;
close(pfd->fd); close(pfd->fd);
pfd->fd = -1; pfd->fd = -1;
continue; continue;
} }
if (!(pfd->revents & POLLIN)) if (!(pfd->revents & POLLIN))
continue; continue;
ret--;
if (read(pfd->fd, &cmd, 1) == 1) if (read(pfd->fd, &cmd, 1) == 1)
cmd = 0 /*process command */; 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 (pfds[i+1].fd < 0) {
if (i + 1 != max) if (i + 1 != max)
memcpy(&pfds[i+1], &pfds[i+2], sizeof(struct pollfd) * (max - i - 1)); 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->server_fd);
close(dmix->poll_fd); close(dmix->hw_fd);
shm_discard(dmix); shm_discard(dmix);
semaphore_discard(dmix);
server_printf("DMIX SERVER EXIT\n");
exit(EXIT_SUCCESS); 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) static int server_discard(snd_pcm_dmix_t *dmix)
{ {
if (dmix->server) { if (dmix->server) {
kill(dmix->server_pid, SIGTERM); //kill(dmix->server_pid, SIGTERM);
waitpid(dmix->server_pid, NULL, 0); //waitpid(dmix->server_pid, NULL, 0);
dmix->server_pid = (pid_t)-1; dmix->server_pid = (pid_t)-1;
} }
if (dmix->server_fd > 0) { if (dmix->server_fd > 0) {
@ -445,7 +476,7 @@ static int client_discard(snd_pcm_dmix_t *dmix)
/* /*
* synchronize shm ring buffer with hardware * 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_dmix_t *dmix = pcm->private_data;
snd_pcm_uframes_t appl_ptr; 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; appl_ptr = dmix->appl_ptr - size;
if (appl_ptr > pcm->boundary) if (appl_ptr > pcm->boundary)
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 * 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) */ /* value is cached for us in pcm->mode (SND_PCM_NONBLOCK flag) */
return 0; 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); 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; 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)); memset(info, 0, sizeof(*info));
info->stream = pcm->stream; info->stream = pcm->stream;
info->card = -1; 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; 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; 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; 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; 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) static int snd_pcm_dmix_status(snd_pcm_t *pcm, snd_pcm_status_t * status)
{ {
snd_pcm_dmix_t *dmix = pcm->private_data; 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; return 0;
} }
static snd_pcm_state_t snd_pcm_dmix_state(snd_pcm_t *pcm) static snd_pcm_state_t snd_pcm_dmix_state(snd_pcm_t *pcm)
{ {
snd_pcm_dmix_t *dmix = pcm->private_data; 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) static int snd_pcm_dmix_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delayp)
{ {
snd_pcm_dmix_t *dmix = pcm->private_data; 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) static int snd_pcm_dmix_hwsync(snd_pcm_t *pcm)
{ {
snd_pcm_dmix_t *dmix = pcm->private_data; 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) static int snd_pcm_dmix_prepare(snd_pcm_t *pcm)
{ {
snd_pcm_dmix_t *dmix = pcm->private_data; 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; return 0;
} }
static int snd_pcm_dmix_reset(snd_pcm_t *pcm) static int snd_pcm_dmix_reset(snd_pcm_t *pcm)
{ {
snd_pcm_dmix_t *dmix = pcm->private_data; snd_pcm_dmix_t *dmix = pcm->private_data;
dmix->hw_ptr %= pcm->period_size;
dmix->appl_ptr = dmix->hw_ptr;
return 0; return 0;
} }
static int snd_pcm_dmix_start(snd_pcm_t *pcm) static int snd_pcm_dmix_start(snd_pcm_t *pcm)
{ {
snd_pcm_dmix_t *dmix = pcm->private_data; 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; return 0;
} }
static int snd_pcm_dmix_drop(snd_pcm_t *pcm) static int snd_pcm_dmix_drop(snd_pcm_t *pcm)
{ {
snd_pcm_dmix_t *dmix = pcm->private_data; 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; return 0;
} }
static int snd_pcm_dmix_drain(snd_pcm_t *pcm) static int snd_pcm_dmix_drain(snd_pcm_t *pcm)
{ {
snd_pcm_dmix_t *dmix = pcm->private_data; 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; return 0;
} }
static int snd_pcm_dmix_pause(snd_pcm_t *pcm, int enable) static int snd_pcm_dmix_pause(snd_pcm_t *pcm, int enable)
{ {
snd_pcm_dmix_t *dmix = pcm->private_data; 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; return 0;
} }
static snd_pcm_sframes_t snd_pcm_dmix_rewind(snd_pcm_t *pcm, snd_pcm_uframes_t frames) 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; 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; return 0;
} }
@ -705,7 +861,7 @@ static int snd_pcm_dmix_close(snd_pcm_t *pcm)
if (dmix->timer) if (dmix->timer)
snd_timer_close(dmix->timer); snd_timer_close(dmix->timer);
semaphore_down(dmix); semaphore_down(dmix, DMIX_IPC_SEM_CLIENT);
snd_pcm_close(dmix->spcm); snd_pcm_close(dmix->spcm);
if (dmix->server) if (dmix->server)
server_discard(dmix); server_discard(dmix);
@ -713,9 +869,10 @@ static int snd_pcm_dmix_close(snd_pcm_t *pcm)
client_discard(dmix); client_discard(dmix);
if (shm_discard(dmix) > 0) { if (shm_discard(dmix) > 0) {
if (semaphore_discard(dmix) < 0) if (semaphore_discard(dmix) < 0)
semaphore_up(dmix); semaphore_up(dmix, DMIX_IPC_SEM_CLIENT);
} } else {
semaphore_up(dmix); semaphore_up(dmix, DMIX_IPC_SEM_CLIENT);
}
pcm->private_data = NULL; pcm->private_data = NULL;
free(dmix); free(dmix);
return 0; 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 offset ATTRIBUTE_UNUSED,
snd_pcm_uframes_t size) snd_pcm_uframes_t size)
{ {
int err;
snd_pcm_mmap_appl_forward(pcm, size); 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; return size;
} }
static snd_pcm_sframes_t snd_pcm_dmix_avail_update(snd_pcm_t *pcm ATTRIBUTE_UNUSED) static snd_pcm_sframes_t snd_pcm_dmix_avail_update(snd_pcm_t *pcm ATTRIBUTE_UNUSED)
{ {
//snd_pcm_dmix_t *dmix = pcm->private_data; int err;
return 0;
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) 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"); snd_output_printf(out, "Direct Stream Mixing PCM\n");
if (pcm->setup) { if (pcm->setup) {
snd_output_printf(out, "\nIts setup is:\n"); snd_output_printf(out, "\nIts setup is:\n");
snd_pcm_dump_setup(pcm, out); snd_pcm_dump_setup(pcm, out);
} }
if (dmix->spcm)
snd_pcm_dump(dmix->spcm, out);
} }
static snd_pcm_ops_t snd_pcm_dmix_ops = { 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, dump: snd_pcm_dmix_dump,
nonblock: snd_pcm_dmix_nonblock, nonblock: snd_pcm_dmix_nonblock,
async: snd_pcm_dmix_async, async: snd_pcm_dmix_async,
poll_revents: snd_pcm_dmix_poll_revents,
mmap: snd_pcm_dmix_mmap, mmap: snd_pcm_dmix_mmap,
munmap: snd_pcm_dmix_munmap, 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_hw_params_t *hw_params;
snd_pcm_sw_params_t *sw_params; snd_pcm_sw_params_t *sw_params;
int ret, buffer_is_not_initialized; int ret, buffer_is_not_initialized;
snd_pcm_uframes_t boundary, buffer_size; snd_pcm_uframes_t boundary;
hw_params = &dmix->shmptr->hw_params; hw_params = &dmix->shmptr->hw_params;
sw_params = &dmix->shmptr->sw_params; sw_params = &dmix->shmptr->sw_params;
@ -887,16 +1058,16 @@ static int snd_pcm_dmix_initialize_slave(snd_pcm_dmix_t *dmix, snd_pcm_t *spcm,
SNDERR("unable to set stop threshold\n"); SNDERR("unable to set stop threshold\n");
return ret; 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");
return ret;
}
ret = snd_pcm_sw_params_set_silence_threshold(spcm, sw_params, buffer_size);
if (ret < 0) { if (ret < 0) {
SNDERR("unable to set silence threshold\n"); SNDERR("unable to set silence threshold\n");
return ret; return ret;
} }
ret = snd_pcm_sw_params_set_silence_size(spcm, sw_params, boundary);
if (ret < 0) {
SNDERR("unable to set silence threshold (please upgrade to 0.9.0rc8+ driver)\n");
return ret;
}
ret = snd_pcm_sw_params(spcm, sw_params); ret = snd_pcm_sw_params(spcm, sw_params);
if (ret < 0) { if (ret < 0) {
@ -924,6 +1095,7 @@ static int snd_pcm_dmix_initialize_poll_fd(snd_pcm_dmix_t *dmix)
snd_pcm_info_t *info; snd_pcm_info_t *info;
snd_timer_params_t *params; snd_timer_params_t *params;
char name[128]; char name[128];
struct pollfd fd;
snd_pcm_info_alloca(&info); snd_pcm_info_alloca(&info);
snd_timer_params_alloca(&params); snd_timer_params_alloca(&params);
@ -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); SNDERR("unable to set timer parameters\n", name);
return ret; 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; return 0;
} }
@ -1002,7 +1180,7 @@ int snd_pcm_dmix_open(snd_pcm_t **pcmp, const char *name,
goto _err; goto _err;
} }
ret = semaphore_down(dmix); ret = semaphore_down(dmix, DMIX_IPC_SEM_CLIENT);
if (ret < 0) { if (ret < 0) {
semaphore_discard(dmix); semaphore_discard(dmix);
goto _err; 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->ops = &snd_pcm_dmix_ops;
pcm->fast_ops = &snd_pcm_dmix_fast_ops; pcm->fast_ops = &snd_pcm_dmix_fast_ops;
pcm->private_data = dmix; pcm->private_data = dmix;
dmix->state = SND_PCM_STATE_OPEN;
if (first_instance) { if (first_instance) {
ret = snd_pcm_open_slave(&spcm, root, sconf, stream, mode); 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_fd = dmix->poll_fd;
pcm->poll_events = POLLIN; /* it's different than other plugins */
dmix->shmptr->type = spcm->type; dmix->shmptr->type = spcm->type;
snd_pcm_set_hw_ptr(pcm, &dmix->hw_ptr, -1, 0); snd_pcm_set_hw_ptr(pcm, &dmix->hw_ptr, -1, 0);
snd_pcm_set_appl_ptr(pcm, &dmix->appl_ptr, -1, 0); snd_pcm_set_appl_ptr(pcm, &dmix->appl_ptr, -1, 0);
semaphore_up(dmix, DMIX_IPC_SEM_CLIENT);
*pcmp = pcm; *pcmp = pcm;
return 0; return 0;
@ -1086,7 +1268,7 @@ int snd_pcm_dmix_open(snd_pcm_t **pcmp, const char *name,
if (shm_discard(dmix) > 0) { if (shm_discard(dmix) > 0) {
if (dmix->semid >= 0) { if (dmix->semid >= 0) {
if (semaphore_discard(dmix) < 0) if (semaphore_discard(dmix) < 0)
semaphore_up(dmix); semaphore_up(dmix, DMIX_IPC_SEM_CLIENT);
} }
} }
} }

View file

@ -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->fast_ops = &snd_pcm_file_fast_ops;
pcm->private_data = file; pcm->private_data = file;
pcm->poll_fd = slave->poll_fd; pcm->poll_fd = slave->poll_fd;
pcm->poll_events = slave->poll_events;
snd_pcm_link_hw_ptr(pcm, slave); snd_pcm_link_hw_ptr(pcm, slave);
snd_pcm_link_appl_ptr(pcm, slave); snd_pcm_link_appl_ptr(pcm, slave);
*pcmp = pcm; *pcmp = pcm;

View file

@ -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->fast_ops = &snd_pcm_hooks_fast_ops;
pcm->private_data = h; pcm->private_data = h;
pcm->poll_fd = slave->poll_fd; pcm->poll_fd = slave->poll_fd;
pcm->poll_events = slave->poll_events;
snd_pcm_link_hw_ptr(pcm, slave); snd_pcm_link_hw_ptr(pcm, slave);
snd_pcm_link_appl_ptr(pcm, slave); snd_pcm_link_appl_ptr(pcm, slave);
*pcmp = pcm; *pcmp = pcm;

View file

@ -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->fast_ops = &snd_pcm_hw_fast_ops;
pcm->private_data = hw; pcm->private_data = hw;
pcm->poll_fd = fd; pcm->poll_fd = fd;
pcm->poll_events = info.stream == SND_PCM_STREAM_PLAYBACK ? POLLOUT : POLLIN;
*pcmp = pcm; *pcmp = pcm;

View file

@ -706,6 +706,7 @@ static snd_pcm_ops_t snd_pcm_ladspa_ops = {
dump: snd_pcm_ladspa_dump, dump: snd_pcm_ladspa_dump,
nonblock: snd_pcm_plugin_nonblock, nonblock: snd_pcm_plugin_nonblock,
async: snd_pcm_plugin_async, async: snd_pcm_plugin_async,
poll_revents: snd_pcm_plugin_poll_revents,
mmap: snd_pcm_plugin_mmap, mmap: snd_pcm_plugin_mmap,
munmap: snd_pcm_plugin_munmap, 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->fast_ops = &snd_pcm_plugin_fast_ops;
pcm->private_data = ladspa; pcm->private_data = ladspa;
pcm->poll_fd = slave->poll_fd; 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_hw_ptr(pcm, &ladspa->plug.hw_ptr, -1, 0);
snd_pcm_set_appl_ptr(pcm, &ladspa->plug.appl_ptr, -1, 0); snd_pcm_set_appl_ptr(pcm, &ladspa->plug.appl_ptr, -1, 0);
*pcmp = pcm; *pcmp = pcm;

View file

@ -360,6 +360,7 @@ static snd_pcm_ops_t snd_pcm_lfloat_ops = {
dump: snd_pcm_lfloat_dump, dump: snd_pcm_lfloat_dump,
nonblock: snd_pcm_plugin_nonblock, nonblock: snd_pcm_plugin_nonblock,
async: snd_pcm_plugin_async, async: snd_pcm_plugin_async,
poll_revents: snd_pcm_plugin_poll_revents,
mmap: snd_pcm_plugin_mmap, mmap: snd_pcm_plugin_mmap,
munmap: snd_pcm_plugin_munmap, 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->fast_ops = &snd_pcm_plugin_fast_ops;
pcm->private_data = lfloat; pcm->private_data = lfloat;
pcm->poll_fd = slave->poll_fd; 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_hw_ptr(pcm, &lfloat->plug.hw_ptr, -1, 0);
snd_pcm_set_appl_ptr(pcm, &lfloat->plug.appl_ptr, -1, 0); snd_pcm_set_appl_ptr(pcm, &lfloat->plug.appl_ptr, -1, 0);
*pcmp = pcm; *pcmp = pcm;

View file

@ -416,6 +416,7 @@ static snd_pcm_ops_t snd_pcm_linear_ops = {
dump: snd_pcm_linear_dump, dump: snd_pcm_linear_dump,
nonblock: snd_pcm_plugin_nonblock, nonblock: snd_pcm_plugin_nonblock,
async: snd_pcm_plugin_async, async: snd_pcm_plugin_async,
poll_revents: snd_pcm_plugin_poll_revents,
mmap: snd_pcm_plugin_mmap, mmap: snd_pcm_plugin_mmap,
munmap: snd_pcm_plugin_munmap, 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->fast_ops = &snd_pcm_plugin_fast_ops;
pcm->private_data = linear; pcm->private_data = linear;
pcm->poll_fd = slave->poll_fd; 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_hw_ptr(pcm, &linear->plug.hw_ptr, -1, 0);
snd_pcm_set_appl_ptr(pcm, &linear->plug.appl_ptr, -1, 0); snd_pcm_set_appl_ptr(pcm, &linear->plug.appl_ptr, -1, 0);
*pcmp = pcm; *pcmp = pcm;

View file

@ -125,6 +125,7 @@ typedef struct {
int (*close)(snd_pcm_t *pcm); int (*close)(snd_pcm_t *pcm);
int (*nonblock)(snd_pcm_t *pcm, int nonblock); int (*nonblock)(snd_pcm_t *pcm, int nonblock);
int (*async)(snd_pcm_t *pcm, int sig, pid_t pid); 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 (*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_refine)(snd_pcm_t *pcm, snd_pcm_hw_params_t *params);
int (*hw_params)(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; snd_pcm_stream_t stream;
int mode; int mode;
int poll_fd; int poll_fd;
unsigned short poll_events;
int setup; int setup;
snd_pcm_access_t access; /* access mode */ snd_pcm_access_t access; /* access mode */
snd_pcm_format_t format; /* SND_PCM_FORMAT_* */ snd_pcm_format_t format; /* SND_PCM_FORMAT_* */

View file

@ -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->fast_ops = &snd_pcm_meter_fast_ops;
pcm->private_data = meter; pcm->private_data = meter;
pcm->poll_fd = slave->poll_fd; pcm->poll_fd = slave->poll_fd;
pcm->poll_events = slave->poll_events;
snd_pcm_link_hw_ptr(pcm, slave); snd_pcm_link_hw_ptr(pcm, slave);
snd_pcm_link_appl_ptr(pcm, slave); snd_pcm_link_appl_ptr(pcm, slave);
*pcmp = pcm; *pcmp = pcm;

View file

@ -415,6 +415,7 @@ static snd_pcm_ops_t snd_pcm_mulaw_ops = {
dump: snd_pcm_mulaw_dump, dump: snd_pcm_mulaw_dump,
nonblock: snd_pcm_plugin_nonblock, nonblock: snd_pcm_plugin_nonblock,
async: snd_pcm_plugin_async, async: snd_pcm_plugin_async,
poll_revents: snd_pcm_plugin_poll_revents,
mmap: snd_pcm_plugin_mmap, mmap: snd_pcm_plugin_mmap,
munmap: snd_pcm_plugin_munmap, 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->fast_ops = &snd_pcm_plugin_fast_ops;
pcm->private_data = mulaw; pcm->private_data = mulaw;
pcm->poll_fd = slave->poll_fd; 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_hw_ptr(pcm, &mulaw->plug.hw_ptr, -1, 0);
snd_pcm_set_appl_ptr(pcm, &mulaw->plug.appl_ptr, -1, 0); snd_pcm_set_appl_ptr(pcm, &mulaw->plug.appl_ptr, -1, 0);
*pcmp = pcm; *pcmp = pcm;

View file

@ -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->fast_ops = &snd_pcm_multi_fast_ops;
pcm->private_data = multi; pcm->private_data = multi;
pcm->poll_fd = multi->slaves[master_slave].pcm->poll_fd; 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_hw_ptr(pcm, multi->slaves[master_slave].pcm);
snd_pcm_link_appl_ptr(pcm, multi->slaves[master_slave].pcm); snd_pcm_link_appl_ptr(pcm, multi->slaves[master_slave].pcm);
*pcmp = pcm; *pcmp = pcm;

View file

@ -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->fast_ops = &snd_pcm_null_fast_ops;
pcm->private_data = null; pcm->private_data = null;
pcm->poll_fd = fd; 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_hw_ptr(pcm, &null->hw_ptr, -1, 0);
snd_pcm_set_appl_ptr(pcm, &null->appl_ptr, -1, 0); snd_pcm_set_appl_ptr(pcm, &null->appl_ptr, -1, 0);
*pcmp = pcm; *pcmp = pcm;

View file

@ -1020,6 +1020,9 @@ int snd_pcm_hw_param_never_eq(const snd_pcm_hw_params_t *params,
return -EINVAL; return -EINVAL;
} }
#if 0
#define CHOOSE_DEBUG
#endif
/* Choose one configuration from configuration space defined by PARAMS /* Choose one configuration from configuration space defined by PARAMS
The configuration chosen is that obtained fixing in this order: 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) static int snd_pcm_hw_params_choose(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)
{ {
int err; 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); err = snd_pcm_hw_param_set_first(pcm, params, SND_PCM_HW_PARAM_ACCESS, NULL, 0);
if (err < 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); err = snd_pcm_hw_param_set_first(pcm, params, SND_PCM_HW_PARAM_TICK_TIME, NULL, 0);
if (err < 0) if (err < 0)
return err; 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; 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); res = pcm->ops->hw_refine(pcm->op_arg, params);
#ifdef REFINE_DEBUG #ifdef REFINE_DEBUG
snd_output_printf(log, "refine done - result = %i\n", res); snd_output_printf(log, "refine done - result = %i\n", res);
snd_pcm_hw_params_dump(params, log);
snd_output_close(log); snd_output_close(log);
#endif #endif
return res; return res;

View file

@ -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); 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) static int snd_pcm_plug_info(snd_pcm_t *pcm, snd_pcm_info_t *info)
{ {
snd_pcm_plug_t *plug = pcm->private_data; 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, dump: snd_pcm_plug_dump,
nonblock: snd_pcm_plug_nonblock, nonblock: snd_pcm_plug_nonblock,
async: snd_pcm_plug_async, async: snd_pcm_plug_async,
poll_revents: snd_pcm_plug_poll_revents,
mmap: snd_pcm_plug_mmap, mmap: snd_pcm_plug_mmap,
munmap: snd_pcm_plug_munmap, 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->fast_op_arg = slave->fast_op_arg;
pcm->private_data = plug; pcm->private_data = plug;
pcm->poll_fd = slave->poll_fd; pcm->poll_fd = slave->poll_fd;
pcm->poll_events = slave->poll_events;
snd_pcm_link_hw_ptr(pcm, slave); snd_pcm_link_hw_ptr(pcm, slave);
snd_pcm_link_appl_ptr(pcm, slave); snd_pcm_link_appl_ptr(pcm, slave);
*pcmp = pcm; *pcmp = pcm;

View file

@ -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); 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) int snd_pcm_plugin_info(snd_pcm_t *pcm, snd_pcm_info_t * info)
{ {
snd_pcm_plugin_t *plugin = pcm->private_data; snd_pcm_plugin_t *plugin = pcm->private_data;

View file

@ -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_card(snd_pcm_t *pcm);
int snd_pcm_plugin_nonblock(snd_pcm_t *pcm, int nonblock); 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_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_info(snd_pcm_t *pcm, snd_pcm_info_t * info);
int snd_pcm_plugin_hw_free(snd_pcm_t *pcm); 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); int snd_pcm_plugin_sw_refine(snd_pcm_t *pcm, snd_pcm_sw_params_t *params);

View file

@ -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_rate_t *rate = pcm->private_data;
snd_pcm_t *slave = rate->plug.slave; snd_pcm_t *slave = rate->plug.slave;
snd_pcm_sw_params_t sparams; snd_pcm_sw_params_t sparams;
snd_pcm_uframes_t boundary1, boundary2;
sparams = *params; 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.avail_min);
recalc(pcm, &sparams.xfer_align); recalc(pcm, &sparams.xfer_align);
recalc(pcm, &sparams.start_threshold); 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_threshold);
recalc(pcm, &sparams.silence_size); recalc(pcm, &sparams.silence_size);
return snd_pcm_sw_params(slave, &sparams); 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, dump: snd_pcm_rate_dump,
nonblock: snd_pcm_plugin_nonblock, nonblock: snd_pcm_plugin_nonblock,
async: snd_pcm_plugin_async, async: snd_pcm_plugin_async,
poll_revents: snd_pcm_plugin_poll_revents,
mmap: snd_pcm_plugin_mmap, mmap: snd_pcm_plugin_mmap,
munmap: snd_pcm_plugin_munmap, 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->fast_ops = &snd_pcm_plugin_fast_ops;
pcm->private_data = rate; pcm->private_data = rate;
pcm->poll_fd = slave->poll_fd; 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_hw_ptr(pcm, &rate->plug.hw_ptr, -1, 0);
snd_pcm_set_appl_ptr(pcm, &rate->plug.appl_ptr, -1, 0); snd_pcm_set_appl_ptr(pcm, &rate->plug.appl_ptr, -1, 0);
*pcmp = pcm; *pcmp = pcm;

View file

@ -732,6 +732,7 @@ static snd_pcm_ops_t snd_pcm_route_ops = {
dump: snd_pcm_route_dump, dump: snd_pcm_route_dump,
nonblock: snd_pcm_plugin_nonblock, nonblock: snd_pcm_plugin_nonblock,
async: snd_pcm_plugin_async, async: snd_pcm_plugin_async,
poll_revents: snd_pcm_plugin_poll_revents,
mmap: snd_pcm_plugin_mmap, mmap: snd_pcm_plugin_mmap,
munmap: snd_pcm_plugin_munmap, 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->fast_ops = &snd_pcm_plugin_fast_ops;
pcm->private_data = route; pcm->private_data = route;
pcm->poll_fd = slave->poll_fd; 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_hw_ptr(pcm, &route->plug.hw_ptr, -1, 0);
snd_pcm_set_appl_ptr(pcm, &route->plug.appl_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); err = route_load_ttable(&route->params, pcm->stream, tt_ssize, ttable, tt_cused, tt_sused);

View file

@ -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->fast_ops = &snd_pcm_share_fast_ops;
pcm->private_data = share; pcm->private_data = share;
pcm->poll_fd = share->client_socket; 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_hw_ptr(pcm, &share->hw_ptr, -1, 0);
snd_pcm_set_appl_ptr(pcm, &share->appl_ptr, -1, 0); snd_pcm_set_appl_ptr(pcm, &share->appl_ptr, -1, 0);

View file

@ -788,6 +788,7 @@ int snd_pcm_shm_open(snd_pcm_t **pcmp, const char *name,
return err; return err;
} }
pcm->poll_fd = 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_hw_ptr(pcm, &ctrl->hw.ptr, -1, 0);
snd_pcm_set_appl_ptr(pcm, &ctrl->appl.ptr, -1, 0); snd_pcm_set_appl_ptr(pcm, &ctrl->appl.ptr, -1, 0);
*pcmp = pcm; *pcmp = pcm;