summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/modules/bluetooth/a2dp-codec-sbc.c19
-rw-r--r--src/modules/bluetooth/bt-codec-api.h3
-rw-r--r--src/modules/bluetooth/module-bluez5-device.c31
3 files changed, 53 insertions, 0 deletions
diff --git a/src/modules/bluetooth/a2dp-codec-sbc.c b/src/modules/bluetooth/a2dp-codec-sbc.c
index 2c069cb6f..5476697f8 100644
--- a/src/modules/bluetooth/a2dp-codec-sbc.c
+++ b/src/modules/bluetooth/a2dp-codec-sbc.c
@@ -57,6 +57,7 @@ struct sbc_info {
uint8_t nr_blocks;
uint8_t nr_subbands;
+ bool boost_source_volume;
/* Size of SBC frame fragment left over from previous decoding iteration */
size_t frame_fragment_size;
/* Maximum SBC frame size is 512 bytes when SBC compression ratio > 1 */
@@ -943,6 +944,9 @@ static int reset(void *codec_info) {
struct sbc_info *sbc_info = (struct sbc_info *) codec_info;
int ret;
+ /* forget about source volume boost */
+ sbc_info->boost_source_volume = false;
+
/* forget last saved frame fragment */
sbc_info->frame_fragment_size = 0;
@@ -1356,6 +1360,10 @@ static size_t decode_buffer_faststream(void *codec_info, const uint8_t *input_bu
* remember this, and keep incoming sample rate at 16000 */
pa_log_debug("FastStream decoder detected SBC frequency %u, expected %u", sbc_info->sbc.frequency, sbc_info->frequency);
sbc_info->frequency = sbc_info->sbc.frequency;
+
+ /* volume is too low for known devices with unexpected source SBC frequency */
+ pa_log_debug("FastStream decoder requesting 20dB boost for source volume");
+ sbc_info->boost_source_volume = true;
}
if (sbc_info->sbc.mode == SBC_MODE_MONO) {
@@ -1396,6 +1404,16 @@ static size_t decode_buffer_faststream(void *codec_info, const uint8_t *input_bu
return d - output_buffer;
}
+/* Boost sink backchannel mic volume by 20dB as it appears too quiet */
+double get_source_output_volume_factor_dB_faststream(void *codec_info) {
+ struct sbc_info *sbc_info = (struct sbc_info *) codec_info;
+
+ if (sbc_info->boost_source_volume)
+ return 20.;
+
+ return 1.0;
+}
+
const pa_a2dp_endpoint_conf pa_a2dp_endpoint_conf_sbc = {
.id = { A2DP_CODEC_SBC, 0, 0 },
.can_be_supported = can_be_supported,
@@ -1547,5 +1565,6 @@ const pa_a2dp_endpoint_conf pa_a2dp_endpoint_conf_faststream = {
.get_encoded_block_size = get_encoded_block_size_faststream,
.encode_buffer = encode_buffer_faststream,
.decode_buffer = decode_buffer_faststream,
+ .get_source_output_volume_factor_dB = get_source_output_volume_factor_dB_faststream,
},
};
diff --git a/src/modules/bluetooth/bt-codec-api.h b/src/modules/bluetooth/bt-codec-api.h
index 3ed47166a..700c28753 100644
--- a/src/modules/bluetooth/bt-codec-api.h
+++ b/src/modules/bluetooth/bt-codec-api.h
@@ -67,4 +67,7 @@ typedef struct pa_bt_codec {
* returns size of filled ouput_buffer and set processed to size of
* processed input_buffer */
size_t (*decode_buffer)(void *codec_info, const uint8_t *input_buffer, size_t input_size, uint8_t *output_buffer, size_t output_size, size_t *processed);
+
+ /* Get volume factor which needs to be applied to output samples */
+ double (*get_source_output_volume_factor_dB)(void *codec_info);
} pa_bt_codec;
diff --git a/src/modules/bluetooth/module-bluez5-device.c b/src/modules/bluetooth/module-bluez5-device.c
index f50521c59..ab1bc098e 100644
--- a/src/modules/bluetooth/module-bluez5-device.c
+++ b/src/modules/bluetooth/module-bluez5-device.c
@@ -116,6 +116,8 @@ struct userdata {
pa_hook_slot *sink_volume_changed_slot;
pa_hook_slot *source_volume_changed_slot;
+ pa_hook_slot *source_output_new_hook_slot;
+
pa_bluetooth_discovery *discovery;
pa_bluetooth_device *device;
pa_bluetooth_transport *transport;
@@ -2755,6 +2757,30 @@ static int device_process_msg(pa_msgobject *obj, int code, void *data, int64_t o
return 0;
}
+/* Run from main thread */
+static pa_hook_result_t a2dp_source_output_fixate_hook_callback(pa_core *c, pa_source_output_new_data *new_data, struct userdata *u) {
+ double volume_factor_dB;
+ pa_cvolume cv;
+
+ pa_assert(c);
+ pa_assert(new_data);
+ pa_assert(u);
+
+ /* When transport is released, there is no decoder and no codec */
+ if (!u->bt_codec || !u->decoder_info)
+ return PA_HOOK_OK;
+
+ if (!u->bt_codec->get_source_output_volume_factor_dB)
+ return PA_HOOK_OK;
+
+ volume_factor_dB = u->bt_codec->get_source_output_volume_factor_dB(u->decoder_info);
+
+ pa_cvolume_set(&cv, u->decoder_sample_spec.channels, pa_sw_volume_from_dB(volume_factor_dB));
+ pa_source_output_new_data_apply_volume_factor_source(new_data, &cv);
+
+ return PA_HOOK_OK;
+}
+
int pa__init(pa_module* m) {
struct userdata *u;
const char *path;
@@ -2836,6 +2862,8 @@ int pa__init(pa_module* m) {
u->transport_source_volume_changed_slot =
pa_hook_connect(pa_bluetooth_discovery_hook(u->discovery, PA_BLUETOOTH_HOOK_TRANSPORT_SOURCE_VOLUME_CHANGED), PA_HOOK_NORMAL, (pa_hook_cb_t) transport_source_volume_changed_cb, u);
+ u->source_output_new_hook_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_NEW], PA_HOOK_EARLY, (pa_hook_cb_t) a2dp_source_output_fixate_hook_callback, u);
+
if (add_card(u) < 0)
goto fail;
@@ -2899,6 +2927,9 @@ void pa__done(pa_module *m) {
stop_thread(u);
+ if (u->source_output_new_hook_slot)
+ pa_hook_slot_free(u->source_output_new_hook_slot);
+
if (u->device_connection_changed_slot)
pa_hook_slot_free(u->device_connection_changed_slot);