mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-10-29 05:40:27 -04:00
bluez5: keepalive A2DP source / SCO AG dynamic node transports
When acting as SCO AG / A2DP sink, the remote end should decide when to close the connection. This does not work currently properly, because stopping sources/sinks releases the transport, which causes it to go idle, and which then destroys dynamic nodes. The sources/sinks should not cause the transport to be released. Implement keepalive flag for spa_bt_transport, such that spa_bt_transport_release does not actually release the transport when the refcount reaches zero. Set the flag for dynamic nodes when the transport becomes pending (remote end connects) and unset the flag when idle (remote end disconnected, or dynamic node removed).
This commit is contained in:
parent
24c97b1c7e
commit
4bb3ff739a
3 changed files with 52 additions and 6 deletions
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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, \
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue