Each codec has different compression ratio and own method how to calculate
buffer size of encoded or decoded samples. So change A2DP codec API to
provide this information for module-bluez5-device module and fix
a2dp_prepare_encoder_buffer() and a2dp_prepare_decoder_buffer() functions.
API functions get_read_buffer_size() and get_write_buffer_size() now set
both decoded and encoded buffer sizes. Function reduce_encoder_bitrate()
was changed to not return new buffer size (it was not obvious if buffer
size was for encoded or decoded samples), but caller rather should call
get_write_buffer_size() to get new sizes.
---
src/modules/bluetooth/a2dp-codec-api.h | 17 ++++++------
src/modules/bluetooth/a2dp-codec-sbc.c | 25 ++++++++++-------
src/modules/bluetooth/module-bluez5-device.c | 41 ++++++++++++++++++----------
3 files changed, 50 insertions(+), 33 deletions(-)
diff --git a/src/modules/bluetooth/a2dp-codec-api.h
b/src/modules/bluetooth/a2dp-codec-api.h
index 55bb9ff70..517dc76f1 100644
--- a/src/modules/bluetooth/a2dp-codec-api.h
+++ b/src/modules/bluetooth/a2dp-codec-api.h
@@ -72,15 +72,14 @@ typedef struct pa_a2dp_codec {
/* Reset internal state of codec info data in codec_info */
void (*reset)(void *codec_info);
- /* Get read block size for codec */
- size_t (*get_read_block_size)(void *codec_info, size_t read_link_mtu);
- /* Get write block size for codec */
- size_t (*get_write_block_size)(void *codec_info, size_t write_link_mtu);
-
- /* Reduce encoder bitrate for codec, returns new write block size or zero
- * if not changed, called when socket is not accepting encoded data fast
- * enough */
- size_t (*reduce_encoder_bitrate)(void *codec_info, size_t write_link_mtu);
+ /* Get buffer sizes for read operations */
+ void (*get_read_buffer_size)(void *codec_info, size_t read_link_mtu,
size_t *output_buffer_size, size_t *encoded_buffer_size);
+ /* Get buffer sizes for write operations */
+ void (*get_write_buffer_size)(void *codec_info, size_t write_link_mtu,
size_t *input_buffer_size, size_t *encoded_buffer_size);
+
+ /* Reduce encoder bitrate for codec, returns non-zero on failure,
+ * called when socket is not accepting encoded data fast enough */
+ int (*reduce_encoder_bitrate)(void *codec_info);
/* Encode input_buffer of input_size to output_buffer of output_size,
* returns size of filled ouput_buffer and set processed to size of
diff --git a/src/modules/bluetooth/a2dp-codec-sbc.c
b/src/modules/bluetooth/a2dp-codec-sbc.c
index cdc20d7f0..f339b570d 100644
--- a/src/modules/bluetooth/a2dp-codec-sbc.c
+++ b/src/modules/bluetooth/a2dp-codec-sbc.c
@@ -423,7 +423,10 @@ static void *init(bool for_encoding, bool for_backchannel,
const uint8_t *config
sbc_info->min_bitpool = config->min_bitpool;
sbc_info->max_bitpool = config->max_bitpool;
- /* Set minimum bitpool for source to get the maximum possible block_size */
+ /* Set minimum bitpool for source to get the maximum possible buffer size
+ * in get_buffer_size() function. Buffer size is inversely proportional to
+ * frame length which depends on bitpool value. Bitpool is controlled by
+ * other side from range [min_bitpool, max_bitpool]. */
sbc_info->initial_bitpool = for_encoding ? sbc_info->max_bitpool :
sbc_info->min_bitpool;
set_params(sbc_info);
@@ -475,20 +478,22 @@ static void reset(void *codec_info) {
sbc_info->seq_num = 0;
}
-static size_t get_block_size(void *codec_info, size_t link_mtu) {
+static void get_buffer_size(void *codec_info, size_t link_mtu, size_t
*decoded_buffer_size, size_t *encoded_buffer_size) {
struct sbc_info *sbc_info = (struct sbc_info *) codec_info;
+ size_t rtp_size = sizeof(struct rtp_header) + sizeof(struct rtp_payload);
+ size_t num_of_frames = (link_mtu - rtp_size) / sbc_info->frame_length;
- return (link_mtu - sizeof(struct rtp_header) - sizeof(struct rtp_payload))
- / sbc_info->frame_length * sbc_info->codesize;
+ *decoded_buffer_size = num_of_frames * sbc_info->codesize;
+ *encoded_buffer_size = num_of_frames * sbc_info->frame_length + rtp_size;
}
-static size_t reduce_encoder_bitrate(void *codec_info, size_t write_link_mtu) {
+static int reduce_encoder_bitrate(void *codec_info) {
struct sbc_info *sbc_info = (struct sbc_info *) codec_info;
uint8_t bitpool;
/* Check if bitpool is already at its limit */
if (sbc_info->sbc.bitpool <= SBC_BITPOOL_DEC_LIMIT)
- return 0;
+ return -1;
bitpool = sbc_info->sbc.bitpool - SBC_BITPOOL_DEC_STEP;
@@ -496,10 +501,10 @@ static size_t reduce_encoder_bitrate(void *codec_info,
size_t write_link_mtu) {
bitpool = SBC_BITPOOL_DEC_LIMIT;
if (sbc_info->sbc.bitpool == bitpool)
- return 0;
+ return -1;
set_bitpool(sbc_info, bitpool);
- return get_block_size(codec_info, write_link_mtu);
+ return 0;
}
static size_t encode_buffer(void *codec_info, uint32_t timestamp, const
uint8_t *input_buffer, size_t input_size, uint8_t *output_buffer, size_t
output_size, size_t *processed) {
@@ -639,8 +644,8 @@ const pa_a2dp_codec pa_a2dp_codec_sbc = {
.init = init,
.deinit = deinit,
.reset = reset,
- .get_read_block_size = get_block_size,
- .get_write_block_size = get_block_size,
+ .get_read_buffer_size = get_buffer_size,
+ .get_write_buffer_size = get_buffer_size,
.reduce_encoder_bitrate = reduce_encoder_bitrate,
.encode_buffer = encode_buffer,
.decode_buffer = decode_buffer,
diff --git a/src/modules/bluetooth/module-bluez5-device.c
b/src/modules/bluetooth/module-bluez5-device.c
index 56c96054d..c0b293d94 100644
--- a/src/modules/bluetooth/module-bluez5-device.c
+++ b/src/modules/bluetooth/module-bluez5-device.c
@@ -125,7 +125,9 @@ struct userdata {
size_t read_link_mtu;
size_t write_link_mtu;
size_t read_block_size;
+ size_t read_encoded_block_size;
size_t write_block_size;
+ size_t write_encoded_block_size;
uint64_t read_index;
uint64_t write_index;
pa_usec_t started_at;
@@ -412,10 +414,10 @@ static int sco_process_push(struct userdata *u) {
static void a2dp_prepare_encoder_buffer(struct userdata *u) {
pa_assert(u);
- if (u->encoder_buffer_size >= u->write_link_mtu)
+ if (u->encoder_buffer_size >= u->write_encoded_block_size)
return;
- u->encoder_buffer_size = 2 * u->write_link_mtu;
+ u->encoder_buffer_size = u->write_encoded_block_size;
pa_xfree(u->encoder_buffer);
u->encoder_buffer = pa_xmalloc(u->encoder_buffer_size);
}
@@ -424,10 +426,10 @@ static void a2dp_prepare_encoder_buffer(struct userdata
*u) {
static void a2dp_prepare_decoder_buffer(struct userdata *u) {
pa_assert(u);
- if (u->decoder_buffer_size >= u->read_link_mtu)
+ if (u->decoder_buffer_size >= u->read_encoded_block_size)
return;
- u->decoder_buffer_size = 2 * u->read_link_mtu;
+ u->decoder_buffer_size = u->read_encoded_block_size;
pa_xfree(u->decoder_buffer);
u->decoder_buffer = pa_xmalloc(u->decoder_buffer_size);
}
@@ -436,6 +438,9 @@ static void a2dp_prepare_decoder_buffer(struct userdata *u)
{
static int a2dp_write_buffer(struct userdata *u, size_t nbytes) {
int ret = 0;
+ if (!nbytes)
+ return 0;
+
for (;;) {
ssize_t l;
@@ -504,14 +509,14 @@ static int a2dp_process_render(struct userdata *u) {
/* Try to create a packet of the full MTU */
ptr = (const uint8_t *) pa_memblock_acquire_chunk(&u->write_memchunk);
- length = u->a2dp_codec->encode_buffer(u->encoder_info, u->write_index /
pa_frame_size(&u->encoder_sample_spec), ptr, u->write_memchunk.length,
u->encoder_buffer, u->encoder_buffer_size, &processed);
+ length = u->a2dp_codec->encode_buffer(u->encoder_info, u->write_index /
pa_frame_size(&u->encoder_sample_spec), ptr, u->write_memchunk.length,
u->encoder_buffer, u->write_encoded_block_size, &processed);
pa_memblock_release(u->write_memchunk.memblock);
- if (length == 0)
+ if (processed != u->write_memchunk.length) {
+ pa_log_error("Encoding error");
return -1;
-
- pa_assert(processed == u->write_memchunk.length);
+ }
return a2dp_write_buffer(u, length);
}
@@ -539,7 +544,7 @@ static int a2dp_process_push(struct userdata *u) {
a2dp_prepare_decoder_buffer(u);
- l = pa_read(u->stream_fd, u->decoder_buffer, u->decoder_buffer_size,
&u->stream_write_type);
+ l = pa_read(u->stream_fd, u->decoder_buffer,
u->read_encoded_block_size, &u->stream_write_type);
if (l <= 0) {
@@ -568,6 +573,14 @@ static int a2dp_process_push(struct userdata *u) {
memchunk.length = pa_memblock_get_length(memchunk.memblock);
memchunk.length = u->a2dp_codec->decode_buffer(u->decoder_info,
u->decoder_buffer, l, ptr, memchunk.length, &processed);
+
+ if (processed != (size_t) l) {
+ pa_log_error("Decoding error");
+ pa_memblock_release(memchunk.memblock);
+ ret = -1;
+ break;
+ }
+
if (memchunk.length == 0) {
pa_memblock_release(memchunk.memblock);
ret = 0;
@@ -732,9 +745,9 @@ static void transport_config_mtu(struct userdata *u) {
} else {
pa_assert(u->a2dp_codec);
if (u->profile == PA_BLUETOOTH_PROFILE_A2DP_SINK) {
- u->write_block_size =
u->a2dp_codec->get_write_block_size(u->encoder_info, u->write_link_mtu);
+ u->a2dp_codec->get_write_buffer_size(u->encoder_info,
u->write_link_mtu, &u->write_block_size, &u->write_encoded_block_size);
} else {
- u->read_block_size =
u->a2dp_codec->get_read_block_size(u->decoder_info, u->read_link_mtu);
+ u->a2dp_codec->get_read_buffer_size(u->decoder_info,
u->read_link_mtu, &u->read_block_size, &u->read_encoded_block_size);
}
}
@@ -1438,9 +1451,9 @@ static void thread_func(void *userdata) {
}
if (u->write_index > 0 && u->profile ==
PA_BLUETOOTH_PROFILE_A2DP_SINK) {
- size_t new_write_block_size =
u->a2dp_codec->reduce_encoder_bitrate(u->encoder_info, u->write_link_mtu);
- if (new_write_block_size) {
- u->write_block_size = new_write_block_size;
+ int failed =
u->a2dp_codec->reduce_encoder_bitrate(u->encoder_info);
+ if (!failed) {
+
u->a2dp_codec->get_write_buffer_size(u->encoder_info, u->write_link_mtu,
&u->write_block_size, &u->write_encoded_block_size);
handle_sink_block_size_change(u);
}
}
--
2.11.0
_______________________________________________
pulseaudio-discuss mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/pulseaudio-discuss