mirror of
https://gitlab.freedesktop.org/pulseaudio/pulseaudio.git
synced 2025-10-29 05:40:23 -04:00
Merge branch 'bluetooth-muting' into 'master'
Draft: bluetooth: Handle muting over A2DP Absolute Volume See merge request pulseaudio/pulseaudio!533
This commit is contained in:
commit
5c0d45342e
3 changed files with 98 additions and 13 deletions
|
|
@ -103,11 +103,7 @@
|
|||
"</node>"
|
||||
|
||||
static pa_volume_t a2dp_gain_to_volume(uint16_t gain) {
|
||||
pa_volume_t volume = (pa_volume_t) ((
|
||||
gain * PA_VOLUME_NORM
|
||||
/* Round to closest by adding half the denominator */
|
||||
+ A2DP_MAX_GAIN / 2
|
||||
) / A2DP_MAX_GAIN);
|
||||
pa_volume_t volume = A2DP_GAIN_TO_VOLUME(gain);
|
||||
|
||||
if (volume > PA_VOLUME_NORM)
|
||||
volume = PA_VOLUME_NORM;
|
||||
|
|
@ -116,11 +112,7 @@ static pa_volume_t a2dp_gain_to_volume(uint16_t gain) {
|
|||
}
|
||||
|
||||
static uint16_t volume_to_a2dp_gain(pa_volume_t volume) {
|
||||
uint16_t gain = (uint16_t) ((
|
||||
volume * A2DP_MAX_GAIN
|
||||
/* Round to closest by adding half the denominator */
|
||||
+ PA_VOLUME_NORM / 2
|
||||
) / PA_VOLUME_NORM);
|
||||
uint16_t gain = VOLUME_TO_A2DP_GAIN(volume);
|
||||
|
||||
if (gain > A2DP_MAX_GAIN)
|
||||
gain = A2DP_MAX_GAIN;
|
||||
|
|
|
|||
|
|
@ -54,9 +54,22 @@
|
|||
#define PA_BLUETOOTH_UUID_HFP_HF "0000111e-0000-1000-8000-00805f9b34fb"
|
||||
#define PA_BLUETOOTH_UUID_HFP_AG "0000111f-0000-1000-8000-00805f9b34fb"
|
||||
|
||||
#define A2DP_MAX_GAIN 127
|
||||
#define HSP_MAX_GAIN 15
|
||||
|
||||
#define A2DP_MAX_GAIN 127
|
||||
/* Some devices only go as low as 1 */
|
||||
#define A2DP_MUTE_GAIN 1
|
||||
#define A2DP_MIN_GAIN (A2DP_MUTE_GAIN + 1)
|
||||
|
||||
/* Round to closest by adding half the denominator */
|
||||
#define A2DP_GAIN_TO_VOLUME(gain) \
|
||||
((pa_volume_t)(((gain)*PA_VOLUME_NORM + A2DP_MAX_GAIN / 2) / A2DP_MAX_GAIN))
|
||||
#define VOLUME_TO_A2DP_GAIN(volume) \
|
||||
((uint16_t)(((volume)*A2DP_MAX_GAIN + PA_VOLUME_NORM / 2) / PA_VOLUME_NORM))
|
||||
|
||||
#define A2DP_MUTE_VOLUME A2DP_GAIN_TO_VOLUME(A2DP_MUTE_GAIN)
|
||||
#define A2DP_MIN_VOLUME A2DP_GAIN_TO_VOLUME(A2DP_MIN_GAIN)
|
||||
|
||||
typedef struct pa_bluetooth_transport pa_bluetooth_transport;
|
||||
typedef struct pa_bluetooth_device pa_bluetooth_device;
|
||||
typedef struct pa_bluetooth_adapter pa_bluetooth_adapter;
|
||||
|
|
|
|||
|
|
@ -945,12 +945,36 @@ static void source_set_volume_cb(pa_source *s) {
|
|||
pa_assert(u->transport);
|
||||
pa_assert(u->transport->set_source_volume);
|
||||
|
||||
volume = pa_cvolume_max(&s->real_volume);
|
||||
|
||||
/* Prevent setting a gain below A2DP_MIN_GAIN, this is used to detect muting */
|
||||
if (volume < A2DP_MIN_VOLUME)
|
||||
volume = A2DP_MIN_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));
|
||||
if (!s->muted)
|
||||
volume = u->transport->set_source_volume(u->transport, volume);
|
||||
|
||||
pa_cvolume_set(&s->real_volume, u->decoder_sample_spec.channels, volume);
|
||||
}
|
||||
|
||||
static void source_set_mute_cb(pa_source *s) {
|
||||
struct userdata *u;
|
||||
|
||||
pa_assert(s);
|
||||
u = s->userdata;
|
||||
pa_assert(u);
|
||||
pa_assert(u->source == s);
|
||||
pa_assert(!pa_bluetooth_profile_should_attenuate_volume(u->profile));
|
||||
pa_assert(u->transport);
|
||||
pa_assert(u->transport->set_source_volume);
|
||||
|
||||
if (s->muted)
|
||||
u->transport->set_source_volume(u->transport, 0);
|
||||
else
|
||||
source_set_volume_cb(s);
|
||||
}
|
||||
|
||||
/* Run from main thread */
|
||||
static void source_setup_volume_callback(pa_source *s) {
|
||||
struct userdata *u;
|
||||
|
|
@ -993,6 +1017,8 @@ static void source_setup_volume_callback(pa_source *s) {
|
|||
u->source_volume_changed_slot = pa_hook_connect(&s->core->hooks[PA_CORE_HOOK_SOURCE_VOLUME_CHANGED],
|
||||
PA_HOOK_NORMAL, sink_source_volume_changed_cb, u);
|
||||
|
||||
// TODO: Mute hook!
|
||||
|
||||
/* Send initial volume to peer, signalling support for volume control */
|
||||
u->transport->set_source_volume(u->transport, pa_cvolume_max(&s->real_volume));
|
||||
} else {
|
||||
|
|
@ -1012,6 +1038,7 @@ static void source_setup_volume_callback(pa_source *s) {
|
|||
pa_source_set_soft_volume(s, NULL);
|
||||
|
||||
pa_source_set_set_volume_callback(s, source_set_volume_cb);
|
||||
pa_source_set_set_mute_callback(s, source_set_mute_cb);
|
||||
s->n_volume_steps = HSP_MAX_GAIN + 1;
|
||||
}
|
||||
}
|
||||
|
|
@ -1193,12 +1220,36 @@ static void sink_set_volume_cb(pa_sink *s) {
|
|||
pa_assert(u->transport);
|
||||
pa_assert(u->transport->set_sink_volume);
|
||||
|
||||
volume = pa_cvolume_max(&s->real_volume);
|
||||
|
||||
/* Prevent setting a gain below A2DP_MIN_GAIN, this is used to detect muting */
|
||||
if (volume < A2DP_MIN_VOLUME)
|
||||
volume = A2DP_MIN_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));
|
||||
if (!s->muted)
|
||||
volume = u->transport->set_sink_volume(u->transport, volume);
|
||||
|
||||
pa_cvolume_set(&s->real_volume, u->encoder_sample_spec.channels, volume);
|
||||
}
|
||||
|
||||
static void sink_set_mute_cb(pa_sink *s) {
|
||||
struct userdata *u;
|
||||
|
||||
pa_assert(s);
|
||||
u = s->userdata;
|
||||
pa_assert(u);
|
||||
pa_assert(u->sink == s);
|
||||
pa_assert(!pa_bluetooth_profile_should_attenuate_volume(u->profile));
|
||||
pa_assert(u->transport);
|
||||
pa_assert(u->transport->set_sink_volume);
|
||||
|
||||
if (s->muted)
|
||||
u->transport->set_sink_volume(u->transport, 0);
|
||||
else
|
||||
sink_set_volume_cb(s);
|
||||
}
|
||||
|
||||
/* Run from main thread */
|
||||
static void sink_setup_volume_callback(pa_sink *s) {
|
||||
struct userdata *u;
|
||||
|
|
@ -1246,6 +1297,8 @@ static void sink_setup_volume_callback(pa_sink *s) {
|
|||
u->sink_volume_changed_slot = pa_hook_connect(&s->core->hooks[PA_CORE_HOOK_SINK_VOLUME_CHANGED],
|
||||
PA_HOOK_NORMAL, sink_source_volume_changed_cb, u);
|
||||
|
||||
// TODO: Hook up mute callback!
|
||||
|
||||
/* Send initial volume to peer, signalling support for volume control */
|
||||
u->transport->set_sink_volume(u->transport, pa_cvolume_max(&s->real_volume));
|
||||
} else {
|
||||
|
|
@ -1258,6 +1311,7 @@ static void sink_setup_volume_callback(pa_sink *s) {
|
|||
pa_sink_set_soft_volume(s, NULL);
|
||||
|
||||
pa_sink_set_set_volume_callback(s, sink_set_volume_cb);
|
||||
pa_sink_set_set_mute_callback(s, sink_set_mute_cb);
|
||||
|
||||
if (u->profile == PA_BLUETOOTH_PROFILE_A2DP_SINK)
|
||||
s->n_volume_steps = A2DP_MAX_GAIN + 1;
|
||||
|
|
@ -2467,12 +2521,25 @@ static pa_hook_result_t transport_sink_volume_changed_cb(pa_bluetooth_discovery
|
|||
|
||||
sink_setup_volume_callback(u->sink);
|
||||
|
||||
if (t->profile == PA_BLUETOOTH_PROFILE_A2DP_SINK) {
|
||||
// TODO: Apply to HSP too
|
||||
if (volume <= A2DP_MUTE_VOLUME) {
|
||||
pa_sink_mute_changed(u->sink, true);
|
||||
/* Do not update local volume; unmute should jump back to previous */
|
||||
return PA_HOOK_OK;
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
pa_sink_volume_changed(u->sink, &v);
|
||||
|
||||
/* Unmute _after_ reflecting peer volume */
|
||||
if(u->sink->muted)
|
||||
pa_sink_mute_changed(u->sink, false);
|
||||
|
||||
return PA_HOOK_OK;
|
||||
}
|
||||
|
||||
|
|
@ -2495,6 +2562,15 @@ static pa_hook_result_t transport_source_volume_changed_cb(pa_bluetooth_discover
|
|||
|
||||
source_setup_volume_callback(u->source);
|
||||
|
||||
if (t->profile == PA_BLUETOOTH_PROFILE_A2DP_SOURCE) {
|
||||
// TODO: Apply to HSP too
|
||||
if (volume <= A2DP_MUTE_VOLUME) {
|
||||
pa_source_mute_changed(u->source, true);
|
||||
/* Do not update local volume; unmute should jump back to previous */
|
||||
return PA_HOOK_OK;
|
||||
}
|
||||
}
|
||||
|
||||
pa_cvolume_set(&v, u->decoder_sample_spec.channels, volume);
|
||||
|
||||
if (pa_bluetooth_profile_should_attenuate_volume(t->profile))
|
||||
|
|
@ -2502,6 +2578,10 @@ static pa_hook_result_t transport_source_volume_changed_cb(pa_bluetooth_discover
|
|||
else
|
||||
pa_source_volume_changed(u->source, &v);
|
||||
|
||||
/* Unmute _after_ reflecting peer volume */
|
||||
if(u->source->muted)
|
||||
pa_source_mute_changed(u->source, false);
|
||||
|
||||
return PA_HOOK_OK;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue