bluez5: don't try to acquire if we are getting errors

If transport goes into error state too often, fail instead of trying to
acquire it again.

This avoids getting into a tight acquire->fail->reacquire loop.
This commit is contained in:
Pauli Virtanen 2023-03-18 14:48:16 +02:00
parent 397059017b
commit 13a9964a71
3 changed files with 41 additions and 8 deletions

View file

@ -65,6 +65,12 @@ enum backend_selection {
#define CODEC_SWITCH_RETRIES 1
/* How many times to retry acquire on errors, and how long delay to require before we can
* try again.
*/
#define TRANSPORT_ERROR_MAX_RETRY 3
#define TRANSPORT_ERROR_TIMEOUT (2*BLUEZ_ACTION_RATE_MSEC*SPA_NSEC_PER_MSEC)
struct spa_bt_monitor {
struct spa_handle handle;
@ -1225,11 +1231,17 @@ struct spa_bt_device *spa_bt_device_find_by_address(struct spa_bt_monitor *monit
return NULL;
}
void spa_bt_device_update_last_bluez_action_time(struct spa_bt_device *device)
static uint64_t get_time_now(struct spa_bt_monitor *monitor)
{
struct timespec ts;
spa_system_clock_gettime(device->monitor->main_system, CLOCK_MONOTONIC, &ts);
device->last_bluez_action_time = SPA_TIMESPEC_TO_NSEC(&ts);
spa_system_clock_gettime(monitor->main_system, CLOCK_MONOTONIC, &ts);
return SPA_TIMESPEC_TO_NSEC(&ts);
}
void spa_bt_device_update_last_bluez_action_time(struct spa_bt_device *device)
{
device->last_bluez_action_time = get_time_now(device->monitor);
}
static struct spa_bt_device *device_create(struct spa_bt_monitor *monitor, const char *path)
@ -2254,6 +2266,18 @@ void spa_bt_transport_set_state(struct spa_bt_transport *transport, enum spa_bt_
spa_bt_transport_emit_state_changed(transport, old, state);
if (state >= SPA_BT_TRANSPORT_STATE_PENDING && old < SPA_BT_TRANSPORT_STATE_PENDING)
transport_sync_volume(transport);
if (state == SPA_BT_TRANSPORT_STATE_ERROR) {
uint64_t now = get_time_now(monitor);
if (now > transport->last_error_time + TRANSPORT_ERROR_TIMEOUT) {
spa_log_error(monitor->log, "Failure in Bluetooth audio transport %s",
transport->path);
}
transport->last_error_time = now;
++transport->error_count;
}
}
}
@ -2341,6 +2365,12 @@ int spa_bt_transport_acquire(struct spa_bt_transport *transport, bool optional)
}
spa_assert(transport->acquire_refcount == 0);
/* If we are getting into error state too often, stop trying */
if (get_time_now(monitor) > transport->last_error_time + TRANSPORT_ERROR_TIMEOUT)
transport->error_count = 0;
if (transport->error_count >= TRANSPORT_ERROR_MAX_RETRY)
return -EIO;
if (!transport->acquired)
res = spa_bt_transport_impl(transport, acquire, 0, optional);
else
@ -3444,12 +3474,10 @@ next:
static void media_codec_switch_process(struct spa_bt_media_codec_switch *sw)
{
while (*sw->codec_iter != NULL && *sw->path_iter != NULL) {
struct timespec ts;
uint64_t now, threshold;
/* Rate limit BlueZ calls */
spa_system_clock_gettime(sw->device->monitor->main_system, CLOCK_MONOTONIC, &ts);
now = SPA_TIMESPEC_TO_NSEC(&ts);
now = get_time_now(sw->device->monitor);
threshold = sw->device->last_bluez_action_time + BLUEZ_ACTION_RATE_MSEC * SPA_NSEC_PER_MSEC;
if (now < threshold) {
/* Wait for timeout */

View file

@ -601,6 +601,8 @@ struct spa_bt_transport {
int acquire_refcount;
bool acquired;
bool keepalive;
int error_count;
uint64_t last_error_time;
int fd;
uint16_t read_mtu;
uint16_t write_mtu;

View file

@ -1672,12 +1672,15 @@ static void transport_state_changed(void *data,
* the transport, we won't get a write error, but instead see a transport
* state change.
*
* Emit a node error, to let upper levels handle it.
* Treat this as a transport error, so that upper levels don't try to
* retry too often.
*/
spa_log_debug(this->log, "%p: transport %p becomes inactive: stop and indicate error",
this, this->transport);
state = SPA_BT_TRANSPORT_STATE_ERROR;
spa_bt_transport_set_state(this->transport, SPA_BT_TRANSPORT_STATE_ERROR);
return;
}
if (state == SPA_BT_TRANSPORT_STATE_ERROR) {