static guint resume_a2dp(struct media_transport *transport, struct media_owner *owner) { struct a2dp_transport *a2dp = transport->data; struct media_endpoint *endpoint = transport->endpoint; struct a2dp_sep *sep = media_endpoint_get_sep(endpoint); guint id; if (a2dp->session == NULL) { a2dp->session = avdtp_get(transport->device); if (a2dp->session == NULL) return 0; } if (state_in_use(transport->state)) return a2dp_resume(a2dp->session, sep, a2dp_resume_complete, owner); if (a2dp_sep_lock(sep, a2dp->session) == FALSE) return 0; id = a2dp_resume(a2dp->session, sep, a2dp_resume_complete, owner); if (id == 0) { a2dp_sep_unlock(sep, a2dp->session); return 0; } if (transport->state == TRANSPORT_STATE_IDLE) transport_set_state(transport, TRANSPORT_STATE_REQUESTING); return id; }
static DBusMessage *sink_connect(DBusConnection *conn, DBusMessage *msg, void *data) { struct audio_device *dev = data; struct sink *sink = dev->sink; struct pending_request *pending; if (!sink->session) sink->session = avdtp_get(&dev->src, &dev->dst); if (!sink->session) return btd_error_failed(msg, "Unable to get a session"); if (sink->connect || sink->disconnect) return btd_error_busy(msg); if (sink->stream_state >= AVDTP_STATE_OPEN) return btd_error_already_connected(msg); if (!sink_setup_stream(sink, NULL)) return btd_error_failed(msg, "Failed to create a stream"); dev->auto_connect = FALSE; pending = sink->connect; pending->conn = dbus_connection_ref(conn); pending->msg = dbus_message_ref(msg); DBG("stream creation in progress"); return NULL; }
int source_connect(struct audio_device *dev) { struct source *source = dev->source; if (!source->session) source->session = avdtp_get(dev); if (!source->session) { DBG("Unable to get a session"); return -EIO; } if (source->connect_id > 0 || source->disconnect_id > 0) return -EBUSY; if (source->stream_state >= AVDTP_STATE_OPEN) return -EALREADY; if (!source_setup_stream(source, NULL)) { DBG("Failed to create a stream"); return -EIO; } DBG("stream creation in progress"); return 0; }
int sink_connect(struct btd_service *service) { struct sink *sink = btd_service_get_user_data(service); if (!sink->session) sink->session = avdtp_get(btd_service_get_device(service)); if (!sink->session) { DBG("Unable to get a session"); return -EIO; } if (sink->connect_id > 0 || sink->disconnect_id > 0) return -EBUSY; if (sink->state == SINK_STATE_CONNECTING) return -EBUSY; if (sink->stream_state >= AVDTP_STATE_OPEN) return -EALREADY; if (!sink_setup_stream(service, NULL)) { DBG("Failed to create a stream"); return -EIO; } DBG("stream creation in progress"); return 0; }
static DBusMessage *sink_connect(DBusConnection *conn, DBusMessage *msg, void *data) { struct audio_device *dev = data; struct sink *sink = dev->sink; struct pending_request *pending; if (!sink->session) sink->session = avdtp_get(&dev->src, &dev->dst); if (!sink->session) return g_dbus_create_error(msg, ERROR_INTERFACE ".Failed", "Unable to get a session"); if (sink->connect || sink->disconnect) return g_dbus_create_error(msg, ERROR_INTERFACE ".Failed", "%s", strerror(EBUSY)); if (sink->state >= AVDTP_STATE_OPEN) return g_dbus_create_error(msg, ERROR_INTERFACE ".AlreadyConnected", "Device Already Connected"); pending = g_new0(struct pending_request, 1); pending->conn = dbus_connection_ref(conn); pending->msg = dbus_message_ref(msg); sink->connect = pending; avdtp_discover(sink->session, discovery_complete, sink); debug("stream creation in progress"); return NULL; }
static void start_discovery(struct audio_device *dev, struct unix_client *client) { struct a2dp_data *a2dp; int err = 0; switch (client->type) { case TYPE_SINK: case TYPE_SOURCE: a2dp = &client->d.a2dp; if (!a2dp->session) a2dp->session = avdtp_get(&dev->src, &dev->dst); if (!a2dp->session) { error("Unable to get a session"); goto failed; } err = avdtp_discover(a2dp->session, a2dp_discovery_complete, client); if (err) { if (a2dp->session) { avdtp_unref(a2dp->session); a2dp->session = NULL; } goto failed; } break; case TYPE_HEADSET: case TYPE_GATEWAY: headset_discovery_complete(dev, client); break; default: error("No known services for device"); goto failed; } client->dev = dev; return; failed: unix_ipc_error(client, BT_GET_CAPABILITIES, err ? : EIO); }
static gboolean avdtp_connect_timeout(gpointer user_data) { struct audio_device *dev = user_data; dev->priv->avdtp_timer = 0; if (dev->sink) { struct avdtp *session = avdtp_get(&dev->src, &dev->dst); if (!session) return FALSE; sink_setup_stream(dev->sink, session); avdtp_unref(session); } return FALSE; }
static DBusMessage *dev_connect(DBusConnection *conn, DBusMessage *msg, void *data) { struct audio_device *dev = data; struct dev_priv *priv = dev->priv; if (priv->state == AUDIO_STATE_CONNECTING) return g_dbus_create_error(msg, ERROR_INTERFACE ".InProgress", "Connect in Progress"); else if (priv->state == AUDIO_STATE_CONNECTED) return g_dbus_create_error(msg, ERROR_INTERFACE ".AlreadyConnected", "Already Connected"); dev->auto_connect = TRUE; if (dev->headset) headset_config_stream(dev, FALSE, NULL, NULL); if (priv->state != AUDIO_STATE_CONNECTING && dev->sink) { struct avdtp *session = avdtp_get(&dev->src, &dev->dst); if (!session) return g_dbus_create_error(msg, ERROR_INTERFACE ".Failed", "Failed to get AVDTP session"); sink_setup_stream(dev->sink, session); avdtp_unref(session); } /* The previous calls should cause a call to the state callback to * indicate AUDIO_STATE_CONNECTING */ if (priv->state != AUDIO_STATE_CONNECTING) return g_dbus_create_error(msg, ERROR_INTERFACE ".ConnectFailed", "Headset connect failed"); priv->conn_req = dbus_message_ref(msg); return NULL; }
static DBusMessage *source_connect(DBusConnection *conn, DBusMessage *msg, void *data) { struct audio_device *dev = data; struct source *source = dev->source; struct pending_request *pending; if (!source->session) source->session = avdtp_get(&dev->src, &dev->dst); if (!source->session) return g_dbus_create_error(msg, ERROR_INTERFACE ".Failed", "Unable to get a session"); if (source->connect || source->disconnect) return g_dbus_create_error(msg, ERROR_INTERFACE ".Failed", "%s", strerror(EBUSY)); if (source->stream_state >= AVDTP_STATE_OPEN) return g_dbus_create_error(msg, ERROR_INTERFACE ".AlreadyConnected", "Device Already Connected"); if (!source_setup_stream(source, NULL)) return g_dbus_create_error(msg, ERROR_INTERFACE ".Failed", "Failed to create a stream"); dev->auto_connect = FALSE; pending = source->connect; pending->conn = dbus_connection_ref(conn); pending->msg = dbus_message_ref(msg); debug("stream creation in progress"); return NULL; }
static guint resume_a2dp(struct media_transport *transport, struct media_owner *owner) { struct a2dp_transport *a2dp = transport->data; struct media_endpoint *endpoint = transport->endpoint; struct audio_device *device = transport->device; struct a2dp_sep *sep = media_endpoint_get_sep(endpoint); if (a2dp->session == NULL) { a2dp->session = avdtp_get(&device->src, &device->dst); if (a2dp->session == NULL) return 0; } if (transport->in_use == TRUE) goto done; transport->in_use = a2dp_sep_lock(sep, a2dp->session); if (transport->in_use == FALSE) return 0; done: return a2dp_resume(a2dp->session, sep, a2dp_resume_complete, owner); }
static void start_config(struct audio_device *dev, struct unix_client *client) { struct a2dp_data *a2dp; struct headset_data *hs; unsigned int id; switch (client->type) { case TYPE_SINK: case TYPE_SOURCE: a2dp = &client->d.a2dp; if (!a2dp->session) a2dp->session = avdtp_get(&dev->src, &dev->dst); if (!a2dp->session) { error("Unable to get a session"); goto failed; } if (!a2dp->sep) { error("seid %d not opened", client->seid); goto failed; } id = a2dp_config(a2dp->session, a2dp->sep, a2dp_config_complete, client->caps, client); client->cancel = a2dp_cancel; break; case TYPE_HEADSET: hs = &client->d.hs; if (!hs->locked) { error("seid %d not opened", client->seid); goto failed; } id = headset_config_stream(dev, TRUE, headset_setup_complete, client); client->cancel = headset_cancel_stream; break; case TYPE_GATEWAY: if (gateway_config_stream(dev, gateway_setup_complete, client) >= 0) { client->cancel = gateway_cancel_stream; id = 1; } else id = 0; break; default: error("No known services for device"); goto failed; } if (id == 0) { error("config failed"); goto failed; } client->req_id = id; return; failed: unix_ipc_error(client, BT_SET_CONFIGURATION, EIO); }
static void start_open(struct audio_device *dev, struct unix_client *client) { struct a2dp_data *a2dp; struct headset_data *hs; struct avdtp_remote_sep *rsep; gboolean unref_avdtp_on_fail = FALSE; switch (client->type) { case TYPE_SINK: case TYPE_SOURCE: a2dp = &client->d.a2dp; if (!a2dp->session) { a2dp->session = avdtp_get(&dev->src, &dev->dst); unref_avdtp_on_fail = TRUE; } if (!a2dp->session) { error("Unable to get a session"); goto failed; } if (a2dp->sep) { error("Client already has an opened session"); goto failed; } rsep = avdtp_get_remote_sep(a2dp->session, client->seid); if (!rsep) { error("Invalid seid %d", client->seid); goto failed; } a2dp->sep = a2dp_get(a2dp->session, rsep); if (!a2dp->sep) { error("seid %d not available or locked", client->seid); goto failed; } if (!a2dp_sep_lock(a2dp->sep, a2dp->session)) { error("Unable to open seid %d", client->seid); a2dp->sep = NULL; goto failed; } break; case TYPE_HEADSET: hs = &client->d.hs; if (hs->locked) { error("Client already has an opened session"); goto failed; } hs->locked = headset_lock(dev, client->lock); if (!hs->locked) { error("Unable to open seid %d", client->seid); goto failed; } break; case TYPE_GATEWAY: break; default: error("No known services for device"); goto failed; } client->dev = dev; open_complete(dev, client); return; failed: if (unref_avdtp_on_fail && a2dp->session) { avdtp_unref(a2dp->session); a2dp->session = NULL; } unix_ipc_error(client, BT_OPEN, EINVAL); }
static void start_suspend(struct audio_device *dev, struct unix_client *client) { struct a2dp_data *a2dp; struct headset_data *hs; unsigned int id; gboolean unref_avdtp_on_fail = FALSE; switch (client->type) { case TYPE_SINK: case TYPE_SOURCE: a2dp = &client->d.a2dp; if (!a2dp->session) { a2dp->session = avdtp_get(&dev->src, &dev->dst); unref_avdtp_on_fail = TRUE; } if (!a2dp->session) { error("Unable to get a session"); goto failed; } if (!a2dp->sep) { error("Unable to get a sep"); goto failed; } id = a2dp_suspend(a2dp->session, a2dp->sep, a2dp_suspend_complete, client); client->cancel = a2dp_cancel; break; case TYPE_HEADSET: hs = &client->d.hs; if (!hs->locked) { error("seid not opened"); goto failed; } id = headset_suspend_stream(dev, headset_suspend_complete, client); client->cancel = headset_cancel_stream; break; case TYPE_GATEWAY: gateway_suspend_stream(dev); client->cancel = gateway_cancel_stream; headset_suspend_complete(dev, client); id = 1; break; default: error("No known services for device"); goto failed; } if (id == 0) { error("suspend failed"); goto failed; } return; failed: if (unref_avdtp_on_fail && a2dp->session) { avdtp_unref(a2dp->session); a2dp->session = NULL; } unix_ipc_error(client, BT_STOP_STREAM, EIO); }
static void start_resume(struct audio_device *dev, struct unix_client *client) { struct a2dp_data *a2dp = NULL; struct headset_data *hs; unsigned int id; struct avdtp *session = NULL; switch (client->type) { case TYPE_SINK: case TYPE_SOURCE: a2dp = &client->d.a2dp; if (!a2dp->sep) { error("seid not opened"); goto failed; } if (!a2dp->session) { session = avdtp_get(&dev->src, &dev->dst); if (!session) { error("Unable to get a session"); goto failed; } a2dp->session = session; } id = a2dp_resume(a2dp->session, a2dp->sep, a2dp_resume_complete, client); client->cancel = a2dp_cancel; break; case TYPE_HEADSET: hs = &client->d.hs; if (!hs->locked) { error("seid not opened"); goto failed; } id = headset_request_stream(dev, headset_resume_complete, client); client->cancel = headset_cancel_stream; break; case TYPE_GATEWAY: id = gateway_request_stream(dev, gateway_resume_complete, client); client->cancel = gateway_cancel_stream; break; default: error("No known services for device"); goto failed; } if (id == 0) { error("start_resume: resume failed"); goto failed; } client->req_id = id; return; failed: if (session) { avdtp_unref(session); a2dp->session = NULL; } unix_ipc_error(client, BT_START_STREAM, EIO); }
static void start_config(struct audio_device *dev, struct unix_client *client) { struct a2dp_data *a2dp; struct headset_data *hs; struct avdtp_remote_sep *rsep; struct avdtp_service_capability *media_scms_t; struct avdtp_content_protection_capability scms_t_cap = {0x02, 0x00}; unsigned int id; switch (client->type) { case TYPE_SINK: case TYPE_SOURCE: a2dp = &client->d.a2dp; if (!a2dp->session) a2dp->session = avdtp_get(&dev->src, &dev->dst); if (!a2dp->session) { error("Unable to get a session"); goto failed; } if (!a2dp->sep) { error("seid %d not opened", client->seid); goto failed; } rsep = avdtp_get_remote_sep(a2dp->session, client->seid); media_scms_t = avdtp_get_remote_sep_protection(rsep); if (media_scms_t && (memcmp(media_scms_t->data, &scms_t_cap, sizeof(scms_t_cap)) == 0)) { media_scms_t = avdtp_service_cap_new(AVDTP_CONTENT_PROTECTION, &scms_t_cap, 2); client->caps = g_slist_append(client->caps, media_scms_t); } id = a2dp_config(a2dp->session, a2dp->sep, a2dp_config_complete, client->caps, client); client->cancel = a2dp_cancel; break; case TYPE_HEADSET: hs = &client->d.hs; if (!hs->locked) { error("seid %d not opened", client->seid); goto failed; } id = headset_config_stream(dev, TRUE, headset_setup_complete, client); client->cancel = headset_cancel_stream; break; case TYPE_GATEWAY: if (gateway_config_stream(dev, gateway_setup_complete, client) >= 0) { client->cancel = gateway_cancel_stream; id = 1; } else id = 0; break; default: error("No known services for device"); goto failed; } if (id == 0) { error("config failed"); goto failed; } client->req_id = id; g_slist_free(client->caps); client->caps = NULL; return; failed: if (client->caps) { g_slist_free(client->caps); client->caps = NULL; } unix_ipc_error(client, BT_SET_CONFIGURATION, EIO); }