summaryrefslogtreecommitdiffstats
path: root/src/modules/bluetooth
diff options
context:
space:
mode:
authorLuiz Augusto von Dentz <luiz.dentz-von@nokia.com>2010-12-23 13:13:44 +0200
committerLuiz Augusto von Dentz <luiz.dentz-von@nokia.com>2011-03-14 13:51:48 -0300
commit1c388f977a4801202c9d0f07d43b705ab3f83f16 (patch)
tree5e8c2ec492de9b131961fc455b6a8f678ea6d2c5 /src/modules/bluetooth
parent8c982a4afece524fec5d928425477f3e7a56b817 (diff)
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.
Diffstat (limited to 'src/modules/bluetooth')
-rw-r--r--src/modules/bluetooth/module-bluetooth-device.c71
1 files changed, 71 insertions, 0 deletions
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);