mirror of
https://gitlab.freedesktop.org/pulseaudio/pulseaudio.git
synced 2025-10-29 05:40:23 -04:00
Merge branch 'bluetooth-sw-volume-compensation' into 'master'
bluetooth: Use software volume for >100%, balance and finer control Closes #1245 See merge request pulseaudio/pulseaudio!532
This commit is contained in:
commit
e0ebc003f1
1 changed files with 50 additions and 10 deletions
|
|
@ -929,9 +929,38 @@ static int source_set_state_in_io_thread_cb(pa_source *s, pa_source_state_t new_
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* Use software volume to compensate for lack in hardware granularity,
|
||||
* provide stereo balance, and >100% amplification */
|
||||
static bool set_software_volume_compensation(const pa_cvolume *real_volume,
|
||||
const pa_volume_t hardware_volume,
|
||||
pa_cvolume *soft_volume) {
|
||||
char hw_volume_str[PA_VOLUME_SNPRINT_VERBOSE_MAX];
|
||||
char volume_str[PA_CVOLUME_SNPRINT_VERBOSE_MAX];
|
||||
bool different = false;
|
||||
|
||||
pa_assert(real_volume->channels == soft_volume->channels);
|
||||
|
||||
for (int i = 0; i < soft_volume->channels; ++i) {
|
||||
/* Calculate in unsigned space since hardware volume can never exceed real_volume */
|
||||
pa_volume_t delta = PA_VOLUME_NORM + real_volume->values[i] - hardware_volume;
|
||||
soft_volume->values[i] = delta;
|
||||
different |= delta != PA_VOLUME_NORM;
|
||||
}
|
||||
|
||||
if (different) {
|
||||
pa_log_debug("Remote all-channel hardware volume %s does not match requested %s",
|
||||
pa_volume_snprint_verbose(hw_volume_str, sizeof(hw_volume_str), hardware_volume, false),
|
||||
pa_cvolume_snprint_verbose(volume_str, sizeof(volume_str), real_volume, NULL, false));
|
||||
pa_log_debug("Compensating with %s",
|
||||
pa_cvolume_snprint_verbose(volume_str, sizeof(volume_str), soft_volume, NULL, false));
|
||||
}
|
||||
|
||||
return different;
|
||||
}
|
||||
|
||||
/* Run from main thread */
|
||||
static void source_set_volume_cb(pa_source *s) {
|
||||
pa_volume_t volume;
|
||||
pa_volume_t volume, hardware_volume;
|
||||
struct userdata *u;
|
||||
|
||||
pa_assert(s);
|
||||
|
|
@ -945,10 +974,14 @@ static void source_set_volume_cb(pa_source *s) {
|
|||
pa_assert(u->transport);
|
||||
pa_assert(u->transport->set_source_volume);
|
||||
|
||||
/* In the AG role, send a command to change microphone gain on the HS/HF */
|
||||
volume = u->transport->set_source_volume(u->transport, pa_cvolume_max(&s->real_volume));
|
||||
volume = pa_cvolume_max(&s->real_volume);
|
||||
|
||||
pa_cvolume_set(&s->real_volume, u->decoder_sample_spec.channels, volume);
|
||||
/* In the AG role, send a command to change microphone gain on the HS/HF */
|
||||
// TODO: Round up for the below compensation to work properly.
|
||||
hardware_volume = u->transport->set_source_volume(u->transport, volume);
|
||||
// TODO: This does not take into account any rounding that might also happen on the headphones
|
||||
// For that we need to know which _incoming_ `Volume` change belongs to a requested volume.
|
||||
set_software_volume_compensation(&s->real_volume, hardware_volume, &s->soft_volume);
|
||||
}
|
||||
|
||||
/* Run from main thread */
|
||||
|
|
@ -1179,7 +1212,7 @@ static int sink_set_state_in_io_thread_cb(pa_sink *s, pa_sink_state_t new_state,
|
|||
|
||||
/* Run from main thread */
|
||||
static void sink_set_volume_cb(pa_sink *s) {
|
||||
pa_volume_t volume;
|
||||
pa_volume_t volume, hardware_volume;
|
||||
struct userdata *u;
|
||||
|
||||
pa_assert(s);
|
||||
|
|
@ -1193,10 +1226,11 @@ static void sink_set_volume_cb(pa_sink *s) {
|
|||
pa_assert(u->transport);
|
||||
pa_assert(u->transport->set_sink_volume);
|
||||
|
||||
/* In the AG role, send a command to change speaker gain on the HS/HF */
|
||||
volume = u->transport->set_sink_volume(u->transport, pa_cvolume_max(&s->real_volume));
|
||||
volume = pa_cvolume_max(&s->real_volume);
|
||||
|
||||
pa_cvolume_set(&s->real_volume, u->encoder_sample_spec.channels, volume);
|
||||
/* In the AG role, send a command to change speaker gain on the HS/HF */
|
||||
hardware_volume = u->transport->set_sink_volume(u->transport, volume);
|
||||
set_software_volume_compensation(&s->real_volume, hardware_volume, &s->soft_volume);
|
||||
}
|
||||
|
||||
/* Run from main thread */
|
||||
|
|
@ -2470,8 +2504,11 @@ static pa_hook_result_t transport_sink_volume_changed_cb(pa_bluetooth_discovery
|
|||
pa_cvolume_set(&v, u->encoder_sample_spec.channels, volume);
|
||||
if (pa_bluetooth_profile_should_attenuate_volume(t->profile))
|
||||
pa_sink_set_volume(u->sink, &v, true, true);
|
||||
else
|
||||
else {
|
||||
/* Reset local attenuation */
|
||||
pa_sink_set_soft_volume(u->sink, NULL);
|
||||
pa_sink_volume_changed(u->sink, &v);
|
||||
}
|
||||
|
||||
return PA_HOOK_OK;
|
||||
}
|
||||
|
|
@ -2499,8 +2536,11 @@ static pa_hook_result_t transport_source_volume_changed_cb(pa_bluetooth_discover
|
|||
|
||||
if (pa_bluetooth_profile_should_attenuate_volume(t->profile))
|
||||
pa_source_set_volume(u->source, &v, true, true);
|
||||
else
|
||||
else {
|
||||
/* Reset local attenuation */
|
||||
pa_source_set_soft_volume(u->source, NULL);
|
||||
pa_source_volume_changed(u->source, &v);
|
||||
}
|
||||
|
||||
return PA_HOOK_OK;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue