mirror of
https://gitlab.freedesktop.org/pulseaudio/pulseaudio.git
synced 2025-11-03 09:01:50 -05:00
source-output: Fix rewinding
If the output implements a process_rewind() callback, the resampler delay is not taken into account. This leads to glitches during volume changes when source and source output rates differ. This patch fixes the problem. Part-of: <https://gitlab.freedesktop.org/pulseaudio/pulseaudio/-/merge_requests/120>
This commit is contained in:
parent
a275a0b811
commit
d55fde2fed
1 changed files with 47 additions and 12 deletions
|
|
@ -29,6 +29,7 @@
|
|||
#include <pulse/xmalloc.h>
|
||||
#include <pulse/util.h>
|
||||
#include <pulse/internal.h>
|
||||
#include <pulse/timeval.h>
|
||||
|
||||
#include <pulsecore/core-format.h>
|
||||
#include <pulsecore/mix.h>
|
||||
|
|
@ -237,6 +238,7 @@ int pa_source_output_new(
|
|||
pa_channel_map volume_map;
|
||||
int r;
|
||||
char *pt;
|
||||
size_t resampler_history;
|
||||
|
||||
pa_assert(_o);
|
||||
pa_assert(core);
|
||||
|
|
@ -499,6 +501,11 @@ int pa_source_output_new(
|
|||
0,
|
||||
&o->source->silence);
|
||||
|
||||
resampler_history = (uint64_t) PA_RESAMPLER_MAX_DELAY_USEC * o->source->sample_spec.rate / PA_USEC_PER_SEC;
|
||||
resampler_history *= pa_frame_size(&o->source->sample_spec);
|
||||
|
||||
pa_memblockq_set_maxrewind(o->thread_info.delay_memblockq, resampler_history + pa_source_get_max_rewind(o->source));
|
||||
|
||||
pa_assert_se(pa_idxset_put(core->source_outputs, o, &o->index) == 0);
|
||||
pa_assert_se(pa_idxset_put(o->source->outputs, pa_source_output_ref(o), NULL) == 0);
|
||||
|
||||
|
|
@ -865,21 +872,36 @@ void pa_source_output_process_rewind(pa_source_output *o, size_t nbytes /* in so
|
|||
return;
|
||||
|
||||
if (o->process_rewind) {
|
||||
pa_assert(pa_memblockq_get_length(o->thread_info.delay_memblockq) == 0);
|
||||
size_t source_output_nbytes;
|
||||
size_t length;
|
||||
|
||||
if (o->thread_info.resampler)
|
||||
nbytes = pa_resampler_result(o->thread_info.resampler, nbytes);
|
||||
/* The length of the memblockq may be non-zero if pa_source_output_rewind() is called twice
|
||||
* without pa_source_output_push() called in between. In that case, the resampler has already
|
||||
* been reset and we can skip that part. */
|
||||
length = pa_memblockq_get_length(o->thread_info.delay_memblockq);
|
||||
|
||||
pa_log_debug("Have to rewind %lu bytes on implementor.", (unsigned long) nbytes);
|
||||
pa_memblockq_rewind(o->thread_info.delay_memblockq, nbytes);
|
||||
|
||||
if (nbytes > 0)
|
||||
o->process_rewind(o, nbytes);
|
||||
source_output_nbytes = pa_resampler_result(o->thread_info.resampler, nbytes);
|
||||
|
||||
if (o->thread_info.resampler)
|
||||
pa_resampler_rewind(o->thread_info.resampler, nbytes, NULL, 0);
|
||||
pa_log_debug("Have to rewind %lu bytes on implementor.", (unsigned long) source_output_nbytes);
|
||||
|
||||
} else
|
||||
pa_memblockq_seek(o->thread_info.delay_memblockq, - ((int64_t) nbytes), PA_SEEK_RELATIVE, true);
|
||||
if (source_output_nbytes > 0)
|
||||
o->process_rewind(o, source_output_nbytes);
|
||||
|
||||
if (o->thread_info.resampler && length == 0) {
|
||||
size_t resampler_bytes;
|
||||
|
||||
/* Round down to full frames */
|
||||
resampler_bytes = (size_t) pa_resampler_get_delay(o->thread_info.resampler, false) * pa_frame_size(&o->source->sample_spec);
|
||||
if (resampler_bytes > 0)
|
||||
pa_memblockq_rewind(o->thread_info.delay_memblockq, resampler_bytes);
|
||||
|
||||
pa_resampler_rewind(o->thread_info.resampler, source_output_nbytes, NULL, 0);
|
||||
}
|
||||
}
|
||||
|
||||
pa_memblockq_seek(o->thread_info.delay_memblockq, - ((int64_t) nbytes), PA_SEEK_RELATIVE, true);
|
||||
}
|
||||
|
||||
/* Called from thread context */
|
||||
|
|
@ -887,18 +909,25 @@ size_t pa_source_output_get_max_rewind(pa_source_output *o) {
|
|||
pa_source_output_assert_ref(o);
|
||||
pa_source_output_assert_io_context(o);
|
||||
|
||||
return o->thread_info.resampler ? pa_resampler_request(o->thread_info.resampler, o->source->thread_info.max_rewind) : o->source->thread_info.max_rewind;
|
||||
return pa_resampler_result(o->thread_info.resampler, o->source->thread_info.max_rewind);
|
||||
}
|
||||
|
||||
/* Called from thread context */
|
||||
void pa_source_output_update_max_rewind(pa_source_output *o, size_t nbytes /* in the source's sample spec */) {
|
||||
size_t resampler_history;
|
||||
|
||||
pa_source_output_assert_ref(o);
|
||||
pa_source_output_assert_io_context(o);
|
||||
pa_assert(PA_SOURCE_OUTPUT_IS_LINKED(o->thread_info.state));
|
||||
pa_assert(pa_frame_aligned(nbytes, &o->source->sample_spec));
|
||||
|
||||
resampler_history = (uint64_t) PA_RESAMPLER_MAX_DELAY_USEC * o->source->sample_spec.rate / PA_USEC_PER_SEC;
|
||||
resampler_history *= pa_frame_size(&o->source->sample_spec);
|
||||
|
||||
pa_memblockq_set_maxrewind(o->thread_info.delay_memblockq, resampler_history + nbytes);
|
||||
|
||||
if (o->update_max_rewind)
|
||||
o->update_max_rewind(o, o->thread_info.resampler ? pa_resampler_result(o->thread_info.resampler, nbytes) : nbytes);
|
||||
o->update_max_rewind(o, pa_resampler_result(o->thread_info.resampler, nbytes));
|
||||
}
|
||||
|
||||
/* Called from thread context */
|
||||
|
|
@ -1785,6 +1814,7 @@ finish:
|
|||
int pa_source_output_update_resampler(pa_source_output *o) {
|
||||
pa_resampler *new_resampler;
|
||||
char *memblockq_name;
|
||||
size_t resampler_history;
|
||||
|
||||
pa_source_output_assert_ref(o);
|
||||
pa_assert_ctl_context();
|
||||
|
|
@ -1842,6 +1872,11 @@ int pa_source_output_update_resampler(pa_source_output *o) {
|
|||
&o->source->silence);
|
||||
pa_xfree(memblockq_name);
|
||||
|
||||
resampler_history = (uint64_t) PA_RESAMPLER_MAX_DELAY_USEC * o->source->sample_spec.rate / PA_USEC_PER_SEC;
|
||||
resampler_history *= pa_frame_size(&o->source->sample_spec);
|
||||
|
||||
pa_memblockq_set_maxrewind(o->thread_info.delay_memblockq, resampler_history + pa_source_get_max_rewind(o->source));
|
||||
|
||||
o->actual_resample_method = new_resampler ? pa_resampler_get_method(new_resampler) : PA_RESAMPLER_INVALID;
|
||||
|
||||
pa_log_debug("Updated resampler for source output %d", o->index);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue