int snd_async_handler_get_signo(snd_async_handler_t *handler);
void *snd_async_handler_get_callback_private(snd_async_handler_t *handler);
+/**
+ * \brief Internal structure for an IPC shm area manager.
+ */
+struct snd_shm_area *snd_shm_area_create(int shmid, void *ptr);
+struct snd_shm_area *snd_shm_area_share(struct snd_shm_area *area);
+int snd_shm_area_destroy(struct snd_shm_area *area);
+
/** Timestamp */
typedef struct timeval snd_timestamp_t;
/** Hi-res timestamp */
endif
lib_LTLIBRARIES = libasound.la
-libasound_la_SOURCES = conf.c confmisc.c input.c output.c async.c error.c dlmisc.c socket.c
+libasound_la_SOURCES = conf.c confmisc.c input.c output.c async.c error.c dlmisc.c socket.c shmarea.c
libasound_la_LIBADD = control/libcontrol.la mixer/libmixer.la pcm/libpcm.la \
rawmidi/librawmidi.la timer/libtimer.la \
hwdep/libhwdep.la seq/libseq.la instr/libinstr.la \
[SND_PCM_HW_PARAM_CHANNELS] = "channels",
[SND_PCM_HW_PARAM_RATE] = "rate",
[SND_PCM_HW_PARAM_PERIOD_TIME] = "period_time",
- [SND_PCM_HW_PARAM_BUFFER_TIME] = "buffer_time"
+ [SND_PCM_HW_PARAM_PERIOD_SIZE] = "period_size",
+ [SND_PCM_HW_PARAM_BUFFER_TIME] = "buffer_time",
+ [SND_PCM_HW_PARAM_BUFFER_SIZE] = "buffer_size",
+ [SND_PCM_HW_PARAM_PERIODS] = "periods"
};
int snd_pcm_slave_conf(snd_config_t *root, snd_config_t *conf,
}
close(dmix->server_fd);
close(dmix->hw_fd);
+ if (dmix->server_free)
+ dmix->server_free(dmix);
snd_pcm_direct_shm_discard(dmix);
snd_pcm_direct_semaphore_discard(dmix);
server_printf("DIRECT SERVER EXIT\n");
} u;
} snd_pcm_direct_share_t;
-typedef struct {
+typedef struct snd_pcm_direct snd_pcm_direct_t;
+
+struct snd_pcm_direct {
snd_pcm_type_t type; /* type (dmix, dsnoop, dshare) */
key_t ipc_key; /* IPC key for semaphore and memory */
int semid; /* IPC global semaphore identification */
unsigned long long chn_mask;
} dshare;
} u;
-} snd_pcm_direct_t;
+ void (*server_free)(snd_pcm_direct_t *direct);
+};
int snd_pcm_direct_semaphore_create_or_connect(snd_pcm_direct_t *dmix);
int snd_pcm_direct_semaphore_discard(snd_pcm_direct_t *dmix);
return ret;
}
+static void dmix_server_free(snd_pcm_direct_t *dmix)
+{
+ /* remove the memory region */
+ shm_sum_create_or_connect(dmix);
+ shm_sum_discard(dmix);
+}
+
/*
* the main function of this plugin: mixing
* FIXME: optimize it for different architectures
}
dmix->spcm = spcm;
+
+ dmix->server_free = dmix_server_free;
ret = snd_pcm_direct_server_create(dmix);
if (ret < 0) {
ret = shm_sum_create_or_connect(dmix);
if (ret < 0) {
- SNDERR("unabel to initialize sum ring buffer");
+ SNDERR("unable to initialize sum ring buffer");
goto _err;
}
params.buffer_time = -1;
bsize = psize = -1;
params.periods = 3;
+
err = snd_pcm_slave_conf(root, slave, &sconf, 8,
SND_PCM_HW_PARAM_FORMAT, 0, ¶ms.format,
SND_PCM_HW_PARAM_RATE, 0, ¶ms.rate,
SND_PCM_HW_PARAM_CHANNELS, 0, ¶ms.channels,
SND_PCM_HW_PARAM_PERIOD_TIME, 0, ¶ms.period_time,
SND_PCM_HW_PARAM_BUFFER_TIME, 0, ¶ms.buffer_time,
- SND_PCM_HW_PARAM_PERIOD_SIZE, 0, &bsize,
- SND_PCM_HW_PARAM_BUFFER_SIZE, 0, &psize,
+ SND_PCM_HW_PARAM_PERIOD_SIZE, 0, &psize,
+ SND_PCM_HW_PARAM_BUFFER_SIZE, 0, &bsize,
SND_PCM_HW_PARAM_PERIODS, 0, ¶ms.periods);
if (err < 0)
return err;
params.period_size = psize;
params.buffer_size = bsize;
+
err = snd_pcm_dmix_open(pcmp, name, ipc_key, ¶ms, bindings, root, sconf, stream, mode);
if (err < 0)
snd_config_delete(sconf);
SND_PCM_HW_PARAM_CHANNELS, 0, ¶ms.channels,
SND_PCM_HW_PARAM_PERIOD_TIME, 0, ¶ms.period_time,
SND_PCM_HW_PARAM_BUFFER_TIME, 0, ¶ms.buffer_time,
- SND_PCM_HW_PARAM_PERIOD_SIZE, 0, &bsize,
- SND_PCM_HW_PARAM_BUFFER_SIZE, 0, &psize,
+ SND_PCM_HW_PARAM_PERIOD_SIZE, 0, &psize,
+ SND_PCM_HW_PARAM_BUFFER_SIZE, 0, &bsize,
SND_PCM_HW_PARAM_PERIODS, 0, ¶ms.periods);
if (err < 0)
return err;
SND_PCM_HW_PARAM_CHANNELS, 0, ¶ms.channels,
SND_PCM_HW_PARAM_PERIOD_TIME, 0, ¶ms.period_time,
SND_PCM_HW_PARAM_BUFFER_TIME, 0, ¶ms.buffer_time,
- SND_PCM_HW_PARAM_PERIOD_SIZE, 0, &bsize,
- SND_PCM_HW_PARAM_BUFFER_SIZE, 0, &psize,
+ SND_PCM_HW_PARAM_PERIOD_SIZE, 0, &psize,
+ SND_PCM_HW_PARAM_BUFFER_SIZE, 0, &bsize,
SND_PCM_HW_PARAM_PERIODS, 0, ¶ms.periods);
if (err < 0)
return err;
avail_update_flag: 1,
mmap_shm: 1;
snd_pcm_uframes_t appl_ptr;
- int shmid;
} snd_pcm_hw_t;
#define SNDRV_FILE_PCM_STREAM_PLAYBACK "/dev/snd/pcmC%iD%ip"
info->u.mmap.offset = i.offset;
return 0;
}
- return snd_pcm_channel_info_shm(pcm, info, hw->shmid);
+ return snd_pcm_channel_info_shm(pcm, info, -1);
}
static int snd_pcm_hw_status(snd_pcm_t *pcm, snd_pcm_status_t * status)
return 0;
}
-static int snd_pcm_hw_mmap(snd_pcm_t *pcm)
+static int snd_pcm_hw_mmap(snd_pcm_t *pcm ATTRIBUTE_UNUSED)
{
- snd_pcm_hw_t *hw = pcm->private_data;
- int err;
- if (hw->mmap_shm) {
- snd_pcm_uframes_t size = snd_pcm_frames_to_bytes(pcm, (snd_pcm_sframes_t) pcm->buffer_size);
- int id = shmget(IPC_PRIVATE, size, 0666);
- hw->mmap_shm = 1;
- if (id < 0) {
- err = -errno;
- SYSERR("shmget failed");
- return err;
- }
- hw->shmid = id;
- }
return 0;
}
-static int snd_pcm_hw_munmap(snd_pcm_t *pcm)
+static int snd_pcm_hw_munmap(snd_pcm_t *pcm ATTRIBUTE_UNUSED)
{
- snd_pcm_hw_t *hw = pcm->private_data;
- int err;
- if (hw->mmap_shm) {
- if (shmctl(hw->shmid, IPC_RMID, 0) < 0) {
- err = -errno;
- SYSERR("shmctl IPC_RMID failed");
- return err;
- }
- }
return 0;
}
enum { SND_PCM_AREA_SHM, SND_PCM_AREA_MMAP } type;
union {
struct {
+ struct snd_shm_area *area;
int shmid;
- int remove;
} shm;
struct {
int fd;
return pcm->ops->channel_info(pcm, info);
}
-int snd_pcm_channel_info_shm(snd_pcm_t *pcm, snd_pcm_channel_info_t *info,
- int shmid)
+int snd_pcm_channel_info_shm(snd_pcm_t *pcm, snd_pcm_channel_info_t *info, int shmid)
{
switch (pcm->access) {
case SND_PCM_ACCESS_MMAP_INTERLEAVED:
info->addr = 0;
info->type = SND_PCM_AREA_SHM;
info->u.shm.shmid = shmid;
- info->u.shm.remove = 0;
+ info->u.shm.area = NULL;
return 0;
}
return -errno;
}
i->u.shm.shmid = id;
- i->u.shm.remove = 1;
+ ptr = shmat(i->u.shm.shmid, 0, 0);
+ if (ptr == (void *) -1) {
+ SYSERR("shmat failed");
+ return -errno;
+ }
+ i->u.shm.area = snd_shm_area_create(id, ptr);
+ if (i->u.shm.area == NULL) {
+ SYSERR("snd_shm_area_create failed");
+ return -ENOMEM;
+ }
if (pcm->access == SND_PCM_ACCESS_MMAP_INTERLEAVED ||
pcm->access == SND_PCM_ACCESS_RW_INTERLEAVED) {
unsigned int c1;
snd_pcm_channel_info_t *i1 = &pcm->mmap_channels[c1];
if (i1->u.shm.shmid < 0) {
i1->u.shm.shmid = id;
- i1->u.shm.remove = 1;
+ i1->u.shm.area = snd_shm_area_share(i->u.shm.area);
}
}
}
- }
- ptr = shmat(i->u.shm.shmid, 0, 0);
- if (ptr == (void*) -1) {
- SYSERR("shmat failed");
- return -errno;
+ } else {
+ ptr = shmat(i->u.shm.shmid, 0, 0);
+ if (ptr == (void*) -1) {
+ SYSERR("shmat failed");
+ return -errno;
+ }
}
i->addr = ptr;
break;
errno = 0;
break;
case SND_PCM_AREA_SHM:
- err = shmdt(i->addr);
- if (err < 0) {
- SYSERR("shmdt failed");
- return -errno;
- }
- if (i->u.shm.remove) {
- if (shmctl(i->u.shm.shmid, IPC_RMID, 0) < 0) {
- SYSERR("shmctl IPC_RMID failed");
+ if (i->u.shm.area) {
+ snd_shm_area_destroy(i->u.shm.area);
+ i->u.shm.area = NULL;
+ } else {
+ err = shmdt(i->addr);
+ if (err < 0) {
+ SYSERR("shmdt failed");
return -errno;
}
- i->u.shm.shmid = -1;
- i->u.shm.remove = 0;
}
break;
default: