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 discovery_complete(struct avdtp *session, GSList *seps, struct avdtp_error *err, void *user_data) { struct sink *sink = user_data; struct pending_request *pending; struct avdtp_local_sep *lsep; struct avdtp_remote_sep *rsep; struct a2dp_sep *sep; GSList *caps = NULL; int id; pending = sink->connect; if (err) { avdtp_unref(sink->session); sink->session = NULL; if (avdtp_error_type(err) == AVDTP_ERROR_ERRNO && avdtp_error_posix_errno(err) != EHOSTDOWN) { DBG("connect:connect XCASE detected"); sink->retry_id = g_timeout_add_seconds(STREAM_SETUP_RETRY_TIMER, stream_setup_retry, sink); } else goto failed; return; } DBG("Discovery complete"); if (avdtp_get_seps(session, AVDTP_SEP_TYPE_SINK, AVDTP_MEDIA_TYPE_AUDIO, A2DP_CODEC_SBC, &lsep, &rsep) < 0) { error("No matching ACP and INT SEPs found"); goto failed; } if (!select_capabilities(session, rsep, &caps)) { error("Unable to select remote SEP capabilities"); goto failed; } sep = a2dp_get(session, rsep); if (!sep) { error("Unable to get a local source SEP"); goto failed; } id = a2dp_config(sink->session, sep, stream_setup_complete, caps, sink); if (id == 0) goto failed; pending->id = id; return; failed: if (pending->msg) error_failed(pending->conn, pending->msg, "Stream setup failed"); pending_request_free(sink->dev, pending); sink->connect = NULL; avdtp_unref(sink->session); sink->session = NULL; }