mirror of
https://gitlab.freedesktop.org/pulseaudio/pulseaudio.git
synced 2026-02-16 22:05:30 -05:00
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:
parent
3929798a53
commit
018b38ec39
3 changed files with 67 additions and 31 deletions
|
|
@ -412,30 +412,45 @@ 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)
|
||||
return;
|
||||
if (u->encoder_buffer_size < u->write_link_mtu) {
|
||||
pa_xfree(u->encoder_buffer);
|
||||
u->encoder_buffer = pa_xmalloc(u->write_link_mtu);
|
||||
}
|
||||
|
||||
u->encoder_buffer_size = 2 * u->write_link_mtu;
|
||||
pa_xfree(u->encoder_buffer);
|
||||
u->encoder_buffer = pa_xmalloc(u->encoder_buffer_size);
|
||||
/* Encoder buffer cannot be larger then link MTU, otherwise
|
||||
* encode method would produce larger packets then link MTU */
|
||||
u->encoder_buffer_size = u->write_link_mtu;
|
||||
}
|
||||
|
||||
/* Run from IO thread */
|
||||
static void a2dp_prepare_decoder_buffer(struct userdata *u) {
|
||||
pa_assert(u);
|
||||
|
||||
if (u->decoder_buffer_size >= u->read_link_mtu)
|
||||
return;
|
||||
if (u->decoder_buffer_size < u->read_link_mtu) {
|
||||
pa_xfree(u->decoder_buffer);
|
||||
u->decoder_buffer = pa_xmalloc(u->read_link_mtu);
|
||||
}
|
||||
|
||||
u->decoder_buffer_size = 2 * u->read_link_mtu;
|
||||
pa_xfree(u->decoder_buffer);
|
||||
u->decoder_buffer = pa_xmalloc(u->decoder_buffer_size);
|
||||
/* Decoder buffer cannot be larger then link MTU, otherwise
|
||||
* decode method would produce larger output then read_block_size */
|
||||
u->decoder_buffer_size = u->read_link_mtu;
|
||||
}
|
||||
|
||||
/* Run from IO thread */
|
||||
static int a2dp_write_buffer(struct userdata *u, size_t nbytes) {
|
||||
int ret = 0;
|
||||
|
||||
/* Encoder function of A2DP codec may provide empty buffer, in this case do
|
||||
* not post any empty buffer via A2DP socket. It may be because of codec
|
||||
* internal state, e.g. encoder is waiting for more samples so it can
|
||||
* provide encoded data. */
|
||||
if (PA_UNLIKELY(!nbytes)) {
|
||||
u->write_index += (uint64_t) u->write_memchunk.length;
|
||||
pa_memblock_unref(u->write_memchunk.memblock);
|
||||
pa_memchunk_reset(&u->write_memchunk);
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
ssize_t l;
|
||||
|
||||
|
|
@ -508,10 +523,10 @@ static int a2dp_process_render(struct userdata *u) {
|
|||
|
||||
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);
|
||||
}
|
||||
|
|
@ -530,6 +545,8 @@ static int a2dp_process_push(struct userdata *u) {
|
|||
memchunk.memblock = pa_memblock_new(u->core->mempool, u->read_block_size);
|
||||
memchunk.index = memchunk.length = 0;
|
||||
|
||||
a2dp_prepare_decoder_buffer(u);
|
||||
|
||||
for (;;) {
|
||||
bool found_tstamp = false;
|
||||
pa_usec_t tstamp;
|
||||
|
|
@ -537,8 +554,6 @@ static int a2dp_process_push(struct userdata *u) {
|
|||
ssize_t l;
|
||||
size_t processed;
|
||||
|
||||
a2dp_prepare_decoder_buffer(u);
|
||||
|
||||
l = pa_read(u->stream_fd, u->decoder_buffer, u->decoder_buffer_size, &u->stream_write_type);
|
||||
|
||||
if (l <= 0) {
|
||||
|
|
@ -568,9 +583,12 @@ 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 (memchunk.length == 0) {
|
||||
pa_memblock_release(memchunk.memblock);
|
||||
ret = 0;
|
||||
|
||||
pa_memblock_release(memchunk.memblock);
|
||||
|
||||
if (processed != (size_t) l) {
|
||||
pa_log_error("Decoding error");
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -578,9 +596,11 @@ static int a2dp_process_push(struct userdata *u) {
|
|||
pa_smoother_put(u->read_smoother, tstamp, pa_bytes_to_usec(u->read_index, &u->decoder_sample_spec));
|
||||
pa_smoother_resume(u->read_smoother, tstamp, true);
|
||||
|
||||
pa_memblock_release(memchunk.memblock);
|
||||
|
||||
pa_source_post(u->source, &memchunk);
|
||||
/* Decoding of A2DP codec data may result in empty buffer, in this case
|
||||
* do not post empty audio samples. It may happen due to algorithmic
|
||||
* delay of audio codec. */
|
||||
if (PA_LIKELY(memchunk.length))
|
||||
pa_source_post(u->source, &memchunk);
|
||||
|
||||
ret = l;
|
||||
break;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue