bluetooth: Fix usage of MTU, buffer sizes and return values of encode/decode methods

Add explanation why minimal bitpool value is used in SBC codec as initial
bitpool value for A2DP source.

Set buffer size for reading/writing from/to A2DP socket to exact link MTU
value. This would ensure that A2DP codec does not produce larger packet as
maximal possible size which can be sent.

Because A2DP socket is of SOCK_SEQPACKET type, it is guaranteed that
we do not read two packets via one read/recvmsg call.

Properly check for all return values of encode/encode methods of A2DP codec
functions. They may fail at different levels. Also encode or decode API
method may return zero length buffer (e.g. because of algorithmic delay of
codec), so do not fail in this case.
This commit is contained in:
Pali Rohár 2019-07-21 17:07:00 +02:00 committed by Tanu Kaskinen
parent 3929798a53
commit 018b38ec39
3 changed files with 67 additions and 31 deletions

View file

@ -426,7 +426,11 @@ 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 block_size
* in get_block_size() function. This block_size is length of buffer used
* for decoded audio data and so 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);
@ -480,9 +484,10 @@ static void reset(void *codec_info) {
static size_t get_block_size(void *codec_info, size_t link_mtu) {
struct sbc_info *sbc_info = (struct sbc_info *) codec_info;
size_t rtp_size = sizeof(struct rtp_header) + sizeof(struct rtp_payload);
size_t frame_count = (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;
return frame_count * sbc_info->codesize;
}
static size_t reduce_encoder_bitrate(void *codec_info, size_t write_link_mtu) {
@ -536,8 +541,12 @@ static size_t encode_buffer(void *codec_info, uint32_t timestamp, const uint8_t
if (PA_UNLIKELY(encoded <= 0)) {
pa_log_error("SBC encoding error (%li)", (long) encoded);
*processed = p - input_buffer;
return 0;
break;
}
if (PA_UNLIKELY(written < 0)) {
pa_log_error("SBC encoding error (%li)", (long) written);
break;
}
pa_assert_fp((size_t) encoded <= to_encode);
@ -559,6 +568,11 @@ static size_t encode_buffer(void *codec_info, uint32_t timestamp, const uint8_t
pa_log_debug("Using SBC codec implementation: %s", pa_strnull(sbc_get_implementation_info(&sbc_info->sbc)));
} PA_ONCE_END;
if (PA_UNLIKELY(frame_count == 0)) {
*processed = 0;
return 0;
}
/* write it to the fifo */
memset(output_buffer, 0, sizeof(*header) + sizeof(*payload));
header->v = 2;
@ -595,7 +609,7 @@ static size_t decode_buffer(void *codec_info, const uint8_t *input_buffer, size_
d = output_buffer;
to_write = output_size;
while (PA_LIKELY(to_decode > 0)) {
while (PA_LIKELY(to_decode > 0 && to_write > 0)) {
size_t written;
ssize_t decoded;
@ -606,8 +620,7 @@ static size_t decode_buffer(void *codec_info, const uint8_t *input_buffer, size_
if (PA_UNLIKELY(decoded <= 0)) {
pa_log_error("SBC decoding error (%li)", (long) decoded);
*processed = p - input_buffer;
return 0;
break;
}
/* Reset frame length, it can be changed due to bitpool change */
@ -616,6 +629,7 @@ static size_t decode_buffer(void *codec_info, const uint8_t *input_buffer, size_
pa_assert_fp((size_t) decoded <= to_decode);
pa_assert_fp((size_t) decoded == sbc_info->frame_length);
pa_assert_fp((size_t) written <= to_write);
pa_assert_fp((size_t) written == sbc_info->codesize);
p += decoded;