mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-11-01 22:58:50 -04:00
bluez5: a2dp-source: release transport if it went idle
Release the transport if it went idle, ensuring that the fd is closed, and add safeguards we won't double-acquire/release it. This can occur if the device pauses the playback. The transport may also activate again later on, and in this case we need to reacquire a new fd. Not closing the old fd causes problems in this case. However, apparently the BlueZ Release() call fails if the transport is idle. We just ignore the error and downgrade the error message; it might not be safe to not call Release() because the idle property update is async.
This commit is contained in:
parent
d3d31c4317
commit
f99eefeb4f
2 changed files with 45 additions and 12 deletions
|
|
@ -112,6 +112,7 @@ struct impl {
|
|||
struct port port;
|
||||
|
||||
unsigned int started:1;
|
||||
unsigned int transport_acquired:1;
|
||||
unsigned int following:1;
|
||||
|
||||
struct spa_source source;
|
||||
|
|
@ -539,11 +540,16 @@ static int transport_start(struct impl *this)
|
|||
int res, val;
|
||||
struct port *port = &this->port;
|
||||
|
||||
if (this->transport_acquired)
|
||||
return 0;
|
||||
|
||||
spa_log_debug(this->log, NAME" %p: transport %p acquire", this,
|
||||
this->transport);
|
||||
if ((res = spa_bt_transport_acquire(this->transport, false)) < 0)
|
||||
return res;
|
||||
|
||||
this->transport_acquired = true;
|
||||
|
||||
this->codec_data = this->codec->init(this->codec, 0,
|
||||
this->transport->configuration,
|
||||
this->transport->configuration_len,
|
||||
|
|
@ -622,6 +628,28 @@ static int do_remove_source(struct spa_loop *loop,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int transport_stop(struct impl *this)
|
||||
{
|
||||
int res;
|
||||
|
||||
spa_log_debug(this->log, NAME" %p: transport stop", this);
|
||||
|
||||
spa_loop_invoke(this->data_loop, do_remove_source, 0, NULL, 0, true, this);
|
||||
|
||||
if (this->transport && this->transport_acquired)
|
||||
res = spa_bt_transport_release(this->transport);
|
||||
else
|
||||
res = 0;
|
||||
|
||||
this->transport_acquired = false;
|
||||
|
||||
if (this->codec_data)
|
||||
this->codec->deinit(this->codec_data);
|
||||
this->codec_data = NULL;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int do_stop(struct impl *this)
|
||||
{
|
||||
int res;
|
||||
|
|
@ -631,19 +659,10 @@ static int do_stop(struct impl *this)
|
|||
|
||||
spa_log_debug(this->log, NAME" %p: stop", this);
|
||||
|
||||
spa_loop_invoke(this->data_loop, do_remove_source, 0, NULL, 0, true, this);
|
||||
res = transport_stop(this);
|
||||
|
||||
this->started = false;
|
||||
|
||||
if (this->transport)
|
||||
res = spa_bt_transport_release(this->transport);
|
||||
else
|
||||
res = 0;
|
||||
|
||||
if (this->codec_data)
|
||||
this->codec->deinit(this->codec_data);
|
||||
this->codec_data = NULL;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
|
@ -1139,6 +1158,7 @@ static int do_transport_destroy(struct spa_loop *loop,
|
|||
{
|
||||
struct impl *this = user_data;
|
||||
this->transport = NULL;
|
||||
this->transport_acquired = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -1158,6 +1178,8 @@ static void transport_state_changed(void *data, enum spa_bt_transport_state old,
|
|||
|
||||
if (state >= SPA_BT_TRANSPORT_STATE_PENDING && old < SPA_BT_TRANSPORT_STATE_PENDING)
|
||||
transport_start(this);
|
||||
else if (state < SPA_BT_TRANSPORT_STATE_PENDING && old >= SPA_BT_TRANSPORT_STATE_PENDING)
|
||||
transport_stop(this);
|
||||
}
|
||||
|
||||
static const struct spa_bt_transport_events transport_events = {
|
||||
|
|
|
|||
|
|
@ -1422,6 +1422,7 @@ static int transport_release(void *data)
|
|||
struct spa_bt_monitor *monitor = transport->monitor;
|
||||
DBusMessage *m, *r;
|
||||
DBusError err;
|
||||
bool is_idle = (transport->state == SPA_BT_TRANSPORT_STATE_IDLE);
|
||||
|
||||
spa_log_debug(monitor->log, NAME": transport %p: Release %s",
|
||||
transport, transport->path);
|
||||
|
|
@ -1446,8 +1447,18 @@ static int transport_release(void *data)
|
|||
dbus_message_unref(r);
|
||||
|
||||
if (dbus_error_is_set(&err)) {
|
||||
spa_log_error(monitor->log, "Failed to release transport %s: %s",
|
||||
transport->path, err.message);
|
||||
if (is_idle) {
|
||||
/* XXX: The fd always needs to be closed. However, Release()
|
||||
* XXX: apparently doesn't need to be called on idle transports
|
||||
* XXX: and fails. We call it just to be sure (e.g. in case
|
||||
* XXX: there's a race with updating the property), but tone down the error.
|
||||
*/
|
||||
spa_log_debug(monitor->log, "Failed to release idle transport %s: %s",
|
||||
transport->path, err.message);
|
||||
} else {
|
||||
spa_log_error(monitor->log, "Failed to release transport %s: %s",
|
||||
transport->path, err.message);
|
||||
}
|
||||
dbus_error_free(&err);
|
||||
}
|
||||
else
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue