static void source_free(struct btd_service *service) { struct source *source = btd_service_get_user_data(service); if (source->cb_id) avdtp_stream_remove_cb(source->session, source->stream, source->cb_id); if (source->session) avdtp_unref(source->session); if (source->connect_id > 0) { btd_service_connecting_complete(source->service, -ECANCELED); a2dp_cancel(source->connect_id); source->connect_id = 0; } if (source->disconnect_id > 0) { btd_service_disconnecting_complete(source->service, -ECANCELED); a2dp_cancel(source->disconnect_id); source->disconnect_id = 0; } avdtp_remove_state_cb(source->avdtp_callback_id); btd_service_unref(source->service); g_free(source); }
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); avdtp_unref(a2dp->session); a2dp->session = NULL; a2dp->stream = NULL; a2dp->sep = NULL; }
static void sink_free(struct audio_device *dev) { struct sink *sink = dev->sink; if (sink->cb_id) avdtp_stream_remove_cb(sink->session, sink->stream, sink->cb_id); if (sink->dc_id) device_remove_disconnect_watch(dev->btd_dev, sink->dc_id); if (sink->session) avdtp_unref(sink->session); if (sink->connect) pending_request_free(dev, sink->connect); if (sink->disconnect) pending_request_free(dev, sink->disconnect); if (sink->retry_id) g_source_remove(sink->retry_id); g_free(sink); dev->sink = NULL; }
static void source_free(struct audio_device *dev) { struct source *source = dev->source; if (source->cb_id) avdtp_stream_remove_cb(source->session, source->stream, source->cb_id); if (source->session) avdtp_unref(source->session); if (source->connect_id > 0) { audio_source_connected(dev->btd_dev, -ECANCELED); a2dp_cancel(dev, source->connect_id); source->connect_id = 0; } if (source->disconnect_id > 0) { audio_source_disconnected(dev->btd_dev, -ECANCELED); a2dp_cancel(dev, source->disconnect_id); source->disconnect_id = 0; } if (source->retry_id) g_source_remove(source->retry_id); avdtp_remove_state_cb(source->avdtp_callback_id); g_free(source); dev->source = NULL; }
static void sink_free(struct audio_device *dev) { struct sink *sink = dev->sink; if (sink->cb_id) avdtp_stream_remove_cb(sink->session, sink->stream, sink->cb_id); if (sink->session) avdtp_unref(sink->session); if (sink->connect_id > 0) { btd_service_connecting_complete(sink->service, -ECANCELED); a2dp_cancel(dev, sink->connect_id); sink->connect_id = 0; } if (sink->disconnect_id > 0) { btd_service_disconnecting_complete(sink->service, -ECANCELED); a2dp_cancel(dev, sink->disconnect_id); sink->disconnect_id = 0; } if (sink->retry_id) g_source_remove(sink->retry_id); avdtp_remove_state_cb(sink->avdtp_callback_id); btd_service_unref(sink->service); g_free(sink); dev->sink = NULL; }
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; }
void sink_free(struct audio_device *dev) { struct sink *sink = dev->sink; if (sink->cb_id) avdtp_stream_remove_cb(sink->session, sink->stream, sink->cb_id); if (sink->session) avdtp_unref(sink->session); if (sink->connect) pending_request_free(sink->connect); if (sink->disconnect) pending_request_free(sink->disconnect); g_free(sink); dev->sink = NULL; }