diff options
-rw-r--r-- | src/modules/bluetooth/bt-codec-msbc.c | 80 |
1 files changed, 47 insertions, 33 deletions
diff --git a/src/modules/bluetooth/bt-codec-msbc.c b/src/modules/bluetooth/bt-codec-msbc.c index 7df837e76..7a26e3c61 100644 --- a/src/modules/bluetooth/bt-codec-msbc.c +++ b/src/modules/bluetooth/bt-codec-msbc.c @@ -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*/ |