From 2c70c13cc3410b494908c499c5533fd8559ca059 Mon Sep 17 00:00:00 2001 From: Pauli Virtanen Date: Fri, 11 Jul 2025 16:12:32 +0300 Subject: [PATCH] bluez5: rate match ISO only from process() Update rate matching only once per process(). This ensures all nodes in the group update their rate matching in the same way. Also account for audio data in ISO output buffer in the reference time. --- spa/plugins/bluez5/media-sink.c | 38 ++++++++++++++++++++++----------- 1 file changed, 26 insertions(+), 12 deletions(-) diff --git a/spa/plugins/bluez5/media-sink.c b/spa/plugins/bluez5/media-sink.c index 42f99d35a..d065592c9 100644 --- a/spa/plugins/bluez5/media-sink.c +++ b/spa/plugins/bluez5/media-sink.c @@ -1194,17 +1194,21 @@ static void drop_frames(struct impl *this, uint32_t req) } } -static void media_iso_pull(struct spa_bt_iso_io *iso_io) +static void media_iso_rate_match(struct impl *this) { - struct impl *this = iso_io->user_data; + struct spa_bt_iso_io *iso_io = this->transport ? this->transport->iso_io : NULL; struct port *port = &this->port; const double period = 0.1 * SPA_NSEC_PER_SEC; + uint64_t ref_time; uint64_t duration_ns; double value, target, err, max_err; + if (!iso_io || !this->transport_started) + return; + if (this->resync || !this->position) { spa_bt_rate_control_init(&port->ratectl, 0); - goto done; + return; } /* @@ -1219,14 +1223,18 @@ static void media_iso_pull(struct spa_bt_iso_io *iso_io) * controller starts processing the packet. */ - value = (int64_t)iso_io->now - (int64_t)get_reference_time(this, &duration_ns); + ref_time = get_reference_time(this, &duration_ns); + if (iso_io->size) + ref_time -= iso_io->duration; + + value = (int64_t)iso_io->now - (int64_t)ref_time; if (this->process_rate) target = this->process_duration * SPA_NSEC_PER_SEC / this->process_rate; else target = 0; target = SPA_MAX(target, iso_io->duration*3/2); err = value - target; - max_err = iso_io->duration; + max_err = SPA_MAX(40 * SPA_NSEC_PER_MSEC, target); if (iso_io->resync && err >= 0) { unsigned int req = (unsigned int)(err * port->current_format.info.raw.rate / SPA_NSEC_PER_SEC); @@ -1252,7 +1260,7 @@ static void media_iso_pull(struct spa_bt_iso_io *iso_io) this, err / SPA_NSEC_PER_MSEC); } else { spa_bt_rate_control_update(&port->ratectl, err, 0, - iso_io->duration, period, RATE_CTL_DIFF_MAX); + duration_ns, period, RATE_CTL_DIFF_MAX); spa_log_trace(this->log, "%p: ISO sync err:%+.3g value:%.6f target:%.6f (ms) corr:%g", this, port->ratectl.avg / SPA_NSEC_PER_MSEC, @@ -1262,8 +1270,12 @@ static void media_iso_pull(struct spa_bt_iso_io *iso_io) } iso_io->resync = false; +} + +static void media_iso_pull(struct spa_bt_iso_io *iso_io) +{ + struct impl *this = iso_io->user_data; -done: this->iso_pending = true; flush_data(this, this->current_time); } @@ -1469,12 +1481,14 @@ static void media_asha_cb(struct spa_source *source) } } -static int do_start_iso_io(struct spa_loop *loop, bool async, uint32_t seq, +static int do_start_transport(struct spa_loop *loop, bool async, uint32_t seq, const void *data, size_t size, void *user_data) { struct impl *this = user_data; - spa_bt_iso_io_set_cb(this->transport->iso_io, media_iso_pull, this); + this->transport_started = true; + if (this->transport->iso_io) + spa_bt_iso_io_set_cb(this->transport->iso_io, media_iso_pull, this); return 0; } @@ -1610,10 +1624,8 @@ static int transport_start(struct impl *this) this->flush_pending = false; this->iso_pending = false; - this->transport_started = true; + spa_loop_locked(this->data_loop, do_start_transport, 0, NULL, 0, this); - if (this->transport->iso_io) - spa_loop_locked(this->data_loop, do_start_iso_io, 0, NULL, 0, this); if (is_asha) { struct spa_bt_asha *asha = this->asha; @@ -2331,6 +2343,8 @@ static int impl_node_process(void *object) setup_matching(this); + media_iso_rate_match(this); + if (this->codec->kind == MEDIA_CODEC_ASHA && !this->asha->set_timer) { struct impl *other = find_other_asha(this); if (other && other->asha->ref_t0 != 0) {