From 1c388f977a4801202c9d0f07d43b705ab3f83f16 Mon Sep 17 00:00:00 2001 From: Luiz Augusto von Dentz Date: Thu, 23 Dec 2010 13:13:44 +0200 Subject: bluetooth: reduce bitpool if audio start skipping When audio skips it could be that there is some bandwidth limitation in the link e.g. headset doesn't support EDR (< 2.0), and by reducing the bitpool it may find a better rate that either prevent the skips completely or at least reduce them. --- src/modules/bluetooth/module-bluetooth-device.c | 71 +++++++++++++++++++++++++ 1 file changed, 71 insertions(+) (limited to 'src/modules/bluetooth') diff --git a/src/modules/bluetooth/module-bluetooth-device.c b/src/modules/bluetooth/module-bluetooth-device.c index 34ff8f8c..99c6e194 100644 --- a/src/modules/bluetooth/module-bluetooth-device.c +++ b/src/modules/bluetooth/module-bluetooth-device.c @@ -58,6 +58,9 @@ #define MAX_BITPOOL 64 #define MIN_BITPOOL 2U +#define BITPOOL_DEC_LIMIT 32 +#define BITPOOL_DEC_STEP 5 + PA_MODULE_AUTHOR("Joao Paulo Rechi Vita"); PA_MODULE_DESCRIPTION("Bluetooth audio sink and source"); PA_MODULE_VERSION(PACKAGE_VERSION); @@ -117,6 +120,8 @@ struct a2dp_info { size_t buffer_size; /* Size of the buffer */ uint16_t seq_num; /* Cumulative packet sequence */ + uint8_t min_bitpool; + uint8_t max_bitpool; }; struct hsp_info { @@ -660,6 +665,9 @@ static void setup_sbc(struct a2dp_info *a2dp) { pa_assert_not_reached(); } + a2dp->min_bitpool = active_capabilities->min_bitpool; + a2dp->max_bitpool = active_capabilities->max_bitpool; + a2dp->sbc.bitpool = active_capabilities->max_bitpool; a2dp->codesize = sbc_get_codesize(&a2dp->sbc); a2dp->frame_length = sbc_get_frame_length(&a2dp->sbc); @@ -743,6 +751,39 @@ static int set_conf(struct userdata *u) { return 0; } +/* from IO thread */ +static void a2dp_set_bitpool(struct userdata *u, uint8_t bitpool) +{ + struct a2dp_info *a2dp; + + pa_assert(u); + + a2dp = &u->a2dp; + + if (a2dp->sbc.bitpool == bitpool) + return; + + if (bitpool > a2dp->max_bitpool) + bitpool = a2dp->max_bitpool; + else if (bitpool < a2dp->min_bitpool) + bitpool = a2dp->min_bitpool; + + a2dp->sbc.bitpool = bitpool; + + a2dp->codesize = sbc_get_codesize(&a2dp->sbc); + a2dp->frame_length = sbc_get_frame_length(&a2dp->sbc); + + pa_log_debug("Bitpool has changed to %u", a2dp->sbc.bitpool); + + u->block_size = + (u->link_mtu - sizeof(struct rtp_header) - sizeof(struct rtp_payload)) + / a2dp->frame_length * a2dp->codesize; + + pa_sink_set_max_request_within_thread(u->sink, u->block_size); + pa_sink_set_fixed_latency_within_thread(u->sink, + FIXED_LATENCY_PLAYBACK_A2DP + pa_bytes_to_usec(u->block_size, &u->sample_spec)); +} + /* from IO thread, except in SCO over PCM */ static int setup_stream(struct userdata *u) { @@ -758,6 +799,9 @@ static int setup_stream(struct userdata *u) { pa_log_debug("Stream properly set up, we're ready to roll!"); + if (u->profile == PROFILE_A2DP) + a2dp_set_bitpool(u, u->a2dp.max_bitpool); + u->rtpoll_item = pa_rtpoll_item_new(u->rtpoll, PA_RTPOLL_NEVER, 1); pollfd = pa_rtpoll_item_get_pollfd(u->rtpoll_item, NULL); pollfd->fd = u->stream_fd; @@ -1489,6 +1533,27 @@ static int a2dp_process_push(struct userdata *u) { return ret; } +static void a2dp_reduce_bitpool(struct userdata *u) +{ + struct a2dp_info *a2dp; + uint8_t bitpool; + + pa_assert(u); + + a2dp = &u->a2dp; + + /* Check if bitpool is already at its limit */ + if (a2dp->sbc.bitpool <= BITPOOL_DEC_LIMIT) + return; + + bitpool = a2dp->sbc.bitpool - BITPOOL_DEC_STEP; + + if (bitpool < BITPOOL_DEC_LIMIT) + bitpool = BITPOOL_DEC_LIMIT; + + a2dp_set_bitpool(u, bitpool); +} + static void thread_func(void *userdata) { struct userdata *u = userdata; unsigned do_write = 0; @@ -1580,6 +1645,9 @@ static void thread_func(void *userdata) { pa_sink_render_full(u->sink, skip_bytes, &tmp); pa_memblock_unref(tmp.memblock); u->write_index += skip_bytes; + + if (u->profile == PROFILE_A2DP) + a2dp_reduce_bitpool(u); } } @@ -2095,6 +2163,9 @@ static int bt_transport_config_a2dp(struct userdata *u) { pa_assert_not_reached(); } + a2dp->min_bitpool = config->min_bitpool; + a2dp->max_bitpool = config->max_bitpool; + a2dp->sbc.bitpool = config->max_bitpool; a2dp->codesize = sbc_get_codesize(&a2dp->sbc); a2dp->frame_length = sbc_get_frame_length(&a2dp->sbc); -- cgit