From eafb7ae5d8fa5ee52757ee0ee9137442d2c39326 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 28 Apr 2006 15:55:32 +0200 Subject: [PATCH] Use O_APPEND mode with dmix & co plugins Use O_APPEND mode (only if available) with dmix, dsnoop and dshare plugins. Using this mode, the plugin requires no resource server any more. --- src/pcm/pcm_direct.c | 46 +++++++++++++++++++++++++++++++ src/pcm/pcm_direct.h | 3 +++ src/pcm/pcm_dmix.c | 64 +++++++++++++++++++++++++++++++------------- src/pcm/pcm_dshare.c | 63 +++++++++++++++++++++++++++++++------------ src/pcm/pcm_dsnoop.c | 62 ++++++++++++++++++++++++++++++------------ src/pcm/pcm_hw.c | 2 ++ src/pcm/pcm_local.h | 2 ++ 7 files changed, 190 insertions(+), 52 deletions(-) diff --git a/src/pcm/pcm_direct.c b/src/pcm/pcm_direct.c index 46664a13..4e2f36cd 100644 --- a/src/pcm/pcm_direct.c +++ b/src/pcm/pcm_direct.c @@ -82,6 +82,8 @@ int snd_pcm_direct_semaphore_create_or_connect(snd_pcm_direct_t *dmix) return 0; } +#define SND_PCM_DIRECT_MAGIC 0xa15ad319 + /* * global shared memory area */ @@ -121,7 +123,13 @@ retryget: buf.shm_perm.gid = dmix->ipc_gid; shmctl(dmix->shmid, IPC_SET, &buf); } + dmix->shmptr->magic = SND_PCM_DIRECT_MAGIC; return 1; + } else { + if (dmix->shmptr->magic != SND_PCM_DIRECT_MAGIC) { + snd_pcm_direct_shm_discard(dmix); + return -errno; + } } return 0; } @@ -1028,6 +1036,14 @@ int snd_pcm_direct_initialize_slave(snd_pcm_direct_t *dmix, snd_pcm_t *spcm, str dmix->slave_boundary = spcm->boundary; spcm->donot_close = 1; + + { + int ver = 0; + ioctl(spcm->poll_fd, SNDRV_PCM_IOCTL_PVERSION, &ver); + if (ver < SNDRV_PROTOCOL_VERSION(2, 0, 8)) + dmix->shmptr->use_server = 1; + } + return 0; } @@ -1148,6 +1164,36 @@ int snd_pcm_direct_open_secondary_client(snd_pcm_t **spcmp, snd_pcm_direct_t *dm return 0; } +/* + * open a slave PCM as secondary client (dup'ed fd) + */ +int snd_pcm_direct_initialize_secondary_slave(snd_pcm_direct_t *dmix, snd_pcm_t *spcm, struct slave_params *params) +{ + int ret; + + spcm->donot_close = 1; + spcm->setup = 1; + /* we copy the slave setting */ + spcm->buffer_size = dmix->shmptr->s.buffer_size; + spcm->sample_bits = dmix->shmptr->s.sample_bits; + spcm->channels = dmix->shmptr->s.channels; + spcm->format = dmix->shmptr->s.format; + spcm->boundary = recalc_boundary_size(dmix->shmptr->s.boundary, spcm->buffer_size); + spcm->info = dmix->shmptr->s.info; + + /* Use the slave setting as SPCM, so far */ + dmix->slave_buffer_size = spcm->buffer_size; + dmix->slave_period_size = dmix->shmptr->s.period_size; + dmix->slave_boundary = spcm->boundary; + + ret = snd_pcm_mmap(spcm); + if (ret < 0) { + SNDERR("unable to mmap channels"); + return ret; + } + return 0; +} + int snd_pcm_direct_set_timer_params(snd_pcm_direct_t *dmix) { snd_timer_params_t *params; diff --git a/src/pcm/pcm_direct.h b/src/pcm/pcm_direct.h index b094fcf3..7cf4b9d5 100644 --- a/src/pcm/pcm_direct.h +++ b/src/pcm/pcm_direct.h @@ -51,8 +51,10 @@ struct slave_params { }; typedef struct { + unsigned int magic; /* magic number */ char socket_name[256]; /* name of communication socket */ snd_pcm_type_t type; /* PCM type (currently only hw) */ + int use_server; struct { unsigned int format; snd_interval_t rate; @@ -168,6 +170,7 @@ int snd_pcm_direct_server_discard(snd_pcm_direct_t *dmix); int snd_pcm_direct_client_connect(snd_pcm_direct_t *dmix); int snd_pcm_direct_client_discard(snd_pcm_direct_t *dmix); int snd_pcm_direct_initialize_slave(snd_pcm_direct_t *dmix, snd_pcm_t *spcm, struct slave_params *params); +int snd_pcm_direct_initialize_secondary_slave(snd_pcm_direct_t *dmix, snd_pcm_t *spcm, struct slave_params *params); int snd_pcm_direct_initialize_poll_fd(snd_pcm_direct_t *dmix); int snd_pcm_direct_check_interleave(snd_pcm_direct_t *dmix, snd_pcm_t *pcm); int snd_pcm_direct_parse_bindings(snd_pcm_direct_t *dmix, diff --git a/src/pcm/pcm_dmix.c b/src/pcm/pcm_dmix.c index 366d69f6..9bd0bd09 100644 --- a/src/pcm/pcm_dmix.c +++ b/src/pcm/pcm_dmix.c @@ -650,8 +650,10 @@ static int snd_pcm_dmix_close(snd_pcm_t *pcm) if (dmix->client) snd_pcm_direct_client_discard(dmix); shm_sum_discard(dmix); - snd_pcm_direct_shm_discard(dmix); - snd_pcm_direct_semaphore_up(dmix, DIRECT_IPC_SEM_CLIENT); + if (snd_pcm_direct_shm_discard(dmix)) + snd_pcm_direct_semaphore_discard(dmix); + else + snd_pcm_direct_semaphore_up(dmix, DIRECT_IPC_SEM_CLIENT); free(dmix->bindings); pcm->private_data = NULL; free(dmix); @@ -877,28 +879,54 @@ int snd_pcm_dmix_open(snd_pcm_t **pcmp, const char *name, dmix->spcm = spcm; - dmix->server_free = dmix_server_free; + if (dmix->shmptr->use_server) { + dmix->server_free = dmix_server_free; - ret = snd_pcm_direct_server_create(dmix); - if (ret < 0) { - SNDERR("unable to create server"); - goto _err; + ret = snd_pcm_direct_server_create(dmix); + if (ret < 0) { + SNDERR("unable to create server"); + goto _err; + } } dmix->shmptr->type = spcm->type; } else { - /* up semaphore to avoid deadlock */ - snd_pcm_direct_semaphore_up(dmix, DIRECT_IPC_SEM_CLIENT); - ret = snd_pcm_direct_client_connect(dmix); - if (ret < 0) { - SNDERR("unable to connect client"); - goto _err_nosem; - } + if (dmix->shmptr->use_server) { + /* up semaphore to avoid deadlock */ + snd_pcm_direct_semaphore_up(dmix, DIRECT_IPC_SEM_CLIENT); + ret = snd_pcm_direct_client_connect(dmix); + if (ret < 0) { + SNDERR("unable to connect client"); + goto _err_nosem; + } - snd_pcm_direct_semaphore_down(dmix, DIRECT_IPC_SEM_CLIENT); - ret = snd_pcm_direct_open_secondary_client(&spcm, dmix, "dmix_client"); - if (ret < 0) - goto _err; + snd_pcm_direct_semaphore_down(dmix, DIRECT_IPC_SEM_CLIENT); + ret = snd_pcm_direct_open_secondary_client(&spcm, dmix, "dmix_client"); + if (ret < 0) + goto _err; + } else { + + ret = snd_pcm_open_slave(&spcm, root, sconf, stream, + mode | SND_PCM_NONBLOCK | + SND_PCM_APPEND, + NULL); + if (ret < 0) { + SNDERR("unable to open slave"); + goto _err; + } + if (snd_pcm_type(spcm) != SND_PCM_TYPE_HW) { + SNDERR("dmix plugin can be only connected to hw plugin"); + ret = -EINVAL; + goto _err; + } + + ret = snd_pcm_direct_initialize_secondary_slave(dmix, spcm, params); + if (ret < 0) { + SNDERR("unable to initialize slave"); + goto _err; + } + } + dmix->spcm = spcm; } diff --git a/src/pcm/pcm_dshare.c b/src/pcm/pcm_dshare.c index 88535e56..54f82a33 100644 --- a/src/pcm/pcm_dshare.c +++ b/src/pcm/pcm_dshare.c @@ -464,8 +464,10 @@ static int snd_pcm_dshare_close(snd_pcm_t *pcm) snd_pcm_direct_server_discard(dshare); if (dshare->client) snd_pcm_direct_client_discard(dshare); - snd_pcm_direct_shm_discard(dshare); - snd_pcm_direct_semaphore_up(dshare, DIRECT_IPC_SEM_CLIENT); + if (snd_pcm_direct_shm_discard(dshare)) + snd_pcm_direct_semaphore_discard(dshare); + else + snd_pcm_direct_semaphore_up(dshare, DIRECT_IPC_SEM_CLIENT); free(dshare->bindings); pcm->private_data = NULL; free(dshare); @@ -688,26 +690,53 @@ int snd_pcm_dshare_open(snd_pcm_t **pcmp, const char *name, dshare->spcm = spcm; - ret = snd_pcm_direct_server_create(dshare); - if (ret < 0) { - SNDERR("unable to create server"); - goto _err; + if (dshare->shmptr->use_server) { + ret = snd_pcm_direct_server_create(dshare); + if (ret < 0) { + SNDERR("unable to create server"); + goto _err; + } } dshare->shmptr->type = spcm->type; } else { - /* up semaphore to avoid deadlock */ - snd_pcm_direct_semaphore_up(dshare, DIRECT_IPC_SEM_CLIENT); - ret = snd_pcm_direct_client_connect(dshare); - if (ret < 0) { - SNDERR("unable to connect client"); - goto _err_nosem; - } + if (dshare->shmptr->use_server) { + /* up semaphore to avoid deadlock */ + snd_pcm_direct_semaphore_up(dshare, DIRECT_IPC_SEM_CLIENT); + ret = snd_pcm_direct_client_connect(dshare); + if (ret < 0) { + SNDERR("unable to connect client"); + goto _err_nosem; + } - snd_pcm_direct_semaphore_down(dshare, DIRECT_IPC_SEM_CLIENT); - ret = snd_pcm_direct_open_secondary_client(&spcm, dshare, "dshare_client"); - if (ret < 0) - goto _err; + snd_pcm_direct_semaphore_down(dshare, DIRECT_IPC_SEM_CLIENT); + ret = snd_pcm_direct_open_secondary_client(&spcm, dshare, "dshare_client"); + if (ret < 0) + goto _err; + + } else { + + ret = snd_pcm_open_slave(&spcm, root, sconf, stream, + mode | SND_PCM_NONBLOCK | + SND_PCM_APPEND, + NULL); + if (ret < 0) { + SNDERR("unable to open slave"); + goto _err; + } + if (snd_pcm_type(spcm) != SND_PCM_TYPE_HW) { + SNDERR("dshare plugin can be only connected to hw plugin"); + ret = -EINVAL; + goto _err; + } + + ret = snd_pcm_direct_initialize_secondary_slave(dshare, spcm, params); + if (ret < 0) { + SNDERR("unable to initialize slave"); + goto _err; + } + } + dshare->spcm = spcm; } diff --git a/src/pcm/pcm_dsnoop.c b/src/pcm/pcm_dsnoop.c index 537e09cb..954826f1 100644 --- a/src/pcm/pcm_dsnoop.c +++ b/src/pcm/pcm_dsnoop.c @@ -360,8 +360,10 @@ static int snd_pcm_dsnoop_close(snd_pcm_t *pcm) snd_pcm_direct_server_discard(dsnoop); if (dsnoop->client) snd_pcm_direct_client_discard(dsnoop); - snd_pcm_direct_shm_discard(dsnoop); - snd_pcm_direct_semaphore_up(dsnoop, DIRECT_IPC_SEM_CLIENT); + if (snd_pcm_direct_shm_discard(dsnoop)) + snd_pcm_direct_semaphore_discard(dsnoop); + else + snd_pcm_direct_semaphore_up(dsnoop, DIRECT_IPC_SEM_CLIENT); free(dsnoop->bindings); pcm->private_data = NULL; free(dsnoop); @@ -570,27 +572,53 @@ int snd_pcm_dsnoop_open(snd_pcm_t **pcmp, const char *name, dsnoop->spcm = spcm; - ret = snd_pcm_direct_server_create(dsnoop); - if (ret < 0) { - SNDERR("unable to create server"); - goto _err; + if (dsnoop->shmptr->use_server) { + ret = snd_pcm_direct_server_create(dsnoop); + if (ret < 0) { + SNDERR("unable to create server"); + goto _err; + } } dsnoop->shmptr->type = spcm->type; } else { - /* up semaphore to avoid deadlock */ - snd_pcm_direct_semaphore_up(dsnoop, DIRECT_IPC_SEM_CLIENT); - ret = snd_pcm_direct_client_connect(dsnoop); - if (ret < 0) { - SNDERR("unable to connect client"); - goto _err_nosem; - } + if (dsnoop->shmptr->use_server) { + /* up semaphore to avoid deadlock */ + snd_pcm_direct_semaphore_up(dsnoop, DIRECT_IPC_SEM_CLIENT); + ret = snd_pcm_direct_client_connect(dsnoop); + if (ret < 0) { + SNDERR("unable to connect client"); + goto _err_nosem; + } - snd_pcm_direct_semaphore_down(dsnoop, DIRECT_IPC_SEM_CLIENT); + snd_pcm_direct_semaphore_down(dsnoop, DIRECT_IPC_SEM_CLIENT); + + ret = snd_pcm_direct_open_secondary_client(&spcm, dsnoop, "dsnoop_client"); + if (ret < 0) + goto _err; + } else { + + ret = snd_pcm_open_slave(&spcm, root, sconf, stream, + mode | SND_PCM_NONBLOCK | + SND_PCM_APPEND, + NULL); + if (ret < 0) { + SNDERR("unable to open slave"); + goto _err; + } + if (snd_pcm_type(spcm) != SND_PCM_TYPE_HW) { + SNDERR("dsnoop plugin can be only connected to hw plugin"); + ret = -EINVAL; + goto _err; + } + + ret = snd_pcm_direct_initialize_secondary_slave(dsnoop, spcm, params); + if (ret < 0) { + SNDERR("unable to initialize slave"); + goto _err; + } + } - ret = snd_pcm_direct_open_secondary_client(&spcm, dsnoop, "dsnoop_client"); - if (ret < 0) - goto _err; dsnoop->spcm = spcm; } diff --git a/src/pcm/pcm_hw.c b/src/pcm/pcm_hw.c index 59e68dfd..5dffb494 100644 --- a/src/pcm/pcm_hw.c +++ b/src/pcm/pcm_hw.c @@ -1240,6 +1240,8 @@ int snd_pcm_hw_open(snd_pcm_t **pcmp, const char *name, fmode |= O_NONBLOCK; if (mode & SND_PCM_ASYNC) fmode |= O_ASYNC; + if (mode & SND_PCM_APPEND) + fmode |= O_APPEND; fd = snd_open_device(filename, fmode); if (fd < 0) { ret = -errno; diff --git a/src/pcm/pcm_local.h b/src/pcm/pcm_local.h index be17e7a2..e691e693 100644 --- a/src/pcm/pcm_local.h +++ b/src/pcm/pcm_local.h @@ -746,6 +746,8 @@ int snd_pcm_hw_strategy_simple_choices(snd_pcm_hw_strategy_t *strategy, int orde int snd_pcm_slave_conf(snd_config_t *root, snd_config_t *conf, snd_config_t **pcm_conf, unsigned int count, ...); +#define SND_PCM_APPEND (1<<8) + int snd_pcm_open_slave(snd_pcm_t **pcmp, snd_config_t *root, snd_config_t *conf, snd_pcm_stream_t stream, int mode, snd_config_t *parent_conf); -- 2.47.1