struct a2dp_channel *chan;
struct avdtp *session;
struct a2dp_sep *sep;
- struct avdtp_remote_sep *rsep;
+ struct a2dp_remote_sep *rsep;
struct avdtp_stream *stream;
struct avdtp_error *err;
avdtp_set_configuration_cb setconf_cb;
return TRUE;
}
+static bool match_remote_sep(const void *data, const void *user_data)
+{
+ const struct a2dp_remote_sep *sep = data;
+ const struct avdtp_remote_sep *rsep = user_data;
+
+ return sep->sep == rsep;
+}
+
+static struct a2dp_remote_sep *find_remote_sep(struct a2dp_channel *chan,
+ struct a2dp_sep *sep)
+{
+ struct avdtp_remote_sep *rsep;
+
+ rsep = avdtp_find_remote_sep(chan->session, sep->lsep);
+
+ return queue_find(chan->seps, match_remote_sep, rsep);
+}
+
static gboolean a2dp_reconfigure(gpointer data)
{
struct a2dp_setup *setup = data;
struct avdtp_service_capability *cap;
if (setup->rsep) {
- cap = avdtp_get_codec(setup->rsep);
+ cap = avdtp_get_codec(setup->rsep->sep);
rsep_codec = (struct avdtp_media_codec_capability *) cap->data;
}
if (!setup->rsep || sep->codec != rsep_codec->media_codec_type)
- setup->rsep = avdtp_find_remote_sep(setup->session, sep->lsep);
+ setup->rsep = find_remote_sep(setup->chan, sep);
- posix_err = avdtp_set_configuration(setup->session, setup->rsep,
+ posix_err = avdtp_set_configuration(setup->session, setup->rsep->sep,
sep->lsep,
setup->caps,
&setup->stream);
return FALSE;
}
+static struct a2dp_remote_sep *get_remote_sep(struct a2dp_channel *chan,
+ struct avdtp_stream *stream)
+{
+ struct avdtp_remote_sep *rsep;
+
+ rsep = avdtp_stream_get_remote_sep(stream);
+
+ return queue_find(chan->seps, match_remote_sep, rsep);
+}
+
static void close_cfm(struct avdtp *session, struct avdtp_local_sep *sep,
struct avdtp_stream *stream, struct avdtp_error *err,
void *user_data)
}
if (!setup->rsep)
- setup->rsep = avdtp_stream_get_remote_sep(stream);
+ setup->rsep = get_remote_sep(setup->chan, stream);
if (setup->reconfigure)
g_timeout_add(RECONFIGURE_TIMEOUT, a2dp_reconfigure, setup);
return NULL;
}
+static void remote_sep_free(void *data)
+{
+ struct a2dp_remote_sep *sep = data;
+
+ free(sep->path);
+ free(sep);
+}
+
static void remove_remote_sep(void *data)
{
struct a2dp_remote_sep *sep = data;
+ if (!sep->path) {
+ remote_sep_free(sep);
+ return;
+ }
+
g_dbus_unregister_interface(btd_get_dbus_connection(), sep->path,
MEDIA_ENDPOINT_INTERFACE);
}
return -ENOMEM;
setup->sep = lsep;
- setup->rsep = rsep->sep;
+ setup->rsep = rsep;
setup_add_caps(setup, caps, size);
}
}
- err = avdtp_set_configuration(setup->session, setup->rsep,
+ err = avdtp_set_configuration(setup->session, setup->rsep->sep,
lsep->lsep,
setup->caps,
&setup->stream);
{ }
};
-static void remote_sep_free(void *data)
-{
- struct a2dp_remote_sep *sep = data;
-
- free(sep->path);
- free(sep);
-}
-
static void register_remote_sep(void *data, void *user_data)
{
struct avdtp_remote_sep *rsep = data;
sep = new0(struct a2dp_remote_sep, 1);
sep->chan = setup->chan;
sep->sep = rsep;
+
+ if (!(g_dbus_get_flags() & G_DBUS_FLAG_ENABLE_EXPERIMENTAL))
+ goto done;
+
asprintf(&sep->path, "%s/sep%d", device_get_path(setup->chan->device),
avdtp_get_seid(rsep));
sep_methods, NULL, sep_properties,
sep, remote_sep_free) == FALSE) {
error("Could not register remote sep %s", sep->path);
- remote_sep_free(sep);
+ free(sep->path);
+ sep->path = NULL;
}
+ DBG("Found remote SEP: %s", sep->path);
+
+done:
queue_push_tail(setup->chan->seps, sep);
}
cb_data->user_data = user_data;
setup->sep = sep;
- setup->rsep = avdtp_find_remote_sep(session, sep->lsep);
+ setup->rsep = find_remote_sep(setup->chan, sep);
if (setup->rsep == NULL) {
error("Could not find remote sep");
goto fail;
}
- service = avdtp_get_codec(setup->rsep);
+ service = avdtp_get_codec(setup->rsep->sep);
codec = (struct avdtp_media_codec_capability *) service->data;
err = sep->endpoint->select_configuration(sep, codec->data,
break;
}
- setup->rsep = avdtp_find_remote_sep(session, sep->lsep);
+ setup->rsep = find_remote_sep(setup->chan, sep);
if (setup->rsep == NULL) {
error("No matching ACP and INT SEPs found");
goto failed;
}
- posix_err = avdtp_set_configuration(session, setup->rsep,
+ posix_err = avdtp_set_configuration(session, setup->rsep->sep,
sep->lsep, caps,
&setup->stream);
if (posix_err < 0) {
return avdtp_get_device(setup->session);
}
+const char *a2dp_setup_remote_path(struct a2dp_setup *setup)
+{
+ if (setup->rsep) {
+ if (setup->rsep->path)
+ return setup->rsep->path;
+ }
+
+ return NULL;
+}
+
static int a2dp_source_probe(struct btd_service *service)
{
struct btd_device *dev = btd_service_get_device(service);
struct media_transport {
char *path; /* Transport object path */
struct btd_device *device; /* Transport device */
+ const char *remote_endpoint; /* Transport remote SEP */
struct media_endpoint *endpoint; /* Transport endpoint */
struct media_owner *owner; /* Transport owner */
uint8_t *configuration; /* Transport configuration */
avrcp_set_volume(transport->device, volume, notify);
}
+static gboolean endpoint_exists(const GDBusPropertyTable *property, void *data)
+{
+ struct media_transport *transport = data;
+
+ return transport->remote_endpoint != NULL;
+}
+
+static gboolean get_endpoint(const GDBusPropertyTable *property,
+ DBusMessageIter *iter, void *data)
+{
+ struct media_transport *transport = data;
+
+ dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH,
+ &transport->remote_endpoint);
+
+ return TRUE;
+}
+
static const GDBusMethodTable transport_methods[] = {
{ GDBUS_ASYNC_METHOD("Acquire",
NULL,
{ "Delay", "q", get_delay, NULL, delay_exists },
#endif
{ "Volume", "q", get_volume, set_volume, volume_exists },
+ { "Endpoint", "o", get_endpoint, NULL, endpoint_exists,
+ G_DBUS_PROPERTY_FLAG_EXPERIMENTAL },
{ }
};
}
struct media_transport *media_transport_create(struct btd_device *device,
+ const char *remote_endpoint,
uint8_t *configuration,
size_t size, void *data)
{
transport->configuration = g_new(uint8_t, size);
memcpy(transport->configuration, configuration, size);
transport->size = size;
- transport->path = g_strdup_printf("%s/fd%d", device_get_path(device),
- fd++);
+ transport->remote_endpoint = remote_endpoint;
+ transport->path = g_strdup_printf("%s/fd%d",
+ remote_endpoint ? remote_endpoint :
+ device_get_path(device), fd++);
transport->fd = -1;
uuid = media_endpoint_get_uuid(endpoint);