static void get_incoming_record_cb(sdp_list_t *recs, int err, gpointer user_data) { struct audio_device *dev = user_data; struct gateway *gw = dev->gateway; GError *gerr = NULL; if (err < 0) { error("Unable to get service record: %s (%d)", strerror(-err), -err); goto fail; } if (!recs || !recs->data) { error("No records found"); goto fail; } gw->version = get_remote_profile_version(recs->data); if (gw->version == 0) goto fail; rfcomm_connect_cb(gw->incoming, gerr, dev); return; fail: gateway_close(dev); }
static void newconnection_reply(DBusPendingCall *call, void *data) { struct audio_device *dev = data; struct gateway *gw = dev->gateway; struct hf_agent *agent = gw->agent; DBusMessage *reply = dbus_pending_call_steal_reply(call); DBusError derr; dbus_pending_call_unref(agent->call); agent->call = NULL; dbus_error_init(&derr); if (!dbus_set_error_from_message(&derr, reply)) { DBG("Agent reply: file descriptor passed successfully"); gw->rfcomm_id = g_io_add_watch(gw->rfcomm, G_IO_ERR | G_IO_HUP | G_IO_NVAL, (GIOFunc) rfcomm_disconnect_cb, dev); change_state(dev, GATEWAY_STATE_CONNECTED); goto done; } DBG("Agent reply: %s", derr.message); dbus_error_free(&derr); gateway_close(dev); done: dbus_message_unref(reply); }
static void newconnection_reply(DBusPendingCall *call, void *data) { struct audio_device *dev = data; DBusMessage *reply = dbus_pending_call_steal_reply(call); DBusError derr; if (!dev->gateway->rfcomm) { DBG("RFCOMM disconnected from server before agent reply"); goto done; } dbus_error_init(&derr); if (!dbus_set_error_from_message(&derr, reply)) { DBG("Agent reply: file descriptor passed successfully"); change_state(dev, GATEWAY_STATE_CONNECTED); goto done; } DBG("Agent reply: %s", derr.message); dbus_error_free(&derr); gateway_close(dev); done: dbus_message_unref(reply); }
static gboolean rfcomm_disconnect_cb(GIOChannel *chan, GIOCondition cond, struct audio_device *dev) { if (cond & G_IO_NVAL) return FALSE; gateway_close(dev); return FALSE; }
static void path_unregister(void *data) { struct audio_device *dev = data; DBG("Unregistered interface %s on path %s", AUDIO_GATEWAY_INTERFACE, dev->path); gateway_close(dev); g_free(dev->gateway); dev->gateway = NULL; }
void gateway_set_state(struct audio_device *dev, gateway_state_t new_state) { switch (new_state) { case GATEWAY_STATE_DISCONNECTED: gateway_close(dev); break; case GATEWAY_STATE_CONNECTING: case GATEWAY_STATE_CONNECTED: case GATEWAY_STATE_PLAYING: break; } }
void gateway_start_service(struct audio_device *dev) { struct gateway *gw = dev->gateway; GError *err = NULL; if (gw->rfcomm == NULL) return; if (!bt_io_accept(gw->rfcomm, rfcomm_incoming_cb, dev, NULL, &err)) { error("bt_io_accept: %s", err->message); g_error_free(err); gateway_close(dev); } }
static void rfcomm_connect_cb(GIOChannel *chan, GError *err, gpointer user_data) { DBusConnection *conn = btd_get_dbus_connection(); struct audio_device *dev = user_data; struct gateway *gw = dev->gateway; DBusMessage *reply; int sk, ret; if (err) { error("connect(): %s", err->message); goto fail; } if (!gw->agent) { error("Handsfree Agent not registered"); goto fail; } sk = g_io_channel_unix_get_fd(chan); if (gw->rfcomm == NULL) gw->rfcomm = g_io_channel_ref(chan); ret = agent_sendfd(gw->agent, sk, newconnection_reply, dev); if (!gw->msg) return; if (ret) reply = dbus_message_new_method_return(gw->msg); else reply = btd_error_failed(gw->msg, "Can't pass file descriptor"); g_dbus_send_message(conn, reply); return; fail: if (gw->msg) { DBusMessage *reply; reply = btd_error_failed(gw->msg, "Connect failed"); g_dbus_send_message(conn, reply); } gateway_close(dev); }
static void rfcomm_incoming_cb(GIOChannel *chan, GError *err, gpointer user_data) { struct audio_device *dev = user_data; struct gateway *gw = dev->gateway; uuid_t uuid; gw->incoming = g_io_channel_ref(chan); sdp_uuid16_create(&uuid, HANDSFREE_AGW_SVCLASS_ID); if (bt_search_service(&dev->src, &dev->dst, &uuid, get_incoming_record_cb, dev, unregister_incoming) == 0) return; unregister_incoming(dev); gateway_close(dev); }
static DBusMessage *ag_disconnect(DBusConnection *conn, DBusMessage *msg, void *data) { struct audio_device *device = data; struct gateway *gw = device->gateway; DBusMessage *reply = NULL; char gw_addr[18]; if (!gw->rfcomm) return btd_error_not_connected(msg); reply = dbus_message_new_method_return(msg); if (!reply) return NULL; gateway_close(device); ba2str(&device->dst, gw_addr); DBG("Disconnected from %s, %s", gw_addr, device->path); return reply; }
static void sco_connect_cb(GIOChannel *chan, GError *err, gpointer user_data) { struct audio_device *dev = (struct audio_device *) user_data; struct gateway *gw = dev->gateway; DBG("at the begin of sco_connect_cb() in gateway.c"); gw->sco = g_io_channel_ref(chan); if (gw->sco_start_cb) gw->sco_start_cb(dev, err, gw->sco_start_cb_data); if (err) { error("sco_connect_cb(): %s", err->message); gateway_close(dev); return; } g_io_add_watch(gw->sco, G_IO_ERR | G_IO_HUP | G_IO_NVAL, (GIOFunc) sco_io_cb, dev); }
static void get_record_cb(sdp_list_t *recs, int err, gpointer user_data) { struct audio_device *dev = user_data; struct gateway *gw = dev->gateway; int ch; sdp_list_t *protos, *classes; uuid_t uuid; GIOChannel *io; GError *gerr = NULL; if (err < 0) { error("Unable to get service record: %s (%d)", strerror(-err), -err); goto fail; } if (!recs || !recs->data) { error("No records found"); err = -EIO; goto fail; } if (sdp_get_service_classes(recs->data, &classes) < 0) { error("Unable to get service classes from record"); err = -EINVAL; goto fail; } if (sdp_get_access_protos(recs->data, &protos) < 0) { error("Unable to get access protocols from record"); err = -ENODATA; goto fail; } gw->version = get_remote_profile_version(recs->data); if (gw->version == 0) { error("Unable to get profile version from record"); err = -EINVAL; goto fail; } memcpy(&uuid, classes->data, sizeof(uuid)); sdp_list_free(classes, free); if (!sdp_uuid128_to_uuid(&uuid) || uuid.type != SDP_UUID16 || uuid.value.uuid16 != HANDSFREE_AGW_SVCLASS_ID) { sdp_list_free(protos, NULL); error("Invalid service record or not HFP"); err = -EIO; goto fail; } ch = sdp_get_proto_port(protos, RFCOMM_UUID); sdp_list_foreach(protos, (sdp_list_func_t) sdp_list_free, NULL); sdp_list_free(protos, NULL); if (ch <= 0) { error("Unable to extract RFCOMM channel from service record"); err = -EIO; goto fail; } io = bt_io_connect(rfcomm_connect_cb, dev, NULL, &gerr, BT_IO_OPT_SOURCE_BDADDR, &dev->src, BT_IO_OPT_DEST_BDADDR, &dev->dst, BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_MEDIUM, BT_IO_OPT_CHANNEL, ch, BT_IO_OPT_INVALID); if (!io) { error("Unable to connect: %s", gerr->message); goto fail; } g_io_channel_unref(io); return; fail: if (gw->msg) { DBusMessage *reply = btd_error_failed(gw->msg, gerr ? gerr->message : strerror(-err)); g_dbus_send_message(btd_get_dbus_connection(), reply); } gateway_close(dev); if (gerr) g_error_free(gerr); }
gboolean gateway_cancel_stream(struct audio_device *dev, unsigned int id) { gateway_close(dev); return TRUE; }