mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-10-29 05:40:27 -04:00
media-session: handle dbus disconnect
Make a signal in media-session to signal dbus disconnect. Get the DBusConnection when we need it in alsa and access-portal. Remove device reservation if dbus disconnects and try again later when needed. See #1099
This commit is contained in:
parent
d8208c5c2d
commit
ba544c8e36
4 changed files with 136 additions and 80 deletions
|
|
@ -58,7 +58,6 @@ struct impl {
|
|||
DBusConnection *bus;
|
||||
};
|
||||
|
||||
|
||||
struct client {
|
||||
struct impl *impl;
|
||||
|
||||
|
|
@ -76,6 +75,8 @@ struct client {
|
|||
enum media_role allowed_media_roles;
|
||||
};
|
||||
|
||||
static DBusConnection *get_dbus_connection(struct impl *impl);
|
||||
|
||||
static void client_info_changed(struct client *client, const struct pw_client_info *info);
|
||||
|
||||
static enum media_role media_role_from_string(const char *media_role_str)
|
||||
|
|
@ -284,11 +285,19 @@ static void session_destroy(void *data)
|
|||
free(impl);
|
||||
}
|
||||
|
||||
static void session_dbus_disconnected(void *data)
|
||||
{
|
||||
struct impl *impl = data;
|
||||
dbus_connection_unref(impl->bus);
|
||||
impl->bus = NULL;
|
||||
}
|
||||
|
||||
static const struct sm_media_session_events session_events = {
|
||||
SM_VERSION_MEDIA_SESSION_EVENTS,
|
||||
.create = session_create,
|
||||
.remove = session_remove,
|
||||
.destroy = session_destroy,
|
||||
.dbus_disconnected = session_dbus_disconnected,
|
||||
};
|
||||
|
||||
static bool
|
||||
|
|
@ -321,6 +330,7 @@ static void do_permission_store_check(struct client *client)
|
|||
const char *id;
|
||||
DBusMessageIter r_iter;
|
||||
DBusMessageIter permissions_iter;
|
||||
DBusConnection *bus;
|
||||
|
||||
if (client->app_id == NULL) {
|
||||
pw_log_debug("Ignoring portal check for broken portal managed client %p",
|
||||
|
|
@ -346,8 +356,9 @@ static void do_permission_store_check(struct client *client)
|
|||
client);
|
||||
return;
|
||||
}
|
||||
if (impl->bus == NULL) {
|
||||
pw_log_debug("Ignoring portal check for client %p: dbus disabled",
|
||||
bus = get_dbus_connection(impl);
|
||||
if (bus == NULL) {
|
||||
pw_log_debug("Ignoring portal check for client %p: no dbus",
|
||||
client);
|
||||
client->allowed_media_roles = MEDIA_ROLE_ALL;
|
||||
sm_media_session_for_each_object(impl->session,
|
||||
|
|
@ -371,7 +382,7 @@ static void do_permission_store_check(struct client *client)
|
|||
id = "camera";
|
||||
dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_STRING, &id);
|
||||
|
||||
if (!(r = dbus_connection_send_with_reply_and_block(impl->bus, m, -1, &error))) {
|
||||
if (!(r = dbus_connection_send_with_reply_and_block(bus, m, -1, &error))) {
|
||||
pw_log_error("Failed to call permission store: %s", error.message);
|
||||
dbus_error_free(&error);
|
||||
goto err_not_allowed;
|
||||
|
|
@ -558,12 +569,21 @@ static DBusHandlerResult permission_store_changed_handler(DBusConnection *connec
|
|||
return DBUS_HANDLER_RESULT_HANDLED;
|
||||
}
|
||||
|
||||
static int init_dbus_connection(struct impl *impl)
|
||||
static DBusConnection *get_dbus_connection(struct impl *impl)
|
||||
{
|
||||
struct sm_media_session *session = impl->session;
|
||||
DBusError error;
|
||||
|
||||
if (impl->bus == NULL)
|
||||
return 0;
|
||||
if (impl->bus)
|
||||
return impl->bus;
|
||||
|
||||
if (session->dbus_connection)
|
||||
impl->bus = spa_dbus_connection_get(session->dbus_connection);
|
||||
if (impl->bus == NULL) {
|
||||
pw_log_warn("no dbus connection, portal access disabled");
|
||||
return NULL;
|
||||
}
|
||||
pw_log_debug("got dbus connection %p", impl->bus);
|
||||
|
||||
dbus_error_init(&error);
|
||||
|
||||
|
|
@ -577,19 +597,18 @@ static int init_dbus_connection(struct impl *impl)
|
|||
pw_log_error("Failed to add permission store changed listener: %s",
|
||||
error.message);
|
||||
dbus_error_free(&error);
|
||||
return -1;
|
||||
impl->bus = NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
dbus_connection_ref(impl->bus);
|
||||
dbus_connection_add_filter(impl->bus, permission_store_changed_handler,
|
||||
impl, NULL);
|
||||
|
||||
return 0;
|
||||
return impl->bus;
|
||||
}
|
||||
|
||||
int sm_access_portal_start(struct sm_media_session *session)
|
||||
{
|
||||
struct impl *impl;
|
||||
int res;
|
||||
|
||||
impl = calloc(1, sizeof(struct impl));
|
||||
if (impl == NULL)
|
||||
|
|
@ -599,22 +618,10 @@ int sm_access_portal_start(struct sm_media_session *session)
|
|||
|
||||
impl->session = session;
|
||||
|
||||
if (session->dbus_connection)
|
||||
impl->bus = spa_dbus_connection_get(session->dbus_connection);
|
||||
if (impl->bus == NULL)
|
||||
pw_log_warn("no dbus connection, portal access disabled");
|
||||
else
|
||||
pw_log_debug("got dbus connection %p", impl->bus);
|
||||
|
||||
if ((res = init_dbus_connection(impl)) < 0)
|
||||
goto error_free;
|
||||
get_dbus_connection(impl);
|
||||
|
||||
sm_media_session_add_listener(impl->session,
|
||||
&impl->listener,
|
||||
&session_events, impl);
|
||||
return 0;
|
||||
|
||||
error_free:
|
||||
free(impl);
|
||||
return res;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -117,8 +117,6 @@ struct impl {
|
|||
struct pw_properties *conf;
|
||||
struct pw_properties *props;
|
||||
|
||||
DBusConnection *conn;
|
||||
|
||||
struct spa_handle *handle;
|
||||
|
||||
struct spa_device *monitor;
|
||||
|
|
@ -128,13 +126,14 @@ struct impl {
|
|||
|
||||
struct spa_source *jack_timeout;
|
||||
struct pw_proxy *jack_device;
|
||||
unsigned int reserve:1;
|
||||
};
|
||||
|
||||
#undef NAME
|
||||
#define NAME "alsa-monitor"
|
||||
|
||||
static int probe_device(struct device *device);
|
||||
static void reserve_acquired(void *data, struct rd_device *d);
|
||||
static int do_device_acquire(struct device *device);
|
||||
|
||||
static struct node *alsa_find_node(struct device *device, uint32_t id, const char *name)
|
||||
{
|
||||
|
|
@ -163,23 +162,6 @@ static void alsa_update_node(struct device *device, struct node *node,
|
|||
pw_properties_update(node->props, info->props);
|
||||
}
|
||||
|
||||
static int do_device_acquire(struct device *device)
|
||||
{
|
||||
int res;
|
||||
if (device->reserve == NULL)
|
||||
return 0;
|
||||
|
||||
res = rd_device_acquire(device->reserve);
|
||||
if (res < 0 && res != -EBUSY) {
|
||||
pw_log_warn("device reserve failed, disabling: %s", spa_strerror(res));
|
||||
reserve_acquired(device, device->reserve);
|
||||
rd_device_destroy(device->reserve);
|
||||
device->reserve = NULL;
|
||||
res = 0;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static int node_acquire(void *data)
|
||||
{
|
||||
struct node *node = data;
|
||||
|
|
@ -192,7 +174,7 @@ static int node_acquire(void *data)
|
|||
|
||||
node->acquired = true;
|
||||
|
||||
if (device && device->n_acquired++ == 0 && device->reserve)
|
||||
if (device && device->n_acquired++ == 0)
|
||||
return do_device_acquire(device);
|
||||
else
|
||||
return 0;
|
||||
|
|
@ -695,19 +677,22 @@ static void add_jack_timeout(struct impl *impl)
|
|||
pw_loop_update_timer(main_loop, impl->jack_timeout, &value, NULL, false);
|
||||
}
|
||||
|
||||
static void reserve_acquired(void *data, struct rd_device *d)
|
||||
static void do_reserve_acquired(struct device *device)
|
||||
{
|
||||
struct device *device = data;
|
||||
|
||||
pw_log_info("%p: reserve acquired %d", device, device->n_acquired);
|
||||
|
||||
if (!device->probed)
|
||||
probe_device(device);
|
||||
|
||||
if (device->n_acquired == 0)
|
||||
if (device->n_acquired == 0 && device->reserve)
|
||||
rd_device_release(device->reserve);
|
||||
}
|
||||
|
||||
static void reserve_acquired(void *data, struct rd_device *d)
|
||||
{
|
||||
struct device *device = data;
|
||||
pw_log_info("%p: reserve acquired %d", device, device->n_acquired);
|
||||
do_reserve_acquired(device);
|
||||
}
|
||||
|
||||
static void complete_release(struct device *device)
|
||||
{
|
||||
if (device->reserve)
|
||||
|
|
@ -802,6 +787,61 @@ static const struct rd_device_callbacks reserve_callbacks = {
|
|||
.available = reserve_available,
|
||||
};
|
||||
|
||||
static int do_device_acquire(struct device *device)
|
||||
{
|
||||
struct impl *impl = device->impl;
|
||||
struct sm_media_session *session = impl->session;
|
||||
int res;
|
||||
|
||||
if (!impl->reserve)
|
||||
goto done;
|
||||
|
||||
if (device->reserve == NULL) {
|
||||
const char *reserve;
|
||||
const char *path = pw_properties_get(device->props, SPA_KEY_API_ALSA_PATH);
|
||||
DBusConnection *conn = NULL;
|
||||
|
||||
if (session->dbus_connection)
|
||||
conn = spa_dbus_connection_get(session->dbus_connection);
|
||||
if (conn == NULL) {
|
||||
pw_log_warn("no dbus connection, device reservation disabled");
|
||||
goto done;
|
||||
}
|
||||
pw_log_debug("got dbus connection %p", conn);
|
||||
|
||||
reserve = pw_properties_get(device->props, "api.dbus.ReserveDevice1");
|
||||
if (reserve == NULL)
|
||||
goto done;
|
||||
|
||||
device->reserve = rd_device_new(conn, reserve,
|
||||
"PipeWire", -10,
|
||||
&reserve_callbacks, device);
|
||||
|
||||
if (device->reserve == NULL) {
|
||||
pw_log_warn("can't create device reserve for %s: %m", reserve);
|
||||
goto done;
|
||||
} else if (path) {
|
||||
rd_device_set_application_device_name(device->reserve, path);
|
||||
} else {
|
||||
pw_log_warn("empty reserve device path for %s", reserve);
|
||||
}
|
||||
}
|
||||
res = rd_device_acquire(device->reserve);
|
||||
if (res < 0 && res != -EBUSY) {
|
||||
pw_log_warn("device reserve failed, disabling: %s", spa_strerror(res));
|
||||
goto done;
|
||||
}
|
||||
return res;
|
||||
|
||||
done:
|
||||
do_reserve_acquired(device);
|
||||
if (device->reserve != NULL) {
|
||||
rd_device_destroy(device->reserve);
|
||||
device->reserve = NULL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void device_destroy(void *data)
|
||||
{
|
||||
struct device *device = data;
|
||||
|
|
@ -949,27 +989,9 @@ static struct device *alsa_create_device(struct impl *impl, uint32_t id,
|
|||
else
|
||||
device->factory_name = strdup(info->factory_name);
|
||||
|
||||
if (impl->conn &&
|
||||
(card = spa_dict_lookup(info->props, SPA_KEY_API_ALSA_CARD)) != NULL) {
|
||||
const char *reserve;
|
||||
const char *path = spa_dict_lookup(info->props, SPA_KEY_API_ALSA_PATH);
|
||||
|
||||
if ((card = spa_dict_lookup(info->props, SPA_KEY_API_ALSA_CARD)) != NULL) {
|
||||
device->priority -= atol(card) * 64;
|
||||
|
||||
pw_properties_setf(device->props, "api.dbus.ReserveDevice1", "Audio%s", card);
|
||||
reserve = pw_properties_get(device->props, "api.dbus.ReserveDevice1");
|
||||
|
||||
device->reserve = rd_device_new(impl->conn, reserve,
|
||||
"PipeWire", -10,
|
||||
&reserve_callbacks, device);
|
||||
|
||||
if (device->reserve == NULL) {
|
||||
pw_log_warn("can't create device reserve for %s: %m", reserve);
|
||||
} else if (path) {
|
||||
rd_device_set_application_device_name(device->reserve, path);
|
||||
} else {
|
||||
pw_log_warn("empty reserve device path for %s", reserve);
|
||||
}
|
||||
}
|
||||
do_device_acquire(device);
|
||||
|
||||
|
|
@ -1054,9 +1076,22 @@ static void session_destroy(void *data)
|
|||
free(impl);
|
||||
}
|
||||
|
||||
static void session_dbus_disconnected(void *data)
|
||||
{
|
||||
struct device *d;
|
||||
struct impl *impl = data;
|
||||
|
||||
spa_list_for_each(d, &impl->device_list, link) {
|
||||
if (d->reserve != NULL)
|
||||
rd_device_destroy(d->reserve);
|
||||
d->reserve = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static const struct sm_media_session_events session_events = {
|
||||
SM_VERSION_MEDIA_SESSION_EVENTS,
|
||||
.destroy = session_destroy,
|
||||
.dbus_disconnected = session_dbus_disconnected,
|
||||
};
|
||||
|
||||
int sm_alsa_monitor_start(struct sm_media_session *session)
|
||||
|
|
@ -1090,14 +1125,8 @@ int sm_alsa_monitor_start(struct sm_media_session *session)
|
|||
pw_properties_update_string(impl->props, str, strlen(str));
|
||||
|
||||
if ((str = pw_properties_get(impl->props, "alsa.reserve")) == NULL ||
|
||||
pw_properties_parse_bool(str)) {
|
||||
if (session->dbus_connection)
|
||||
impl->conn = spa_dbus_connection_get(session->dbus_connection);
|
||||
if (impl->conn == NULL)
|
||||
pw_log_warn("no dbus connection, device reservation disabled");
|
||||
else
|
||||
pw_log_debug("got dbus connection %p", impl->conn);
|
||||
}
|
||||
pw_properties_parse_bool(str))
|
||||
impl->reserve = true;
|
||||
|
||||
impl->handle = pw_context_load_spa_handle(context, SPA_NAME_API_ALSA_ENUM_UDEV, NULL);
|
||||
if (impl->handle == NULL) {
|
||||
|
|
|
|||
|
|
@ -80,6 +80,7 @@
|
|||
#define sm_media_session_emit_shutdown(s) sm_media_session_emit(s, shutdown, 0)
|
||||
#define sm_media_session_emit_destroy(s) sm_media_session_emit(s, destroy, 0)
|
||||
#define sm_media_session_emit_seat_active(s,...) sm_media_session_emit(s, seat_active, 0, __VA_ARGS__)
|
||||
#define sm_media_session_emit_dbus_disconnected(s) sm_media_session_emit(s, dbus_disconnected, 0)
|
||||
|
||||
int sm_access_flatpak_start(struct sm_media_session *sess);
|
||||
int sm_access_portal_start(struct sm_media_session *sess);
|
||||
|
|
@ -128,6 +129,7 @@ struct impl {
|
|||
|
||||
struct pw_main_loop *loop;
|
||||
struct spa_dbus *dbus;
|
||||
struct spa_hook dbus_connection_listener;
|
||||
|
||||
struct pw_core *monitor_core;
|
||||
struct spa_hook monitor_listener;
|
||||
|
|
@ -2307,6 +2309,18 @@ static int sm_pulse_bridge_start(struct sm_media_session *sess)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void dbus_connection_disconnected(void *data)
|
||||
{
|
||||
struct impl *impl = data;
|
||||
pw_log_info("DBus disconnected");
|
||||
sm_media_session_emit_dbus_disconnected(impl);
|
||||
}
|
||||
|
||||
static const struct spa_dbus_connection_events dbus_connection_events = {
|
||||
SPA_VERSION_DBUS_CONNECTION_EVENTS,
|
||||
.disconnected = dbus_connection_disconnected
|
||||
};
|
||||
|
||||
static void do_quit(void *data, int signal_number)
|
||||
{
|
||||
struct impl *impl = data;
|
||||
|
|
@ -2517,8 +2531,12 @@ int main(int argc, char *argv[])
|
|||
impl.this.dbus_connection = spa_dbus_get_connection(impl.dbus, SPA_DBUS_TYPE_SESSION);
|
||||
if (impl.this.dbus_connection == NULL)
|
||||
pw_log_warn("no dbus connection");
|
||||
else
|
||||
else {
|
||||
pw_log_debug("got dbus connection %p", impl.this.dbus_connection);
|
||||
spa_dbus_connection_add_listener(impl.this.dbus_connection,
|
||||
&impl.dbus_connection_listener,
|
||||
&dbus_connection_events, &impl);
|
||||
}
|
||||
} else {
|
||||
pw_log_info("dbus disabled");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -242,6 +242,8 @@ struct sm_media_session_events {
|
|||
void (*destroy) (void *data);
|
||||
|
||||
void (*seat_active) (void *data, bool active);
|
||||
|
||||
void (*dbus_disconnected) (void *data);
|
||||
};
|
||||
|
||||
struct sm_media_session {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue