diff --git a/spa/plugins/bluez5/backend-hsp-native.c b/spa/plugins/bluez5/backend-hsp-native.c index 316c2962c..4709d00d7 100644 --- a/spa/plugins/bluez5/backend-hsp-native.c +++ b/spa/plugins/bluez5/backend-hsp-native.c @@ -233,6 +233,7 @@ static int sco_acquire_cb(void *data, bool optional) if (sock < 0) goto fail; + t->fd = sock; t->read_mtu = 48; t->write_mtu = 48; @@ -250,7 +251,9 @@ static int sco_acquire_cb(void *data, bool optional) t->write_mtu = sco_opt.mtu; } } - return sock; + + return 0; + fail: return -1; } @@ -259,8 +262,14 @@ static int sco_release_cb(void *data) { struct spa_bt_transport *t = data; struct spa_bt_backend *backend = t->backend; - spa_log_info(backend->log, NAME": Transport %s released", t->path); - /* device will close the SCO socket for us */ + + spa_log_info(backend->log, "Transport %s released", t->path); + + /* Shutdown and close the socket */ + shutdown(t->fd, SHUT_RDWR); + close(t->fd); + t->fd = -1; + return 0; } @@ -661,4 +670,4 @@ struct spa_bt_backend *backend_hsp_native_new(struct spa_bt_monitor *monitor, backend->conn = dbus_connection; return backend; -} \ No newline at end of file +} diff --git a/spa/plugins/bluez5/backend-hsphfpd.c b/spa/plugins/bluez5/backend-hsphfpd.c index bf1c11398..3601f0824 100644 --- a/spa/plugins/bluez5/backend-hsphfpd.c +++ b/spa/plugins/bluez5/backend-hsphfpd.c @@ -921,6 +921,9 @@ static int hsphfpd_audio_acquire(void *data, bool optional) DBusPendingCall *call; DBusError err; + spa_log_debug(backend->log, NAME": transport %p: Acquire %s", + transport, transport->path); + if (backend->acquire_in_progress) return -EINPROGRESS; @@ -950,7 +953,7 @@ static int hsphfpd_audio_acquire(void *data, bool optional) while (backend->acquire_in_progress && dbus_connection_read_write_dispatch(backend->conn, -1)) ; // empty loop body - return transport->fd; + return 0; } static int hsphfpd_audio_release(void *data) @@ -959,11 +962,6 @@ static int hsphfpd_audio_release(void *data) struct spa_bt_backend *backend = transport->backend; struct hsphfpd_transport_data *transport_data = transport->user_data; - if (transport->fd < 0) { - spa_log_info(backend->log, NAME": transport %s already released", transport->path); - return 0; - } - spa_log_debug(backend->log, NAME": transport %p: Release %s", transport, transport->path); diff --git a/spa/plugins/bluez5/backend-ofono.c b/spa/plugins/bluez5/backend-ofono.c index 180bb0622..e6b62b186 100644 --- a/spa/plugins/bluez5/backend-ofono.c +++ b/spa/plugins/bluez5/backend-ofono.c @@ -232,7 +232,7 @@ static int ofono_audio_acquire(void *data, bool optional) transport->path, transport->fd, transport->codec); ofono_transport_get_mtu(backend, transport); - ret = transport->fd; + ret = 0; finish: return ret; @@ -243,11 +243,6 @@ static int ofono_audio_release(void *data) struct spa_bt_transport *transport = data; struct spa_bt_backend *backend = transport->backend; - if (transport->fd < 0) { - spa_log_info(backend->log, NAME": transport %s already released", transport->path); - return 0; - } - spa_log_debug(backend->log, NAME": transport %p: Release %s", transport, transport->path); diff --git a/spa/plugins/bluez5/bluez5-dbus.c b/spa/plugins/bluez5/bluez5-dbus.c index cd332dca4..51dd4174b 100644 --- a/spa/plugins/bluez5/bluez5-dbus.c +++ b/spa/plugins/bluez5/bluez5-dbus.c @@ -686,6 +686,7 @@ struct spa_bt_transport *spa_bt_transport_create(struct spa_bt_monitor *monitor, if (t == NULL) return NULL; + t->acquire_refcount = 0; t->monitor = monitor; t->path = path; t->fd = -1; @@ -721,6 +722,12 @@ void spa_bt_transport_free(struct spa_bt_transport *transport) spa_bt_transport_destroy(transport); + if (transport->fd >= 0) { + shutdown(transport->fd, SHUT_RDWR); + close(transport->fd); + transport->fd = -1; + } + spa_list_remove(&transport->link); if (transport->device) { transport->device->connected_profiles &= ~transport->profile; @@ -730,6 +737,50 @@ void spa_bt_transport_free(struct spa_bt_transport *transport) free(transport); } +int spa_bt_transport_acquire(struct spa_bt_transport *transport, bool optional) +{ + struct spa_bt_monitor *monitor = transport->monitor; + int res; + + if (transport->acquire_refcount > 0) { + spa_log_debug(monitor->log, "transport %p: incref %s", transport, transport->path); + transport->acquire_refcount += 1; + return 0; + } + spa_assert(transport->acquire_refcount == 0); + + res = spa_bt_transport_impl(transport, acquire, 0, optional); + + if (res >= 0) + transport->acquire_refcount = 1; + + return res; +} + +int spa_bt_transport_release(struct spa_bt_transport *transport) +{ + struct spa_bt_monitor *monitor = transport->monitor; + int res; + + if (transport->acquire_refcount > 1) { + spa_log_debug(monitor->log, "transport %p: decref %s", transport, transport->path); + transport->acquire_refcount -= 1; + return 0; + } + else if (transport->acquire_refcount == 0) { + spa_log_info(monitor->log, "transport %s already released", transport->path); + return 0; + } + spa_assert(transport->acquire_refcount == 1); + + res = spa_bt_transport_impl(transport, release, 0); + + if (res >= 0) + transport->acquire_refcount = 0; + + return res; +} + static int transport_update_props(struct spa_bt_transport *transport, DBusMessageIter *props_iter, DBusMessageIter *invalidated_iter) @@ -840,9 +891,6 @@ static int transport_acquire(void *data, bool optional) int ret = 0; const char *method = optional ? "TryAcquire" : "Acquire"; - if (transport->fd >= 0) - return 0; - m = dbus_message_new_method_call(BLUEZ_SERVICE, transport->path, BLUEZ_MEDIA_TRANSPORT_INTERFACE, @@ -900,10 +948,7 @@ static int transport_release(void *data) DBusMessage *m, *r; DBusError err; - if (transport->fd < 0) - return 0; - - spa_log_debug(monitor->log, "transport %p: Release %s", + spa_log_debug(monitor->log, NAME": transport %p: Release %s", transport, transport->path); close(transport->fd); diff --git a/spa/plugins/bluez5/defs.h b/spa/plugins/bluez5/defs.h index d390c9a6c..1d6ab2480 100644 --- a/spa/plugins/bluez5/defs.h +++ b/spa/plugins/bluez5/defs.h @@ -284,7 +284,7 @@ struct spa_bt_transport { void *configuration; int configuration_len; - bool acquired; + int acquire_refcount; int fd; uint16_t read_mtu; uint16_t write_mtu; @@ -302,6 +302,9 @@ struct spa_bt_transport *spa_bt_transport_find_full(struct spa_bt_monitor *monit bool (*callback) (struct spa_bt_transport *t, const void *data), const void *data); +int spa_bt_transport_acquire(struct spa_bt_transport *t, bool optional); +int spa_bt_transport_release(struct spa_bt_transport *t); + #define spa_bt_transport_emit(t,m,v,...) spa_hook_list_call(&(t)->listener_list, \ struct spa_bt_transport_events, \ m, v, ##__VA_ARGS__) @@ -323,8 +326,6 @@ struct spa_bt_transport *spa_bt_transport_find_full(struct spa_bt_monitor *monit res; \ }) -#define spa_bt_transport_acquire(t,o) spa_bt_transport_impl(t, acquire, 0, o) -#define spa_bt_transport_release(t) spa_bt_transport_impl(t, release, 0) #define spa_bt_transport_destroy(t) spa_bt_transport_impl(t, destroy, 0) static inline enum spa_bt_transport_state spa_bt_transport_state_from_string(const char *value) diff --git a/spa/plugins/bluez5/sco-sink.c b/spa/plugins/bluez5/sco-sink.c index 316bcff7f..b5fe5bf16 100644 --- a/spa/plugins/bluez5/sco-sink.c +++ b/spa/plugins/bluez5/sco-sink.c @@ -110,7 +110,6 @@ struct impl { /* Transport */ struct spa_bt_transport *transport; struct spa_hook transport_listener; - int sock_fd; /* Port */ struct port port; @@ -381,7 +380,7 @@ static void flush_data(struct impl *this) } next_write: - written = write(this->sock_fd, packet, this->transport->write_mtu); + written = write(this->transport->fd, packet, this->transport->write_mtu); if (written <= 0) { spa_log_debug(this->log, "failed to write data"); goto stop; @@ -472,6 +471,7 @@ static int lcm(int a, int b) { static int do_start(struct impl *this) { bool do_accept; + int res; /* Dont do anything if the node has already started */ if (this->started) @@ -484,9 +484,8 @@ static int do_start(struct impl *this) do_accept = this->transport->profile & SPA_BT_PROFILE_HEADSET_AUDIO_GATEWAY; /* acquire the socked fd (false -> connect | true -> accept) */ - this->sock_fd = spa_bt_transport_acquire(this->transport, do_accept); - if (this->sock_fd < 0) - return -1; + if ((res = spa_bt_transport_acquire(this->transport, do_accept)) < 0) + return res; /* Init mSBC if needed */ if (this->transport->codec == HFP_AUDIO_CODEC_MSBC) { @@ -557,13 +556,8 @@ static int do_stop(struct impl *this) } if (this->transport) { - /* Release the transport */ + /* Release the transport; it is responsible for closing the fd */ res = spa_bt_transport_release(this->transport); - - /* Shutdown and close the socket */ - shutdown(this->sock_fd, SHUT_RDWR); - close(this->sock_fd); - this->sock_fd = -1; } return res; @@ -1141,7 +1135,6 @@ impl_init(const struct spa_handle_factory *factory, } spa_bt_transport_add_listener(this->transport, &this->transport_listener, &transport_events, this); - this->sock_fd = -1; this->timerfd = spa_system_timerfd_create(this->data_system, CLOCK_MONOTONIC, SPA_FD_CLOEXEC | SPA_FD_NONBLOCK); diff --git a/spa/plugins/bluez5/sco-source.c b/spa/plugins/bluez5/sco-source.c index 2fa75cdff..932c205f8 100644 --- a/spa/plugins/bluez5/sco-source.c +++ b/spa/plugins/bluez5/sco-source.c @@ -107,7 +107,6 @@ struct impl { struct spa_bt_transport *transport; struct spa_hook transport_listener; - int sock_fd; struct port port; @@ -287,7 +286,7 @@ static int read_data(struct impl *this, uint8_t *data, uint32_t data_size) int res = 0; again: - res = read(this->sock_fd, data, data_size); + res = read(this->transport->fd, data, data_size); if (res <= 0) { /* retry if interrupted */ if (errno == EINTR) @@ -513,6 +512,7 @@ stop: static int do_start(struct impl *this) { bool do_accept; + int res; /* Dont do anything if the node has already started */ if (this->started) @@ -525,9 +525,8 @@ static int do_start(struct impl *this) do_accept = this->transport->profile & SPA_BT_PROFILE_HEADSET_AUDIO_GATEWAY; /* acquire the socked fd (false -> connect | true -> accept) */ - this->sock_fd = spa_bt_transport_acquire(this->transport, do_accept); - if (this->sock_fd < 0) - return -1; + if ((res = spa_bt_transport_acquire(this->transport, do_accept)) < 0) + return res; /* Reset the buffers and sample count */ reset_buffers(&this->port); @@ -543,7 +542,7 @@ static int do_start(struct impl *this) /* Add the ready read callback */ this->source.data = this; - this->source.fd = this->sock_fd; + this->source.fd = this->transport->fd; this->source.func = sco_on_ready_read; this->source.mask = SPA_IO_IN; this->source.rmask = 0; @@ -584,13 +583,8 @@ static int do_stop(struct impl *this) this->started = false; if (this->transport) { - /* Release the transport */ + /* Release the transport; it is responsible for closing the fd */ res = spa_bt_transport_release(this->transport); - - /* Shutdown and close the socket */ - shutdown(this->sock_fd, SHUT_RDWR); - close(this->sock_fd); - this->sock_fd = -1; } return res; @@ -1197,7 +1191,6 @@ impl_init(const struct spa_handle_factory *factory, } spa_bt_transport_add_listener(this->transport, &this->transport_listener, &transport_events, this); - this->sock_fd = -1; return 0; }