mirror of
https://gitlab.freedesktop.org/pulseaudio/pulseaudio.git
synced 2025-10-31 22:25:33 -04:00
bluetooth: Handle fragmented faststream frames
Incoming frames can span multiple packets, add support for this. Part-of: <https://gitlab.freedesktop.org/pulseaudio/pulseaudio/-/merge_requests/628>
This commit is contained in:
parent
697a1a309a
commit
76e01b25f5
1 changed files with 61 additions and 13 deletions
|
|
@ -39,6 +39,8 @@
|
||||||
#define SBC_BITPOOL_DEC_STEP 5
|
#define SBC_BITPOOL_DEC_STEP 5
|
||||||
#define SBC_BITPOOL_INC_STEP 1
|
#define SBC_BITPOOL_INC_STEP 1
|
||||||
|
|
||||||
|
#define SBC_SYNCWORD 0x9C
|
||||||
|
|
||||||
struct sbc_info {
|
struct sbc_info {
|
||||||
sbc_t sbc; /* Codec data */
|
sbc_t sbc; /* Codec data */
|
||||||
size_t codesize, frame_length; /* SBC Codesize, frame_length. We simply cache those values here */
|
size_t codesize, frame_length; /* SBC Codesize, frame_length. We simply cache those values here */
|
||||||
|
|
@ -54,6 +56,11 @@ struct sbc_info {
|
||||||
|
|
||||||
uint8_t nr_blocks;
|
uint8_t nr_blocks;
|
||||||
uint8_t nr_subbands;
|
uint8_t nr_subbands;
|
||||||
|
|
||||||
|
/* Size of SBC frame fragment left over from previous decoding iteration */
|
||||||
|
size_t frame_fragment_size;
|
||||||
|
/* Maximum SBC frame size is 512 bytes when SBC compression ratio > 1 */
|
||||||
|
uint8_t frame_fragment[512];
|
||||||
};
|
};
|
||||||
|
|
||||||
static bool can_be_supported(bool for_encoding) {
|
static bool can_be_supported(bool for_encoding) {
|
||||||
|
|
@ -936,6 +943,9 @@ static int reset(void *codec_info) {
|
||||||
struct sbc_info *sbc_info = (struct sbc_info *) codec_info;
|
struct sbc_info *sbc_info = (struct sbc_info *) codec_info;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
/* forget last saved frame fragment */
|
||||||
|
sbc_info->frame_fragment_size = 0;
|
||||||
|
|
||||||
ret = sbc_reinit(&sbc_info->sbc, 0);
|
ret = sbc_reinit(&sbc_info->sbc, 0);
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
pa_log_error("SBC reinitialization failed: %d", ret);
|
pa_log_error("SBC reinitialization failed: %d", ret);
|
||||||
|
|
@ -1279,27 +1289,60 @@ static size_t decode_buffer_faststream(void *codec_info, const uint8_t *input_bu
|
||||||
.rate = 16000U
|
.rate = 16000U
|
||||||
};
|
};
|
||||||
uint8_t decode_buffer[4096];
|
uint8_t decode_buffer[4096];
|
||||||
|
uint8_t frame_buffer[4096];
|
||||||
|
|
||||||
p = input_buffer;
|
|
||||||
to_decode = input_size;
|
to_decode = input_size;
|
||||||
|
|
||||||
|
/* append input buffer to fragment left from previous decode call */
|
||||||
|
if (sbc_info->frame_fragment_size) {
|
||||||
|
|
||||||
|
if (sbc_info->frame_fragment_size + to_decode > sizeof(frame_buffer)) {
|
||||||
|
pa_log_debug("FastStream SBC input (saved + incoming) size %lu larger than buffer size %lu, input truncated to fit",
|
||||||
|
sbc_info->frame_fragment_size + to_decode, sizeof(frame_buffer));
|
||||||
|
to_decode = sizeof(frame_buffer) - sbc_info->frame_fragment_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(frame_buffer, sbc_info->frame_fragment, sbc_info->frame_fragment_size);
|
||||||
|
memcpy(frame_buffer + sbc_info->frame_fragment_size, input_buffer, to_decode);
|
||||||
|
|
||||||
|
to_decode += sbc_info->frame_fragment_size;
|
||||||
|
p = frame_buffer;
|
||||||
|
|
||||||
|
/* clear saved fragment */
|
||||||
|
sbc_info->frame_fragment_size = 0;
|
||||||
|
} else
|
||||||
|
p = input_buffer;
|
||||||
|
|
||||||
d = output_buffer;
|
d = output_buffer;
|
||||||
to_write = output_size;
|
to_write = output_size;
|
||||||
|
|
||||||
while (PA_LIKELY(to_decode > 0 && to_write > 0)) {
|
while (PA_LIKELY(to_decode > 0 && to_write > 0)) {
|
||||||
size_t written;
|
size_t written = 0;
|
||||||
ssize_t decoded;
|
ssize_t decoded;
|
||||||
|
|
||||||
|
/* skip to SBC sync word before attempting decode */
|
||||||
|
if (*p != SBC_SYNCWORD) {
|
||||||
|
++p;
|
||||||
|
--to_decode;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
decoded = sbc_decode(&sbc_info->sbc,
|
decoded = sbc_decode(&sbc_info->sbc,
|
||||||
p, to_decode,
|
p, to_decode,
|
||||||
decode_buffer, sizeof(decode_buffer),
|
decode_buffer, sizeof(decode_buffer),
|
||||||
&written);
|
&written);
|
||||||
|
|
||||||
if (PA_UNLIKELY(decoded <= 0)) {
|
if (PA_UNLIKELY(decoded <= 0)) {
|
||||||
|
/* sbc_decode returns -1 if input too short,
|
||||||
|
* break from loop to save this frame fragment for next decode iteration */
|
||||||
|
if (decoded == -1) {
|
||||||
|
pa_log_debug("FastStream SBC decoding error (%li) input %lu is too short", (long) decoded, to_decode);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* otherwise failed to decode frame, skip to next SBC sync word */
|
||||||
pa_log_error("FastStream SBC decoding error (%li)", (long) decoded);
|
pa_log_error("FastStream SBC decoding error (%li)", (long) decoded);
|
||||||
decoded = PA_MIN(sbc_info->frame_length, to_decode);
|
decoded = 1;
|
||||||
written = PA_MIN(sbc_info->codesize, to_write);
|
|
||||||
pa_silence_memory(decode_buffer, written, &decoded_sample_spec);
|
|
||||||
} else {
|
} else {
|
||||||
/* Reset codesize and frame_length to values found by decoder */
|
/* Reset codesize and frame_length to values found by decoder */
|
||||||
sbc_info->codesize = sbc_get_codesize(&sbc_info->sbc);
|
sbc_info->codesize = sbc_get_codesize(&sbc_info->sbc);
|
||||||
|
|
@ -1325,14 +1368,7 @@ static size_t decode_buffer_faststream(void *codec_info, const uint8_t *input_bu
|
||||||
memcpy(d, decode_buffer, written);
|
memcpy(d, decode_buffer, written);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((sbc_info->frame_length & 1) && decoded < to_decode) {
|
|
||||||
++decoded;
|
|
||||||
++sbc_info->frame_length;
|
|
||||||
}
|
|
||||||
|
|
||||||
pa_assert_fp((size_t) decoded <= to_decode);
|
pa_assert_fp((size_t) decoded <= to_decode);
|
||||||
pa_assert_fp((size_t) decoded == PA_MIN(sbc_info->frame_length, to_decode));
|
|
||||||
|
|
||||||
pa_assert_fp((size_t) written <= to_write);
|
pa_assert_fp((size_t) written <= to_write);
|
||||||
|
|
||||||
p += decoded;
|
p += decoded;
|
||||||
|
|
@ -1342,7 +1378,19 @@ static size_t decode_buffer_faststream(void *codec_info, const uint8_t *input_bu
|
||||||
to_write -= written;
|
to_write -= written;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* XXX eat remainder, may need to fix this if input frames are split across packets */
|
if (to_decode) {
|
||||||
|
if (to_decode > sizeof(sbc_info->frame_fragment)) {
|
||||||
|
pa_log_debug("FastStream remaining SBC fragment size %lu larger than buffer size %lu, remainder truncated to fit",
|
||||||
|
to_decode, sizeof(sbc_info->frame_fragment));
|
||||||
|
p += to_decode - sizeof(sbc_info->frame_fragment);
|
||||||
|
to_decode = sizeof(sbc_info->frame_fragment);
|
||||||
|
}
|
||||||
|
|
||||||
|
pa_log_debug("FastStream saving SBC fragment size %lu for next decoding iteration", to_decode);
|
||||||
|
memcpy(sbc_info->frame_fragment, p, to_decode);
|
||||||
|
sbc_info->frame_fragment_size = to_decode;
|
||||||
|
}
|
||||||
|
|
||||||
*processed = input_size;
|
*processed = input_size;
|
||||||
|
|
||||||
return d - output_buffer;
|
return d - output_buffer;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue