From f32935ec8a7152d870b36ce190f54ba2e3c5459a Mon Sep 17 00:00:00 2001 From: Pauli Virtanen Date: Mon, 31 Jan 2022 19:48:09 +0200 Subject: [PATCH] bluez5: sco-sink: fix behavior as follower When sink is follower, and no data to write is available, it should not schedule a timeout, but wait for the driver to wake it up again. Fixes process ending up busylooping in data thread as follower, under some conditions. Also, clean up the code to be more clear about timeout logic. Just loop directly instead of setting timeout 1, if we need to just flush more immediately. --- spa/plugins/bluez5/sco-sink.c | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/spa/plugins/bluez5/sco-sink.c b/spa/plugins/bluez5/sco-sink.c index 6f55e7cbd..4a08be37c 100644 --- a/spa/plugins/bluez5/sco-sink.c +++ b/spa/plugins/bluez5/sco-sink.c @@ -269,7 +269,7 @@ static int set_timers(struct impl *this) static uint64_t get_next_timeout(struct impl *this, uint64_t now_time, uint64_t processed_samples) { struct port *port = &this->port; - uint64_t playback_time = 0, elapsed_time = 0, next_time = 1; + uint64_t playback_time = 0, elapsed_time = 0, next_time = 0; this->total_samples += processed_samples; @@ -380,7 +380,6 @@ static void flush_data(struct impl *this) { struct port *port = &this->port; struct spa_data *datas; - uint64_t next_timeout = 1; const uint32_t min_in_size = (this->transport->codec == HFP_AUDIO_CODEC_MSBC) ? MSBC_DECODED_SIZE : this->transport->write_mtu; @@ -391,7 +390,8 @@ static void flush_data(struct impl *this) if (this->transport == NULL || this->transport->sco_io == NULL) return; - if (!spa_list_is_empty(&port->ready)) { +again: + while (!spa_list_is_empty(&port->ready) && port->write_buffer_size < min_in_size) { /* get buffer */ if (!port->current_buffer) { spa_return_if_fail(!spa_list_is_empty(&port->ready)); @@ -434,6 +434,7 @@ static void flush_data(struct impl *this) int processed = 0; ssize_t out_encoded; int written; + uint64_t next_timeout; spa_system_clock_gettime(this->data_system, CLOCK_MONOTONIC, &this->now); now_time = SPA_TIMESPEC_TO_NSEC(&this->now); @@ -468,7 +469,6 @@ static void flush_data(struct impl *this) written, spa_strerror(written)); goto stop; } - spa_log_trace(this->log, "wrote socket data %d", written); this->buffer_head += written; @@ -507,17 +507,29 @@ static void flush_data(struct impl *this) next_timeout = get_next_timeout(this, now_time, processed / port->frame_size); - if (this->clock) { + if (!this->following && this->clock) { this->clock->nsec = now_time; this->clock->position = this->total_samples; this->clock->delay = processed / port->frame_size; this->clock->rate_diff = 1.0f; - this->clock->next_nsec = next_timeout; + this->clock->next_nsec = now_time + next_timeout; } + + if (next_timeout == 0) + goto again; + + spa_log_trace(this->log, "timeout %"PRIu64" ns", next_timeout); + set_timeout(this, next_timeout); + } else { + /* As follower, driver will wake us up when there is data */ + if (this->following) + return; + + /* As driver, run timeout now to schedule data */ + spa_log_trace(this->log, "timeout 1 ns (driver: schedule now)"); + set_timeout(this, 1); } - /* schedule next timeout */ - set_timeout(this, next_timeout); return; stop: