diff --git a/spa/plugins/bluez5/decode-buffer.h b/spa/plugins/bluez5/decode-buffer.h index 0f1345572..c2104a5dc 100644 --- a/spa/plugins/bluez5/decode-buffer.h +++ b/spa/plugins/bluez5/decode-buffer.h @@ -221,7 +221,7 @@ static inline void spa_bt_decode_buffer_set_max_extra_latency(struct spa_bt_deco this->max_extra = samples; } -static inline int32_t spa_bt_decode_buffer_get_target_latency(struct spa_bt_decode_buffer *this) +static inline int32_t spa_bt_decode_buffer_get_auto_latency(struct spa_bt_decode_buffer *this) { const int32_t duration = this->duration; const int32_t packet_size = SPA_CLAMP(this->packet_size.max, 0, INT32_MAX/8); @@ -229,16 +229,20 @@ static inline int32_t spa_bt_decode_buffer_get_target_latency(struct spa_bt_deco const int32_t spike = SPA_CLAMP(this->spike.max, 0, max_buf); int32_t target; - if (this->target) - target = this->target; - else - target = SPA_CLAMP(SPA_ROUND_UP(SPA_MAX(spike * 3/2, duration), - SPA_CLAMP((int)this->rate / 50, 1, INT32_MAX)), - duration, max_buf - 2*packet_size); + target = SPA_CLAMP(SPA_ROUND_UP(SPA_MAX(spike * 3/2, duration), + SPA_CLAMP((int)this->rate / 50, 1, INT32_MAX)), + duration, max_buf - 2*packet_size); return SPA_MIN(target, duration + SPA_CLAMP(this->max_extra, 0, INT32_MAX - duration)); } +static inline int32_t spa_bt_decode_buffer_get_target_latency(struct spa_bt_decode_buffer *this) +{ + if (this->target) + return this->target; + return spa_bt_decode_buffer_get_auto_latency(this); +} + static inline void spa_bt_decode_buffer_process(struct spa_bt_decode_buffer *this, uint32_t samples, uint32_t duration, double rate_diff, uint64_t next_nsec) { diff --git a/spa/plugins/bluez5/iso-io.c b/spa/plugins/bluez5/iso-io.c index 8fc488eec..69f6748ea 100644 --- a/spa/plugins/bluez5/iso-io.c +++ b/spa/plugins/bluez5/iso-io.c @@ -21,6 +21,7 @@ #include "media-codecs.h" #include "defs.h" +#include "decode-buffer.h" SPA_LOG_TOPIC_DEFINE_STATIC(log_topic, "spa.bluez5.iso"); #undef SPA_LOG_TOPIC_DEFAULT @@ -62,6 +63,8 @@ struct stream { uint32_t block_size; struct spa_bt_latency tx_latency; + + struct spa_bt_decode_buffer *source_buf; }; struct modify_info @@ -593,3 +596,27 @@ int spa_bt_iso_io_recv_errqueue(struct spa_bt_iso_io *this) return spa_bt_latency_recv_errqueue(&stream->tx_latency, stream->fd, group->log); } + +/** Must be called from data thread */ +void spa_bt_iso_io_set_source_buffer(struct spa_bt_iso_io *this, struct spa_bt_decode_buffer *buffer) +{ + struct stream *stream = SPA_CONTAINER_OF(this, struct stream, this); + + stream->source_buf = buffer; +} + +/** Must be called from data thread */ +void spa_bt_iso_io_update_source_latency(struct spa_bt_iso_io *this) +{ + struct stream *stream = SPA_CONTAINER_OF(this, struct stream, this); + struct group *group = stream->group; + struct stream *s; + int32_t latency = 0; + + spa_list_for_each(s, &group->streams, link) + if (s->source_buf) + latency = SPA_MAX(latency, spa_bt_decode_buffer_get_auto_latency(s->source_buf)); + + if (stream->source_buf) + spa_bt_decode_buffer_set_target_latency(stream->source_buf, latency); +} diff --git a/spa/plugins/bluez5/iso-io.h b/spa/plugins/bluez5/iso-io.h index ed49c77c1..1ff6285c1 100644 --- a/spa/plugins/bluez5/iso-io.h +++ b/spa/plugins/bluez5/iso-io.h @@ -11,6 +11,7 @@ #include #include +struct spa_bt_decode_buffer; struct spa_bt_transport; /** @@ -46,4 +47,7 @@ void spa_bt_iso_io_destroy(struct spa_bt_iso_io *io); void spa_bt_iso_io_set_cb(struct spa_bt_iso_io *io, spa_bt_iso_io_pull_t pull, void *user_data); int spa_bt_iso_io_recv_errqueue(struct spa_bt_iso_io *io); +void spa_bt_iso_io_set_source_buffer(struct spa_bt_iso_io *io, struct spa_bt_decode_buffer *buffer); +void spa_bt_iso_io_update_source_latency(struct spa_bt_iso_io *io); + #endif diff --git a/spa/plugins/bluez5/media-source.c b/spa/plugins/bluez5/media-source.c index e151b986e..7d78e186f 100644 --- a/spa/plugins/bluez5/media-source.c +++ b/spa/plugins/bluez5/media-source.c @@ -843,8 +843,10 @@ static int do_start_sco_iso_io(struct spa_loop *loop, bool async, uint32_t seq, if (this->transport->sco_io) spa_bt_sco_io_set_source_cb(this->transport->sco_io, media_sco_pull, this); - if (this->transport->iso_io) + if (this->transport->iso_io) { spa_bt_iso_io_set_cb(this->transport->iso_io, media_iso_pull, this); + spa_bt_iso_io_set_source_buffer(this->transport->iso_io, &this->port.buffer); + } return 0; } @@ -1008,8 +1010,10 @@ static int do_remove_source(struct spa_loop *loop, if (this->timer_source.loop) spa_loop_remove_source(this->data_loop, &this->timer_source); - if (this->transport && this->transport->iso_io) + if (this->transport && this->transport->iso_io) { spa_bt_iso_io_set_cb(this->transport->iso_io, NULL, NULL); + spa_bt_iso_io_set_source_buffer(this->transport->iso_io, NULL); + } if (this->transport && this->transport->sco_io) spa_bt_sco_io_set_source_cb(this->transport->sco_io, NULL, NULL); set_timeout(this, 0); @@ -1646,9 +1650,19 @@ static void update_target_latency(struct impl *this) if (this->transport == NULL || !port->have_format) return; + if (this->codec->kind != MEDIA_CODEC_BAP) + return; - if (this->codec->kind != MEDIA_CODEC_BAP || this->is_input || - this->transport->delay_us == SPA_BT_UNKNOWN_DELAY) + if (this->is_input) { + /* BAP Client. Should use same buffer size for all streams in the same + * group, so that capture is in sync. + */ + if (this->transport->iso_io) + spa_bt_iso_io_update_source_latency(this->transport->iso_io); + return; + } + + if (this->transport->delay_us == SPA_BT_UNKNOWN_DELAY) return; get_samples(this, &duration);