void avctp_unregister(const bdaddr_t *src) { struct avctp_server *server; server = find_server(servers, src); if (!server) return; while (server->sessions) avctp_disconnected(server->sessions->data); servers = g_slist_remove(servers, server); g_io_channel_shutdown(server->io, TRUE, NULL); g_io_channel_unref(server->io); g_free(server); if (servers) return; if (passthrough_id) { avctp_unregister_pdu_handler(passthrough_id); passthrough_id = 0; } if (unit_id) { avctp_unregister_pdu_handler(unit_id); passthrough_id = 0; } if (subunit_id) { avctp_unregister_pdu_handler(subunit_id); subunit_id = 0; } }
static void avctp_set_state(struct control *control, avctp_state_t new_state) { GSList *l; struct audio_device *dev = control->dev; avdtp_session_state_t old_state = control->state; gboolean value; switch (new_state) { case AVCTP_STATE_DISCONNECTED: DBG("AVCTP Disconnected"); avctp_disconnected(control->dev); if (old_state != AVCTP_STATE_CONNECTED) break; value = FALSE; g_dbus_emit_signal(dev->conn, dev->path, AUDIO_CONTROL_INTERFACE, "Disconnected", DBUS_TYPE_INVALID); emit_property_changed(dev->conn, dev->path, AUDIO_CONTROL_INTERFACE, "Connected", DBUS_TYPE_BOOLEAN, &value); if (!audio_device_is_active(dev, NULL)) audio_device_set_authorized(dev, FALSE); break; case AVCTP_STATE_CONNECTING: DBG("AVCTP Connecting"); break; case AVCTP_STATE_CONNECTED: DBG("AVCTP Connected"); value = TRUE; g_dbus_emit_signal(control->dev->conn, control->dev->path, AUDIO_CONTROL_INTERFACE, "Connected", DBUS_TYPE_INVALID); emit_property_changed(control->dev->conn, control->dev->path, AUDIO_CONTROL_INTERFACE, "Connected", DBUS_TYPE_BOOLEAN, &value); break; default: error("Invalid AVCTP state %d", new_state); return; } control->state = new_state; for (l = avctp_callbacks; l != NULL; l = l->next) { struct avctp_state_callback *cb = l->data; cb->cb(control->dev, old_state, new_state, cb->user_data); } }
static void path_unregister(void *data) { struct audio_device *dev = data; struct control *control = dev->control; DBG("Unregistered interface %s on path %s", AUDIO_CONTROL_INTERFACE, dev->path); if (control->state != AVCTP_STATE_DISCONNECTED) avctp_disconnected(dev); g_free(control); dev->control = NULL; }
static void avctp_set_state(struct avctp *session, avctp_state_t new_state) { GSList *l; struct audio_device *dev; avctp_state_t old_state = session->state; dev = manager_get_device(&session->server->src, &session->dst, FALSE); if (dev == NULL) { error("avdtp_set_state(): no matching audio device"); return; } session->state = new_state; for (l = callbacks; l != NULL; l = l->next) { struct avctp_state_callback *cb = l->data; cb->cb(dev, old_state, new_state, cb->user_data); } switch (new_state) { case AVCTP_STATE_DISCONNECTED: DBG("AVCTP Disconnected"); avctp_disconnected(session); if (old_state != AVCTP_STATE_CONNECTED) break; if (!audio_device_is_active(dev, NULL)) audio_device_set_authorized(dev, FALSE); break; case AVCTP_STATE_CONNECTING: DBG("AVCTP Connecting"); break; case AVCTP_STATE_CONNECTED: DBG("AVCTP Connected"); break; default: error("Invalid AVCTP state %d", new_state); return; } }
static void avctp_set_state(struct avctp *session, avctp_state_t new_state) { GSList *l; struct audio_device *dev; avctp_state_t old_state = session->state; dev = manager_get_audio_device(session->device, FALSE); if (dev == NULL) { error("%s(): No matching audio device", __func__); return; } session->state = new_state; for (l = callbacks; l != NULL; l = l->next) { struct avctp_state_callback *cb = l->data; cb->cb(dev, old_state, new_state, cb->user_data); } switch (new_state) { case AVCTP_STATE_DISCONNECTED: DBG("AVCTP Disconnected"); avctp_disconnected(session); break; case AVCTP_STATE_CONNECTING: DBG("AVCTP Connecting"); break; case AVCTP_STATE_CONNECTED: DBG("AVCTP Connected"); break; case AVCTP_STATE_BROWSING_CONNECTING: DBG("AVCTP Browsing Connecting"); break; case AVCTP_STATE_BROWSING_CONNECTED: DBG("AVCTP Browsing Connected"); break; default: error("Invalid AVCTP state %d", new_state); return; } }
static void avctp_set_state(struct avctp *session, avctp_state_t new_state, int err) { GSList *l; avctp_state_t old_state = session->state; session->state = new_state; for (l = callbacks; l != NULL; l = l->next) { struct avctp_state_callback *cb = l->data; if (cb->dev && cb->dev != session->device) continue; cb->cb(session->device, old_state, new_state, err, cb->user_data); } switch (new_state) { case AVCTP_STATE_DISCONNECTED: DBG("AVCTP Disconnected"); avctp_disconnected(session); break; case AVCTP_STATE_CONNECTING: DBG("AVCTP Connecting"); break; case AVCTP_STATE_CONNECTED: DBG("AVCTP Connected"); break; case AVCTP_STATE_BROWSING_CONNECTING: DBG("AVCTP Browsing Connecting"); break; case AVCTP_STATE_BROWSING_CONNECTED: DBG("AVCTP Browsing Connected"); break; default: error("Invalid AVCTP state %d", new_state); return; } }
void avctp_unregister(struct btd_adapter *adapter) { struct avctp_server *server; server = find_server(servers, adapter); if (!server) return; while (server->sessions) avctp_disconnected(server->sessions->data); servers = g_slist_remove(servers, server); g_io_channel_shutdown(server->browsing_io, TRUE, NULL); g_io_channel_unref(server->browsing_io); server->browsing_io = NULL; g_io_channel_shutdown(server->control_io, TRUE, NULL); g_io_channel_unref(server->control_io); btd_adapter_unref(server->adapter); g_free(server); }
static void avctp_confirm_cb(GIOChannel *chan, gpointer data) { struct avctp *session; struct audio_device *dev; char address[18]; bdaddr_t src, dst; GError *err = NULL; bt_io_get(chan, BT_IO_L2CAP, &err, BT_IO_OPT_SOURCE_BDADDR, &src, BT_IO_OPT_DEST_BDADDR, &dst, BT_IO_OPT_DEST, address, BT_IO_OPT_INVALID); if (err) { error("%s", err->message); g_error_free(err); g_io_channel_shutdown(chan, TRUE, NULL); return; } DBG("AVCTP: incoming connect from %s", address); session = avctp_get_internal(&src, &dst); if (!session) goto drop; dev = manager_get_device(&src, &dst, FALSE); if (!dev) { dev = manager_get_device(&src, &dst, TRUE); if (!dev) { error("Unable to get audio device object for %s", address); goto drop; } } if (dev->control == NULL) { btd_device_add_uuid(dev->btd_dev, AVRCP_REMOTE_UUID); if (dev->control == NULL) goto drop; } if (session->io) { /* AVCTP collision fix. (Collision was found with Sony headset DR-BT30Q). */ DBG("Canceling outgoing and accepting incoming connection from %s", address); avctp_disconnected(session); session = avctp_get_internal(&src, &dst); if (!session) goto drop; } avctp_set_state(session, AVCTP_STATE_CONNECTING); session->io = g_io_channel_ref(chan); if (audio_device_request_authorization(dev, AVRCP_TARGET_UUID, auth_cb, session) < 0) goto drop; session->io_id = g_io_add_watch(chan, G_IO_ERR | G_IO_HUP | G_IO_NVAL, session_cb, session); return; drop: if (!session || !session->io) g_io_channel_shutdown(chan, TRUE, NULL); if (session) avctp_set_state(session, AVCTP_STATE_DISCONNECTED); }