static gboolean mpeg_setconf_ind(struct avdtp *session, struct avdtp_local_sep *sep, struct avdtp_stream *stream, GSList *caps, uint8_t *err, uint8_t *category, void *user_data) { struct a2dp_sep *a2dp_sep = user_data; struct audio_device *dev; if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK) debug("Sink %p: Set_Configuration_Ind", sep); else debug("Source %p: Set_Configuration_Ind", sep); dev = a2dp_get_dev(session); if (!dev) { *err = AVDTP_UNSUPPORTED_CONFIGURATION; *category = 0x00; return FALSE; } avdtp_stream_add_cb(session, stream, stream_state_changed, a2dp_sep); a2dp_sep->stream = stream; if (a2dp_sep->type == AVDTP_SEP_TYPE_SOURCE) sink_new_stream(dev, session, stream); return TRUE; }
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 gboolean auto_config(gpointer data) { struct a2dp_setup *setup = data; /* Check if configuration was aborted */ if (setup->sep->stream == NULL) return FALSE; if (setup->err != NULL) goto done; avdtp_stream_add_cb(setup->session, setup->stream, stream_state_changed, setup->sep); if (setup->sep->type == AVDTP_SEP_TYPE_SOURCE) sink_new_stream(setup->dev, setup->session, setup->stream); else source_new_stream(setup->dev, setup->session, setup->stream); done: if (setup->setconf_cb) setup->setconf_cb(setup->session, setup->stream, setup->err); finalize_config(setup); if (setup->err) { g_free(setup->err); setup->err = NULL; } setup_unref(setup); return FALSE; }
static gboolean sbc_setconf_ind(struct avdtp *session, struct avdtp_local_sep *sep, struct avdtp_stream *stream, GSList *caps, uint8_t *err, uint8_t *category, void *user_data) { struct a2dp_sep *a2dp_sep = user_data; struct audio_device *dev; struct avdtp_service_capability *cap; struct avdtp_media_codec_capability *codec_cap; struct sbc_codec_cap *sbc_cap; if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK) debug("Sink %p: Set_Configuration_Ind", sep); else debug("Source %p: Set_Configuration_Ind", sep); dev = a2dp_get_dev(session); if (!dev) { *err = AVDTP_UNSUPPORTED_CONFIGURATION; *category = 0x00; return FALSE; } /* Check bipool range */ for (codec_cap = NULL; caps; caps = g_slist_next(caps)) { cap = caps->data; if (cap->category != AVDTP_MEDIA_CODEC) continue; if (cap->length < sizeof(struct sbc_codec_cap)) continue; codec_cap = (void *) cap->data; if (codec_cap->media_codec_type != A2DP_CODEC_SBC) continue; sbc_cap = (void *) codec_cap; if (sbc_cap->min_bitpool < MIN_BITPOOL || sbc_cap->max_bitpool > MAX_BITPOOL) { *err = AVDTP_UNSUPPORTED_CONFIGURATION; *category = AVDTP_MEDIA_CODEC; return FALSE; } break; } avdtp_stream_add_cb(session, stream, stream_state_changed, a2dp_sep); a2dp_sep->stream = stream; if (a2dp_sep->type == AVDTP_SEP_TYPE_SOURCE) sink_new_stream(dev, session, stream); return TRUE; }
static void setconf_cfm(struct avdtp *session, struct avdtp_local_sep *sep, struct avdtp_stream *stream, struct avdtp_error *err, void *user_data) { struct a2dp_sep *a2dp_sep = user_data; struct a2dp_setup *setup; struct audio_device *dev; int ret; if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK) DBG("Sink %p: Set_Configuration_Cfm", sep); else DBG("Source %p: Set_Configuration_Cfm", sep); setup = find_setup_by_session(session); if (err) { if (setup) { setup->err = err; finalize_config(setup); } return; } avdtp_stream_add_cb(session, stream, stream_state_changed, a2dp_sep); a2dp_sep->stream = stream; if (!setup) return; dev = a2dp_get_dev(session); /* Notify D-Bus interface of the new stream */ if (a2dp_sep->type == AVDTP_SEP_TYPE_SOURCE) sink_new_stream(dev, session, setup->stream); else source_new_stream(dev, session, setup->stream); ret = avdtp_open(session, stream); if (ret < 0) { error("Error on avdtp_open %s (%d)", strerror(-ret), -ret); setup->stream = NULL; finalize_config_errno(setup, ret); } }
gboolean source_new_stream(struct btd_service *service, struct avdtp *session, struct avdtp_stream *stream) { struct source *source = btd_service_get_user_data(service); if (source->stream) return FALSE; if (!source->session) source->session = avdtp_ref(session); source->stream = stream; source->cb_id = avdtp_stream_add_cb(session, stream, stream_state_changed, service); return TRUE; }
gboolean sink_new_stream(struct audio_device *dev, struct avdtp *session, struct avdtp_stream *stream) { struct sink *sink = dev->sink; if (sink->stream) return FALSE; if (!sink->session) sink->session = avdtp_ref(session); sink->stream = stream; sink->cb_id = avdtp_stream_add_cb(session, stream, stream_state_changed, dev); return TRUE; }
gboolean source_new_stream(struct audio_device *dev, struct avdtp *session, struct avdtp_stream *stream) { struct source *source = dev->source; if (source->stream) return FALSE; if (!source->session) source->session = avdtp_ref(session); source->stream = stream; source->cb_id = avdtp_stream_add_cb(session, stream, stream_state_changed, dev); return TRUE; }
static gboolean mpeg_setconf_ind(struct avdtp *session, struct avdtp_local_sep *sep, struct avdtp_stream *stream, GSList *caps, uint8_t *err, uint8_t *category, void *user_data) { struct a2dp_sep *a2dp_sep = user_data; struct audio_device *dev; if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK) DBG("Sink %p: Set_Configuration_Ind", sep); else DBG("Source %p: Set_Configuration_Ind", sep); dev = a2dp_get_dev(session); if (!dev) { *err = AVDTP_UNSUPPORTED_CONFIGURATION; *category = 0x00; return FALSE; } for (; caps != NULL; caps = g_slist_next(caps)) { struct avdtp_service_capability *cap = caps->data; if (cap->category == AVDTP_DELAY_REPORTING && !a2dp_sep->delay_reporting) { *err = AVDTP_UNSUPPORTED_CONFIGURATION; *category = AVDTP_DELAY_REPORTING; return FALSE; } } avdtp_stream_add_cb(session, stream, stream_state_changed, a2dp_sep); a2dp_sep->stream = stream; if (a2dp_sep->type == AVDTP_SEP_TYPE_SOURCE) sink_new_stream(dev, session, stream); return TRUE; }
static gboolean auto_config(gpointer data) { struct a2dp_setup *setup = data; struct btd_device *dev = avdtp_get_device(setup->session); struct btd_service *service; /* Check if configuration was aborted */ if (setup->sep->stream == NULL) return FALSE; if (setup->err != NULL) goto done; avdtp_stream_add_cb(setup->session, setup->stream, stream_state_changed, setup->sep); if (setup->sep->type == AVDTP_SEP_TYPE_SOURCE) { service = btd_device_get_service(dev, A2DP_SINK_UUID); sink_new_stream(service, setup->session, setup->stream); } else { service = btd_device_get_service(dev, A2DP_SOURCE_UUID); source_new_stream(service, setup->session, setup->stream); } done: if (setup->setconf_cb) setup->setconf_cb(setup->session, setup->stream, setup->err); finalize_config(setup); if (setup->err) { g_free(setup->err); setup->err = NULL; } setup_unref(setup); return FALSE; }