struct avdtp_remote_sep *sep;
};
+struct a2dp_last_used {
+ struct a2dp_sep *lsep;
+ struct a2dp_remote_sep *rsep;
+};
+
struct a2dp_channel {
struct a2dp_server *server;
struct btd_device *device;
unsigned int auth_id;
struct avdtp *session;
struct queue *seps;
- struct a2dp_remote_sep *last_used;
+ struct a2dp_last_used *last_used;
};
static GSList *servers = NULL;
g_io_channel_unref(s->io);
}
+ queue_destroy(s->eps, NULL);
+
setups = g_slist_remove(setups, s);
if (s->session)
avdtp_unref(s->session);
return sep->sep == rsep;
}
-static void store_last_used(struct a2dp_channel *chan,
- struct avdtp_remote_sep *rsep)
+static void store_last_used(struct a2dp_channel *chan, uint8_t lseid,
+ uint8_t rseid)
{
GKeyFile *key_file;
char filename[PATH_MAX];
char dst_addr[18];
- char value[4];
+ char value[6];
char *data;
size_t len = 0;
key_file = g_key_file_new();
g_key_file_load_from_file(key_file, filename, 0, NULL);
- sprintf(value, "%02hhx", avdtp_get_seid(rsep));
+ sprintf(value, "%02hhx:%02hhx", lseid, rseid);
g_key_file_set_string(key_file, "Endpoints", "LastUsed", value);
g_key_file_free(key_file);
}
-static void update_last_used(struct a2dp_channel *chan,
- struct avdtp_stream *stream)
+static void add_last_used(struct a2dp_channel *chan, struct a2dp_sep *lsep,
+ struct a2dp_remote_sep *rsep)
+{
+ if (!chan->last_used)
+ chan->last_used = new0(struct a2dp_last_used, 1);
+
+ chan->last_used->lsep = lsep;
+ chan->last_used->rsep = rsep;
+}
+
+static void update_last_used(struct a2dp_channel *chan, struct a2dp_sep *lsep,
+ struct avdtp_stream *stream)
{
struct avdtp_remote_sep *rsep;
struct a2dp_remote_sep *sep;
rsep = avdtp_stream_get_remote_sep(stream);
-
- /* Update last used */
sep = queue_find(chan->seps, match_remote_sep, rsep);
- if (chan->last_used == sep)
+ if (!sep) {
+ error("Unable to find remote SEP");
+ return;
+ }
+
+ /* Check if already stored then skip */
+ if (chan->last_used && (chan->last_used->lsep == lsep &&
+ chan->last_used->rsep == sep))
return;
- chan->last_used = sep;
- store_last_used(chan, rsep);
+ add_last_used(chan, lsep, sep);
+
+ store_last_used(chan, avdtp_sep_get_seid(lsep->lsep),
+ avdtp_get_seid(rsep));
}
static gboolean open_ind(struct avdtp *session, struct avdtp_local_sep *sep,
setup->stream = stream;
if (!err && setup->chan)
- update_last_used(setup->chan, stream);
+ update_last_used(setup->chan, a2dp_sep, stream);
if (setup->reconfigure)
setup->reconfigure = FALSE;
if (setup->start)
finalize_resume(setup);
} else if (setup->chan)
- update_last_used(setup->chan, stream);
+ update_last_used(setup->chan, a2dp_sep, stream);
finalize_config(setup);
avdtp_remove_state_cb(chan->state_id);
queue_destroy(chan->seps, remove_remote_sep);
+ free(chan->last_used);
g_free(chan);
}
setup->sep = lsep;
setup->rsep = rsep;
+ g_slist_free_full(setup->caps, g_free);
+ setup->caps = NULL;
+
caps_add_codec(&setup->caps, setup->sep->codec, caps, size);
l = avdtp_get_type(rsep->sep) == AVDTP_SEP_TYPE_SINK ?
return avdtp_get_seid(sep->sep) == *seid;
}
+static int match_sep(const void *data, const void *user_data)
+{
+ struct a2dp_sep *sep = (void *) data;
+ const uint8_t *seid = user_data;
+
+ return *seid - avdtp_sep_get_seid(sep->lsep);
+}
+
+static struct a2dp_sep *find_sep_by_seid(struct a2dp_server *server,
+ uint8_t seid)
+{
+ GSList *l;
+
+ l = g_slist_find_custom(server->sources, &seid, match_sep);
+ if (l)
+ return l->data;
+
+ l = g_slist_find_custom(server->sinks, &seid, match_sep);
+ if (l)
+ return l->data;
+
+ return NULL;
+}
+
static void load_remote_sep(struct a2dp_channel *chan, GKeyFile *key_file,
char **seids)
{
- struct avdtp_remote_sep *sep;
- uint8_t seid;
+ struct a2dp_sep *lsep;
+ struct a2dp_remote_sep *sep;
+ struct avdtp_remote_sep *rsep;
+ uint8_t lseid, rseid;
char *value;
if (!seids)
for (; *seids; seids++) {
uint8_t type;
uint8_t codec;
+ GSList *l = NULL;
char caps[256];
uint8_t data[128];
int i, size;
- GSList *l = NULL;
- if (sscanf(*seids, "%02hhx", &seid) != 1)
+ if (sscanf(*seids, "%02hhx", &rseid) != 1)
continue;
value = g_key_file_get_string(key_file, "Endpoints", *seids,
if (sscanf(value, "%02hhx:%02hhx:%s", &type, &codec,
caps) != 3) {
- warn("Unable to load Endpoint: seid %u", seid);
+ warn("Unable to load Endpoint: seid %u", rseid);
g_free(value);
continue;
}
uint8_t *tmp = data + i / 2;
if (sscanf(caps + i, "%02hhx", tmp) != 1) {
- warn("Unable to load Endpoint: seid %u", seid);
+ warn("Unable to load Endpoint: seid %u", rseid);
+ g_free(value);
break;
}
}
caps_add_codec(&l, codec, data, size / 2);
- sep = avdtp_register_remote_sep(chan->session, seid, type, l);
- if (!sep) {
- warn("Unable to register Endpoint: seid %u", seid);
+ rsep = avdtp_register_remote_sep(chan->session, rseid, type, l);
+ if (!rsep) {
+ warn("Unable to register Endpoint: seid %u", rseid);
continue;
}
- register_remote_sep(sep, chan);
+ register_remote_sep(rsep, chan);
}
value = g_key_file_get_string(key_file, "Endpoints", "LastUsed", NULL);
if (!value)
return;
- if (sscanf(value, "%02hhx", &seid) != 1)
+ if (sscanf(value, "%02hhx:%02hhx", &lseid, &rseid) != 2) {
+ warn("Unable to load LastUsed");
+ return;
+ }
+
+ g_free(value);
+
+ lsep = find_sep_by_seid(chan->server, lseid);
+ if (!lsep) {
+ warn("Unable to load LastUsed: lseid %u not found", lseid);
return;
+ }
+
+ sep = queue_find(chan->seps, match_seid, &rseid);
+ if (!sep) {
+ warn("Unable to load LastUsed: rseid %u not found", rseid);
+ return;
+ }
- chan->last_used = queue_find(chan->seps, match_seid, &seid);
+ add_last_used(chan, lsep, sep);
}
static void load_remote_seps(struct a2dp_channel *chan)
setup->sep = queue_pop_head(setup->eps);
if (!setup->sep) {
error("Unable to select a valid configuration");
- queue_destroy(setup->eps, NULL);
goto done;
}
err = setup->sep->endpoint->select_configuration(setup->sep,
codec->data,
service->length - sizeof(*codec),
- setup_ref(setup),
+ setup,
select_cb, setup->sep->user_data);
if (err == 0)
return;
seps = queue_new();
#endif
/* Prepend last used so it is preferred over others */
- if (chan->last_used && chan->last_used->sep == rsep)
+ if (chan->last_used && (chan->last_used->lsep == sep &&
+ chan->last_used->rsep->sep == rsep))
queue_push_head(seps, sep);
else
queue_push_tail(seps, sep);
key_file = g_key_file_new();
g_key_file_load_from_file(key_file, filename, 0, NULL);
+ data = g_key_file_get_string(key_file, "Endpoints", "LastUsed", NULL);
+
/* Remove current endpoints since it might have changed */
g_key_file_remove_group(key_file, "Endpoints", NULL);
queue_foreach(chan->seps, store_remote_sep, key_file);
+ if (data) {
+ g_key_file_set_string(key_file, "Endpoints", "LastUsed", data);
+ g_free(data);
+ }
+
data = g_key_file_to_data(key_file, &length, NULL);
g_file_set_contents(filename, data, length, NULL);
codec = (struct avdtp_media_codec_capability *) service->data;
err = setup->sep->endpoint->select_configuration(setup->sep,
- codec->data,
- service->length - sizeof(*codec),
- setup_ref(setup),
- select_cb, setup->sep->user_data);
+ codec->data,
+ service->length -
+ sizeof(*codec),
+ setup_ref(setup),
+ select_cb,
+ setup->sep->user_data);
if (err == 0)
return cb_data->id;