Commit 9916f0ea authored by Igor Kovalenko's avatar Igor Kovalenko Committed by PulseAudio Marge Bot
Browse files

bluetooth: mSBC: Decode packets larger than mSBC frame

Bluetooth transport layer already allows for packets larger than mSBC frame, and
there are up to 1 + MTU / (mSBC packet size) complete frames to be decoded from
each incoming SCO packet.

Now decoder fails when there is more than one complete frame available, which
could happen if MTU size is larger than 1.5 * (mSBC packet size) = 90

Fix this by adding a loop over avialable frames, and adjust decoded buffer size
to allow decoding up to 1 + MTU / (mSBC packet size) frames at once.

Part-of: <pulseaudio/pulseaudio!706>
parent 65889fbd
Pipeline #597623 passed with stages
in 1 minute and 59 seconds
......@@ -112,7 +112,15 @@ static size_t get_read_block_size(void *codec_info, size_t link_mtu) {
block_size = pa_frame_align(block_size, &info->sample_spec);
}
return block_size;
/* If MTU exceeds mSBC frame size there could be up to 1 + MTU / (mSBC frame size)
* frames decoded for single incoming packet.
* See also pa_bluetooth_transport::last_read_size handling
* and comment about MTU size in bt_prepare_encoder_buffer()
*/
if (link_mtu <= MSBC_PACKET_SIZE)
return block_size;
return block_size * (1 + link_mtu / MSBC_PACKET_SIZE);
}
static size_t get_write_block_size(void *codec_info, size_t link_mtu) {
......@@ -204,10 +212,10 @@ static inline bool is_all_zero(const uint8_t *ptr, size_t len) {
/*
* We build a msbc frame up in the sbc_info buffer until we have a whole one
*/
static struct msbc_frame *msbc_find_frame(struct sbc_info *si, ssize_t *len,
static struct msbc_frame *msbc_find_frame(struct sbc_info *si, size_t *len,
const uint8_t *buf, int *pseq)
{
int i;
size_t i;
uint8_t *p = si->input_buffer;
/* skip input if it has all zero bytes
......@@ -241,7 +249,7 @@ static struct msbc_frame *msbc_find_frame(struct sbc_info *si, ssize_t *len,
id1.b = p[1];
*pseq = (id1.s.sn0 & 0x1) | (id1.s.sn1 & 0x2);
si->msbc_push_offset = 0;
*len = *len - i;
*len -= i + 1;
return (struct msbc_frame *)p;
}
continue;
......@@ -255,49 +263,55 @@ static struct msbc_frame *msbc_find_frame(struct sbc_info *si, ssize_t *len,
static size_t decode_buffer(void *codec_info, const uint8_t *input_buffer, size_t input_size, uint8_t *output_buffer, size_t output_size, size_t *processed) {
struct sbc_info *sbc_info = (struct sbc_info *) codec_info;
ssize_t remaining;
size_t save_input_size;
ssize_t decoded;
size_t written = 0;
size_t total_written = 0;
size_t total_processed = 0;
struct msbc_frame *frame;
int seq;
remaining = input_size;
frame = msbc_find_frame(sbc_info, &remaining, input_buffer, &seq);
while (input_size > 0) {
/* only process when we have a full frame */
if (!frame) {
*processed = input_size - remaining;
return 0;
}
save_input_size = input_size;
frame = msbc_find_frame(sbc_info, &input_size, input_buffer + total_processed, &seq);
uint8_t lost_packets = (4 + seq - sbc_info->msbc_seq++) % 4;
total_processed += save_input_size - input_size;
if (lost_packets) {
pa_log_debug("Lost %d input audio packet(s)", lost_packets);
sbc_info->msbc_seq = seq + 1;
}
/* Only full mSBC frame should be decoded */
if (!frame)
break;
uint8_t lost_packets = (4 + seq - sbc_info->msbc_seq++) % 4;
decoded = sbc_decode(&sbc_info->sbc, frame->payload, MSBC_FRAME_SIZE, output_buffer, output_size, &written);
if (lost_packets) {
pa_log_debug("Lost %d input audio packet(s)", lost_packets);
sbc_info->msbc_seq = seq + 1;
}
/* now we've consumed the sbc_info buffer, start a new one with
* the partial frame we have */
if (remaining > 0)
msbc_find_frame(sbc_info, &remaining, input_buffer + input_size - remaining, &seq);
/* pa_bt_codec::get_read_block_size must provide space for all decoded frames */
pa_assert_fp(output_size >= sbc_info->codesize);
pa_assert_fp(remaining == 0);
decoded = sbc_decode(&sbc_info->sbc, frame->payload, MSBC_FRAME_SIZE, output_buffer, output_size, &written);
if (PA_UNLIKELY(decoded <= 0)) {
pa_log_error("mSBC decoding error (%li)", (long) decoded);
pa_silence_memory(output_buffer, sbc_info->codesize, &sbc_info->sample_spec);
decoded = sbc_info->frame_length;
written = sbc_info->codesize;
}
if (PA_UNLIKELY(decoded <= 0)) {
pa_log_error("mSBC decoding error (%li)", (long) decoded);
pa_silence_memory(output_buffer, sbc_info->codesize, &sbc_info->sample_spec);
decoded = sbc_info->frame_length;
written = sbc_info->codesize;
}
pa_assert_fp((size_t)decoded == sbc_info->frame_length);
pa_assert_fp((size_t)written == sbc_info->codesize);
pa_assert_fp((size_t)decoded == sbc_info->frame_length);
pa_assert_fp((size_t)written == sbc_info->codesize);
output_buffer += written;
output_size -= written;
total_written += written;
}
*processed = input_size - remaining;
return written;
*processed = total_processed;
return total_written;
}
/* Modified SBC codec for HFP Wideband Speech*/
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment