From 9699511215a39b688061a2640205c37c7dcd02a1 Mon Sep 17 00:00:00 2001 From: "Igor V. Kovalenko" Date: Wed, 20 Jan 2021 12:51:14 +0300 Subject: [PATCH] bluetooth: allow increasing output bitrate Bluetooth thread may ask encoder to reduce bitrate if writing is not keeping up with inputs or writing to bluetooth socket takes too much time. Assuming conditions leading to reduced bitrate are intermittent, allow periodic attempts to increase encoder bitrate, by default at most twice per second. Part-of: --- src/modules/bluetooth/a2dp-codec-api.h | 5 ++++ src/modules/bluetooth/bluez5-util.h | 1 + src/modules/bluetooth/module-bluez5-device.c | 28 ++++++++++++++++++++ 3 files changed, 34 insertions(+) diff --git a/src/modules/bluetooth/a2dp-codec-api.h b/src/modules/bluetooth/a2dp-codec-api.h index 744e5664a..1d7212f36 100644 --- a/src/modules/bluetooth/a2dp-codec-api.h +++ b/src/modules/bluetooth/a2dp-codec-api.h @@ -88,6 +88,11 @@ typedef struct pa_a2dp_codec { * enough */ size_t (*reduce_encoder_bitrate)(void *codec_info, size_t write_link_mtu); + /* Increase encoder bitrate for codec, returns new write block size or zero + * if not changed, called periodically when socket is keeping up with + * encoded data */ + size_t (*increase_encoder_bitrate)(void *codec_info, size_t write_link_mtu); + /* Encode input_buffer of input_size to output_buffer of output_size, * returns size of filled ouput_buffer and set processed to size of * processed input_buffer */ diff --git a/src/modules/bluetooth/bluez5-util.h b/src/modules/bluetooth/bluez5-util.h index e994a8d9a..64f37798f 100644 --- a/src/modules/bluetooth/bluez5-util.h +++ b/src/modules/bluetooth/bluez5-util.h @@ -110,6 +110,7 @@ struct pa_bluetooth_device { bool valid; bool autodetect_mtu; bool codec_switching_in_progress; + uint32_t output_rate_refresh_interval_ms; /* Device information */ char *path; diff --git a/src/modules/bluetooth/module-bluez5-device.c b/src/modules/bluetooth/module-bluez5-device.c index 54471324a..94726e8ed 100644 --- a/src/modules/bluetooth/module-bluez5-device.c +++ b/src/modules/bluetooth/module-bluez5-device.c @@ -66,6 +66,8 @@ PA_MODULE_USAGE("path=" #define HSP_MAX_GAIN 15 +#define DEFAULT_OUTPUT_RATE_REFRESH_INTERVAL_MS 500 + static const char* const valid_modargs[] = { "path", "autodetect_mtu", @@ -1362,6 +1364,8 @@ static void thread_func(void *userdata) { struct userdata *u = userdata; unsigned blocks_to_write = 0; unsigned bytes_to_write = 0; + struct timeval tv_last_output_rate_change; + pa_usec_t ts_elapsed; pa_assert(u); pa_assert(u->transport); @@ -1377,6 +1381,8 @@ static void thread_func(void *userdata) { if (u->transport_acquired) setup_stream(u); + pa_gettimeofday(&tv_last_output_rate_change); + for (;;) { struct pollfd *pollfd; int ret; @@ -1525,6 +1531,7 @@ static void thread_func(void *userdata) { u->write_block_size = new_write_block_size; handle_sink_block_size_change(u); } + pa_gettimeofday(&tv_last_output_rate_change); } } @@ -1557,6 +1564,19 @@ static void thread_func(void *userdata) { next_write_at = pa_bytes_to_usec(u->write_index, &u->encoder_sample_spec); sleep_for = time_passed < next_write_at ? next_write_at - time_passed : 0; /* pa_log("Sleeping for %lu; time passed %lu, next write at %lu", (unsigned long) sleep_for, (unsigned long) time_passed, (unsigned long)next_write_at); */ + + if (u->profile == PA_BLUETOOTH_PROFILE_A2DP_SINK && u->write_memchunk.memblock == NULL) { + /* write_block() is keeping up with input, try increasing bitrate */ + if (u->a2dp_codec->increase_encoder_bitrate + && pa_timeval_age(&tv_last_output_rate_change) >= u->device->output_rate_refresh_interval_ms * PA_USEC_PER_MSEC) { + size_t new_write_block_size = u->a2dp_codec->increase_encoder_bitrate(u->encoder_info, u->write_link_mtu); + if (new_write_block_size) { + u->write_block_size = new_write_block_size; + handle_sink_block_size_change(u); + } + pa_gettimeofday(&tv_last_output_rate_change); + } + } } else /* We could not write because the stream was not ready. Let's try * again in 500 ms and drop audio if we still can't write. The @@ -2488,6 +2508,7 @@ int pa__init(pa_module* m) { pa_modargs *ma; bool autodetect_mtu; char *message_handler_path; + uint32_t output_rate_refresh_interval_ms = DEFAULT_OUTPUT_RATE_REFRESH_INTERVAL_MS; pa_assert(m); @@ -2526,6 +2547,13 @@ int pa__init(pa_module* m) { u->device->autodetect_mtu = autodetect_mtu; + if (pa_modargs_get_value_u32(ma, "output-rate-refresh-interval-ms", &output_rate_refresh_interval_ms) < 0) { + pa_log("Invalid output_rate_refresh_interval."); + goto fail_free_modargs; + } + + u->device->output_rate_refresh_interval_ms = output_rate_refresh_interval_ms; + pa_modargs_free(ma); u->device_connection_changed_slot =