Each codec has different compression ratio and own method how to calculate buffer size of encoded or decoded samples. So change A2DP codec API to provide this information for module-bluez5-device module and fix a2dp_prepare_encoder_buffer() and a2dp_prepare_decoder_buffer() functions.
API functions get_read_buffer_size() and get_write_buffer_size() now set both decoded and encoded buffer sizes. Function reduce_encoder_bitrate() was changed to not return new buffer size (it was not obvious if buffer size was for encoded or decoded samples), but caller rather should call get_write_buffer_size() to get new sizes. --- src/modules/bluetooth/a2dp-codec-api.h | 17 ++++++------ src/modules/bluetooth/a2dp-codec-sbc.c | 25 ++++++++++------- src/modules/bluetooth/module-bluez5-device.c | 41 ++++++++++++++++++---------- 3 files changed, 50 insertions(+), 33 deletions(-) diff --git a/src/modules/bluetooth/a2dp-codec-api.h b/src/modules/bluetooth/a2dp-codec-api.h index 55bb9ff70..517dc76f1 100644 --- a/src/modules/bluetooth/a2dp-codec-api.h +++ b/src/modules/bluetooth/a2dp-codec-api.h @@ -72,15 +72,14 @@ typedef struct pa_a2dp_codec { /* Reset internal state of codec info data in codec_info */ void (*reset)(void *codec_info); - /* Get read block size for codec */ - size_t (*get_read_block_size)(void *codec_info, size_t read_link_mtu); - /* Get write block size for codec */ - size_t (*get_write_block_size)(void *codec_info, size_t write_link_mtu); - - /* Reduce encoder bitrate for codec, returns new write block size or zero - * if not changed, called when socket is not accepting encoded data fast - * enough */ - size_t (*reduce_encoder_bitrate)(void *codec_info, size_t write_link_mtu); + /* Get buffer sizes for read operations */ + void (*get_read_buffer_size)(void *codec_info, size_t read_link_mtu, size_t *output_buffer_size, size_t *encoded_buffer_size); + /* Get buffer sizes for write operations */ + void (*get_write_buffer_size)(void *codec_info, size_t write_link_mtu, size_t *input_buffer_size, size_t *encoded_buffer_size); + + /* Reduce encoder bitrate for codec, returns non-zero on failure, + * called when socket is not accepting encoded data fast enough */ + int (*reduce_encoder_bitrate)(void *codec_info); /* Encode input_buffer of input_size to output_buffer of output_size, * returns size of filled ouput_buffer and set processed to size of diff --git a/src/modules/bluetooth/a2dp-codec-sbc.c b/src/modules/bluetooth/a2dp-codec-sbc.c index cdc20d7f0..f339b570d 100644 --- a/src/modules/bluetooth/a2dp-codec-sbc.c +++ b/src/modules/bluetooth/a2dp-codec-sbc.c @@ -423,7 +423,10 @@ 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 buffer size + * in get_buffer_size() function. Buffer size 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); @@ -475,20 +478,22 @@ static void reset(void *codec_info) { sbc_info->seq_num = 0; } -static size_t get_block_size(void *codec_info, size_t link_mtu) { +static void get_buffer_size(void *codec_info, size_t link_mtu, size_t *decoded_buffer_size, size_t *encoded_buffer_size) { struct sbc_info *sbc_info = (struct sbc_info *) codec_info; + size_t rtp_size = sizeof(struct rtp_header) + sizeof(struct rtp_payload); + size_t num_of_frames = (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; + *decoded_buffer_size = num_of_frames * sbc_info->codesize; + *encoded_buffer_size = num_of_frames * sbc_info->frame_length + rtp_size; } -static size_t reduce_encoder_bitrate(void *codec_info, size_t write_link_mtu) { +static int reduce_encoder_bitrate(void *codec_info) { struct sbc_info *sbc_info = (struct sbc_info *) codec_info; uint8_t bitpool; /* Check if bitpool is already at its limit */ if (sbc_info->sbc.bitpool <= SBC_BITPOOL_DEC_LIMIT) - return 0; + return -1; bitpool = sbc_info->sbc.bitpool - SBC_BITPOOL_DEC_STEP; @@ -496,10 +501,10 @@ static size_t reduce_encoder_bitrate(void *codec_info, size_t write_link_mtu) { bitpool = SBC_BITPOOL_DEC_LIMIT; if (sbc_info->sbc.bitpool == bitpool) - return 0; + return -1; set_bitpool(sbc_info, bitpool); - return get_block_size(codec_info, write_link_mtu); + return 0; } static size_t encode_buffer(void *codec_info, uint32_t timestamp, const uint8_t *input_buffer, size_t input_size, uint8_t *output_buffer, size_t output_size, size_t *processed) { @@ -639,8 +644,8 @@ const pa_a2dp_codec pa_a2dp_codec_sbc = { .init = init, .deinit = deinit, .reset = reset, - .get_read_block_size = get_block_size, - .get_write_block_size = get_block_size, + .get_read_buffer_size = get_buffer_size, + .get_write_buffer_size = get_buffer_size, .reduce_encoder_bitrate = reduce_encoder_bitrate, .encode_buffer = encode_buffer, .decode_buffer = decode_buffer, diff --git a/src/modules/bluetooth/module-bluez5-device.c b/src/modules/bluetooth/module-bluez5-device.c index 56c96054d..c0b293d94 100644 --- a/src/modules/bluetooth/module-bluez5-device.c +++ b/src/modules/bluetooth/module-bluez5-device.c @@ -125,7 +125,9 @@ struct userdata { size_t read_link_mtu; size_t write_link_mtu; size_t read_block_size; + size_t read_encoded_block_size; size_t write_block_size; + size_t write_encoded_block_size; uint64_t read_index; uint64_t write_index; pa_usec_t started_at; @@ -412,10 +414,10 @@ 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) + if (u->encoder_buffer_size >= u->write_encoded_block_size) return; - u->encoder_buffer_size = 2 * u->write_link_mtu; + u->encoder_buffer_size = u->write_encoded_block_size; pa_xfree(u->encoder_buffer); u->encoder_buffer = pa_xmalloc(u->encoder_buffer_size); } @@ -424,10 +426,10 @@ static void a2dp_prepare_encoder_buffer(struct userdata *u) { static void a2dp_prepare_decoder_buffer(struct userdata *u) { pa_assert(u); - if (u->decoder_buffer_size >= u->read_link_mtu) + if (u->decoder_buffer_size >= u->read_encoded_block_size) return; - u->decoder_buffer_size = 2 * u->read_link_mtu; + u->decoder_buffer_size = u->read_encoded_block_size; pa_xfree(u->decoder_buffer); u->decoder_buffer = pa_xmalloc(u->decoder_buffer_size); } @@ -436,6 +438,9 @@ static void a2dp_prepare_decoder_buffer(struct userdata *u) { static int a2dp_write_buffer(struct userdata *u, size_t nbytes) { int ret = 0; + if (!nbytes) + return 0; + for (;;) { ssize_t l; @@ -504,14 +509,14 @@ static int a2dp_process_render(struct userdata *u) { /* Try to create a packet of the full MTU */ ptr = (const uint8_t *) pa_memblock_acquire_chunk(&u->write_memchunk); - length = u->a2dp_codec->encode_buffer(u->encoder_info, u->write_index / pa_frame_size(&u->encoder_sample_spec), ptr, u->write_memchunk.length, u->encoder_buffer, u->encoder_buffer_size, &processed); + length = u->a2dp_codec->encode_buffer(u->encoder_info, u->write_index / pa_frame_size(&u->encoder_sample_spec), ptr, u->write_memchunk.length, u->encoder_buffer, u->write_encoded_block_size, &processed); 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); } @@ -539,7 +544,7 @@ static int a2dp_process_push(struct userdata *u) { a2dp_prepare_decoder_buffer(u); - l = pa_read(u->stream_fd, u->decoder_buffer, u->decoder_buffer_size, &u->stream_write_type); + l = pa_read(u->stream_fd, u->decoder_buffer, u->read_encoded_block_size, &u->stream_write_type); if (l <= 0) { @@ -568,6 +573,14 @@ 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 (processed != (size_t) l) { + pa_log_error("Decoding error"); + pa_memblock_release(memchunk.memblock); + ret = -1; + break; + } + if (memchunk.length == 0) { pa_memblock_release(memchunk.memblock); ret = 0; @@ -732,9 +745,9 @@ static void transport_config_mtu(struct userdata *u) { } else { pa_assert(u->a2dp_codec); if (u->profile == PA_BLUETOOTH_PROFILE_A2DP_SINK) { - u->write_block_size = u->a2dp_codec->get_write_block_size(u->encoder_info, u->write_link_mtu); + u->a2dp_codec->get_write_buffer_size(u->encoder_info, u->write_link_mtu, &u->write_block_size, &u->write_encoded_block_size); } else { - u->read_block_size = u->a2dp_codec->get_read_block_size(u->decoder_info, u->read_link_mtu); + u->a2dp_codec->get_read_buffer_size(u->decoder_info, u->read_link_mtu, &u->read_block_size, &u->read_encoded_block_size); } } @@ -1438,9 +1451,9 @@ static void thread_func(void *userdata) { } if (u->write_index > 0 && u->profile == PA_BLUETOOTH_PROFILE_A2DP_SINK) { - size_t new_write_block_size = u->a2dp_codec->reduce_encoder_bitrate(u->encoder_info, u->write_link_mtu); - if (new_write_block_size) { - u->write_block_size = new_write_block_size; + int failed = u->a2dp_codec->reduce_encoder_bitrate(u->encoder_info); + if (!failed) { + u->a2dp_codec->get_write_buffer_size(u->encoder_info, u->write_link_mtu, &u->write_block_size, &u->write_encoded_block_size); handle_sink_block_size_change(u); } } -- 2.11.0 _______________________________________________ pulseaudio-discuss mailing list pulseaudio-discuss@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/pulseaudio-discuss