From ffdb04c3eac74f818b4a19c63b081e46ed3c0518 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 2 Sep 2005 16:36:40 +0000 Subject: [PATCH] Fix buffer allocation and mmap with plugins Fixed the bug producing silent tones with some combinations of plugins. The internal buffer handling is now better (cleaner) integrated with snd_pcm_generic_*(). --- src/pcm/pcm_file.c | 24 ++---------------------- src/pcm/pcm_generic.c | 28 +++++++++++++++++++++++++--- src/pcm/pcm_generic.h | 1 + src/pcm/pcm_local.h | 9 +++++++-- src/pcm/pcm_mmap.c | 5 ----- src/pcm/pcm_null.c | 21 +++------------------ src/pcm/pcm_plug.c | 25 +++---------------------- src/pcm/pcm_rate.c | 7 +------ src/pcm/pcm_softvol.c | 6 ++++++ 9 files changed, 48 insertions(+), 78 deletions(-) diff --git a/src/pcm/pcm_file.c b/src/pcm/pcm_file.c index 3808aaae..e7259444 100644 --- a/src/pcm/pcm_file.c +++ b/src/pcm/pcm_file.c @@ -302,26 +302,6 @@ static int snd_pcm_file_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params) return 0; } -static int snd_pcm_file_mmap(snd_pcm_t *pcm ATTRIBUTE_UNUSED) -{ - snd_pcm_file_t *file = pcm->private_data; - snd_pcm_t *slave = file->gen.slave; - pcm->running_areas = slave->running_areas; - pcm->stopped_areas = slave->stopped_areas; - pcm->mmap_channels = slave->mmap_channels; - pcm->mmap_shadow = 1; - return 0; -} - -static int snd_pcm_file_munmap(snd_pcm_t *pcm ATTRIBUTE_UNUSED) -{ - pcm->mmap_channels = NULL; - pcm->running_areas = NULL; - pcm->stopped_areas = NULL; - pcm->mmap_shadow = 0; - return 0; -} - static void snd_pcm_file_dump(snd_pcm_t *pcm, snd_output_t *out) { snd_pcm_file_t *file = pcm->private_data; @@ -348,8 +328,8 @@ static snd_pcm_ops_t snd_pcm_file_ops = { .dump = snd_pcm_file_dump, .nonblock = snd_pcm_generic_nonblock, .async = snd_pcm_generic_async, - .mmap = snd_pcm_file_mmap, - .munmap = snd_pcm_file_munmap, + .mmap = snd_pcm_generic_mmap, + .munmap = snd_pcm_generic_munmap, }; static snd_pcm_fast_ops_t snd_pcm_file_fast_ops = { diff --git a/src/pcm/pcm_generic.c b/src/pcm/pcm_generic.c index 10f9bea0..295cca6c 100644 --- a/src/pcm/pcm_generic.c +++ b/src/pcm/pcm_generic.c @@ -113,7 +113,16 @@ int snd_pcm_generic_prepare(snd_pcm_t *pcm) int snd_pcm_generic_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t *info) { snd_pcm_generic_t *generic = pcm->private_data; - return snd_pcm_channel_info(generic->slave, info); + if (pcm->mmap_shadow) { + /* No own buffer is required - the plugin won't change + * the data on the buffer, or do safely on-the-place + * conversion + */ + return snd_pcm_channel_info(generic->slave, info); + } else { + /* Allocate own buffer */ + return snd_pcm_channel_info_shm(generic->slave, info, -1); + } } int snd_pcm_generic_status(snd_pcm_t *pcm, snd_pcm_status_t * status) @@ -290,13 +299,26 @@ snd_pcm_sframes_t snd_pcm_generic_avail_update(snd_pcm_t *pcm) return snd_pcm_avail_update(generic->slave); } -int snd_pcm_generic_mmap(snd_pcm_t *pcm ATTRIBUTE_UNUSED) +int snd_pcm_generic_mmap(snd_pcm_t *pcm) { + if (pcm->mmap_shadow) { + /* Copy the slave mmapped buffer data */ + snd_pcm_generic_t *generic = pcm->private_data; + pcm->mmap_channels = generic->slave->mmap_channels; + pcm->running_areas = generic->slave->running_areas; + pcm->stopped_areas = generic->slave->stopped_areas; + } return 0; } -int snd_pcm_generic_munmap(snd_pcm_t *pcm ATTRIBUTE_UNUSED) +int snd_pcm_generic_munmap(snd_pcm_t *pcm) { + if (pcm->mmap_shadow) { + /* Clean up */ + pcm->mmap_channels = NULL; + pcm->running_areas = NULL; + pcm->stopped_areas = NULL; + } return 0; } diff --git a/src/pcm/pcm_generic.h b/src/pcm/pcm_generic.h index 6acb6131..c2339a8c 100644 --- a/src/pcm/pcm_generic.h +++ b/src/pcm/pcm_generic.h @@ -36,6 +36,7 @@ int snd_pcm_generic_sw_params(snd_pcm_t *pcm, snd_pcm_sw_params_t *params); int snd_pcm_generic_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params); int snd_pcm_generic_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t *params); int snd_pcm_generic_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t * info); +int snd_pcm_generic_channel_info_no_buffer(snd_pcm_t *pcm, snd_pcm_channel_info_t * info); int snd_pcm_generic_status(snd_pcm_t *pcm, snd_pcm_status_t * status); snd_pcm_state_t snd_pcm_generic_state(snd_pcm_t *pcm); int snd_pcm_generic_prepare(snd_pcm_t *pcm); diff --git a/src/pcm/pcm_local.h b/src/pcm/pcm_local.h index 45b979c8..24786392 100644 --- a/src/pcm/pcm_local.h +++ b/src/pcm/pcm_local.h @@ -212,7 +212,9 @@ struct _snd_pcm { snd_pcm_rbptr_t hw; snd_pcm_uframes_t min_align; unsigned int mmap_rw: 1; /* use always mmapped buffer */ - unsigned int mmap_shadow: 1; /* don't call actual mmap */ + unsigned int mmap_shadow: 1; /* don't call actual mmap, + * use the mmaped buffer of the slave + */ unsigned int donot_close: 1; /* don't close this PCM */ snd_pcm_channel_info_t *mmap_channels; snd_pcm_channel_area_t *running_areas; @@ -266,7 +268,10 @@ snd_pcm_sframes_t snd_pcm_write_areas(snd_pcm_t *pcm, const snd_pcm_channel_area snd_pcm_xfer_areas_func_t func); snd_pcm_sframes_t snd_pcm_read_mmap(snd_pcm_t *pcm, snd_pcm_uframes_t size); snd_pcm_sframes_t snd_pcm_write_mmap(snd_pcm_t *pcm, snd_pcm_uframes_t size); -int snd_pcm_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t *info); +static inline 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_poll_descriptor(snd_pcm_t *pcm); int _snd_pcm_link_descriptors(snd_pcm_t *pcm, int *fds, int size, int (**failed)(snd_pcm_t *, int)); diff --git a/src/pcm/pcm_mmap.c b/src/pcm/pcm_mmap.c index 876b6494..7015fb6c 100644 --- a/src/pcm/pcm_mmap.c +++ b/src/pcm/pcm_mmap.c @@ -262,11 +262,6 @@ snd_pcm_sframes_t snd_pcm_mmap_readn(snd_pcm_t *pcm, void **bufs, snd_pcm_uframe snd_pcm_mmap_read_areas); } -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) { switch (pcm->access) { diff --git a/src/pcm/pcm_null.c b/src/pcm/pcm_null.c index 6fe4c51c..8fd61fcf 100644 --- a/src/pcm/pcm_null.c +++ b/src/pcm/pcm_null.c @@ -79,11 +79,6 @@ static int snd_pcm_null_info(snd_pcm_t *pcm, snd_pcm_info_t * info) return 0; } -static int snd_pcm_null_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t * info) -{ - return snd_pcm_channel_info_shm(pcm, info, -1); -} - static int snd_pcm_null_status(snd_pcm_t *pcm, snd_pcm_status_t * status) { snd_pcm_null_t *null = pcm->private_data; @@ -276,16 +271,6 @@ static int snd_pcm_null_sw_params(snd_pcm_t *pcm ATTRIBUTE_UNUSED, snd_pcm_sw_pa return 0; } -static int snd_pcm_null_mmap(snd_pcm_t *pcm ATTRIBUTE_UNUSED) -{ - return 0; -} - -static int snd_pcm_null_munmap(snd_pcm_t *pcm ATTRIBUTE_UNUSED) -{ - return 0; -} - static void snd_pcm_null_dump(snd_pcm_t *pcm, snd_output_t *out) { snd_output_printf(out, "Null PCM\n"); @@ -302,12 +287,12 @@ static snd_pcm_ops_t snd_pcm_null_ops = { .hw_params = snd_pcm_null_hw_params, .hw_free = snd_pcm_null_hw_free, .sw_params = snd_pcm_null_sw_params, - .channel_info = snd_pcm_null_channel_info, + .channel_info = snd_pcm_generic_channel_info, .dump = snd_pcm_null_dump, .nonblock = snd_pcm_null_nonblock, .async = snd_pcm_null_async, - .mmap = snd_pcm_null_mmap, - .munmap = snd_pcm_null_munmap, + .mmap = snd_pcm_generic_mmap, + .munmap = snd_pcm_generic_munmap, }; static snd_pcm_fast_ops_t snd_pcm_null_fast_ops = { diff --git a/src/pcm/pcm_plug.c b/src/pcm/pcm_plug.c index 754cedee..c3d4f651 100644 --- a/src/pcm/pcm_plug.c +++ b/src/pcm/pcm_plug.c @@ -917,26 +917,6 @@ static int snd_pcm_plug_hw_free(snd_pcm_t *pcm) return err; } -static int snd_pcm_plug_mmap(snd_pcm_t *pcm) -{ - snd_pcm_plug_t *plug = pcm->private_data; - pcm->mmap_channels = plug->gen.slave->mmap_channels; - pcm->running_areas = plug->gen.slave->running_areas; - pcm->stopped_areas = plug->gen.slave->stopped_areas; - pcm->mmap_shadow = 1; - return 0; -} - -static int snd_pcm_plug_munmap(snd_pcm_t *pcm) -{ - // snd_pcm_plug_t *plug = pcm->private_data; - pcm->mmap_channels = NULL; - pcm->running_areas = NULL; - pcm->stopped_areas = NULL; - pcm->mmap_shadow = 0; - return 0; -} - static void snd_pcm_plug_dump(snd_pcm_t *pcm, snd_output_t *out) { snd_pcm_plug_t *plug = pcm->private_data; @@ -955,8 +935,8 @@ static snd_pcm_ops_t snd_pcm_plug_ops = { .dump = snd_pcm_plug_dump, .nonblock = snd_pcm_generic_nonblock, .async = snd_pcm_generic_async, - .mmap = snd_pcm_plug_mmap, - .munmap = snd_pcm_plug_munmap, + .mmap = snd_pcm_generic_mmap, + .munmap = snd_pcm_generic_munmap, }; /** @@ -1010,6 +990,7 @@ int snd_pcm_plug_open(snd_pcm_t **pcmp, pcm->private_data = plug; pcm->poll_fd = slave->poll_fd; pcm->poll_events = slave->poll_events; + pcm->mmap_shadow = 1; snd_pcm_link_hw_ptr(pcm, slave); snd_pcm_link_appl_ptr(pcm, slave); *pcmp = pcm; diff --git a/src/pcm/pcm_rate.c b/src/pcm/pcm_rate.c index f166a2e2..ca6bb52d 100644 --- a/src/pcm/pcm_rate.c +++ b/src/pcm/pcm_rate.c @@ -620,11 +620,6 @@ static int snd_pcm_rate_hw_free(snd_pcm_t *pcm) return snd_pcm_hw_free(rate->gen.slave); } -static int snd_pcm_rate_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t * info) -{ - return snd_pcm_channel_info_shm(pcm, info, -1); -} - static void recalc(snd_pcm_t *pcm, snd_pcm_uframes_t *val) { snd_pcm_rate_t *rate = pcm->private_data; @@ -1393,7 +1388,7 @@ static snd_pcm_ops_t snd_pcm_rate_ops = { .hw_params = snd_pcm_rate_hw_params, .hw_free = snd_pcm_rate_hw_free, .sw_params = snd_pcm_rate_sw_params, - .channel_info = snd_pcm_rate_channel_info, + .channel_info = snd_pcm_generic_channel_info, .dump = snd_pcm_rate_dump, .nonblock = snd_pcm_generic_nonblock, .async = snd_pcm_generic_async, diff --git a/src/pcm/pcm_softvol.c b/src/pcm/pcm_softvol.c index 2b7a9449..5c0413d8 100644 --- a/src/pcm/pcm_softvol.c +++ b/src/pcm/pcm_softvol.c @@ -658,6 +658,12 @@ int snd_pcm_softvol_open(snd_pcm_t **pcmp, const char *name, pcm->private_data = svol; pcm->poll_fd = slave->poll_fd; pcm->poll_events = slave->poll_events; + /* + * Since the softvol converts on the place, and the format/channels + * must be identical between source and destination, we don't need + * an extra buffer. + */ + pcm->mmap_shadow = 1; snd_pcm_set_hw_ptr(pcm, &svol->plug.hw_ptr, -1, 0); snd_pcm_set_appl_ptr(pcm, &svol->plug.appl_ptr, -1, 0); *pcmp = pcm; -- 2.47.1