pa_assert(t);
pa_assert(t->device);
- pa_assert(t->profile == PA_BLUETOOTH_PROFILE_A2DP_SINK || t->profile == PA_BLUETOOTH_PROFILE_A2DP_SOURCE);
+ pa_assert(pa_bluetooth_profile_is_a2dp(t->profile));
pa_assert(t->device->discovery);
gain = volume_to_a2dp_gain(volume);
char volume_str[PA_VOLUME_SNPRINT_MAX];
pa_assert(t);
+ pa_assert(t->device);
+
+ if (!t->device->avrcp_absolute_volume)
+ return;
is_source = t->profile == PA_BLUETOOTH_PROFILE_A2DP_SOURCE;
pa_assert(t->device);
pa_assert(t->device->discovery);
- pa_assert(t->profile == PA_BLUETOOTH_PROFILE_A2DP_SINK || t->profile == PA_BLUETOOTH_PROFILE_A2DP_SOURCE);
+ pa_assert(pa_bluetooth_profile_is_a2dp(t->profile));
pa_assert_se(m = dbus_message_new_method_call(BLUEZ_SERVICE, t->path, DBUS_INTERFACE_PROPERTIES, "Get"));
pa_assert_se(dbus_message_append_args(m,
void pa_bluetooth_transport_load_a2dp_sink_volume(pa_bluetooth_transport *t) {
pa_assert(t);
+ pa_assert(t->device);
+
+ if (!t->device->avrcp_absolute_volume)
+ return;
if (t->profile == PA_BLUETOOTH_PROFILE_A2DP_SINK)
/* A2DP Absolute Volume control (AVRCP 1.4) is optional */
pa_assert_not_reached();
}
+bool pa_bluetooth_profile_is_a2dp(pa_bluetooth_profile_t profile) {
+ return profile == PA_BLUETOOTH_PROFILE_A2DP_SINK || profile == PA_BLUETOOTH_PROFILE_A2DP_SOURCE;
+}
+
static const pa_a2dp_endpoint_conf *a2dp_sep_to_a2dp_endpoint_conf(const char *endpoint) {
const char *codec_name;
bool valid;
bool autodetect_mtu;
bool codec_switching_in_progress;
+ bool avrcp_absolute_volume;
uint32_t output_rate_refresh_interval_ms;
/* Device information */
const char *pa_bluetooth_profile_to_string(pa_bluetooth_profile_t profile);
bool pa_bluetooth_profile_should_attenuate_volume(pa_bluetooth_profile_t profile);
+bool pa_bluetooth_profile_is_a2dp(pa_bluetooth_profile_t profile);
static inline bool pa_bluetooth_uuid_is_hsp_hs(const char *uuid) {
return pa_streq(uuid, PA_BLUETOOTH_UUID_HSP_HS) || pa_streq(uuid, PA_BLUETOOTH_UUID_HSP_HS_ALT);
"path=<device object path>"
"autodetect_mtu=<boolean>"
"output_rate_refresh_interval_ms=<interval between attempts to improve output rate in milliseconds>"
+ "avrcp_absolute_volume=<synchronize volume with peer, true by default>"
);
#define FIXED_LATENCY_PLAYBACK_A2DP (25 * PA_USEC_PER_MSEC)
"path",
"autodetect_mtu",
"output_rate_refresh_interval_ms",
+ "avrcp_absolute_volume",
NULL
};
pa_assert(u->source == s);
pa_assert(u->transport);
+ if (pa_bluetooth_profile_is_a2dp(u->profile) && !u->transport->device->avrcp_absolute_volume)
+ return;
+
/* Remote volume control has to be supported for the callback to make sense,
* otherwise this source should continue performing attenuation in software
* without HW_VOLUME_CTL.
pa_assert(u->sink == s);
pa_assert(u->transport);
+ if (pa_bluetooth_profile_is_a2dp(u->profile) && !u->transport->device->avrcp_absolute_volume)
+ return;
+
/* Remote volume control has to be supported for the callback to make sense,
* otherwise this sink should continue performing attenuation in software
* without HW_VOLUME_CTL.
pa_json_encoder_begin_element_array(encoder);
- if (u->profile == PA_BLUETOOTH_PROFILE_A2DP_SINK || u->profile == PA_BLUETOOTH_PROFILE_A2DP_SOURCE) {
+ if (pa_bluetooth_profile_is_a2dp(u->profile)) {
is_a2dp_sink = u->profile == PA_BLUETOOTH_PROFILE_A2DP_SINK;
a2dp_endpoints = is_a2dp_sink ? u->device->a2dp_sink_endpoints : u->device->a2dp_source_endpoints;
struct userdata *u;
const char *path;
pa_modargs *ma;
- bool autodetect_mtu;
+ bool autodetect_mtu, avrcp_absolute_volume;
char *message_handler_path;
uint32_t output_rate_refresh_interval_ms;
u->device->output_rate_refresh_interval_ms = output_rate_refresh_interval_ms;
+ avrcp_absolute_volume = true;
+ if (pa_modargs_get_value_boolean(ma, "avrcp_absolute_volume", &avrcp_absolute_volume) < 0) {
+ pa_log("Invalid boolean value for avrcp_absolute_volume parameter");
+ goto fail_free_modargs;
+ }
+
+ u->device->avrcp_absolute_volume = avrcp_absolute_volume;
+
pa_modargs_free(ma);
u->device_connection_changed_slot =
"output_rate_refresh_interval_ms=<interval between attempts to improve output rate in milliseconds>"
"enable_native_hsp_hs=<boolean, enable HSP support in native backend>"
"enable_native_hfp_hf=<boolean, enable HFP support in native backend>"
+ "avrcp_absolute_volume=<synchronize volume with peer, true by default>"
);
static const char* const valid_modargs[] = {
"output_rate_refresh_interval_ms",
"enable_native_hsp_hs",
"enable_native_hfp_hf",
+ "avrcp_absolute_volume",
NULL
};
pa_hook_slot *device_connection_changed_slot;
pa_bluetooth_discovery *discovery;
bool autodetect_mtu;
+ bool avrcp_absolute_volume;
uint32_t output_rate_refresh_interval_ms;
};
if (!module_loaded && pa_bluetooth_device_any_transport_connected(d)) {
/* a new device has been connected */
pa_module *m;
- char *args = pa_sprintf_malloc("path=%s autodetect_mtu=%i output_rate_refresh_interval_ms=%u",
- d->path, (int)u->autodetect_mtu, u->output_rate_refresh_interval_ms);
+ char *args = pa_sprintf_malloc("path=%s autodetect_mtu=%i output_rate_refresh_interval_ms=%u"
+ " avrcp_absolute_volume=%i",
+ d->path,
+ (int)u->autodetect_mtu,
+ u->output_rate_refresh_interval_ms,
+ (int)u->avrcp_absolute_volume);
pa_log_debug("Loading module-bluez5-device %s", args);
pa_module_load(&m, u->module->core, "module-bluez5-device", args);
int headset_backend;
bool autodetect_mtu;
bool enable_msbc;
+ bool avrcp_absolute_volume;
uint32_t output_rate_refresh_interval_ms;
bool enable_native_hsp_hs;
bool enable_native_hfp_hf;
goto fail;
}
+ avrcp_absolute_volume = true;
+ if (pa_modargs_get_value_boolean(ma, "avrcp_absolute_volume", &avrcp_absolute_volume) < 0) {
+ pa_log("avrcp_absolute_volume must be true or false");
+ goto fail;
+ }
+
output_rate_refresh_interval_ms = DEFAULT_OUTPUT_RATE_REFRESH_INTERVAL_MS;
if (pa_modargs_get_value_u32(ma, "output_rate_refresh_interval_ms", &output_rate_refresh_interval_ms) < 0) {
pa_log("Invalid value for output_rate_refresh_interval parameter.");
u->module = m;
u->core = m->core;
u->autodetect_mtu = autodetect_mtu;
+ u->avrcp_absolute_volume = avrcp_absolute_volume;
u->output_rate_refresh_interval_ms = output_rate_refresh_interval_ms;
u->loaded_device_paths = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);