mirror of
https://gitlab.freedesktop.org/pulseaudio/pulseaudio.git
synced 2025-12-22 08:56:52 -05:00
alsa-sink/source, sink, source: Consider sample format for avoid-resampling/passthrough
Sample format(e.g. 16 bit, 24 bit) was not considered even if the avoid-resampling option is set or the passthrough mode is used. This patch checks both sample format and rate of a stream to determine whether to avoid resampling in case of the option is set. In other word, it is possble to use the stream's original sample format and rate without resampling as long as these are supported by the device. pa_sink_input_update_rate() and pa_source_output_update_rate() are renamed to pa_sink_input_update_resampler() and pa_source_output _update_resampler() respectively. functions are added as below. pa_sink_set_sample_format(), pa_sink_set_sample_rate(), pa_source_set_sample_format(), pa_source_set_sample_rate() Signed-off-by: Sangchul Lee <sc11.lee@samsung.com>
This commit is contained in:
parent
73156649e7
commit
547998db44
11 changed files with 335 additions and 165 deletions
|
|
@ -1020,8 +1020,9 @@ void pa_source_post_direct(pa_source*s, pa_source_output *o, const pa_memchunk *
|
|||
}
|
||||
|
||||
/* Called from main thread */
|
||||
int pa_source_reconfigure(pa_source *s, pa_sample_spec *spec, bool passthrough) {
|
||||
int ret;
|
||||
void pa_source_reconfigure(pa_source *s, pa_sample_spec *spec, bool passthrough) {
|
||||
uint32_t idx;
|
||||
pa_source_output *o;
|
||||
pa_sample_spec desired_spec;
|
||||
uint32_t default_rate = s->default_sample_rate;
|
||||
uint32_t alternate_rate = s->alternate_sample_rate;
|
||||
|
|
@ -1029,50 +1030,53 @@ int pa_source_reconfigure(pa_source *s, pa_sample_spec *spec, bool passthrough)
|
|||
bool alternate_rate_is_usable = false;
|
||||
bool avoid_resampling = s->avoid_resampling;
|
||||
|
||||
/* We currently only try to reconfigure the sample rate */
|
||||
|
||||
if (pa_sample_spec_equal(spec, &s->sample_spec))
|
||||
return 0;
|
||||
return;
|
||||
|
||||
if (!s->reconfigure && !s->monitor_of)
|
||||
return -1;
|
||||
return;
|
||||
|
||||
if (PA_UNLIKELY(default_rate == alternate_rate && !passthrough && !avoid_resampling)) {
|
||||
pa_log_debug("Default and alternate sample rates are the same, so there is no point in switching.");
|
||||
return -1;
|
||||
return;
|
||||
}
|
||||
|
||||
if (PA_SOURCE_IS_RUNNING(s->state)) {
|
||||
pa_log_info("Cannot update rate, SOURCE_IS_RUNNING, will keep using %u Hz",
|
||||
s->sample_spec.rate);
|
||||
return -1;
|
||||
pa_log_info("Cannot update sample spec, SOURCE_IS_RUNNING, will keep using %s and %u Hz",
|
||||
pa_sample_format_to_string(s->sample_spec.format), s->sample_spec.rate);
|
||||
return;
|
||||
}
|
||||
|
||||
if (s->monitor_of) {
|
||||
if (PA_SINK_IS_RUNNING(s->monitor_of->state)) {
|
||||
pa_log_info("Cannot update rate, this is a monitor source and the sink is running.");
|
||||
return -1;
|
||||
pa_log_info("Cannot update sample spec, this is a monitor source and the sink is running.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (PA_UNLIKELY(!pa_sample_spec_valid(spec)))
|
||||
return -1;
|
||||
return;
|
||||
|
||||
desired_spec = s->sample_spec;
|
||||
|
||||
if (passthrough) {
|
||||
/* We have to try to use the source output rate */
|
||||
/* We have to try to use the source output format and rate */
|
||||
desired_spec.format = spec->format;
|
||||
desired_spec.rate = spec->rate;
|
||||
|
||||
} else if (avoid_resampling && (spec->rate >= default_rate || spec->rate >= alternate_rate)) {
|
||||
} else if (avoid_resampling) {
|
||||
/* We just try to set the source output's sample rate if it's not too low */
|
||||
desired_spec.rate = spec->rate;
|
||||
if (spec->rate >= default_rate || spec->rate >= alternate_rate)
|
||||
desired_spec.rate = spec->rate;
|
||||
desired_spec.format = spec->format;
|
||||
|
||||
} else if (default_rate == spec->rate || alternate_rate == spec->rate) {
|
||||
/* We can directly try to use this rate */
|
||||
desired_spec.rate = spec->rate;
|
||||
|
||||
} else {
|
||||
}
|
||||
|
||||
if (desired_spec.rate != spec->rate) {
|
||||
/* See if we can pick a rate that results in less resampling effort */
|
||||
if (default_rate % 11025 == 0 && spec->rate % 11025 == 0)
|
||||
default_rate_is_usable = true;
|
||||
|
|
@ -1090,16 +1094,17 @@ int pa_source_reconfigure(pa_source *s, pa_sample_spec *spec, bool passthrough)
|
|||
}
|
||||
|
||||
if (pa_sample_spec_equal(&desired_spec, &s->sample_spec) && passthrough == pa_source_is_passthrough(s))
|
||||
return -1;
|
||||
return;
|
||||
|
||||
if (!passthrough && pa_source_used_by(s) > 0)
|
||||
return -1;
|
||||
return;
|
||||
|
||||
pa_log_debug("Suspending source %s due to changing the sample rate to %u", s->name, desired_spec.rate);
|
||||
pa_log_debug("Suspending source %s due to changing format, desired format = %s rate = %u",
|
||||
s->name, pa_sample_format_to_string(desired_spec.format), desired_spec.rate);
|
||||
pa_source_suspend(s, true, PA_SUSPEND_INTERNAL);
|
||||
|
||||
if (s->reconfigure)
|
||||
ret = s->reconfigure(s, &desired_spec, passthrough);
|
||||
s->reconfigure(s, &desired_spec, passthrough);
|
||||
else {
|
||||
/* This is a monitor source. */
|
||||
|
||||
|
|
@ -1107,43 +1112,22 @@ int pa_source_reconfigure(pa_source *s, pa_sample_spec *spec, bool passthrough)
|
|||
* have no idea whether the behaviour with passthrough streams is
|
||||
* sensible. */
|
||||
if (!passthrough) {
|
||||
pa_sample_spec old_spec = s->sample_spec;
|
||||
|
||||
s->sample_spec = desired_spec;
|
||||
ret = pa_sink_reconfigure(s->monitor_of, &desired_spec, false);
|
||||
|
||||
if (ret < 0) {
|
||||
/* Changing the sink rate failed, roll back the old rate for
|
||||
* the monitor source. Why did we set the source rate before
|
||||
* calling pa_sink_reconfigure(), you may ask. The reason is
|
||||
* that pa_sink_reconfigure() tries to update the monitor
|
||||
* source rate, but we are already in the process of updating
|
||||
* the monitor source rate, so there's a risk of entering an
|
||||
* infinite loop. Setting the source rate before calling
|
||||
* pa_sink_reconfigure() makes the rate == s->sample_spec.rate
|
||||
* check in the beginning of this function return early, so we
|
||||
* avoid looping. */
|
||||
s->sample_spec = old_spec;
|
||||
}
|
||||
pa_sink_reconfigure(s->monitor_of, &desired_spec, false);
|
||||
s->sample_spec = s->monitor_of->sample_spec;
|
||||
} else
|
||||
ret = -1;
|
||||
goto unsuspend;
|
||||
}
|
||||
|
||||
if (ret >= 0) {
|
||||
uint32_t idx;
|
||||
pa_source_output *o;
|
||||
|
||||
PA_IDXSET_FOREACH(o, s->outputs, idx) {
|
||||
if (o->state == PA_SOURCE_OUTPUT_CORKED)
|
||||
pa_source_output_update_rate(o);
|
||||
}
|
||||
|
||||
pa_log_info("Changed sampling rate successfully");
|
||||
PA_IDXSET_FOREACH(o, s->outputs, idx) {
|
||||
if (o->state == PA_SOURCE_OUTPUT_CORKED)
|
||||
pa_source_output_update_resampler(o);
|
||||
}
|
||||
|
||||
pa_log_info("Reconfigured successfully");
|
||||
|
||||
unsuspend:
|
||||
pa_source_suspend(s, false, PA_SUSPEND_INTERNAL);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Called from main thread */
|
||||
|
|
@ -2935,6 +2919,43 @@ done:
|
|||
return out_formats;
|
||||
}
|
||||
|
||||
/* Called from the main thread */
|
||||
void pa_source_set_sample_format(pa_source *s, pa_sample_format_t format) {
|
||||
pa_sample_format_t old_format;
|
||||
|
||||
pa_assert(s);
|
||||
pa_assert(pa_sample_format_valid(format));
|
||||
|
||||
old_format = s->sample_spec.format;
|
||||
if (old_format == format)
|
||||
return;
|
||||
|
||||
pa_log_info("%s: format: %s -> %s",
|
||||
s->name, pa_sample_format_to_string(old_format), pa_sample_format_to_string(format));
|
||||
|
||||
s->sample_spec.format = format;
|
||||
|
||||
pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE | PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
|
||||
}
|
||||
|
||||
/* Called from the main thread */
|
||||
void pa_source_set_sample_rate(pa_source *s, uint32_t rate) {
|
||||
uint32_t old_rate;
|
||||
|
||||
pa_assert(s);
|
||||
pa_assert(pa_sample_rate_valid(rate));
|
||||
|
||||
old_rate = s->sample_spec.rate;
|
||||
if (old_rate == rate)
|
||||
return;
|
||||
|
||||
pa_log_info("%s: rate: %u -> %u", s->name, old_rate, rate);
|
||||
|
||||
s->sample_spec.rate = rate;
|
||||
|
||||
pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE | PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
|
||||
}
|
||||
|
||||
/* Called from the main thread. */
|
||||
void pa_source_set_reference_volume_direct(pa_source *s, const pa_cvolume *volume) {
|
||||
pa_cvolume old_volume;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue