mirror of
https://gitlab.freedesktop.org/pulseaudio/pulseaudio.git
synced 2025-10-29 05:40:23 -04:00
sink-input: Limit rewinding to max_rewind for virtual sinks
This patch is in preparation of allowing virtual sinks to specify their own max_rewind limit. Currently, virtual sinks cannot specify their max_rewind limit, but just copy the value from the master sink. This may not be correct, if the DSP code of the virtual sink has limited (or no) rewinding capability. Because the DSP code of the virtual sink is rewound in the process_rewind() callback of the sink input, it must be ensured, that rewinding a sink input to the master of a virtual sink is limited similar to rewinding a sink. There are two remaining exceptions: 1) If an underrun is detected. In that case, the filter should be reset anyway. 2) When the sink input of the filter is moved and attached to the destination sink. The move case is handled without involvement of the implementer, so the implementer can only receive a rewind larger than max_rewind when the filter should be reset anyway. All existing virtual sinks do not distinguish between reset and rewind of the filter. Part-of: <https://gitlab.freedesktop.org/pulseaudio/pulseaudio/-/merge_requests/120>
This commit is contained in:
parent
f121779f88
commit
5c6d91a97c
3 changed files with 50 additions and 5 deletions
|
|
@ -2461,13 +2461,31 @@ void pa_sink_input_request_rewind(
|
|||
/* Check if rewinding for the maximum is requested, and if so, fix up */
|
||||
if (nbytes <= 0) {
|
||||
|
||||
/* Calculate maximum number of bytes that could be rewound in theory */
|
||||
nbytes = i->sink->thread_info.max_rewind + lbq;
|
||||
/* Calculate maximum number of bytes that could be rewound in theory.
|
||||
* If the sink has a virtual sink attached, limit rewinding to max_rewind.
|
||||
*
|
||||
* The max_rewind value of a virtual sink depends on the rewinding capability
|
||||
* of its DSP code. The DSP code is rewound in the process_rewind() callback
|
||||
* of the sink input. Therefore rewinding must be limited to max_rewind here. */
|
||||
nbytes = i->sink->thread_info.max_rewind;
|
||||
if (!pa_sink_has_filter_attached(i->sink) && !pa_sink_is_filter(i->sink))
|
||||
nbytes += lbq;
|
||||
|
||||
/* Transform from sink domain */
|
||||
nbytes = pa_resampler_request(i->thread_info.resampler, nbytes);
|
||||
}
|
||||
|
||||
/* For virtual sinks there are two situations where nbytes may exceed max_rewind:
|
||||
* 1) If an underrun was detected.
|
||||
* 2) When the sink input is rewound during a move when it is attached to
|
||||
* the destination sink.
|
||||
* Moving a sink input is handled without involving the implementer, so the
|
||||
* implementer will only be asked to rewind more than max_rewind if an
|
||||
* underrun occurs. In that case, the DSP code of virtual sinks should be
|
||||
* reset instead of rewound. Therefore the rewind function of filters should
|
||||
* check if the requested rewind exceeds the maximum possible rewind of the
|
||||
* filter. */
|
||||
|
||||
/* Remember how much we actually want to rewrite */
|
||||
if (i->thread_info.rewrite_nbytes != (size_t) -1) {
|
||||
if (rewrite) {
|
||||
|
|
|
|||
|
|
@ -1657,6 +1657,27 @@ bool pa_sink_flat_volume_enabled(pa_sink *s) {
|
|||
return false;
|
||||
}
|
||||
|
||||
/* Check if the sink has a virtual sink attached.
|
||||
* Called from the IO thread. */
|
||||
bool pa_sink_has_filter_attached(pa_sink *s) {
|
||||
bool vsink_attached = false;
|
||||
void *state = NULL;
|
||||
pa_sink_input *i;
|
||||
|
||||
pa_assert(s);
|
||||
|
||||
if (PA_SINK_IS_LINKED(s->thread_info.state)) {
|
||||
PA_HASHMAP_FOREACH(i, s->thread_info.inputs, state) {
|
||||
if (!i->origin_sink)
|
||||
continue;
|
||||
|
||||
vsink_attached = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return vsink_attached;
|
||||
}
|
||||
|
||||
/* Called from the main thread (and also from the IO thread while the main
|
||||
* thread is waiting). */
|
||||
pa_sink *pa_sink_get_master(pa_sink *s) {
|
||||
|
|
@ -2669,8 +2690,8 @@ int pa_sink_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offse
|
|||
}
|
||||
|
||||
pa_hashmap_remove_and_free(s->thread_info.inputs, PA_UINT32_TO_PTR(i->index));
|
||||
pa_sink_invalidate_requested_latency(s, true);
|
||||
pa_sink_request_rewind(s, (size_t) -1);
|
||||
pa_sink_invalidate_requested_latency(s, true);
|
||||
|
||||
/* In flat volume mode we need to update the volume as
|
||||
* well */
|
||||
|
|
@ -2709,11 +2730,13 @@ int pa_sink_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offse
|
|||
/* Let's remove the sink input ...*/
|
||||
pa_hashmap_remove_and_free(s->thread_info.inputs, PA_UINT32_TO_PTR(i->index));
|
||||
|
||||
pa_sink_invalidate_requested_latency(s, true);
|
||||
|
||||
/* The rewind must be requested before invalidating the latency, otherwise
|
||||
* the max_rewind value of the sink may change before the rewind. */
|
||||
pa_log_debug("Requesting rewind due to started move");
|
||||
pa_sink_request_rewind(s, (size_t) -1);
|
||||
|
||||
pa_sink_invalidate_requested_latency(s, true);
|
||||
|
||||
/* In flat volume mode we need to update the volume as
|
||||
* well */
|
||||
return o->process_msg(o, PA_SINK_MESSAGE_SET_SHARED_VOLUME, NULL, 0, NULL);
|
||||
|
|
|
|||
|
|
@ -470,6 +470,10 @@ int pa_sink_suspend_all(pa_core *c, bool suspend, pa_suspend_cause_t cause);
|
|||
/* Use this instead of checking s->flags & PA_SINK_FLAT_VOLUME directly. */
|
||||
bool pa_sink_flat_volume_enabled(pa_sink *s);
|
||||
|
||||
/* Check if the sink has a virtual sink attached.
|
||||
* Called from the IO thread. */
|
||||
bool pa_sink_has_filter_attached(pa_sink *s);
|
||||
|
||||
/* Get the master sink when sharing volumes */
|
||||
pa_sink *pa_sink_get_master(pa_sink *s);
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue