static gboolean audio_device_is_connected(struct audio_device *dev) { if (dev->headset) { headset_state_t state = headset_get_state(dev); if (state == HEADSET_STATE_CONNECTED || state == HEADSET_STATE_PLAY_IN_PROGRESS || state == HEADSET_STATE_PLAYING) return TRUE; } if (dev->sink) { sink_state_t state = sink_get_state(dev); if (state == SINK_STATE_CONNECTED || state == SINK_STATE_PLAYING) return TRUE; } if (dev->source) { source_state_t state = source_get_state(dev); if (state == SOURCE_STATE_CONNECTED || state == SOURCE_STATE_PLAYING) return TRUE; } return FALSE; }
static DBusMessage *device_get_connected(DBusConnection *conn, DBusMessage *msg, void *data) { DBusMessageIter iter, array_iter; struct audio_device *device = data; DBusMessage *reply; const char *iface; reply = dbus_message_new_method_return(msg); if (!reply) return NULL; dbus_message_iter_init_append(reply, &iter); dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, DBUS_TYPE_STRING_AS_STRING, &array_iter); #ifndef BT_ALT_STACK if (device->headset && headset_get_state(device) >= HEADSET_STATE_CONNECTED) { iface = AUDIO_HEADSET_INTERFACE; dbus_message_iter_append_basic(&array_iter, DBUS_TYPE_STRING, &iface); } #endif dbus_message_iter_close_container(&iter, &array_iter); return reply; }
gboolean manager_allow_headset_connection(struct audio_device *device) { GSList *l; int connected = 0; for (l = devices; l != NULL; l = l->next) { struct audio_device *dev = l->data; struct headset *hs = dev->headset; if (dev == device) continue; if (bacmp(&dev->src, &device->src)) continue; if (!hs) continue; if (headset_get_state(dev) > HEADSET_STATE_DISCONNECTED) connected++; if (connected >= max_connected_headsets) return FALSE; } return TRUE; }
uint8_t device_get_state(struct audio_device *dev) { avdtp_state_t sink_state; headset_state_t hs_state; if (dev->sink && sink_is_active(dev)) { sink_state = sink_get_state(dev); return avdtp_to_ipc_state(sink_state); } else if (dev->headset && headset_is_active(dev)) { hs_state = headset_get_state(dev); return hs_to_ipc_state(hs_state); } else if (dev->control && control_is_active(dev)) return STATE_CONNECTED; return STATE_DISCONNECTED; }
static void sco_server_cb(GIOChannel *chan, GError *err, gpointer data) { int sk; struct audio_device *device; char addr[18]; bdaddr_t src, dst; if (err) { error("sco_server_cb: %s", err->message); return; } bt_io_get(chan, BT_IO_SCO, &err, BT_IO_OPT_SOURCE_BDADDR, &src, BT_IO_OPT_DEST_BDADDR, &dst, BT_IO_OPT_DEST, addr, BT_IO_OPT_INVALID); if (err) { error("bt_io_get: %s", err->message); goto drop; } device = manager_find_device(NULL, &src, &dst, AUDIO_HEADSET_INTERFACE, FALSE); if (!device) device = manager_find_device(NULL, &src, &dst, AUDIO_GATEWAY_INTERFACE, FALSE); if (!device) goto drop; if (device->headset) { if (headset_get_state(device) < HEADSET_STATE_CONNECTED) { DBG("Refusing SCO from non-connected headset"); goto drop; } if (!get_hfp_active(device)) { error("Refusing non-HFP SCO connect attempt from %s", addr); goto drop; } if (headset_connect_sco(device, chan) < 0) goto drop; headset_set_state(device, HEADSET_STATE_PLAYING); } else if (device->gateway) { if (!gateway_is_connected(device)) { DBG("Refusing SCO from non-connected AG"); goto drop; } if (gateway_connect_sco(device, chan) < 0) goto drop; } else goto drop; sk = g_io_channel_unix_get_fd(chan); fcntl(sk, F_SETFL, 0); DBG("Accepted SCO connection from %s", addr); return; drop: g_io_channel_shutdown(chan, TRUE, NULL); }
static void ag_confirm(GIOChannel *chan, gpointer data) { const char *server_uuid, *remote_uuid; struct audio_device *device; gboolean hfp_active; bdaddr_t src, dst; int perr; GError *err = NULL; uint8_t ch; bt_io_get(chan, BT_IO_RFCOMM, &err, BT_IO_OPT_SOURCE_BDADDR, &src, BT_IO_OPT_DEST_BDADDR, &dst, BT_IO_OPT_CHANNEL, &ch, BT_IO_OPT_INVALID); if (err) { error("%s", err->message); g_error_free(err); goto drop; } if (ch == DEFAULT_HS_AG_CHANNEL) { hfp_active = FALSE; server_uuid = HSP_AG_UUID; remote_uuid = HSP_HS_UUID; } else { hfp_active = TRUE; server_uuid = HFP_AG_UUID; remote_uuid = HFP_HS_UUID; } device = manager_get_device(&src, &dst, TRUE); if (!device) goto drop; if (!manager_allow_headset_connection(device)) { DBG("Refusing headset: too many existing connections"); goto drop; } if (!device->headset) { btd_device_add_uuid(device->btd_dev, remote_uuid); if (!device->headset) goto drop; } if (headset_get_state(device) > HEADSET_STATE_DISCONNECTED) { DBG("Refusing new connection since one already exists"); goto drop; } set_hfp_active(device, hfp_active); if (headset_connect_rfcomm(device, chan) < 0) { error("headset_connect_rfcomm failed"); goto drop; } headset_set_state(device, HEADSET_STATE_CONNECTING); perr = audio_device_request_authorization(device, server_uuid, headset_auth_cb, device); if (perr < 0) { DBG("Authorization denied: %s", strerror(-perr)); headset_set_state(device, HEADSET_STATE_DISCONNECTED); return; } device->hs_preauth_id = g_io_add_watch(chan, G_IO_NVAL | G_IO_HUP | G_IO_ERR, hs_preauth_cb, device); device->auto_connect = auto_connect; return; drop: g_io_channel_shutdown(chan, TRUE, NULL); }