static void a2dp_suspend_complete(struct avdtp *session, struct avdtp_error *err, void *user_data) { struct unix_client *client = user_data; char buf[BT_SUGGESTED_BUFFER_SIZE]; struct bt_stop_stream_rsp *rsp = (void *) buf; struct a2dp_data *a2dp = &client->d.a2dp; if (err) goto failed; memset(buf, 0, sizeof(buf)); rsp->h.type = BT_RESPONSE; rsp->h.name = BT_STOP_STREAM; rsp->h.length = sizeof(*rsp); unix_ipc_sendmsg(client, &rsp->h); return; failed: error("suspend failed"); unix_ipc_error(client, BT_STOP_STREAM, EIO); if (a2dp->sep) { a2dp_sep_unlock(a2dp->sep, a2dp->session); a2dp->sep = NULL; } avdtp_unref(a2dp->session); a2dp->session = NULL; a2dp->stream = 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 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 void stream_state_changed(struct avdtp_stream *stream, avdtp_state_t old_state, avdtp_state_t new_state, struct avdtp_error *err, void *user_data) { struct unix_client *client = user_data; struct a2dp_data *a2dp = &client->d.a2dp; switch (new_state) { case AVDTP_STATE_IDLE: if (a2dp->sep) { a2dp_sep_unlock(a2dp->sep, a2dp->session); a2dp->sep = NULL; } if (a2dp->session) { avdtp_unref(a2dp->session); a2dp->session = NULL; } a2dp->stream = NULL; client->cb_id = 0; break; default: break; } }
static void start_close(struct audio_device *dev, struct unix_client *client, gboolean reply) { struct a2dp_data *a2dp; struct headset_data *hs; if (!client->dev) goto failed; switch (client->type) { case TYPE_HEADSET: hs = &client->d.hs; if (client->dev && hs->locked) { headset_unlock(client->dev, client->lock); hs->locked = FALSE; } break; case TYPE_GATEWAY: break; case TYPE_SOURCE: case TYPE_SINK: a2dp = &client->d.a2dp; if (client->cb_id > 0) { avdtp_stream_remove_cb(a2dp->session, a2dp->stream, client->cb_id); client->cb_id = 0; } if (a2dp->sep) { a2dp_sep_unlock(a2dp->sep, a2dp->session); a2dp->sep = NULL; } if (a2dp->session) { avdtp_unref(a2dp->session); a2dp->session = NULL; } a2dp->stream = NULL; break; default: error("No known services for device"); goto failed; } if (!reply) return; close_complete(dev, client); client->dev = NULL; return; failed: if (reply) unix_ipc_error(client, BT_STOP_STREAM, EINVAL); }
static void a2dp_resume_complete(struct avdtp *session, struct avdtp_error *err, void *user_data) { struct unix_client *client = user_data; char buf[BT_SUGGESTED_BUFFER_SIZE]; struct bt_start_stream_rsp *rsp = (void *) buf; struct bt_new_stream_ind *ind = (void *) buf; struct a2dp_data *a2dp = &client->d.a2dp; if (err) goto failed; memset(buf, 0, sizeof(buf)); rsp->h.type = BT_RESPONSE; rsp->h.name = BT_START_STREAM; rsp->h.length = sizeof(*rsp); unix_ipc_sendmsg(client, &rsp->h); memset(buf, 0, sizeof(buf)); ind->h.type = BT_RESPONSE; ind->h.name = BT_NEW_STREAM; rsp->h.length = sizeof(*ind); unix_ipc_sendmsg(client, &ind->h); if (unix_sendmsg_fd(client->sock, client->data_fd) < 0) { error("unix_sendmsg_fd: %s(%d)", strerror(errno), errno); goto failed; } return; failed: error("resume failed"); unix_ipc_error(client, BT_START_STREAM, EIO); if (client->cb_id > 0) { avdtp_stream_remove_cb(a2dp->session, a2dp->stream, client->cb_id); client->cb_id = 0; } if (a2dp->sep) { a2dp_sep_unlock(a2dp->sep, a2dp->session); a2dp->sep = NULL; } avdtp_unref(a2dp->session); a2dp->session = NULL; a2dp->stream = NULL; }
static guint suspend_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); if (!owner) { a2dp_sep_unlock(sep, a2dp->session); transport->in_use = FALSE; return 0; } return a2dp_suspend(a2dp->session, sep, a2dp_suspend_complete, owner); }
static guint suspend_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); if (owner != NULL) return a2dp_suspend(a2dp->session, sep, a2dp_suspend_complete, owner); transport_set_state(transport, TRANSPORT_STATE_IDLE); a2dp_sep_unlock(sep, a2dp->session); return 0; }
static void a2dp_suspend_complete(struct avdtp *session, struct avdtp_error *err, void *user_data) { struct media_owner *owner = user_data; struct media_transport *transport = owner->transport; struct a2dp_sep *sep = media_endpoint_get_sep(transport->endpoint); /* Release always succeeds */ if (owner->pending) { owner->pending->id = 0; media_request_reply(owner->pending, transport->conn, 0); media_owner_remove(owner); } a2dp_sep_unlock(sep, transport->session); transport->in_use = FALSE; media_transport_remove(transport, owner); }
static void a2dp_suspend_complete(struct avdtp *session, struct avdtp_error *err, void *user_data) { struct media_owner *owner = user_data; struct media_transport *transport = owner->transport; struct a2dp_transport *a2dp = transport->data; struct a2dp_sep *sep = media_endpoint_get_sep(transport->endpoint); /* Release always succeeds */ if (owner->pending) { owner->pending->id = 0; media_request_reply(owner->pending, 0); media_owner_remove(owner); } a2dp_sep_unlock(sep, a2dp->session); transport_set_state(transport, TRANSPORT_STATE_IDLE); media_transport_remove_owner(transport); }
static void a2dp_discovery_complete(struct avdtp *session, GSList *seps, struct avdtp_error *err, void *user_data) { struct unix_client *client = user_data; char buf[BT_SUGGESTED_BUFFER_SIZE]; struct bt_get_capabilities_rsp *rsp = (void *) buf; struct a2dp_data *a2dp = &client->d.a2dp; GSList *l; if (!g_slist_find(clients, client)) { DBG("Client disconnected during discovery"); return; } if (err) goto failed; memset(buf, 0, sizeof(buf)); client->req_id = 0; rsp->h.type = BT_RESPONSE; rsp->h.name = BT_GET_CAPABILITIES; rsp->h.length = sizeof(*rsp); ba2str(&client->dev->src, rsp->source); ba2str(&client->dev->dst, rsp->destination); strncpy(rsp->object, client->dev->path, sizeof(rsp->object)); for (l = seps; l; l = g_slist_next(l)) { struct avdtp_remote_sep *rsep = l->data; struct a2dp_sep *sep; struct avdtp_service_capability *cap; struct avdtp_stream *stream; uint8_t type, seid, configured = 0, lock = 0; GSList *cl; type = avdtp_get_type(rsep); if (type != AVDTP_SEP_TYPE_SINK && type != AVDTP_SEP_TYPE_SOURCE) continue; cap = avdtp_get_codec(rsep); if (cap->category != AVDTP_MEDIA_CODEC) continue; seid = avdtp_get_seid(rsep); if (client->seid != 0 && client->seid != seid) continue; stream = avdtp_get_stream(rsep); if (stream) { configured = 1; if (client->seid == seid) cap = avdtp_stream_get_codec(stream); } for (cl = clients; cl; cl = cl->next) { struct unix_client *c = cl->data; struct a2dp_data *ca2dp = &c->d.a2dp; if (ca2dp->session == session && c->seid == seid) { lock = c->lock; break; } } sep = a2dp_get_sep(session, stream); if (sep && a2dp_sep_get_lock(sep)) lock = BT_WRITE_LOCK; a2dp_append_codec(rsp, cap, seid, type, configured, lock); } unix_ipc_sendmsg(client, &rsp->h); return; failed: error("discovery failed"); unix_ipc_error(client, BT_GET_CAPABILITIES, EIO); if (a2dp->sep) { a2dp_sep_unlock(a2dp->sep, a2dp->session); a2dp->sep = NULL; } avdtp_unref(a2dp->session); a2dp->session = NULL; a2dp->stream = NULL; }
static void a2dp_config_complete(struct avdtp *session, struct a2dp_sep *sep, struct avdtp_stream *stream, struct avdtp_error *err, void *user_data) { struct unix_client *client = user_data; char buf[BT_SUGGESTED_BUFFER_SIZE]; struct bt_set_configuration_rsp *rsp = (void *) buf; struct a2dp_data *a2dp = &client->d.a2dp; uint16_t imtu, omtu; GSList *caps; client->req_id = 0; if (err) goto failed; memset(buf, 0, sizeof(buf)); if (!stream) goto failed; if (client->cb_id > 0) avdtp_stream_remove_cb(a2dp->session, a2dp->stream, client->cb_id); a2dp->sep = sep; a2dp->stream = stream; if (!avdtp_stream_get_transport(stream, &client->data_fd, &imtu, &omtu, &caps)) { error("Unable to get stream transport"); goto failed; } rsp->h.type = BT_RESPONSE; rsp->h.name = BT_SET_CONFIGURATION; rsp->h.length = sizeof(*rsp); /* FIXME: Use imtu when fd_opt is CFG_FD_OPT_READ */ rsp->link_mtu = omtu; unix_ipc_sendmsg(client, &rsp->h); client->cb_id = avdtp_stream_add_cb(session, stream, stream_state_changed, client); return; failed: error("config failed"); unix_ipc_error(client, BT_SET_CONFIGURATION, EIO); if (a2dp->sep && a2dp_sep_get_lock(a2dp->sep)) { a2dp_sep_unlock(a2dp->sep, a2dp->session); a2dp->sep = NULL; } avdtp_unref(a2dp->session); a2dp->session = NULL; a2dp->stream = NULL; a2dp->sep = NULL; }