diff --git a/spa/plugins/bluez5/bluez5-dbus.c b/spa/plugins/bluez5/bluez5-dbus.c index cb71c0032..92d47a8d2 100644 --- a/spa/plugins/bluez5/bluez5-dbus.c +++ b/spa/plugins/bluez5/bluez5-dbus.c @@ -1823,6 +1823,8 @@ void spa_bt_transport_free(struct spa_bt_transport *transport) spa_bt_transport_set_state(transport, SPA_BT_TRANSPORT_STATE_IDLE); + spa_bt_transport_keepalive(transport, false); + spa_bt_transport_emit_destroy(transport); spa_bt_transport_stop_volume_timer(transport); @@ -1857,6 +1859,23 @@ void spa_bt_transport_free(struct spa_bt_transport *transport) free(transport); } +int spa_bt_transport_keepalive(struct spa_bt_transport *t, bool keepalive) +{ + if (keepalive) { + t->keepalive = true; + return 0; + } + + t->keepalive = false; + + if (t->acquire_refcount == 0 && t->acquired) { + t->acquire_refcount = 1; + return spa_bt_transport_release(t); + } + + return 0; +} + int spa_bt_transport_acquire(struct spa_bt_transport *transport, bool optional) { struct spa_bt_monitor *monitor = transport->monitor; @@ -1869,10 +1888,15 @@ int spa_bt_transport_acquire(struct spa_bt_transport *transport, bool optional) } spa_assert(transport->acquire_refcount == 0); - res = spa_bt_transport_impl(transport, acquire, 0, optional); + if (!transport->acquired) + res = spa_bt_transport_impl(transport, acquire, 0, optional); + else + res = 0; - if (res >= 0) + if (res >= 0) { transport->acquire_refcount = 1; + transport->acquired = true; + } return res; } @@ -1892,14 +1916,22 @@ int spa_bt_transport_release(struct spa_bt_transport *transport) return 0; } spa_assert(transport->acquire_refcount == 1); + spa_assert(transport->acquired); if (SPA_BT_TRANSPORT_IS_SCO(transport)) { /* Postpone SCO transport releases, since we might need it again soon */ res = spa_bt_transport_start_release_timer(transport); + } else if (transport->keepalive) { + res = 0; + transport->acquire_refcount = 0; + spa_log_debug(monitor->log, "transport %p: keepalive %s on release", + transport, transport->path); } else { res = spa_bt_transport_impl(transport, release, 0); - if (res >= 0) + if (res >= 0) { transport->acquire_refcount = 0; + transport->acquired = false; + } } return res; @@ -1909,13 +1941,15 @@ static int spa_bt_transport_release_now(struct spa_bt_transport *transport) { int res; - if (transport->acquire_refcount == 0) + if (!transport->acquired) return 0; spa_bt_transport_stop_release_timer(transport); res = spa_bt_transport_impl(transport, release, 0); - if (res >= 0) + if (res >= 0) { transport->acquire_refcount = 0; + transport->acquired = false; + } return res; } @@ -1974,11 +2008,18 @@ static void spa_bt_transport_release_timer_event(struct spa_source *source) struct spa_bt_monitor *monitor = transport->monitor; spa_assert(transport->acquire_refcount >= 1); + spa_assert(transport->acquired); spa_bt_transport_stop_release_timer(transport); if (transport->acquire_refcount == 1) { - spa_bt_transport_impl(transport, release, 0); + if (!transport->keepalive) { + spa_bt_transport_impl(transport, release, 0); + transport->acquired = false; + } else { + spa_log_debug(monitor->log, "transport %p: keepalive %s on release", + transport, transport->path); + } } else { spa_log_debug(monitor->log, "transport %p: delayed decref %s", transport, transport->path); } diff --git a/spa/plugins/bluez5/bluez5-device.c b/spa/plugins/bluez5/bluez5-device.c index f1473a8e6..800f3f83b 100644 --- a/spa/plugins/bluez5/bluez5-device.c +++ b/spa/plugins/bluez5/bluez5-device.c @@ -519,11 +519,13 @@ static void dynamic_node_transport_state_changed(void *data, if (state >= SPA_BT_TRANSPORT_STATE_PENDING && old < SPA_BT_TRANSPORT_STATE_PENDING) { if (!SPA_FLAG_IS_SET(this->id, DYNAMIC_NODE_ID_FLAG)) { SPA_FLAG_SET(this->id, DYNAMIC_NODE_ID_FLAG); + spa_bt_transport_keepalive(t, true); emit_node(impl, t, this->id, this->factory_name, this->a2dp_duplex); } } else if (state < SPA_BT_TRANSPORT_STATE_PENDING && old >= SPA_BT_TRANSPORT_STATE_PENDING) { if (SPA_FLAG_IS_SET(this->id, DYNAMIC_NODE_ID_FLAG)) { SPA_FLAG_CLEAR(this->id, DYNAMIC_NODE_ID_FLAG); + spa_bt_transport_keepalive(t, false); spa_device_emit_object_info(&impl->hooks, this->id, NULL); } } diff --git a/spa/plugins/bluez5/defs.h b/spa/plugins/bluez5/defs.h index f379ad8b2..1754a0c8a 100644 --- a/spa/plugins/bluez5/defs.h +++ b/spa/plugins/bluez5/defs.h @@ -583,6 +583,8 @@ struct spa_bt_transport { struct spa_bt_transport_volume volumes[SPA_BT_VOLUME_ID_TERM]; int acquire_refcount; + bool acquired; + bool keepalive; int fd; uint16_t read_mtu; uint16_t write_mtu; @@ -612,6 +614,7 @@ bool spa_bt_transport_volume_enabled(struct spa_bt_transport *transport); int spa_bt_transport_acquire(struct spa_bt_transport *t, bool optional); int spa_bt_transport_release(struct spa_bt_transport *t); +int spa_bt_transport_keepalive(struct spa_bt_transport *t, bool keepalive); int spa_bt_transport_ensure_sco_io(struct spa_bt_transport *t, struct spa_loop *data_loop); #define spa_bt_transport_emit(t,m,v,...) spa_hook_list_call(&(t)->listener_list, \