* [PATCH 1/2] ALSA: pcm: rewrite snd_pcm_playback_silence()
@ 2023-04-05 20:12 Oswald Buddenhagen
2023-04-05 20:12 ` [PATCH 2/2] ALSA: pcm: auto-fill buffer with silence when draining playback Oswald Buddenhagen
` (2 more replies)
0 siblings, 3 replies; 29+ messages in thread
From: Oswald Buddenhagen @ 2023-04-05 20:12 UTC (permalink / raw)
To: alsa-devel
The auto-silencer supports two modes: "thresholded" to fill up "just
enough", and "top-up" to fill up "as much as possible". The two modes
used rather distinct code paths, which this patch unifies. The only
remaining distinction is how much we actually want to fill.
This fixes a bug in thresholded mode, where we failed to use new_hw_ptr,
resulting in under-fill.
Top-up mode is now more well-behaved and much easier to understand in
corner cases.
This also updates comments in the proximity of silencing-related data
structures.
Signed-off-by: Oswald Buddenhagen <oswald.buddenhagen@gmx.de>
---
.../kernel-api/writing-an-alsa-driver.rst | 14 +--
include/sound/pcm.h | 14 +--
include/uapi/sound/asound.h | 9 +-
sound/core/pcm_lib.c | 86 ++++++++-----------
sound/core/pcm_local.h | 3 +-
sound/core/pcm_native.c | 6 +-
6 files changed, 62 insertions(+), 70 deletions(-)
diff --git a/Documentation/sound/kernel-api/writing-an-alsa-driver.rst b/Documentation/sound/kernel-api/writing-an-alsa-driver.rst
index a368529e8ed3..f2834a016473 100644
--- a/Documentation/sound/kernel-api/writing-an-alsa-driver.rst
+++ b/Documentation/sound/kernel-api/writing-an-alsa-driver.rst
@@ -1577,14 +1577,16 @@ are the contents of this file:
unsigned int period_step;
unsigned int sleep_min; /* min ticks to sleep */
snd_pcm_uframes_t start_threshold;
- snd_pcm_uframes_t stop_threshold;
- snd_pcm_uframes_t silence_threshold; /* Silence filling happens when
- noise is nearest than this */
- snd_pcm_uframes_t silence_size; /* Silence filling size */
+ // The following two thresholds alleviate playback buffer underruns; when
+ // hw_avail drops below the threshold, the respective action is triggered:
+ snd_pcm_uframes_t stop_threshold; /* stop playback */
+ snd_pcm_uframes_t silence_threshold; /* pre-fill buffer with silence */
+ snd_pcm_uframes_t silence_size; /* msx size of silence pre-fill */
snd_pcm_uframes_t boundary; /* pointers wrap point */
- snd_pcm_uframes_t silenced_start;
- snd_pcm_uframes_t silenced_size;
+ // internal data of auto-silencer
+ snd_pcm_uframes_t silence_start; /* starting pointer to silence area */
+ snd_pcm_uframes_t silence_filled; /* size filled with silence */
snd_pcm_sync_id_t sync; /* hardware synchronization ID */
diff --git a/include/sound/pcm.h b/include/sound/pcm.h
index 27040b472a4f..f20400bb7032 100644
--- a/include/sound/pcm.h
+++ b/include/sound/pcm.h
@@ -378,18 +378,18 @@ struct snd_pcm_runtime {
unsigned int rate_den;
unsigned int no_period_wakeup: 1;
- /* -- SW params -- */
- int tstamp_mode; /* mmap timestamp is updated */
+ /* -- SW params; see struct snd_pcm_sw_params for comments -- */
+ int tstamp_mode;
unsigned int period_step;
snd_pcm_uframes_t start_threshold;
snd_pcm_uframes_t stop_threshold;
- snd_pcm_uframes_t silence_threshold; /* Silence filling happens when
- noise is nearest than this */
- snd_pcm_uframes_t silence_size; /* Silence filling size */
- snd_pcm_uframes_t boundary; /* pointers wrap point */
+ snd_pcm_uframes_t silence_threshold;
+ snd_pcm_uframes_t silence_size;
+ snd_pcm_uframes_t boundary;
+ // internal data of auto-silencer
snd_pcm_uframes_t silence_start; /* starting pointer to silence area */
- snd_pcm_uframes_t silence_filled; /* size filled with silence */
+ snd_pcm_uframes_t silence_filled; /* already filled part of silence area */
union snd_pcm_sync_id sync; /* hardware synchronization ID */
diff --git a/include/uapi/sound/asound.h b/include/uapi/sound/asound.h
index de6810e94abe..50aa1d98873f 100644
--- a/include/uapi/sound/asound.h
+++ b/include/uapi/sound/asound.h
@@ -429,9 +429,12 @@ struct snd_pcm_sw_params {
snd_pcm_uframes_t avail_min; /* min avail frames for wakeup */
snd_pcm_uframes_t xfer_align; /* obsolete: xfer size need to be a multiple */
snd_pcm_uframes_t start_threshold; /* min hw_avail frames for automatic start */
- snd_pcm_uframes_t stop_threshold; /* min avail frames for automatic stop */
- snd_pcm_uframes_t silence_threshold; /* min distance from noise for silence filling */
- snd_pcm_uframes_t silence_size; /* silence block size */
+ // The following two thresholds alleviate playback buffer underruns; when
+ // hw_avail drops below the threshold, the respective action is triggered:
+ snd_pcm_uframes_t stop_threshold; /* stop playback */
+ snd_pcm_uframes_t silence_threshold; /* pre-fill buffer with silence */
+ snd_pcm_uframes_t silence_size; /* max size of silence pre-fill; when >= boundary,
+ * fill played area with silence immediately */
snd_pcm_uframes_t boundary; /* pointers wrap point */
unsigned int proto; /* protocol version */
unsigned int tstamp_type; /* timestamp type (req. proto >= 2.0.12) */
diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c
index 02fd65993e7e..b074c5b926db 100644
--- a/sound/core/pcm_lib.c
+++ b/sound/core/pcm_lib.c
@@ -42,70 +42,58 @@ static int fill_silence_frames(struct snd_pcm_substream *substream,
*
* when runtime->silence_size >= runtime->boundary - fill processed area with silence immediately
*/
-void snd_pcm_playback_silence(struct snd_pcm_substream *substream, snd_pcm_uframes_t new_hw_ptr)
+void snd_pcm_playback_silence(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
+ snd_pcm_uframes_t appl_ptr = READ_ONCE(runtime->control->appl_ptr);
+ snd_pcm_sframes_t hw_avail, added, noise_dist;
snd_pcm_uframes_t frames, ofs, transfer;
int err;
+ // This will "legitimately" turn negative on underrun, and will be mangled
+ // into a huge number by the boundary crossing handling. The initial state
+ // might also be not quite sane. The code below MUST account for these cases.
+ hw_avail = appl_ptr - runtime->status->hw_ptr;
+ if (hw_avail < 0)
+ hw_avail += runtime->boundary;
+ else if ((snd_pcm_uframes_t) hw_avail >= runtime->boundary)
+ hw_avail -= runtime->boundary;
+
+ added = appl_ptr - runtime->silence_start;
+ if (added) {
+ if (added < 0)
+ added += runtime->boundary;
+ if ((snd_pcm_uframes_t)added < runtime->silence_filled)
+ runtime->silence_filled -= added;
+ else
+ runtime->silence_filled = 0;
+ runtime->silence_start = appl_ptr;
+ }
+
+ noise_dist = hw_avail + runtime->silence_filled;
if (runtime->silence_size < runtime->boundary) {
- snd_pcm_sframes_t noise_dist, n;
- snd_pcm_uframes_t appl_ptr = READ_ONCE(runtime->control->appl_ptr);
- if (runtime->silence_start != appl_ptr) {
- n = appl_ptr - runtime->silence_start;
- if (n < 0)
- n += runtime->boundary;
- if ((snd_pcm_uframes_t)n < runtime->silence_filled)
- runtime->silence_filled -= n;
- else
- runtime->silence_filled = 0;
- runtime->silence_start = appl_ptr;
- }
- if (runtime->silence_filled >= runtime->buffer_size)
- return;
- noise_dist = snd_pcm_playback_hw_avail(runtime) + runtime->silence_filled;
- if (noise_dist >= (snd_pcm_sframes_t) runtime->silence_threshold)
- return;
frames = runtime->silence_threshold - noise_dist;
+ if ((snd_pcm_sframes_t) frames <= 0)
+ return;
if (frames > runtime->silence_size)
frames = runtime->silence_size;
} else {
- if (new_hw_ptr == ULONG_MAX) { /* initialization */
- snd_pcm_sframes_t avail = snd_pcm_playback_hw_avail(runtime);
- if (avail > runtime->buffer_size)
- avail = runtime->buffer_size;
- runtime->silence_filled = avail > 0 ? avail : 0;
- runtime->silence_start = (runtime->status->hw_ptr +
- runtime->silence_filled) %
- runtime->boundary;
- } else {
- ofs = runtime->status->hw_ptr;
- frames = new_hw_ptr - ofs;
- if ((snd_pcm_sframes_t)frames < 0)
- frames += runtime->boundary;
- runtime->silence_filled -= frames;
- if ((snd_pcm_sframes_t)runtime->silence_filled < 0) {
- runtime->silence_filled = 0;
- runtime->silence_start = new_hw_ptr;
- } else {
- runtime->silence_start = ofs;
- }
- }
- frames = runtime->buffer_size - runtime->silence_filled;
+ frames = runtime->buffer_size - noise_dist;
+ if ((snd_pcm_sframes_t) frames <= 0)
+ return;
}
+
if (snd_BUG_ON(frames > runtime->buffer_size))
return;
- if (frames == 0)
- return;
- ofs = runtime->silence_start % runtime->buffer_size;
- while (frames > 0) {
+ ofs = (runtime->silence_start + runtime->silence_filled) % runtime->buffer_size;
+ do {
transfer = ofs + frames > runtime->buffer_size ? runtime->buffer_size - ofs : frames;
err = fill_silence_frames(substream, ofs, transfer);
snd_BUG_ON(err < 0);
runtime->silence_filled += transfer;
frames -= transfer;
ofs = 0;
- }
+ } while (frames > 0);
snd_pcm_dma_buffer_sync(substream, SNDRV_DMA_SYNC_DEVICE);
}
@@ -439,10 +427,6 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream,
return 0;
}
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
- runtime->silence_size > 0)
- snd_pcm_playback_silence(substream, new_hw_ptr);
-
if (in_interrupt) {
delta = new_hw_ptr - runtime->hw_ptr_interrupt;
if (delta < 0)
@@ -460,6 +444,10 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream,
runtime->hw_ptr_wrap += runtime->boundary;
}
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
+ runtime->silence_size > 0)
+ snd_pcm_playback_silence(substream);
+
update_audio_tstamp(substream, &curr_tstamp, &audio_tstamp);
return snd_pcm_update_state(substream, runtime);
diff --git a/sound/core/pcm_local.h b/sound/core/pcm_local.h
index ecb21697ae3a..42fe3a4e9154 100644
--- a/sound/core/pcm_local.h
+++ b/sound/core/pcm_local.h
@@ -29,8 +29,7 @@ int snd_pcm_update_state(struct snd_pcm_substream *substream,
struct snd_pcm_runtime *runtime);
int snd_pcm_update_hw_ptr(struct snd_pcm_substream *substream);
-void snd_pcm_playback_silence(struct snd_pcm_substream *substream,
- snd_pcm_uframes_t new_hw_ptr);
+void snd_pcm_playback_silence(struct snd_pcm_substream *substream);
static inline snd_pcm_uframes_t
snd_pcm_avail(struct snd_pcm_substream *substream)
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index 331380c2438b..0e3e7997dc58 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -958,7 +958,7 @@ static int snd_pcm_sw_params(struct snd_pcm_substream *substream,
if (snd_pcm_running(substream)) {
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
runtime->silence_size > 0)
- snd_pcm_playback_silence(substream, ULONG_MAX);
+ snd_pcm_playback_silence(substream);
err = snd_pcm_update_state(substream, runtime);
}
snd_pcm_stream_unlock_irq(substream);
@@ -1455,7 +1455,7 @@ static void snd_pcm_post_start(struct snd_pcm_substream *substream,
__snd_pcm_set_state(runtime, state);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
runtime->silence_size > 0)
- snd_pcm_playback_silence(substream, ULONG_MAX);
+ snd_pcm_playback_silence(substream);
snd_pcm_timer_notify(substream, SNDRV_TIMER_EVENT_MSTART);
}
@@ -1916,7 +1916,7 @@ static void snd_pcm_post_reset(struct snd_pcm_substream *substream,
runtime->control->appl_ptr = runtime->status->hw_ptr;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
runtime->silence_size > 0)
- snd_pcm_playback_silence(substream, ULONG_MAX);
+ snd_pcm_playback_silence(substream);
snd_pcm_stream_unlock_irq(substream);
}
--
2.40.0.152.g15d061e6df
^ permalink raw reply related [flat|nested] 29+ messages in thread
* [PATCH 2/2] ALSA: pcm: auto-fill buffer with silence when draining playback
2023-04-05 20:12 [PATCH 1/2] ALSA: pcm: rewrite snd_pcm_playback_silence() Oswald Buddenhagen
@ 2023-04-05 20:12 ` Oswald Buddenhagen
2023-04-07 23:58 ` Jaroslav Kysela
2023-04-06 14:53 ` [PATCH 1/2] ALSA: pcm: rewrite snd_pcm_playback_silence() Takashi Iwai
2023-04-11 10:47 ` Jaroslav Kysela
2 siblings, 1 reply; 29+ messages in thread
From: Oswald Buddenhagen @ 2023-04-05 20:12 UTC (permalink / raw)
To: alsa-devel
Draining will always playback somewhat beyond the end of the filled
buffer. This would produce artifacts if the user did not set up the
auto-silencing machinery. This patch makes it work out of the box.
Rather than figuring out the right threshold (which is one period plus
the card-specific FIFO size plus some IRQ jitter), we use "top-up" mode.
Signed-off-by: Oswald Buddenhagen <oswald.buddenhagen@gmx.de>
---
sound/core/pcm_lib.c | 5 +++--
sound/core/pcm_native.c | 3 ++-
2 files changed, 5 insertions(+), 3 deletions(-)
diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c
index b074c5b926db..1dd870a2093d 100644
--- a/sound/core/pcm_lib.c
+++ b/sound/core/pcm_lib.c
@@ -71,7 +71,8 @@ void snd_pcm_playback_silence(struct snd_pcm_substream *substream)
}
noise_dist = hw_avail + runtime->silence_filled;
- if (runtime->silence_size < runtime->boundary) {
+ if (runtime->silence_size < runtime->boundary &&
+ runtime->state != SNDRV_PCM_STATE_DRAINING) {
frames = runtime->silence_threshold - noise_dist;
if ((snd_pcm_sframes_t) frames <= 0)
return;
@@ -445,7 +446,7 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream,
}
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
- runtime->silence_size > 0)
+ (runtime->silence_size > 0 || runtime->state == SNDRV_PCM_STATE_DRAINING))
snd_pcm_playback_silence(substream);
update_audio_tstamp(substream, &curr_tstamp, &audio_tstamp);
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index 0e3e7997dc58..6ecb6a733606 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -1454,7 +1454,7 @@ static void snd_pcm_post_start(struct snd_pcm_substream *substream,
runtime->rate;
__snd_pcm_set_state(runtime, state);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
- runtime->silence_size > 0)
+ (runtime->silence_size > 0 || state == SNDRV_PCM_STATE_DRAINING))
snd_pcm_playback_silence(substream);
snd_pcm_timer_notify(substream, SNDRV_TIMER_EVENT_MSTART);
}
@@ -2045,6 +2045,7 @@ static int snd_pcm_do_drain_init(struct snd_pcm_substream *substream,
break;
case SNDRV_PCM_STATE_RUNNING:
__snd_pcm_set_state(runtime, SNDRV_PCM_STATE_DRAINING);
+ snd_pcm_playback_silence(substream);
break;
case SNDRV_PCM_STATE_XRUN:
__snd_pcm_set_state(runtime, SNDRV_PCM_STATE_SETUP);
--
2.40.0.152.g15d061e6df
^ permalink raw reply related [flat|nested] 29+ messages in thread
* Re: [PATCH 1/2] ALSA: pcm: rewrite snd_pcm_playback_silence()
2023-04-05 20:12 [PATCH 1/2] ALSA: pcm: rewrite snd_pcm_playback_silence() Oswald Buddenhagen
2023-04-05 20:12 ` [PATCH 2/2] ALSA: pcm: auto-fill buffer with silence when draining playback Oswald Buddenhagen
@ 2023-04-06 14:53 ` Takashi Iwai
2023-04-11 10:47 ` Jaroslav Kysela
2 siblings, 0 replies; 29+ messages in thread
From: Takashi Iwai @ 2023-04-06 14:53 UTC (permalink / raw)
To: Oswald Buddenhagen; +Cc: alsa-devel
On Wed, 05 Apr 2023 22:12:18 +0200,
Oswald Buddenhagen wrote:
>
> The auto-silencer supports two modes: "thresholded" to fill up "just
> enough", and "top-up" to fill up "as much as possible". The two modes
> used rather distinct code paths, which this patch unifies. The only
> remaining distinction is how much we actually want to fill.
>
> This fixes a bug in thresholded mode, where we failed to use new_hw_ptr,
> resulting in under-fill.
>
> Top-up mode is now more well-behaved and much easier to understand in
> corner cases.
>
> This also updates comments in the proximity of silencing-related data
> structures.
>
> Signed-off-by: Oswald Buddenhagen <oswald.buddenhagen@gmx.de>
Applied both patches now to for-next branch.
thanks,
Takashi
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH 2/2] ALSA: pcm: auto-fill buffer with silence when draining playback
2023-04-05 20:12 ` [PATCH 2/2] ALSA: pcm: auto-fill buffer with silence when draining playback Oswald Buddenhagen
@ 2023-04-07 23:58 ` Jaroslav Kysela
2023-04-08 5:55 ` Takashi Iwai
2023-04-08 7:24 ` Oswald Buddenhagen
0 siblings, 2 replies; 29+ messages in thread
From: Jaroslav Kysela @ 2023-04-07 23:58 UTC (permalink / raw)
To: Oswald Buddenhagen, alsa-devel, Takashi Iwai
On 05. 04. 23 22:12, Oswald Buddenhagen wrote:
> Draining will always playback somewhat beyond the end of the filled
> buffer. This would produce artifacts if the user did not set up the
> auto-silencing machinery. This patch makes it work out of the box.
>
> Rather than figuring out the right threshold (which is one period plus
> the card-specific FIFO size plus some IRQ jitter), we use "top-up" mode.
>
> Signed-off-by: Oswald Buddenhagen <oswald.buddenhagen@gmx.de>
I think that it was really bad decision to apply this patch without a broader
discussion. When we designed the API, we knew about described problems and we
decided to keep this up to applications. The silencing may not help in all
cases where the PCM samples ends with a high volume. A volume ramping should
be used and it's an application job. Also, silencing touches the DMA buffer
which may not be desired. And lastly drivers can handle draining correctly
(stop at the exact position - see substream->ops->trigger with
SNDRV_PCM_TRIGGER_DRAIN argument).
I would create a new API extension for this (new ioctl or sw_params flag), but
the default behaviour should be retained.
I will try to review the first patch too, but my time is limited over Easter.
Jaroslav
--
Jaroslav Kysela <perex@perex.cz>
Linux Sound Maintainer; ALSA Project; Red Hat, Inc.
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH 2/2] ALSA: pcm: auto-fill buffer with silence when draining playback
2023-04-07 23:58 ` Jaroslav Kysela
@ 2023-04-08 5:55 ` Takashi Iwai
2023-04-08 7:24 ` Oswald Buddenhagen
1 sibling, 0 replies; 29+ messages in thread
From: Takashi Iwai @ 2023-04-08 5:55 UTC (permalink / raw)
To: Jaroslav Kysela; +Cc: Oswald Buddenhagen, alsa-devel
On Sat, 08 Apr 2023 01:58:21 +0200,
Jaroslav Kysela wrote:
>
> On 05. 04. 23 22:12, Oswald Buddenhagen wrote:
> > Draining will always playback somewhat beyond the end of the filled
> > buffer. This would produce artifacts if the user did not set up the
> > auto-silencing machinery. This patch makes it work out of the box.
> >
> > Rather than figuring out the right threshold (which is one period plus
> > the card-specific FIFO size plus some IRQ jitter), we use "top-up" mode.
> >
> > Signed-off-by: Oswald Buddenhagen <oswald.buddenhagen@gmx.de>
>
> I think that it was really bad decision to apply this patch without a
> broader discussion. When we designed the API, we knew about described
> problems and we decided to keep this up to applications. The silencing
> may not help in all cases where the PCM samples ends with a high
> volume. A volume ramping should be used and it's an application
> job. Also, silencing touches the DMA buffer which may not be
> desired. And lastly drivers can handle draining correctly (stop at the
> exact position - see substream->ops->trigger with
> SNDRV_PCM_TRIGGER_DRAIN argument).
>
> I would create a new API extension for this (new ioctl or sw_params
> flag), but the default behaviour should be retained.
>
> I will try to review the first patch too, but my time is limited over Easter.
OK, thanks. I'll drop the patch meanwhile.
Applying the silencing blindly might be an overkill, indeed, although
this could be seen as an easy solution. Let's see.
Takashi
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH 2/2] ALSA: pcm: auto-fill buffer with silence when draining playback
2023-04-07 23:58 ` Jaroslav Kysela
2023-04-08 5:55 ` Takashi Iwai
@ 2023-04-08 7:24 ` Oswald Buddenhagen
2023-04-11 11:09 ` Jaroslav Kysela
1 sibling, 1 reply; 29+ messages in thread
From: Oswald Buddenhagen @ 2023-04-08 7:24 UTC (permalink / raw)
To: Jaroslav Kysela; +Cc: alsa-devel, Takashi Iwai
On Sat, Apr 08, 2023 at 01:58:21AM +0200, Jaroslav Kysela wrote:
>On 05. 04. 23 22:12, Oswald Buddenhagen wrote:
>> Draining will always playback somewhat beyond the end of the filled
>> buffer. This would produce artifacts if the user did not set up the
>> auto-silencing machinery. This patch makes it work out of the box.
>>
>I think that it was really bad decision to apply this patch without a
>broader discussion.
>When we designed the API, we knew about described problems and we
>decided to keep this up to applications.
>
i ran into no documentation of either the problems nor the decisions and
their implications for the user.
>The silencing may not help in all cases where the PCM samples ends with
>a high volume.
>
that would just create a slight crack, which isn't any different from a
"regular" sudden stop.
> A volume ramping should be used and it's an application job.
>
imo, that entirely misses the point - the volume is most likely already
zero at the end of the buffer. that doesn't mean that it's ok to play
the samples again where the volume might not be *quite* zero yet.
>Also, silencing touches the DMA buffer which may not be desired.
>
hypothetically, yes. but practically? why would anyone want to play the
same samples after draining? draining is most likely followed by closing
the device. and even if not, in most cases (esp. where draining would
actually make sense) one wouldn't play a fixed pattern that could be
just re-used, so one would have to re-fill the buffer prior to starting
again anyway. never mind the effort necessary to track the state of the
buffer instead of just re-filling it. so for all practical purposes,
already played samples can be considered undefined data and thus safe to
overwrite.
>And lastly drivers can handle draining correctly (stop at the exact
>position - see substream->ops->trigger with SNDRV_PCM_TRIGGER_DRAIN
>argument).
>
yeah. hypothetically. afaict, there is exactly one driver which supports
this. most (older) hardware wouldn't even have the capability to do such
precise timing without external help.
On Sat, Apr 08, 2023 at 07:55:48AM +0200, Takashi Iwai wrote:
>Applying the silencing blindly might be an overkill, indeed, although
>this could be seen as an easy solution. Let's see.
>
i don't think that "overkill" is right here. someone has to do the
silencing for draining to be useful at all, and so the question is only
who that should be. my argument is that not auto-silencing is
*extremely* unexpected, and thus just bad api. i'm pretty certain that
about 99% of the usages of DRAIN start out missing this, and most never
get fixed.
imo, if any api is added, it should be to opt *out* of auto-silencing.
but i don't think this makes any sense; there would be ~zero users of
this ever.
regards
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH 1/2] ALSA: pcm: rewrite snd_pcm_playback_silence()
2023-04-05 20:12 [PATCH 1/2] ALSA: pcm: rewrite snd_pcm_playback_silence() Oswald Buddenhagen
2023-04-05 20:12 ` [PATCH 2/2] ALSA: pcm: auto-fill buffer with silence when draining playback Oswald Buddenhagen
2023-04-06 14:53 ` [PATCH 1/2] ALSA: pcm: rewrite snd_pcm_playback_silence() Takashi Iwai
@ 2023-04-11 10:47 ` Jaroslav Kysela
2023-04-12 10:33 ` Oswald Buddenhagen
2 siblings, 1 reply; 29+ messages in thread
From: Jaroslav Kysela @ 2023-04-11 10:47 UTC (permalink / raw)
To: Oswald Buddenhagen, alsa-devel, Takashi Iwai
On 05. 04. 23 22:12, Oswald Buddenhagen wrote:
> The auto-silencer supports two modes: "thresholded" to fill up "just
> enough", and "top-up" to fill up "as much as possible". The two modes
> used rather distinct code paths, which this patch unifies. The only
> remaining distinction is how much we actually want to fill.
>
> This fixes a bug in thresholded mode, where we failed to use new_hw_ptr,
> resulting in under-fill.
I don't follow what you refer here. The old code uses
snd_pcm_playback_hw_avail() thus new hw_ptr for the threshold mode, too.
> Top-up mode is now more well-behaved and much easier to understand in
> corner cases.
>
> This also updates comments in the proximity of silencing-related data
> structures.
>
> Signed-off-by: Oswald Buddenhagen <oswald.buddenhagen@gmx.de>
> ---
> .../kernel-api/writing-an-alsa-driver.rst | 14 +--
> include/sound/pcm.h | 14 +--
> include/uapi/sound/asound.h | 9 +-
> sound/core/pcm_lib.c | 86 ++++++++-----------
> sound/core/pcm_local.h | 3 +-
> sound/core/pcm_native.c | 6 +-
> 6 files changed, 62 insertions(+), 70 deletions(-)
>
> diff --git a/Documentation/sound/kernel-api/writing-an-alsa-driver.rst b/Documentation/sound/kernel-api/writing-an-alsa-driver.rst
> index a368529e8ed3..f2834a016473 100644
> --- a/Documentation/sound/kernel-api/writing-an-alsa-driver.rst
> +++ b/Documentation/sound/kernel-api/writing-an-alsa-driver.rst
> @@ -1577,14 +1577,16 @@ are the contents of this file:
> unsigned int period_step;
> unsigned int sleep_min; /* min ticks to sleep */
> snd_pcm_uframes_t start_threshold;
> - snd_pcm_uframes_t stop_threshold;
> - snd_pcm_uframes_t silence_threshold; /* Silence filling happens when
> - noise is nearest than this */
> - snd_pcm_uframes_t silence_size; /* Silence filling size */
> + // The following two thresholds alleviate playback buffer underruns; when
> + // hw_avail drops below the threshold, the respective action is triggered:
> + snd_pcm_uframes_t stop_threshold; /* stop playback */
> + snd_pcm_uframes_t silence_threshold; /* pre-fill buffer with silence */
> + snd_pcm_uframes_t silence_size; /* msx size of silence pre-fill */
> snd_pcm_uframes_t boundary; /* pointers wrap point */
>
> - snd_pcm_uframes_t silenced_start;
> - snd_pcm_uframes_t silenced_size;
> + // internal data of auto-silencer
> + snd_pcm_uframes_t silence_start; /* starting pointer to silence area */
> + snd_pcm_uframes_t silence_filled; /* size filled with silence */
>
> snd_pcm_sync_id_t sync; /* hardware synchronization ID */
>
> diff --git a/include/sound/pcm.h b/include/sound/pcm.h
> index 27040b472a4f..f20400bb7032 100644
> --- a/include/sound/pcm.h
> +++ b/include/sound/pcm.h
> @@ -378,18 +378,18 @@ struct snd_pcm_runtime {
> unsigned int rate_den;
> unsigned int no_period_wakeup: 1;
>
> - /* -- SW params -- */
> - int tstamp_mode; /* mmap timestamp is updated */
> + /* -- SW params; see struct snd_pcm_sw_params for comments -- */
> + int tstamp_mode;
> unsigned int period_step;
> snd_pcm_uframes_t start_threshold;
> snd_pcm_uframes_t stop_threshold;
> - snd_pcm_uframes_t silence_threshold; /* Silence filling happens when
> - noise is nearest than this */
> - snd_pcm_uframes_t silence_size; /* Silence filling size */
> - snd_pcm_uframes_t boundary; /* pointers wrap point */
> + snd_pcm_uframes_t silence_threshold;
> + snd_pcm_uframes_t silence_size;
> + snd_pcm_uframes_t boundary;
>
> + // internal data of auto-silencer
I would use traditional C-style comment style here (to match other descriptions).
> snd_pcm_uframes_t silence_start; /* starting pointer to silence area */
> - snd_pcm_uframes_t silence_filled; /* size filled with silence */
> + snd_pcm_uframes_t silence_filled; /* already filled part of silence area */
>
> union snd_pcm_sync_id sync; /* hardware synchronization ID */
>
> diff --git a/include/uapi/sound/asound.h b/include/uapi/sound/asound.h
> index de6810e94abe..50aa1d98873f 100644
> --- a/include/uapi/sound/asound.h
> +++ b/include/uapi/sound/asound.h
> @@ -429,9 +429,12 @@ struct snd_pcm_sw_params {
> snd_pcm_uframes_t avail_min; /* min avail frames for wakeup */
> snd_pcm_uframes_t xfer_align; /* obsolete: xfer size need to be a multiple */
> snd_pcm_uframes_t start_threshold; /* min hw_avail frames for automatic start */
> - snd_pcm_uframes_t stop_threshold; /* min avail frames for automatic stop */
> - snd_pcm_uframes_t silence_threshold; /* min distance from noise for silence filling */
> - snd_pcm_uframes_t silence_size; /* silence block size */
> + // The following two thresholds alleviate playback buffer underruns; when
> + // hw_avail drops below the threshold, the respective action is triggered:
Traditional C-style comments.
> + snd_pcm_uframes_t stop_threshold; /* stop playback */
> + snd_pcm_uframes_t silence_threshold; /* pre-fill buffer with silence */
> + snd_pcm_uframes_t silence_size; /* max size of silence pre-fill; when >= boundary,
> + * fill played area with silence immediately */
> snd_pcm_uframes_t boundary; /* pointers wrap point */
> unsigned int proto; /* protocol version */
> unsigned int tstamp_type; /* timestamp type (req. proto >= 2.0.12) */
> diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c
> index 02fd65993e7e..b074c5b926db 100644
> --- a/sound/core/pcm_lib.c
> +++ b/sound/core/pcm_lib.c
> @@ -42,70 +42,58 @@ static int fill_silence_frames(struct snd_pcm_substream *substream,
> *
> * when runtime->silence_size >= runtime->boundary - fill processed area with silence immediately
> */
> -void snd_pcm_playback_silence(struct snd_pcm_substream *substream, snd_pcm_uframes_t new_hw_ptr)
> +void snd_pcm_playback_silence(struct snd_pcm_substream *substream)
> {
> struct snd_pcm_runtime *runtime = substream->runtime;
> + snd_pcm_uframes_t appl_ptr = READ_ONCE(runtime->control->appl_ptr);
> + snd_pcm_sframes_t hw_avail, added, noise_dist;
> snd_pcm_uframes_t frames, ofs, transfer;
> int err;
>
> + // This will "legitimately" turn negative on underrun, and will be mangled
> + // into a huge number by the boundary crossing handling. The initial state
> + // might also be not quite sane. The code below MUST account for these cases.
> + hw_avail = appl_ptr - runtime->status->hw_ptr;
> + if (hw_avail < 0)
> + hw_avail += runtime->boundary;
> + else if ((snd_pcm_uframes_t) hw_avail >= runtime->boundary)
> + hw_avail -= runtime->boundary;
If hw_avail is above runtime->boundary then the initial condition is totaly
bogus. I would use snd_BUG_ON() and direct return here.
> +
> + added = appl_ptr - runtime->silence_start;
> + if (added) {
> + if (added < 0)
> + added += runtime->boundary;
> + if ((snd_pcm_uframes_t)added < runtime->silence_filled)
> + runtime->silence_filled -= added;
> + else
> + runtime->silence_filled = 0;
> + runtime->silence_start = appl_ptr;
> + }
> +
> + noise_dist = hw_avail + runtime->silence_filled;
> if (runtime->silence_size < runtime->boundary) {
> - snd_pcm_sframes_t noise_dist, n;
...
> - if (noise_dist >= (snd_pcm_sframes_t) runtime->silence_threshold)
> - return;
> frames = runtime->silence_threshold - noise_dist;
> + if ((snd_pcm_sframes_t) frames <= 0)
> + return;
The retyping does not look good here. Could we move the if before frames
assignment like:
if (runtime->silence_threshold <= noise_dist)
return;
frames = runtime->silence_threshold - noise_dist;
> if (frames > runtime->silence_size)
> frames = runtime->silence_size;
> } else {
> - if (new_hw_ptr == ULONG_MAX) { /* initialization */
...
> - frames = runtime->buffer_size - runtime->silence_filled;
> + frames = runtime->buffer_size - noise_dist;
> + if ((snd_pcm_sframes_t) frames <= 0)
> + return;
Similar thing, move the check before the frames assignment.
Jaroslav
--
Jaroslav Kysela <perex@perex.cz>
Linux Sound Maintainer; ALSA Project; Red Hat, Inc.
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH 2/2] ALSA: pcm: auto-fill buffer with silence when draining playback
2023-04-08 7:24 ` Oswald Buddenhagen
@ 2023-04-11 11:09 ` Jaroslav Kysela
2023-04-11 13:57 ` Oswald Buddenhagen
0 siblings, 1 reply; 29+ messages in thread
From: Jaroslav Kysela @ 2023-04-11 11:09 UTC (permalink / raw)
To: alsa-devel, Takashi Iwai, Oswald Buddenhagen
On 08. 04. 23 9:24, Oswald Buddenhagen wrote:
> On Sat, Apr 08, 2023 at 01:58:21AM +0200, Jaroslav Kysela wrote:
>> On 05. 04. 23 22:12, Oswald Buddenhagen wrote:
>>> Draining will always playback somewhat beyond the end of the filled
>>> buffer. This would produce artifacts if the user did not set up the
>>> auto-silencing machinery. This patch makes it work out of the box.
>>>
>> I think that it was really bad decision to apply this patch without a
>> broader discussion.
>
>> When we designed the API, we knew about described problems and we
>> decided to keep this up to applications.
>>
> i ran into no documentation of either the problems nor the decisions and
> their implications for the user.
The documentation may be improved, but the "period transfers" are described.
>> The silencing may not help in all cases where the PCM samples ends with
>> a high volume.
>>
> that would just create a slight crack, which isn't any different from a
> "regular" sudden stop.
>
>> A volume ramping should be used and it's an application job.
>>
> imo, that entirely misses the point - the volume is most likely already
> zero at the end of the buffer. that doesn't mean that it's ok to play
> the samples again where the volume might not be *quite* zero yet.
>
>> Also, silencing touches the DMA buffer which may not be desired.
>>
> hypothetically, yes. but practically? why would anyone want to play the
> same samples after draining? draining is most likely followed by closing
> the device. and even if not, in most cases (esp. where draining would
> actually make sense) one wouldn't play a fixed pattern that could be
> just re-used, so one would have to re-fill the buffer prior to starting
> again anyway. never mind the effort necessary to track the state of the
> buffer instead of just re-filling it. so for all practical purposes,
> already played samples can be considered undefined data and thus safe to
> overwrite.
The buffers can be mmaped so used directly for application and hardware. I
don't really feel that it's a good thing to modify this buffer for playback
when the application has not requested for that.
>> And lastly drivers can handle draining correctly (stop at the exact
>> position - see substream->ops->trigger with SNDRV_PCM_TRIGGER_DRAIN
>> argument).
>>
> yeah. hypothetically. afaict, there is exactly one driver which supports
> this. most (older) hardware wouldn't even have the capability to do such
> precise timing without external help.
Most hardware has FIFO and most drivers uses the DMA position, so I think that
the interrupt -> stop DMA latency may be covered with this FIFO in most cases.
But I would really keep this on the driver code to handle this rather than do
the forced silencing.
> On Sat, Apr 08, 2023 at 07:55:48AM +0200, Takashi Iwai wrote:
>> Applying the silencing blindly might be an overkill, indeed, although
>> this could be seen as an easy solution. Let's see.
>>
> i don't think that "overkill" is right here. someone has to do the
> silencing for draining to be useful at all, and so the question is only
> who that should be. my argument is that not auto-silencing is
> *extremely* unexpected, and thus just bad api. i'm pretty certain that
> about 99% of the usages of DRAIN start out missing this, and most never
> get fixed.
Again, I would improve the documentation. Also, the silencing is controlled
using sw_params, so applications may request the silencing before drain.
> imo, if any api is added, it should be to opt *out* of auto-silencing.
> but i don't think this makes any sense; there would be ~zero users of
> this ever.
Lastly, I think that you cannot call updated snd_pcm_playback_silence()
function with runtime->silence_size == 0.
if (runtime->silence_size < runtime->boundary) {
frames = runtime->silence_threshold - noise_dist;
if ((snd_pcm_sframes_t) frames <= 0)
return;
if (frames > runtime->silence_size)
frames = runtime->silence_size;
} else {
The frames variable will be 0, so your code will do nothing.
Jaroslav
--
Jaroslav Kysela <perex@perex.cz>
Linux Sound Maintainer; ALSA Project; Red Hat, Inc.
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH 2/2] ALSA: pcm: auto-fill buffer with silence when draining playback
2023-04-11 11:09 ` Jaroslav Kysela
@ 2023-04-11 13:57 ` Oswald Buddenhagen
2023-04-11 14:48 ` Jaroslav Kysela
0 siblings, 1 reply; 29+ messages in thread
From: Oswald Buddenhagen @ 2023-04-11 13:57 UTC (permalink / raw)
To: Jaroslav Kysela; +Cc: alsa-devel, Takashi Iwai
On Tue, Apr 11, 2023 at 01:09:59PM +0200, Jaroslav Kysela wrote:
>On 08. 04. 23 9:24, Oswald Buddenhagen wrote:
>>> Also, silencing touches the DMA buffer which may not be desired.
>>>
>> hypothetically, yes. but practically? [...]
>
>The buffers can be mmaped so used directly for application and
>hardware.
>
yes, and they are owned by the hardware/driver. an application would
know better than doing with them anything they were not designed for.
>>> And lastly drivers can handle draining correctly (stop at the exact
>>> position - see substream->ops->trigger with SNDRV_PCM_TRIGGER_DRAIN
>>> argument).
>>>
>> yeah. hypothetically. afaict, there is exactly one driver which supports
>> this. most (older) hardware wouldn't even have the capability to do such
>> precise timing without external help.
>
>Most hardware has FIFO and most drivers uses the DMA position, so I think that
>the interrupt -> stop DMA latency may be covered with this FIFO in most cases.
>
on most hardware it would be quite a stunt to re-program the buffer
pointers on the fly to enable a mid-period interrupt. and given the
reliability problems insisted on by takashi in the other thread, the
approach seems questionable at best. and that's still ignoring the
effort of migrating tens (hundreds?) of drivers.
>Again, I would improve the documentation.
>
no amount of documentation will fix a bad api. it's just not how humans
work.
>the silencing is controlled using sw_params, so applications may
>request the silencing before drain.
>
yeah, they could, but they don't, and most won't ever.
you're arguing for not doing a very practical and simple change that
will fix a lot of user code at once, for the sake of preventing an
entirely hypothetical and implausible problem. that is not a good
trade-off.
>Lastly, I think that you cannot call updated snd_pcm_playback_silence()
>function with runtime->silence_size == 0.
>
> if (runtime->silence_size < runtime->boundary) {
>
you missed the hunk that adjusts the code accordingly.
regards
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH 2/2] ALSA: pcm: auto-fill buffer with silence when draining playback
2023-04-11 13:57 ` Oswald Buddenhagen
@ 2023-04-11 14:48 ` Jaroslav Kysela
2023-04-11 16:50 ` Oswald Buddenhagen
0 siblings, 1 reply; 29+ messages in thread
From: Jaroslav Kysela @ 2023-04-11 14:48 UTC (permalink / raw)
To: alsa-devel, Takashi Iwai, Oswald Buddenhagen
On 11. 04. 23 15:57, Oswald Buddenhagen wrote:
> On Tue, Apr 11, 2023 at 01:09:59PM +0200, Jaroslav Kysela wrote:
>> On 08. 04. 23 9:24, Oswald Buddenhagen wrote:
>>>> Also, silencing touches the DMA buffer which may not be desired.
>>>>
>>> hypothetically, yes. but practically? [...]
>>
>> The buffers can be mmaped so used directly for application and
>> hardware.
>>
> yes, and they are owned by the hardware/driver. an application would
> know better than doing with them anything they were not designed for.
>
>>>> And lastly drivers can handle draining correctly (stop at the exact
>>>> position - see substream->ops->trigger with SNDRV_PCM_TRIGGER_DRAIN
>>>> argument).
>>>>
>>> yeah. hypothetically. afaict, there is exactly one driver which supports
>>> this. most (older) hardware wouldn't even have the capability to do such
>>> precise timing without external help.
>>
>> Most hardware has FIFO and most drivers uses the DMA position, so I think that
>> the interrupt -> stop DMA latency may be covered with this FIFO in most cases.
>>
> on most hardware it would be quite a stunt to re-program the buffer
> pointers on the fly to enable a mid-period interrupt. and given the
> reliability problems insisted on by takashi in the other thread, the
> approach seems questionable at best. and that's still ignoring the
> effort of migrating tens (hundreds?) of drivers.
I said to not change things at the moment. Drivers may be revised at some
point. If we have large buffers, the silencing may consume many CPU ticks. If
the driver already behaves nicely for the drain operation, this is an extra
step which should be avoided. This can be handled using new snd_pcm_ops, of
course.
You're using a hammer to fix a little issue.
>> Again, I would improve the documentation.
>>
> no amount of documentation will fix a bad api. it's just not how humans
> work.
Which code does not fill the last period? Alsa utilities do it. We can
eventually handle this in alsa-lib.
>> the silencing is controlled using sw_params, so applications may
>> request the silencing before drain.
>>
> yeah, they could, but they don't, and most won't ever.
>
> you're arguing for not doing a very practical and simple change that
> will fix a lot of user code at once, for the sake of preventing an
> entirely hypothetical and implausible problem. that is not a good
> trade-off.
I'm arguing that we should not do anything extra with the buffers until the
application requests that. That's the clear API context.
>> Lastly, I think that you cannot call updated snd_pcm_playback_silence()
>> function with runtime->silence_size == 0.
>>
>> if (runtime->silence_size < runtime->boundary) {
>>
> you missed the hunk that adjusts the code accordingly.
Ohh, yes. You're right.
If we allow modification of the PCM buffer, I think that we should:
- Do not modify the buffer for drivers already working with the
appl_ptr data (end position) only.
- Handle the situation with the large buffer; it may make sense
to change the "wait" operation from the end-of-period interrupt to time
scheduler and stop the drain more early when the end-of-valid data condition
is fulfilled.
- Increase the protocol version.
But as I wrote, I would make those extensions configurable
(SNDRV_PCM_HW_PARAMS_DRAIN_ALLOW_SILENCE). It can be turned on by default.
Jaroslav
--
Jaroslav Kysela <perex@perex.cz>
Linux Sound Maintainer; ALSA Project; Red Hat, Inc.
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH 2/2] ALSA: pcm: auto-fill buffer with silence when draining playback
2023-04-11 14:48 ` Jaroslav Kysela
@ 2023-04-11 16:50 ` Oswald Buddenhagen
2023-04-11 17:23 ` Jaroslav Kysela
0 siblings, 1 reply; 29+ messages in thread
From: Oswald Buddenhagen @ 2023-04-11 16:50 UTC (permalink / raw)
To: alsa-devel
On Tue, Apr 11, 2023 at 04:48:58PM +0200, Jaroslav Kysela wrote:
>You're using a hammer to fix a little issue.
>
yes, but at the time it seemed like a rather small hammer to me.
if large buffers are actually a thing (what for?), then the fill could
be limited to two periods or something. it would make the code uglier,
though.
>Which code does not fill the last period?
>
a lot, i imagine - doing that is rather counter-intuitive when using the
write() access method.
also, just the last period is not enough, due to the fifo, and possibly
delayed/lost irqs.
>>> the silencing is controlled using sw_params, so applications may
>>> request the silencing before drain.
>>>
>> yeah, they could, but they don't, and most won't ever.
>>
>> you're arguing for not doing a very practical and simple change that
>> will fix a lot of user code at once, for the sake of preventing an
>> entirely hypothetical and implausible problem. that is not a good
>> trade-off.
>
>I'm arguing that we should not do anything extra with the buffers until
>the application requests that.
>That's the clear API context.
>
no, it's not. you cannot assume this to be understood as the central
guiding principle which trumps more immediate issues. people use an api
to solve a specific problem, and they want to do that with the least
effort possible. no-one is going to read the whole docu top to bottom
and remember every caveat. if it appears to work, people will just call
it a day, and that's exactly what will be the case with the use of DRAIN
(one needs a somewhat specific configuration and content to even notice
that there is a problem).
>If we allow modification of the PCM buffer, I think that we should:
>
>- Do not modify the buffer for drivers already working with the
> appl_ptr data (end position) only.
>
i suppose that should be detected by the drain callback being set up?
>- Handle the situation with the large buffer; it may make sense
> to change the "wait" operation from the end-of-period interrupt to time
> scheduler and stop the drain more early when the end-of-valid data condition
> is fulfilled.
>
i don't understand what you're asking for.
>- Increase the protocol version.
>
>But as I wrote, I would make those extensions configurable
>(SNDRV_PCM_HW_PARAMS_DRAIN_ALLOW_SILENCE). It can be turned on by default.
>
i have no clue what would be involved in doing that. to me that sounds
like overkill (solving a non-issue), and goes waaaay beyond what i
expected to invest into this issue (really, i just wanted to verify that
the emu10k1 fixes work, and accidentally discovered that there is a
mid-layer issue that affects user space, as the pyalsaaudio lib i'm
using doesn't handle it).
regards
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH 2/2] ALSA: pcm: auto-fill buffer with silence when draining playback
2023-04-11 16:50 ` Oswald Buddenhagen
@ 2023-04-11 17:23 ` Jaroslav Kysela
2023-04-12 7:54 ` Takashi Iwai
0 siblings, 1 reply; 29+ messages in thread
From: Jaroslav Kysela @ 2023-04-11 17:23 UTC (permalink / raw)
To: alsa-devel, Takashi Iwai, Oswald Buddenhagen
On 11. 04. 23 18:50, Oswald Buddenhagen wrote:
>> If we allow modification of the PCM buffer, I think that we should:
>>
>> - Do not modify the buffer for drivers already working with the
>> appl_ptr data (end position) only.
>>
> i suppose that should be detected by the drain callback being set up?
Yes, but it would be probably better to add a default silencing callback with
a warning to notify authors of drivers to review and eventually correct the
behavior.
>> - Handle the situation with the large buffer; it may make sense
>> to change the "wait" operation from the end-of-period interrupt to time
>> scheduler and stop the drain more early when the end-of-valid data condition
>> is fulfilled.
>>
> i don't understand what you're asking for.
Use jiffies/timeout instead waiting to the interrupt. In this case, the stop
may be called earlier (in the middle of period). In this case the silenced
area may be much smaller.
>> - Increase the protocol version.
>>
>> But as I wrote, I would make those extensions configurable
>> (SNDRV_PCM_HW_PARAMS_DRAIN_ALLOW_SILENCE). It can be turned on by default.
>>
> i have no clue what would be involved in doing that. to me that sounds
> like overkill (solving a non-issue), and goes waaaay beyond what i
> expected to invest into this issue (really, i just wanted to verify that
> the emu10k1 fixes work, and accidentally discovered that there is a
> mid-layer issue that affects user space, as the pyalsaaudio lib i'm
> using doesn't handle it).
OK. I don't think that it's a pyalsaudio job to resolve the issue with the
minimal transfer chunk / period (which you set / know before the transfer is
initiated).
Jaroslav
--
Jaroslav Kysela <perex@perex.cz>
Linux Sound Maintainer; ALSA Project; Red Hat, Inc.
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH 2/2] ALSA: pcm: auto-fill buffer with silence when draining playback
2023-04-11 17:23 ` Jaroslav Kysela
@ 2023-04-12 7:54 ` Takashi Iwai
2023-04-12 8:04 ` Oswald Buddenhagen
0 siblings, 1 reply; 29+ messages in thread
From: Takashi Iwai @ 2023-04-12 7:54 UTC (permalink / raw)
To: Jaroslav Kysela; +Cc: alsa-devel, Oswald Buddenhagen
On Tue, 11 Apr 2023 19:23:17 +0200,
Jaroslav Kysela wrote:
>
> On 11. 04. 23 18:50, Oswald Buddenhagen wrote:
>
> >> If we allow modification of the PCM buffer, I think that we should:
> >>
> >> - Do not modify the buffer for drivers already working with the
> >> appl_ptr data (end position) only.
> >>
> > i suppose that should be detected by the drain callback being set up?
>
> Yes, but it would be probably better to add a default silencing
> callback with a warning to notify authors of drivers to review and
> eventually correct the behavior.
>
> >> - Handle the situation with the large buffer; it may make sense
> >> to change the "wait" operation from the end-of-period interrupt to time
> >> scheduler and stop the drain more early when the end-of-valid data condition
> >> is fulfilled.
> >>
> > i don't understand what you're asking for.
>
> Use jiffies/timeout instead waiting to the interrupt. In this case,
> the stop may be called earlier (in the middle of period). In this case
> the silenced area may be much smaller.
Does this difference matter so much? I guess you're concerned about
the performance, right? This sounds a bit too complex just for the
simple purpose...
> >> - Increase the protocol version.
> >>
> >> But as I wrote, I would make those extensions configurable
> >> (SNDRV_PCM_HW_PARAMS_DRAIN_ALLOW_SILENCE). It can be turned on by default.
> >>
> > i have no clue what would be involved in doing that. to me that sounds
> > like overkill (solving a non-issue), and goes waaaay beyond what i
> > expected to invest into this issue (really, i just wanted to verify that
> > the emu10k1 fixes work, and accidentally discovered that there is a
> > mid-layer issue that affects user space, as the pyalsaaudio lib i'm
> > using doesn't handle it).
>
> OK. I don't think that it's a pyalsaudio job to resolve the issue with
> the minimal transfer chunk / period (which you set / know before the
> transfer is initiated).
I'm thinking whether we need to change anything in the kernel side for
this at all. Can't it be changed rather in alsa-lib side instead?
Takashi
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH 2/2] ALSA: pcm: auto-fill buffer with silence when draining playback
2023-04-12 7:54 ` Takashi Iwai
@ 2023-04-12 8:04 ` Oswald Buddenhagen
2023-04-12 10:37 ` Takashi Iwai
0 siblings, 1 reply; 29+ messages in thread
From: Oswald Buddenhagen @ 2023-04-12 8:04 UTC (permalink / raw)
To: alsa-devel
On Wed, Apr 12, 2023 at 09:54:54AM +0200, Takashi Iwai wrote:
>I'm thinking whether we need to change anything in the kernel side for
>this at all. Can't it be changed rather in alsa-lib side instead?
>
it could, but it would be a lot uglier. user space would have to do a
"man-in-the-middle attack" on the data, while in the kernel we can just
slightly modify the consumer. this would be particularly obvious in the
case of write() access.
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH 1/2] ALSA: pcm: rewrite snd_pcm_playback_silence()
2023-04-11 10:47 ` Jaroslav Kysela
@ 2023-04-12 10:33 ` Oswald Buddenhagen
2023-04-12 19:23 ` Jaroslav Kysela
0 siblings, 1 reply; 29+ messages in thread
From: Oswald Buddenhagen @ 2023-04-12 10:33 UTC (permalink / raw)
To: alsa-devel
[-- Attachment #1: Type: text/plain, Size: 1995 bytes --]
On Tue, Apr 11, 2023 at 12:47:26PM +0200, Jaroslav Kysela wrote:
>On 05. 04. 23 22:12, Oswald Buddenhagen wrote:
>> This fixes a bug in thresholded mode, where we failed to use
>> new_hw_ptr,
>> resulting in under-fill.
>
>I don't follow what you refer here. The old code uses
>snd_pcm_playback_hw_avail()
>
yes
>thus new hw_ptr for the threshold mode, too.
>
not before my patch. the silencer was called before the new pointer was
stored. it had to be, as otherwise the delta for top-up mode could not
be calculated.
>> + // This will "legitimately" turn negative on underrun, and will be mangled
>> + // into a huge number by the boundary crossing handling. The initial state
>> + // might also be not quite sane. The code below MUST account for these cases.
>> + hw_avail = appl_ptr - runtime->status->hw_ptr;
>> + if (hw_avail < 0)
>> + hw_avail += runtime->boundary;
>> + else if ((snd_pcm_uframes_t) hw_avail >= runtime->boundary)
>> + hw_avail -= runtime->boundary;
>
>If hw_avail is above runtime->boundary then the initial condition is totaly
>bogus. I would use snd_BUG_ON() and direct return here.
>
this is only there as a result of inlining
snd_pcm_playback_hw_avail()/snd_pcm_playback_avail() somewhat
mindlessly. the check does indeed make no sense, so i'll just drop it.
(the broader lesson of this is the attached patch. i can re-post it
separately if you like it.)
>> frames = runtime->silence_threshold - noise_dist;
>> + if ((snd_pcm_sframes_t) frames <= 0)
>> + return;
>
>The retyping does not look good here. Could we move the if before frames
>assignment like:
>
> if (runtime->silence_threshold <= noise_dist)
> return;
> frames = runtime->silence_threshold - noise_dist;
>
dunno, i don't like it - it's more noisy and imo it loses
expressiveness, as the question we're asking is "how many frames do we
need to fill?".
note that due to use of unsigned types in the runtime struct, such
retyping is rather common in comparisons.
regards
[-- Attachment #2: 0001-ALSA-pcm-reshuffle-implementations-of-snd_pcm_playba.patch --]
[-- Type: text/x-diff, Size: 2635 bytes --]
>From 02b303326b1be1ddb52afb38a384d26d79fa8b53 Mon Sep 17 00:00:00 2001
From: Oswald Buddenhagen <oswald.buddenhagen@gmx.de>
Date: Wed, 12 Apr 2023 12:28:49 +0200
Subject: [PATCH] ALSA: pcm: reshuffle implementations of
snd_pcm_playback_{,hw}_avail()
Implementing snd_pcm_playback_hw_avail() in terms of
snd_pcm_playback_avail() doesn't actually make sense - it should be the
other way around, the opposite of the respective functions for capture.
This makes the code clearer by illustrating the inverse data flow
better, and saving a conditional.
Signed-off-by: Oswald Buddenhagen <oswald.buddenhagen@gmx.de>
---
include/sound/pcm.h | 32 +++++++++++++++-----------------
1 file changed, 15 insertions(+), 17 deletions(-)
diff --git a/include/sound/pcm.h b/include/sound/pcm.h
index f20400bb7032..81854813a567 100644
--- a/include/sound/pcm.h
+++ b/include/sound/pcm.h
@@ -783,22 +783,31 @@ static inline size_t snd_pcm_lib_period_bytes(struct snd_pcm_substream *substrea
return frames_to_bytes(runtime, runtime->period_size);
}
+/**
+ * snd_pcm_playback_hw_avail - Get the queued space for playback
+ * @runtime: PCM runtime instance
+ *
+ * Return: available frame size
+ */
+static inline snd_pcm_sframes_t snd_pcm_playback_hw_avail(struct snd_pcm_runtime *runtime)
+{
+ snd_pcm_sframes_t avail = runtime->control->appl_ptr - runtime->status->hw_ptr;
+ if (avail < 0)
+ avail += runtime->boundary;
+ return avail;
+}
+
/**
* snd_pcm_playback_avail - Get the available (writable) space for playback
* @runtime: PCM runtime instance
*
* Result is between 0 ... (boundary - 1)
*
* Return: available frame size
*/
static inline snd_pcm_uframes_t snd_pcm_playback_avail(struct snd_pcm_runtime *runtime)
{
- snd_pcm_sframes_t avail = runtime->status->hw_ptr + runtime->buffer_size - runtime->control->appl_ptr;
- if (avail < 0)
- avail += runtime->boundary;
- else if ((snd_pcm_uframes_t) avail >= runtime->boundary)
- avail -= runtime->boundary;
- return avail;
+ return runtime->buffer_size - snd_pcm_playback_hw_avail(runtime);
}
/**
@@ -817,17 +826,6 @@ static inline snd_pcm_uframes_t snd_pcm_capture_avail(struct snd_pcm_runtime *ru
return avail;
}
-/**
- * snd_pcm_playback_hw_avail - Get the queued space for playback
- * @runtime: PCM runtime instance
- *
- * Return: available frame size
- */
-static inline snd_pcm_sframes_t snd_pcm_playback_hw_avail(struct snd_pcm_runtime *runtime)
-{
- return runtime->buffer_size - snd_pcm_playback_avail(runtime);
-}
-
/**
* snd_pcm_capture_hw_avail - Get the free space for capture
* @runtime: PCM runtime instance
--
2.40.0.152.g15d061e6df
^ permalink raw reply related [flat|nested] 29+ messages in thread
* Re: [PATCH 2/2] ALSA: pcm: auto-fill buffer with silence when draining playback
2023-04-12 8:04 ` Oswald Buddenhagen
@ 2023-04-12 10:37 ` Takashi Iwai
2023-04-12 11:38 ` Oswald Buddenhagen
2023-04-12 19:59 ` Jaroslav Kysela
0 siblings, 2 replies; 29+ messages in thread
From: Takashi Iwai @ 2023-04-12 10:37 UTC (permalink / raw)
To: Oswald Buddenhagen; +Cc: alsa-devel
On Wed, 12 Apr 2023 10:04:31 +0200,
Oswald Buddenhagen wrote:
>
> On Wed, Apr 12, 2023 at 09:54:54AM +0200, Takashi Iwai wrote:
> > I'm thinking whether we need to change anything in the kernel side for
> > this at all. Can't it be changed rather in alsa-lib side instead?
> >
> it could, but it would be a lot uglier. user space would have to do a
> "man-in-the-middle attack" on the data, while in the kernel we can
> just slightly modify the consumer. this would be particularly obvious
> in the case of write() access.
But basically it'd be like fiddling sw_params temporarily for
draining, I suppose? And the "attack" here can be taken too
seriously; the whole PCM operation can be somehow interfered if a
process may have the access to the PCM device, and changing sw_params
itself must not introduce too much trouble.
thanks,
Takashi
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH 2/2] ALSA: pcm: auto-fill buffer with silence when draining playback
2023-04-12 10:37 ` Takashi Iwai
@ 2023-04-12 11:38 ` Oswald Buddenhagen
2023-04-12 19:59 ` Jaroslav Kysela
1 sibling, 0 replies; 29+ messages in thread
From: Oswald Buddenhagen @ 2023-04-12 11:38 UTC (permalink / raw)
To: alsa-devel
On Wed, Apr 12, 2023 at 12:37:56PM +0200, Takashi Iwai wrote:
>On Wed, 12 Apr 2023 10:04:31 +0200,
>Oswald Buddenhagen wrote:
>>
>> On Wed, Apr 12, 2023 at 09:54:54AM +0200, Takashi Iwai wrote:
>> > I'm thinking whether we need to change anything in the kernel side for
>> > this at all. Can't it be changed rather in alsa-lib side instead?
>> >
>> it could, but it would be a lot uglier. user space would have to do a
>> "man-in-the-middle attack" on the data, while in the kernel we can
>> just slightly modify the consumer. this would be particularly obvious
>> in the case of write() access.
>
>But basically it'd be like fiddling sw_params temporarily for
>draining, I suppose?
>
err, right - i was still assuming manual padding.
i actually tried temporarily changing the params (and pondered
introducing "shadow" params) when i was doing the kernel patch, but that
was a lot uglier than what i did in the end. i think it would be even
worse in user space due to the need to support async operation.
regards
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH 1/2] ALSA: pcm: rewrite snd_pcm_playback_silence()
2023-04-12 10:33 ` Oswald Buddenhagen
@ 2023-04-12 19:23 ` Jaroslav Kysela
2023-04-13 9:44 ` Oswald Buddenhagen
0 siblings, 1 reply; 29+ messages in thread
From: Jaroslav Kysela @ 2023-04-12 19:23 UTC (permalink / raw)
To: alsa-devel, Takashi Iwai, Oswald Buddenhagen
On 12. 04. 23 12:33, Oswald Buddenhagen wrote:
> On Tue, Apr 11, 2023 at 12:47:26PM +0200, Jaroslav Kysela wrote:
>> On 05. 04. 23 22:12, Oswald Buddenhagen wrote:
>>> This fixes a bug in thresholded mode, where we failed to use
>>> new_hw_ptr,
>>> resulting in under-fill.
>>
>> I don't follow what you refer here. The old code uses
>> snd_pcm_playback_hw_avail()
>>
> yes
>
>> thus new hw_ptr for the threshold mode, too.
>>
> not before my patch. the silencer was called before the new pointer was
> stored. it had to be, as otherwise the delta for top-up mode could not
> be calculated.
>
>>> + // This will "legitimately" turn negative on underrun, and will be mangled
>>> + // into a huge number by the boundary crossing handling. The initial state
>>> + // might also be not quite sane. The code below MUST account for these cases.
>>> + hw_avail = appl_ptr - runtime->status->hw_ptr;
>>> + if (hw_avail < 0)
>>> + hw_avail += runtime->boundary;
>
>>> + else if ((snd_pcm_uframes_t) hw_avail >= runtime->boundary)
>>> + hw_avail -= runtime->boundary;
>>
>> If hw_avail is above runtime->boundary then the initial condition is totaly
>> bogus. I would use snd_BUG_ON() and direct return here.
>>
> this is only there as a result of inlining
> snd_pcm_playback_hw_avail()/snd_pcm_playback_avail() somewhat
> mindlessly. the check does indeed make no sense, so i'll just drop it.
> (the broader lesson of this is the attached patch. i can re-post it
> separately if you like it.)
I will correct that it will make sense where hw_ptr is nearby boundary
(boundary - buffer_size ... boundary - 1) and appl_ptr is cropped using
boundary (0 ... buffer_size). But because appl_ptr can be set by application
without any kernel side correction, it may be possible to check if the
appl_ptr is in 0 ... boundary range before any use. Sorry for the confusion.
>>> frames = runtime->silence_threshold - noise_dist;
>>> + if ((snd_pcm_sframes_t) frames <= 0)
>>> + return;
>>
>> The retyping does not look good here. Could we move the if before frames
>> assignment like:
>>
>> if (runtime->silence_threshold <= noise_dist)
>> return;
>> frames = runtime->silence_threshold - noise_dist;
>>
> dunno, i don't like it - it's more noisy and imo it loses
> expressiveness, as the question we're asking is "how many frames do we
> need to fill?".
> note that due to use of unsigned types in the runtime struct, such
> retyping is rather common in comparisons.
It seems that you have answer to everything. My suggestion is perfectly
readable (is the requested silence threshold fulfilled? or is the noise
distance greater than the whole buffer / buffer_size?).
Jaroslav
--
Jaroslav Kysela <perex@perex.cz>
Linux Sound Maintainer; ALSA Project; Red Hat, Inc.
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH 2/2] ALSA: pcm: auto-fill buffer with silence when draining playback
2023-04-12 10:37 ` Takashi Iwai
2023-04-12 11:38 ` Oswald Buddenhagen
@ 2023-04-12 19:59 ` Jaroslav Kysela
2023-04-13 5:42 ` Takashi Iwai
1 sibling, 1 reply; 29+ messages in thread
From: Jaroslav Kysela @ 2023-04-12 19:59 UTC (permalink / raw)
To: Takashi Iwai; +Cc: ALSA development, Oswald Buddenhagen
On 12. 04. 23 12:37, Takashi Iwai wrote:
> On Wed, 12 Apr 2023 10:04:31 +0200,
> Oswald Buddenhagen wrote:
>>
>> On Wed, Apr 12, 2023 at 09:54:54AM +0200, Takashi Iwai wrote:
>>> I'm thinking whether we need to change anything in the kernel side for
>>> this at all. Can't it be changed rather in alsa-lib side instead?
>>>
>> it could, but it would be a lot uglier. user space would have to do a
>> "man-in-the-middle attack" on the data, while in the kernel we can
>> just slightly modify the consumer. this would be particularly obvious
>> in the case of write() access.
>
> But basically it'd be like fiddling sw_params temporarily for
> draining, I suppose? And the "attack" here can be taken too
> seriously; the whole PCM operation can be somehow interfered if a
> process may have the access to the PCM device, and changing sw_params
> itself must not introduce too much trouble.
This looks like a sane proposal, but some drivers does not require the
silencing at all, so we can probably skip this step for them (new
SNDRV_PCM_INFO_PERFECT_DRAIN flag?).
The other not-yet-discussed option is to just print an warning in alsa-lib
that the residue samples may be played (when no silencing / period size align
is used). Then introduce a new helper function to setup silencing for the
drivers without new SNDRV_PCM_INFO_PERFECT_DRAIN flag set.
Jaroslav
--
Jaroslav Kysela <perex@perex.cz>
Linux Sound Maintainer; ALSA Project; Red Hat, Inc.
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH 2/2] ALSA: pcm: auto-fill buffer with silence when draining playback
2023-04-12 19:59 ` Jaroslav Kysela
@ 2023-04-13 5:42 ` Takashi Iwai
2023-04-13 10:16 ` Oswald Buddenhagen
0 siblings, 1 reply; 29+ messages in thread
From: Takashi Iwai @ 2023-04-13 5:42 UTC (permalink / raw)
To: Jaroslav Kysela; +Cc: ALSA development, Oswald Buddenhagen
On Wed, 12 Apr 2023 21:59:28 +0200,
Jaroslav Kysela wrote:
>
> On 12. 04. 23 12:37, Takashi Iwai wrote:
> > On Wed, 12 Apr 2023 10:04:31 +0200,
> > Oswald Buddenhagen wrote:
> >>
> >> On Wed, Apr 12, 2023 at 09:54:54AM +0200, Takashi Iwai wrote:
> >>> I'm thinking whether we need to change anything in the kernel side for
> >>> this at all. Can't it be changed rather in alsa-lib side instead?
> >>>
> >> it could, but it would be a lot uglier. user space would have to do a
> >> "man-in-the-middle attack" on the data, while in the kernel we can
> >> just slightly modify the consumer. this would be particularly obvious
> >> in the case of write() access.
> >
> > But basically it'd be like fiddling sw_params temporarily for
> > draining, I suppose? And the "attack" here can be taken too
> > seriously; the whole PCM operation can be somehow interfered if a
> > process may have the access to the PCM device, and changing sw_params
> > itself must not introduce too much trouble.
>
> This looks like a sane proposal, but some drivers does not require the
> silencing at all, so we can probably skip this step for them (new
> SNDRV_PCM_INFO_PERFECT_DRAIN flag?).
Sure, we should apply it only conditionally. Also, we may skip the
workaround for applications accessing directly via mmap as default.
Also we may provide a flag in asoundrc config, if any, too.
The implementation in alsa-lib is more flexible in this regard.
> The other not-yet-discussed option is to just print an warning in
> alsa-lib that the residue samples may be played (when no silencing /
> period size align is used). Then introduce a new helper function to
> setup silencing for the drivers without new
> SNDRV_PCM_INFO_PERFECT_DRAIN flag set.
Hm, I don't think this would be useful. Spewing warnings are rather
annoying or confusing for end users, and I bet the old applications
wouldn't be fixed even with such annoyance.
thanks,
Takashi
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH 1/2] ALSA: pcm: rewrite snd_pcm_playback_silence()
2023-04-12 19:23 ` Jaroslav Kysela
@ 2023-04-13 9:44 ` Oswald Buddenhagen
0 siblings, 0 replies; 29+ messages in thread
From: Oswald Buddenhagen @ 2023-04-13 9:44 UTC (permalink / raw)
To: alsa-devel
On Wed, Apr 12, 2023 at 09:23:23PM +0200, Jaroslav Kysela wrote:
>On 12. 04. 23 12:33, Oswald Buddenhagen wrote:
>> On Tue, Apr 11, 2023 at 12:47:26PM +0200, Jaroslav Kysela wrote:
>>> On 05. 04. 23 22:12, Oswald Buddenhagen wrote:
>>>> + else if ((snd_pcm_uframes_t) hw_avail >= runtime->boundary)
>>>> + hw_avail -= runtime->boundary;
>>>
>>> If hw_avail is above runtime->boundary then the initial condition is totaly
>>> bogus. I would use snd_BUG_ON() and direct return here.
>>>
>I will correct that it will make sense where hw_ptr is nearby boundary
>(boundary - buffer_size ... boundary - 1) and appl_ptr is cropped using
>boundary (0 ... buffer_size).
>
no, that's the case where it goes negative.
because it's a subtraction, it plain cannot go over the boundary when
both inputs are bounded.
due to the remaining correction, it could still go "very big" in an
underrun condition, as the comment in the patch says.
we should discuss the implications of the latter for the
snd_pcm_*_avail() functions separately (the apidoc doesn't make the
contract clear at all).
>But because appl_ptr can be set by application without any kernel side
>correction, it may be possible to check if the appl_ptr is in 0 ...
>boundary range before any use.
>
that should be rather obviously done *somewhere*, as otherwise appl_ptr
can often be even slightly above 2*boundary, at which point the above
correction (and many alike) wouldn't even work. but for the sake of
efficiency, that should be done asap, so when it is set or the boundary
changes. no?
>>>> frames = runtime->silence_threshold - noise_dist;
>>>> + if ((snd_pcm_sframes_t) frames <= 0)
>>>> + return;
>>>
>>> The retyping does not look good here. Could we move the if before frames
>>> assignment like:
>>>
>>> if (runtime->silence_threshold <= noise_dist)
>>> return;
>>> frames = runtime->silence_threshold - noise_dist;
>>>
>> dunno, i don't like it - it's more noisy and imo it loses
>> expressiveness, as the question we're asking is "how many frames do we
>> need to fill?".
>
>It seems that you have answer to everything.
>
only to the parts that i actually reply to ...
>(is the requested silence threshold fulfilled? or is the noise distance
>greater than the whole buffer / buffer_size?).
>
but why would you want to approach it that way? it's just an extra step
to think through. to reinforce the point: if the compiler is any good,
then your variant will be optimized into mine.
regards
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH 2/2] ALSA: pcm: auto-fill buffer with silence when draining playback
2023-04-13 5:42 ` Takashi Iwai
@ 2023-04-13 10:16 ` Oswald Buddenhagen
2023-04-13 10:28 ` Takashi Iwai
0 siblings, 1 reply; 29+ messages in thread
From: Oswald Buddenhagen @ 2023-04-13 10:16 UTC (permalink / raw)
To: ALSA development
On Thu, Apr 13, 2023 at 07:42:06AM +0200, Takashi Iwai wrote:
>On Wed, 12 Apr 2023 21:59:28 +0200,
>Jaroslav Kysela wrote:
>> This looks like a sane proposal, but some drivers does not require
>> the
>> silencing at all, so we can probably skip this step for them (new
>> SNDRV_PCM_INFO_PERFECT_DRAIN flag?).
>
>Sure, we should apply it only conditionally.
>
i don't think the extra complexity is justified. with my improved
proposal, we're talking about a cost of filling two periods per draining
op, which aren't exactly super-frequent.
>Also, we may skip the
>workaround for applications accessing directly via mmap as default.
>
no, because one may easily miss that more than one period is required.
also, i think that forgetting it entirely is an easy mistake to make,
even if it's harder with mmap than with write.
regards
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH 2/2] ALSA: pcm: auto-fill buffer with silence when draining playback
2023-04-13 10:16 ` Oswald Buddenhagen
@ 2023-04-13 10:28 ` Takashi Iwai
2023-04-13 11:10 ` Oswald Buddenhagen
0 siblings, 1 reply; 29+ messages in thread
From: Takashi Iwai @ 2023-04-13 10:28 UTC (permalink / raw)
To: Oswald Buddenhagen; +Cc: ALSA development
On Thu, 13 Apr 2023 12:16:04 +0200,
Oswald Buddenhagen wrote:
>
> On Thu, Apr 13, 2023 at 07:42:06AM +0200, Takashi Iwai wrote:
> > On Wed, 12 Apr 2023 21:59:28 +0200,
> > Jaroslav Kysela wrote:
> >> This looks like a sane proposal, but some drivers does not require
> >> the
> >> silencing at all, so we can probably skip this step for them (new
> >> SNDRV_PCM_INFO_PERFECT_DRAIN flag?).
> >
> > Sure, we should apply it only conditionally.
> >
> i don't think the extra complexity is justified. with my improved
> proposal, we're talking about a cost of filling two periods per
> draining op, which aren't exactly super-frequent.
I'm not much fan of introducing a new flag for that behavior, either.
> > Also, we may skip the
> > workaround for applications accessing directly via mmap as default.
> >
> no, because one may easily miss that more than one period is required.
> also, i think that forgetting it entirely is an easy mistake to make,
> even if it's harder with mmap than with write.
I don't agree with that point -- if application wants the access only
via mmap (without any write actions via alsa-lib functions), the
buffer and data management relies fully on the application itself.
Manipulating the data *silently* is no good action for such
applications. For them, the drain simply means to stop at the certain
point. OTOH, for the explicit write, basically alsa-lib / kernel is
responsible for the buffer / data management, and the workaround can
be applied.
That's I mentioned to "apply conditionally". There are cases where we
shouldn't touch the data at all. For the usual cases with the
standard write, we may apply it.
thanks,
Takashi
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH 2/2] ALSA: pcm: auto-fill buffer with silence when draining playback
2023-04-13 10:28 ` Takashi Iwai
@ 2023-04-13 11:10 ` Oswald Buddenhagen
2023-04-13 12:06 ` Takashi Iwai
0 siblings, 1 reply; 29+ messages in thread
From: Oswald Buddenhagen @ 2023-04-13 11:10 UTC (permalink / raw)
To: ALSA development
On Thu, Apr 13, 2023 at 12:28:34PM +0200, Takashi Iwai wrote:
>On Thu, 13 Apr 2023 12:16:04 +0200, Oswald Buddenhagen wrote:
>> On Thu, Apr 13, 2023 at 07:42:06AM +0200, Takashi Iwai wrote:
>> > Also, we may skip the
>> > workaround for applications accessing directly via mmap as default.
>> >
>> no, because one may easily miss that more than one period is required.
>> also, i think that forgetting it entirely is an easy mistake to make,
>> even if it's harder with mmap than with write.
>
>I don't agree with that point -- if application wants the access only
>via mmap (without any write actions via alsa-lib functions), the
>buffer and data management relies fully on the application itself.
>Manipulating the data *silently* is no good action for such
>applications.
>For them, the drain simply means to stop at the certain point.
>
i don't think that's true. if an app wants to control things finely, it
would just use start/stop and manage the timing itself. draining otoh is
a convenient fire-and-forget operation. that makes it easy to miss the
finer details, which is why i'm so insistent that it should just work
out of the box.
if you exclude mmapped devices in kernel, you exclude plughw with
emulated write(), so you'd have to add yet more code to compensate for
that. and doing it all in user space is yet more code. for all i can
tell, it's really just layers of complexity to solve a non-problem.
regards
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH 2/2] ALSA: pcm: auto-fill buffer with silence when draining playback
2023-04-13 11:10 ` Oswald Buddenhagen
@ 2023-04-13 12:06 ` Takashi Iwai
2023-04-13 14:59 ` Oswald Buddenhagen
0 siblings, 1 reply; 29+ messages in thread
From: Takashi Iwai @ 2023-04-13 12:06 UTC (permalink / raw)
To: Oswald Buddenhagen; +Cc: ALSA development
On Thu, 13 Apr 2023 13:10:34 +0200,
Oswald Buddenhagen wrote:
>
> On Thu, Apr 13, 2023 at 12:28:34PM +0200, Takashi Iwai wrote:
> > On Thu, 13 Apr 2023 12:16:04 +0200, Oswald Buddenhagen wrote:
> >> On Thu, Apr 13, 2023 at 07:42:06AM +0200, Takashi Iwai wrote:
> >> > Also, we may skip the
> >> > workaround for applications accessing directly via mmap as default.
> >> > no, because one may easily miss that more than one period is
> >> required.
> >> also, i think that forgetting it entirely is an easy mistake to make,
> >> even if it's harder with mmap than with write.
> >
> > I don't agree with that point -- if application wants the access only
> > via mmap (without any write actions via alsa-lib functions), the
> > buffer and data management relies fully on the application itself.
> > Manipulating the data *silently* is no good action for such
> > applications.
>
> > For them, the drain simply means to stop at the certain point.
> >
> i don't think that's true. if an app wants to control things finely,
> it would just use start/stop and manage the timing itself. draining
> otoh is a convenient fire-and-forget operation. that makes it easy to
> miss the finer details, which is why i'm so insistent that it should
> just work out of the box.
Sure, but that's still no excuse to ignore the possibility blindly.
> if you exclude mmapped devices in kernel, you exclude plughw with
> emulated write(), so you'd have to add yet more code to compensate for
> that.
No, I wrote "if application wants the access only via mmap (without
any write actions via alsa-lib functions)". So if application writes
via plugin write(), we should apply the workaround, too.
> and doing it all in user space is yet more code. for all i can
> tell, it's really just layers of complexity to solve a non-problem.
I don't get it: we're talking about the sw_params call in alsa-lib's
drain function, and how can it be *so* complex...?
Takashi
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH 2/2] ALSA: pcm: auto-fill buffer with silence when draining playback
2023-04-13 12:06 ` Takashi Iwai
@ 2023-04-13 14:59 ` Oswald Buddenhagen
2023-04-14 8:26 ` Takashi Iwai
0 siblings, 1 reply; 29+ messages in thread
From: Oswald Buddenhagen @ 2023-04-13 14:59 UTC (permalink / raw)
To: ALSA development
On Thu, Apr 13, 2023 at 02:06:49PM +0200, Takashi Iwai wrote:
>On Thu, 13 Apr 2023 13:10:34 +0200, Oswald Buddenhagen wrote:
>> i don't think that's true. if an app wants to control things finely,
>> it would just use start/stop and manage the timing itself. draining
>> otoh is a convenient fire-and-forget operation. that makes it easy to
>> miss the finer details, which is why i'm so insistent that it should
>> just work out of the box.
>
>Sure, but that's still no excuse to ignore the possibility blindly.
>
it's not blindly. it's after considering it, and concluding that it's a
hypothetical problem at best.
we could of course do a survey of actually existing publicly accessible
code, to quantify the trade-off between apps fixed and apps broken. i
actually sort of tried that ...
first thing is that i found lots of stackoverflow answers and similar,
and *none* of them even mentioned the need to clear the rest of the
buffer. i found a bunch of libs, and none of the apidocs mentioned it in
the parts i read. i found one cross-platform how-to which did actually
mention it. yay.
code search was trickier, with rather predictable results:
basically all hits for drain() were immediately followed by close().
i found some simple cases of write+drain, and none of them did any
additional padding. this includes alsa's own pcm example. but never
mind, we're in agreement about this case.
most other code was some abstraction, so it would be impossible to asses
the bigger picture quickly.
that would be even more the case for apps that use mmap. so i won't even
try to provide actual data.
one thing to consider here is that most of the code are cross-platform
abstractions. under such circumstances, it seems kinda inconceivable
that the higher level code would make any assumptions about buffer space
that has not been filled with fresh samples.
>> and doing it all in user space is yet more code. for all i can
>> tell, it's really just layers of complexity to solve a non-problem.
>
>I don't get it: we're talking about the sw_params call in alsa-lib's
>drain function, and how can it be *so* complex...?
>
the "drain function" bit is critical here, because it kind of implies
resetting it, potentially asynchronously. but if we add a specific bit
to the kernel to enable it, then it can be actually set already when the
device is set up, and the user space would be rather simple. however,
that would overall be still a lot more code than doing it
unconditionally, and fully in kernel.
regards
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH 2/2] ALSA: pcm: auto-fill buffer with silence when draining playback
2023-04-13 14:59 ` Oswald Buddenhagen
@ 2023-04-14 8:26 ` Takashi Iwai
2023-04-14 8:56 ` Oswald Buddenhagen
0 siblings, 1 reply; 29+ messages in thread
From: Takashi Iwai @ 2023-04-14 8:26 UTC (permalink / raw)
To: Oswald Buddenhagen; +Cc: ALSA development
On Thu, 13 Apr 2023 16:59:02 +0200,
Oswald Buddenhagen wrote:
>
> On Thu, Apr 13, 2023 at 02:06:49PM +0200, Takashi Iwai wrote:
> > On Thu, 13 Apr 2023 13:10:34 +0200, Oswald Buddenhagen wrote:
> >> i don't think that's true. if an app wants to control things finely,
> >> it would just use start/stop and manage the timing itself. draining
> >> otoh is a convenient fire-and-forget operation. that makes it easy to
> >> miss the finer details, which is why i'm so insistent that it should
> >> just work out of the box.
> >
> > Sure, but that's still no excuse to ignore the possibility blindly.
> >
> it's not blindly. it's after considering it, and concluding that it's
> a hypothetical problem at best.
>
> we could of course do a survey of actually existing publicly
> accessible code, to quantify the trade-off between apps fixed and apps
> broken. i actually sort of tried that ...
>
> first thing is that i found lots of stackoverflow answers and similar,
> and *none* of them even mentioned the need to clear the rest of the
> buffer. i found a bunch of libs, and none of the apidocs mentioned it
> in the parts i read. i found one cross-platform how-to which did
> actually mention it. yay.
>
> code search was trickier, with rather predictable results:
> basically all hits for drain() were immediately followed by close().
> i found some simple cases of write+drain, and none of them did any
> additional padding. this includes alsa's own pcm example. but never
> mind, we're in agreement about this case.
> most other code was some abstraction, so it would be impossible to
> asses the bigger picture quickly.
> that would be even more the case for apps that use mmap. so i won't
> even try to provide actual data.
> one thing to consider here is that most of the code are cross-platform
> abstractions. under such circumstances, it seems kinda inconceivable
> that the higher level code would make any assumptions about buffer
> space that has not been filled with fresh samples.
Those whole context should have been mentioned before the
discussion... But still we'd better survey the actual usage for the
decision.
ATM, I still hesitate taking the behavior change in the kernel,
*iff* it can be worked around differently.
While the mmap situation is admittedly a corner case, the point of
alsa-lib implementation is the flexibility. And, your implementation
means to modify the mmapped data silently, which never happened in the
past -- this is another side of coin of fixing in API side, and we
don't know the side-effect to any wild applications. Some additional
configuration or flexible workaround might be required, and that's
often harder to apply in the kernel.
And, another concern is, as already discussed, whether we really have
to apply it unconditionally at every draining call. Obviously the
workaround is superfluous for the drivers like USB-audio, which never
overrun without the filled data.
> >> and doing it all in user space is yet more code. for all i can
> >> tell, it's really just layers of complexity to solve a non-problem.
> >
> > I don't get it: we're talking about the sw_params call in alsa-lib's
> > drain function, and how can it be *so* complex...?
> >
> the "drain function" bit is critical here, because it kind of implies
> resetting it, potentially asynchronously. but if we add a specific bit
> to the kernel to enable it, then it can be actually set already when
> the device is set up, and the user space would be rather
> simple. however, that would overall be still a lot more code than
> doing it unconditionally, and fully in kernel.
Indeed we might want to take the kernel-side fix in the end, but let's
check things a bit more beforehand.
BTW, I guess that one missing piece in your patch is the case where
the drain is called at the moment of fully filled data. You added
snd_pcm_playback_silence() at snd_pcm_do_drain_init(), but in this
scenario, the call wouldn't do anything at this moment. But
snd_pcm_playback_silence() won't be called afterwards because
runtime->silence_size = 0. So this workaround won't take effect in
that case, no?
thanks,
Takashi
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH 2/2] ALSA: pcm: auto-fill buffer with silence when draining playback
2023-04-14 8:26 ` Takashi Iwai
@ 2023-04-14 8:56 ` Oswald Buddenhagen
2023-04-14 9:28 ` Takashi Iwai
0 siblings, 1 reply; 29+ messages in thread
From: Oswald Buddenhagen @ 2023-04-14 8:56 UTC (permalink / raw)
To: ALSA development
On Fri, Apr 14, 2023 at 10:26:26AM +0200, Takashi Iwai wrote:
>Indeed we might want to take the kernel-side fix in the end, but let's
>check things a bit more beforehand.
>
i'll post updated patches soon, then you can sleep over it. :-D
(i'm being a bit slow, because i'm also developing tooling for
maintaining stacked branches and (re-)posting them, and of course i want
to try it out with real data.)
>BTW, I guess that one missing piece in your patch is the case where
>the drain is called at the moment of fully filled data. You added
>snd_pcm_playback_silence() at snd_pcm_do_drain_init(), but in this
>scenario, the call wouldn't do anything at this moment. But
>snd_pcm_playback_silence() won't be called afterwards because
>runtime->silence_size = 0. So this workaround won't take effect in
>that case, no?
>
the hunk in snd_pcm_update_hw_ptr0() should take care of that.
regards
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH 2/2] ALSA: pcm: auto-fill buffer with silence when draining playback
2023-04-14 8:56 ` Oswald Buddenhagen
@ 2023-04-14 9:28 ` Takashi Iwai
0 siblings, 0 replies; 29+ messages in thread
From: Takashi Iwai @ 2023-04-14 9:28 UTC (permalink / raw)
To: Oswald Buddenhagen; +Cc: ALSA development
On Fri, 14 Apr 2023 10:56:10 +0200,
Oswald Buddenhagen wrote:
>
> On Fri, Apr 14, 2023 at 10:26:26AM +0200, Takashi Iwai wrote:
> > BTW, I guess that one missing piece in your patch is the case where
> > the drain is called at the moment of fully filled data. You added
> > snd_pcm_playback_silence() at snd_pcm_do_drain_init(), but in this
> > scenario, the call wouldn't do anything at this moment. But
> > snd_pcm_playback_silence() won't be called afterwards because
> > runtime->silence_size = 0. So this workaround won't take effect in
> > that case, no?
> >
> the hunk in snd_pcm_update_hw_ptr0() should take care of that.
OK, I see. Thanks.
Takashi
^ permalink raw reply [flat|nested] 29+ messages in thread
end of thread, other threads:[~2023-04-14 9:30 UTC | newest]
Thread overview: 29+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2023-04-05 20:12 [PATCH 1/2] ALSA: pcm: rewrite snd_pcm_playback_silence() Oswald Buddenhagen
2023-04-05 20:12 ` [PATCH 2/2] ALSA: pcm: auto-fill buffer with silence when draining playback Oswald Buddenhagen
2023-04-07 23:58 ` Jaroslav Kysela
2023-04-08 5:55 ` Takashi Iwai
2023-04-08 7:24 ` Oswald Buddenhagen
2023-04-11 11:09 ` Jaroslav Kysela
2023-04-11 13:57 ` Oswald Buddenhagen
2023-04-11 14:48 ` Jaroslav Kysela
2023-04-11 16:50 ` Oswald Buddenhagen
2023-04-11 17:23 ` Jaroslav Kysela
2023-04-12 7:54 ` Takashi Iwai
2023-04-12 8:04 ` Oswald Buddenhagen
2023-04-12 10:37 ` Takashi Iwai
2023-04-12 11:38 ` Oswald Buddenhagen
2023-04-12 19:59 ` Jaroslav Kysela
2023-04-13 5:42 ` Takashi Iwai
2023-04-13 10:16 ` Oswald Buddenhagen
2023-04-13 10:28 ` Takashi Iwai
2023-04-13 11:10 ` Oswald Buddenhagen
2023-04-13 12:06 ` Takashi Iwai
2023-04-13 14:59 ` Oswald Buddenhagen
2023-04-14 8:26 ` Takashi Iwai
2023-04-14 8:56 ` Oswald Buddenhagen
2023-04-14 9:28 ` Takashi Iwai
2023-04-06 14:53 ` [PATCH 1/2] ALSA: pcm: rewrite snd_pcm_playback_silence() Takashi Iwai
2023-04-11 10:47 ` Jaroslav Kysela
2023-04-12 10:33 ` Oswald Buddenhagen
2023-04-12 19:23 ` Jaroslav Kysela
2023-04-13 9:44 ` Oswald Buddenhagen
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.