return 0;
}
+#define SND_PCM_DIRECT_MAGIC 0xa15ad319
+
/*
* global shared memory area
*/
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;
}
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;
}
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;
};
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;
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,
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);
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;
}
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);
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;
}
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);
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;
}
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;
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);