From 573f85dc1d68223040bb74697da32679875bc1d7 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Wed, 23 Apr 2003 12:41:55 +0000 Subject: [PATCH] - added shm area manager code - fixed parsing of period_size/buffer_size options for dmix, dsnoop and dshare plugins --- include/global.h | 7 +++++++ src/Makefile.am | 2 +- src/pcm/pcm.c | 5 ++++- src/pcm/pcm_direct.c | 2 ++ src/pcm/pcm_direct.h | 7 +++++-- src/pcm/pcm_dmix.c | 17 +++++++++++++--- src/pcm/pcm_dshare.c | 4 ++-- src/pcm/pcm_dsnoop.c | 4 ++-- src/pcm/pcm_hw.c | 29 +++------------------------- src/pcm/pcm_local.h | 2 +- src/pcm/pcm_mmap.c | 46 +++++++++++++++++++++++++------------------- 11 files changed, 67 insertions(+), 58 deletions(-) diff --git a/include/global.h b/include/global.h index 8e59f073..2969949b 100644 --- a/include/global.h +++ b/include/global.h @@ -114,6 +114,13 @@ int snd_async_handler_get_fd(snd_async_handler_t *handler); 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 */ diff --git a/src/Makefile.am b/src/Makefile.am index afe7d59b..feeec572 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -9,7 +9,7 @@ VSYMS = 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 \ diff --git a/src/pcm/pcm.c b/src/pcm/pcm.c index b7ec2670..36fb018a 100644 --- a/src/pcm/pcm.c +++ b/src/pcm/pcm.c @@ -6246,7 +6246,10 @@ static const char *names[SND_PCM_HW_PARAM_LAST_INTERVAL + 1] = { [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, diff --git a/src/pcm/pcm_direct.c b/src/pcm/pcm_direct.c index 5a0f146d..dded984c 100644 --- a/src/pcm/pcm_direct.c +++ b/src/pcm/pcm_direct.c @@ -278,6 +278,8 @@ static void server_job(snd_pcm_direct_t *dmix) } 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"); diff --git a/src/pcm/pcm_direct.h b/src/pcm/pcm_direct.h index fd9e1c10..bb60b9fc 100644 --- a/src/pcm/pcm_direct.h +++ b/src/pcm/pcm_direct.h @@ -72,7 +72,9 @@ typedef struct { } 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 */ @@ -109,7 +111,8 @@ typedef struct { 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); diff --git a/src/pcm/pcm_dmix.c b/src/pcm/pcm_dmix.c index 3d381e2f..0361c742 100644 --- a/src/pcm/pcm_dmix.c +++ b/src/pcm/pcm_dmix.c @@ -96,6 +96,13 @@ static int shm_sum_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 @@ -954,6 +961,8 @@ int snd_pcm_dmix_open(snd_pcm_t **pcmp, const char *name, } dmix->spcm = spcm; + + dmix->server_free = dmix_server_free; ret = snd_pcm_direct_server_create(dmix); if (ret < 0) { @@ -992,7 +1001,7 @@ int snd_pcm_dmix_open(snd_pcm_t **pcmp, const char *name, 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; } @@ -1177,20 +1186,22 @@ int _snd_pcm_dmix_open(snd_pcm_t **pcmp, const char *name, 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); diff --git a/src/pcm/pcm_dshare.c b/src/pcm/pcm_dshare.c index 54752cee..ec018dc2 100644 --- a/src/pcm/pcm_dshare.c +++ b/src/pcm/pcm_dshare.c @@ -984,8 +984,8 @@ int _snd_pcm_dshare_open(snd_pcm_t **pcmp, const char *name, 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; diff --git a/src/pcm/pcm_dsnoop.c b/src/pcm/pcm_dsnoop.c index cc4403ff..6158caee 100644 --- a/src/pcm/pcm_dsnoop.c +++ b/src/pcm/pcm_dsnoop.c @@ -936,8 +936,8 @@ int _snd_pcm_dsnoop_open(snd_pcm_t **pcmp, const char *name, 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; diff --git a/src/pcm/pcm_hw.c b/src/pcm/pcm_hw.c index e0869438..e64faafc 100644 --- a/src/pcm/pcm_hw.c +++ b/src/pcm/pcm_hw.c @@ -95,7 +95,6 @@ typedef struct { 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" @@ -395,7 +394,7 @@ static int snd_pcm_hw_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t * info 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) @@ -733,35 +732,13 @@ static int snd_pcm_hw_munmap_control(snd_pcm_t *pcm) 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; } diff --git a/src/pcm/pcm_local.h b/src/pcm/pcm_local.h index 5873b1bd..48ba437a 100644 --- a/src/pcm/pcm_local.h +++ b/src/pcm/pcm_local.h @@ -110,8 +110,8 @@ typedef struct _snd_pcm_channel_info { 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; diff --git a/src/pcm/pcm_mmap.c b/src/pcm/pcm_mmap.c index 92320942..31ebec70 100644 --- a/src/pcm/pcm_mmap.c +++ b/src/pcm/pcm_mmap.c @@ -261,8 +261,7 @@ int snd_pcm_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t *info) 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: @@ -282,7 +281,7 @@ int snd_pcm_channel_info_shm(snd_pcm_t *pcm, snd_pcm_channel_info_t *info, 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; } @@ -362,7 +361,16 @@ int snd_pcm_mmap(snd_pcm_t *pcm) 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; @@ -370,15 +378,16 @@ int snd_pcm_mmap(snd_pcm_t *pcm) 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; @@ -446,18 +455,15 @@ int snd_pcm_munmap(snd_pcm_t *pcm) 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: -- 2.47.1