summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohan Hedberg <johan.hedberg@nokia.com>2007-08-24 12:15:20 +0000
committerJohan Hedberg <johan.hedberg@nokia.com>2007-08-24 12:15:20 +0000
commit666938b54d631956826343ed278e2af4b982fc29 (patch)
tree90828ce9054d431a304bda457ac392cd3798bd9e
parentc3cd59ae39ebb53e27ddd99ee48f1875bd480c1d (diff)
Support up to two simultaneous streams
-rw-r--r--audio/a2dp.c435
-rw-r--r--audio/a2dp.h5
-rw-r--r--audio/avdtp.c92
-rw-r--r--audio/avdtp.h50
-rw-r--r--audio/sink.c6
-rw-r--r--audio/unix.c8
6 files changed, 364 insertions, 232 deletions
diff --git a/audio/a2dp.c b/audio/a2dp.c
index febc112c..daeda70c 100644
--- a/audio/a2dp.c
+++ b/audio/a2dp.c
@@ -54,12 +54,13 @@
#endif
struct a2dp_sep {
+ uint8_t type;
struct avdtp_local_sep *sep;
struct avdtp *session;
struct avdtp_stream *stream;
struct device *used_by;
- uint32_t record_id;
guint suspend_timer;
+ gboolean locked;
gboolean start_requested;
gboolean suspending;
gboolean starting;
@@ -82,8 +83,11 @@ struct a2dp_stream_setup {
static DBusConnection *connection = NULL;
-static struct a2dp_sep sink = { NULL };
-static struct a2dp_sep source = { NULL };
+static GSList *sinks = NULL;
+static GSList *sources = NULL;
+
+static uint32_t source_record_id = 0;
+static uint32_t sink_record_id = 0;
static struct a2dp_stream_setup *setup = NULL;
@@ -138,19 +142,16 @@ static gboolean setconf_ind(struct avdtp *session,
struct avdtp_local_sep *sep,
struct avdtp_stream *stream,
GSList *caps, uint8_t *err,
- uint8_t *category)
+ uint8_t *category, void *user_data)
{
- struct a2dp_sep *a2dp_sep;
+ struct a2dp_sep *a2dp_sep = user_data;
struct device *dev;
bdaddr_t addr;
- if (sep == sink.sep) {
+ if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)
debug("SBC Sink: Set_Configuration_Ind");
- a2dp_sep = &sink;
- } else {
+ else
debug("SBC Source: Set_Configuration_Ind");
- a2dp_sep = &source;
- }
avdtp_get_peers(session, NULL, &addr);
@@ -164,19 +165,20 @@ static gboolean setconf_ind(struct avdtp *session,
avdtp_stream_add_cb(session, stream, stream_state_changed, a2dp_sep);
a2dp_sep->stream = stream;
- if (a2dp_sep == &source)
+ if (a2dp_sep->type == AVDTP_SEP_TYPE_SOURCE)
sink_new_stream(dev, session, stream);
return TRUE;
}
static gboolean getcap_ind(struct avdtp *session, struct avdtp_local_sep *sep,
- GSList **caps, uint8_t *err)
+ GSList **caps, uint8_t *err, void *user_data)
{
+ struct a2dp_sep *a2dp_sep = user_data;
struct avdtp_service_capability *media_transport, *media_codec;
struct sbc_codec_cap sbc_cap;
- if (sep == sink.sep)
+ if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)
debug("SBC Sink: Get_Capability_Ind");
else
debug("SBC Source: Get_Capability_Ind");
@@ -226,18 +228,15 @@ static gboolean getcap_ind(struct avdtp *session, struct avdtp_local_sep *sep,
static void setconf_cfm(struct avdtp *session, struct avdtp_local_sep *sep,
struct avdtp_stream *stream,
- struct avdtp_error *err)
+ struct avdtp_error *err, void *user_data)
{
- struct a2dp_sep *a2dp_sep;
+ struct a2dp_sep *a2dp_sep = user_data;
int ret;
- if (sep == sink.sep) {
+ if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)
debug("SBC Sink: Set_Configuration_Cfm");
- a2dp_sep = &sink;
- } else {
+ else
debug("SBC Source: Set_Configuration_Cfm");
- a2dp_sep = &source;
- }
if (err) {
if (setup)
@@ -261,9 +260,11 @@ static void setconf_cfm(struct avdtp *session, struct avdtp_local_sep *sep,
}
static gboolean getconf_ind(struct avdtp *session, struct avdtp_local_sep *sep,
- uint8_t *err)
+ uint8_t *err, void *user_data)
{
- if (sep == sink.sep)
+ struct a2dp_sep *a2dp_sep = user_data;
+
+ if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)
debug("SBC Sink: Get_Configuration_Ind");
else
debug("SBC Source: Get_Configuration_Ind");
@@ -271,18 +272,24 @@ static gboolean getconf_ind(struct avdtp *session, struct avdtp_local_sep *sep,
}
static void getconf_cfm(struct avdtp *session, struct avdtp_local_sep *sep,
- struct avdtp_stream *stream, struct avdtp_error *err)
+ struct avdtp_stream *stream, struct avdtp_error *err,
+ void *user_data)
{
- if (sep == sink.sep)
+ struct a2dp_sep *a2dp_sep = user_data;
+
+ if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)
debug("SBC Sink: Set_Configuration_Cfm");
else
debug("SBC Source: Set_Configuration_Cfm");
}
static gboolean open_ind(struct avdtp *session, struct avdtp_local_sep *sep,
- struct avdtp_stream *stream, uint8_t *err)
+ struct avdtp_stream *stream, uint8_t *err,
+ void *user_data)
{
- if (sep == sink.sep)
+ struct a2dp_sep *a2dp_sep = user_data;
+
+ if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)
debug("SBC Sink: Open_Ind");
else
debug("SBC Source: Open_Ind");
@@ -290,9 +297,12 @@ static gboolean open_ind(struct avdtp *session, struct avdtp_local_sep *sep,
}
static void open_cfm(struct avdtp *session, struct avdtp_local_sep *sep,
- struct avdtp_stream *stream, struct avdtp_error *err)
+ struct avdtp_stream *stream, struct avdtp_error *err,
+ void *user_data)
{
- if (sep == sink.sep)
+ struct a2dp_sep *a2dp_sep = user_data;
+
+ if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)
debug("SBC Sink: Open_Cfm");
else
debug("SBC Source: Open_Cfm");
@@ -338,18 +348,15 @@ static gboolean suspend_timeout(struct a2dp_sep *sep)
}
static gboolean start_ind(struct avdtp *session, struct avdtp_local_sep *sep,
- struct avdtp_stream *stream, uint8_t *err)
+ struct avdtp_stream *stream, uint8_t *err,
+ void *user_data)
{
- struct a2dp_sep *a2dp_sep;
+ struct a2dp_sep *a2dp_sep = user_data;
- if (sep == sink.sep) {
+ if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)
debug("SBC Sink: Start_Ind");
- a2dp_sep = &sink;
- }
- else {
+ else
debug("SBC Source: Start_Ind");
- a2dp_sep = &source;
- }
a2dp_sep->session = avdtp_ref(session);
@@ -360,9 +367,12 @@ static gboolean start_ind(struct avdtp *session, struct avdtp_local_sep *sep,
}
static void start_cfm(struct avdtp *session, struct avdtp_local_sep *sep,
- struct avdtp_stream *stream, struct avdtp_error *err)
+ struct avdtp_stream *stream, struct avdtp_error *err,
+ void *user_data)
{
- if (sep == sink.sep)
+ struct a2dp_sep *a2dp_sep = user_data;
+
+ if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)
debug("SBC Sink: Start_Cfm");
else
debug("SBC Source: Start_Cfm");
@@ -384,9 +394,12 @@ static void start_cfm(struct avdtp *session, struct avdtp_local_sep *sep,
}
static gboolean suspend_ind(struct avdtp *session, struct avdtp_local_sep *sep,
- struct avdtp_stream *stream, uint8_t *err)
+ struct avdtp_stream *stream, uint8_t *err,
+ void *user_data)
{
- if (sep == sink.sep)
+ struct a2dp_sep *a2dp_sep = user_data;
+
+ if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)
debug("SBC Sink: Suspend_Ind");
else
debug("SBC Source: Suspend_Ind");
@@ -394,17 +407,15 @@ static gboolean suspend_ind(struct avdtp *session, struct avdtp_local_sep *sep,
}
static void suspend_cfm(struct avdtp *session, struct avdtp_local_sep *sep,
- struct avdtp_stream *stream, struct avdtp_error *err)
+ struct avdtp_stream *stream, struct avdtp_error *err,
+ void *user_data)
{
- struct a2dp_sep *a2dp_sep;
+ struct a2dp_sep *a2dp_sep = user_data;
- if (sep == sink.sep) {
+ if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)
debug("SBC Sink: Suspend_Cfm");
- a2dp_sep = &sink;
- } else {
+ else
debug("SBC Source: Suspend_Cfm");
- a2dp_sep = &source;
- }
a2dp_sep->suspending = FALSE;
@@ -422,69 +433,63 @@ static void suspend_cfm(struct avdtp *session, struct avdtp_local_sep *sep,
}
static gboolean close_ind(struct avdtp *session, struct avdtp_local_sep *sep,
- struct avdtp_stream *stream, uint8_t *err)
+ struct avdtp_stream *stream, uint8_t *err,
+ void *user_data)
{
- struct a2dp_sep *a2dp_sep;
+ struct a2dp_sep *a2dp_sep = user_data;
- if (sep == sink.sep) {
+ if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)
debug("SBC Sink: Close_Ind");
- a2dp_sep = &sink;
- } else {
+ else
debug("SBC Source: Close_Ind");
- a2dp_sep = &source;
- }
return TRUE;
}
static void close_cfm(struct avdtp *session, struct avdtp_local_sep *sep,
- struct avdtp_stream *stream, struct avdtp_error *err)
+ struct avdtp_stream *stream, struct avdtp_error *err,
+ void *user_data)
{
- struct a2dp_sep *a2dp_sep;
+ struct a2dp_sep *a2dp_sep = user_data;
- if (sep == sink.sep) {
+ if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)
debug("SBC Sink: Close_Cfm");
- a2dp_sep = &sink;
- } else {
+ else
debug("SBC Source: Close_Cfm");
- a2dp_sep = &source;
- }
}
static gboolean abort_ind(struct avdtp *session, struct avdtp_local_sep *sep,
- struct avdtp_stream *stream, uint8_t *err)
+ struct avdtp_stream *stream, uint8_t *err,
+ void *user_data)
{
- struct a2dp_sep *a2dp_sep;
+ struct a2dp_sep *a2dp_sep = user_data;
- if (sep == sink.sep) {
+ if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)
debug("SBC Sink: Abort_Ind");
- a2dp_sep = &sink;
- } else {
+ else
debug("SBC Source: Abort_Ind");
- a2dp_sep = &source;
- }
return TRUE;
}
static void abort_cfm(struct avdtp *session, struct avdtp_local_sep *sep,
- struct avdtp_stream *stream, struct avdtp_error *err)
+ struct avdtp_stream *stream, struct avdtp_error *err,
+ void *user_data)
{
- struct a2dp_sep *a2dp_sep;
+ struct a2dp_sep *a2dp_sep = user_data;
- if (sep == sink.sep) {
+ if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)
debug("SBC Sink: Abort_Cfm");
- a2dp_sep = &sink;
- } else {
+ else
debug("SBC Source: Abort_Cfm");
- a2dp_sep = &source;
- }
}
static gboolean reconf_ind(struct avdtp *session, struct avdtp_local_sep *sep,
- uint8_t *err)
+ uint8_t *err, void *user_data)
{
- if (sep == sink.sep)
+ struct a2dp_sep *a2dp_sep = user_data;
+
+ if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)
debug("SBC Sink: ReConfigure_Ind");
else
debug("SBC Source: ReConfigure_Ind");
@@ -492,9 +497,12 @@ static gboolean reconf_ind(struct avdtp *session, struct avdtp_local_sep *sep,
}
static void reconf_cfm(struct avdtp *session, struct avdtp_local_sep *sep,
- struct avdtp_stream *stream, struct avdtp_error *err)
+ struct avdtp_stream *stream, struct avdtp_error *err,
+ void *user_data)
{
- if (sep == sink.sep)
+ struct a2dp_sep *a2dp_sep = user_data;
+
+ if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)
debug("SBC Sink: ReConfigure_Cfm");
else
debug("SBC Source: ReConfigure_Cfm");
@@ -594,10 +602,62 @@ static int a2dp_sink_record(sdp_buf_t *buf)
return 0;
}
-int a2dp_init(DBusConnection *conn, gboolean enable_sink, gboolean enable_source)
+static struct a2dp_sep *a2dp_add_sep(DBusConnection *conn, uint8_t type)
{
+ struct a2dp_sep *sep;
+ GSList **l;
+ int (*create_record)(sdp_buf_t *buf);
+ uint32_t *record_id;
sdp_buf_t buf;
+ sep = g_new0(struct a2dp_sep, 1);
+
+ sep->sep = avdtp_register_sep(type, AVDTP_MEDIA_TYPE_AUDIO,
+ &ind, &cfm, sep);
+ if (sep->sep == NULL) {
+ g_free(sep);
+ return NULL;
+ }
+
+ sep->type = type;
+
+ if (type == AVDTP_SEP_TYPE_SOURCE) {
+ l = &sources;
+ create_record = a2dp_source_record;
+ record_id = &source_record_id;
+ } else {
+ l = &sinks;
+ create_record = a2dp_sink_record;
+ record_id = &sink_record_id;
+ }
+
+ if (*record_id != 0)
+ goto add;
+
+ if (create_record(&buf) < 0) {
+ error("Unable to allocate new service record");
+ avdtp_unregister_sep(sep->sep);
+ g_free(sep);
+ return NULL;
+ }
+
+ *record_id = add_service_record(conn, &buf);
+ free(buf.data);
+ if (!*record_id) {
+ error("Unable to register A2DP service record");
+ avdtp_unregister_sep(sep->sep);
+ g_free(sep);
+ return NULL;
+ }
+
+add:
+ *l = g_slist_append(*l, sep);
+
+ return sep;
+}
+
+int a2dp_init(DBusConnection *conn, gboolean enable_sink, gboolean enable_source)
+{
if (!enable_sink && !enable_source)
return 0;
@@ -606,68 +666,40 @@ int a2dp_init(DBusConnection *conn, gboolean enable_sink, gboolean enable_source
avdtp_init();
if (enable_sink) {
- source.sep = avdtp_register_sep(AVDTP_SEP_TYPE_SOURCE,
- AVDTP_MEDIA_TYPE_AUDIO,
- &ind, &cfm);
- if (source.sep == NULL)
- return -1;
-
- if (a2dp_source_record(&buf) < 0) {
- error("Unable to allocate new service record");
- return -1;
- }
-
- source.record_id = add_service_record(conn, &buf);
- free(buf.data);
- if (!source.record_id) {
- error("Unable to register A2DP Source service record");
- return -1;
- }
+ a2dp_add_sep(conn, AVDTP_SEP_TYPE_SOURCE);
+ a2dp_add_sep(conn, AVDTP_SEP_TYPE_SOURCE);
}
- if (enable_source) {
- sink.sep = avdtp_register_sep(AVDTP_SEP_TYPE_SINK,
- AVDTP_MEDIA_TYPE_AUDIO,
- &ind, &cfm);
- if (sink.sep == NULL)
- return -1;
-
- if (a2dp_sink_record(&buf) < 0) {
- error("Unable to allocate new service record");
- return -1;
- }
-
- sink.record_id = add_service_record(conn, &buf);
- free(buf.data);
- if (!sink.record_id) {
- error("Unable to register A2DP Sink service record");
- return -1;
- }
- }
+ if (enable_source)
+ a2dp_add_sep(conn, AVDTP_SEP_TYPE_SINK);
return 0;
}
+static void a2dp_unregister_sep(struct a2dp_sep *sep)
+{
+ avdtp_unregister_sep(sep->sep);
+ g_free(sep);
+}
+
void a2dp_exit()
{
- if (sink.sep) {
- avdtp_unregister_sep(sink.sep);
- sink.sep = NULL;
- }
+ g_slist_foreach(sinks, (GFunc) a2dp_unregister_sep, NULL);
+ g_slist_free(sinks);
+ sinks = NULL;
- if (source.sep) {
- avdtp_unregister_sep(source.sep);
- source.sep = NULL;
- }
+ g_slist_foreach(sources, (GFunc) a2dp_unregister_sep, NULL);
+ g_slist_free(sources);
+ sources = NULL;
- if (source.record_id) {
- remove_service_record(connection, source.record_id);
- source.record_id = 0;
+ if (source_record_id) {
+ remove_service_record(connection, source_record_id);
+ source_record_id = 0;
}
- if (sink.record_id) {
- remove_service_record(connection, sink.record_id);
- sink.record_id = 0;
+ if (sink_record_id) {
+ remove_service_record(connection, sink_record_id);
+ sink_record_id = 0;
}
dbus_connection_unref(connection);
@@ -878,15 +910,31 @@ gboolean a2dp_source_cancel_stream(int id)
}
unsigned int a2dp_source_request_stream(struct avdtp *session,
- struct device *dev,
- gboolean start, a2dp_stream_cb_t cb,
- void *user_data)
+ struct device *dev,
+ gboolean start,
+ a2dp_stream_cb_t cb,
+ void *user_data,
+ struct a2dp_sep **ret)
{
struct a2dp_stream_cb *cb_data;
static unsigned int cb_id = 0;
+ GSList *l;
+ struct a2dp_sep *sep = NULL;
- if (source.used_by != NULL && source.used_by != dev) {
- error("a2dp_source_request_stream: SEP is locked");
+ for (l = sources; l != NULL; l = l->next) {
+ struct a2dp_sep *tmp = l->data;
+
+ if (tmp->locked)
+ continue;
+
+ if (tmp->used_by == NULL || tmp->used_by == dev) {
+ sep = tmp;
+ break;
+ }
+ }
+
+ if (!sep) {
+ error("a2dp_source_request_stream: no available SEP found");
return 0;
}
@@ -896,6 +944,10 @@ unsigned int a2dp_source_request_stream(struct avdtp *session,
return 0;
}
+ sep->used_by = dev;
+
+ debug("a2dp_source_request_stream: selected SEP %p", sep);
+
cb_data = g_new(struct a2dp_stream_cb, 1);
cb_data->cb = cb;
cb_data->user_data = user_data;
@@ -914,9 +966,9 @@ unsigned int a2dp_source_request_stream(struct avdtp *session,
setup->dev = dev;
setup->cb = g_slist_append(setup->cb, cb_data);
setup->start = start;
- setup->stream = source.stream;
+ setup->stream = sep->stream;
- switch (avdtp_sep_get_state(source.sep)) {
+ switch (avdtp_sep_get_state(sep->sep)) {
case AVDTP_STATE_IDLE:
if (avdtp_discover(session, discovery_complete, setup) < 0) {
error("avdtp_discover failed");
@@ -928,32 +980,35 @@ unsigned int a2dp_source_request_stream(struct avdtp *session,
g_idle_add((GSourceFunc) finalize_stream_setup, setup);
break;
}
- if (source.starting)
+ if (sep->starting)
break;
- if (avdtp_start(session, source.stream) < 0) {
+ if (avdtp_start(session, sep->stream) < 0) {
error("avdtp_start failed");
goto failed;
}
break;
case AVDTP_STATE_STREAMING:
- if (!start || !source.suspending) {
- if (source.suspend_timer) {
- g_source_remove(source.suspend_timer);
- source.suspend_timer = 0;
+ if (!start || !sep->suspending) {
+ if (sep->suspend_timer) {
+ g_source_remove(sep->suspend_timer);
+ sep->suspend_timer = 0;
}
- if (source.session) {
- avdtp_unref(source.session);
- source.session = NULL;
+ if (sep->session) {
+ avdtp_unref(sep->session);
+ sep->session = NULL;
}
g_idle_add((GSourceFunc) finalize_stream_setup, setup);
return cb_data->id;
}
- source.start_requested = TRUE;
+ sep->start_requested = TRUE;
break;
default:
error("SEP in bad state for requesting a new stream");
goto failed;
}
+
+ if (ret)
+ *ret = sep;
return cb_data->id;
@@ -965,33 +1020,51 @@ failed:
gboolean a2dp_source_lock(struct device *dev, struct avdtp *session)
{
- if (source.used_by)
- return FALSE;
+ GSList *l;
- debug("SBC Source locked");
+ for (l = sources; l != NULL; l = l->next) {
+ struct a2dp_sep *sep = l->data;
- source.used_by = dev;
+ if (sep->locked)
+ continue;
- return TRUE;
+ debug("SBC Source SEP %p locked", sep);
+ sep->locked = TRUE;
+ return TRUE;
+ }
+
+ return FALSE;
}
gboolean a2dp_source_unlock(struct device *dev, struct avdtp *session)
{
avdtp_state_t state;
+ GSList *l;
+ struct a2dp_sep *sep = NULL;
- if (!source.sep)
- return FALSE;
+ for (l = sources; l != NULL; l = l->next) {
+ struct a2dp_sep *tmp = l->data;
+
+ if (!sep->locked)
+ continue;
+
+ if (tmp->sep && tmp->used_by == dev) {
+ sep = tmp;
+ break;
+ }
+ }
- if (source.used_by != dev)
+ if (!sep)
return FALSE;
- state = avdtp_sep_get_state(source.sep);
+ state = avdtp_sep_get_state(sep->sep);
- source.used_by = NULL;
+ sep->locked = FALSE;
+ sep->used_by = NULL;
- debug("SBC Source unlocked");
+ debug("SBC Source SEP %p unlocked", sep);
- if (!source.stream || state == AVDTP_STATE_IDLE)
+ if (!sep->stream || state == AVDTP_STATE_IDLE)
return TRUE;
switch (state) {
@@ -999,8 +1072,8 @@ gboolean a2dp_source_unlock(struct device *dev, struct avdtp *session)
/* Set timer here */
break;
case AVDTP_STATE_STREAMING:
- if (avdtp_suspend(session, source.stream) == 0)
- source.suspending = TRUE;
+ if (avdtp_suspend(session, sep->stream) == 0)
+ sep->suspending = TRUE;
break;
default:
break;
@@ -1012,20 +1085,28 @@ gboolean a2dp_source_unlock(struct device *dev, struct avdtp *session)
gboolean a2dp_source_suspend(struct device *dev, struct avdtp *session)
{
avdtp_state_t state;
+ GSList *l;
+ struct a2dp_sep *sep = NULL;
- if (!source.sep)
- return FALSE;
+ for (l = sources; l != NULL; l = l->next) {
+ struct a2dp_sep *tmp = l->data;
- if (source.used_by != dev)
+ if (tmp->sep && tmp->used_by == dev) {
+ sep = tmp;
+ break;
+ }
+ }
+
+ if (!sep)
return FALSE;
- state = avdtp_sep_get_state(source.sep);
+ state = avdtp_sep_get_state(sep->sep);
- if (!source.stream || state != AVDTP_STATE_STREAMING)
+ if (!sep->stream || state != AVDTP_STATE_STREAMING)
return TRUE;
- if (avdtp_suspend(session, source.stream) == 0) {
- source.suspending = TRUE;
+ if (avdtp_suspend(session, sep->stream) == 0) {
+ sep->suspending = TRUE;
return TRUE;
}
@@ -1035,14 +1116,22 @@ gboolean a2dp_source_suspend(struct device *dev, struct avdtp *session)
gboolean a2dp_source_start_stream(struct device *dev, struct avdtp *session)
{
avdtp_state_t state;
+ GSList *l;
+ struct a2dp_sep *sep = NULL;
- if (!source.sep)
- return FALSE;
+ for (l = sources; l != NULL; l = l->next) {
+ struct a2dp_sep *tmp = l->data;
+
+ if (tmp->sep && tmp->used_by == dev) {
+ sep = tmp;
+ break;
+ }
+ }
- if (source.used_by != dev)
+ if (!sep)
return FALSE;
- state = avdtp_sep_get_state(source.sep);
+ state = avdtp_sep_get_state(sep->sep);
if (state < AVDTP_STATE_OPEN) {
error("a2dp_source_start_stream: no stream open");
@@ -1052,7 +1141,7 @@ gboolean a2dp_source_start_stream(struct device *dev, struct avdtp *session)
if (state == AVDTP_STATE_STREAMING)
return TRUE;
- if (avdtp_start(session, source.stream) < 0)
+ if (avdtp_start(session, sep->stream) < 0)
return FALSE;
return TRUE;
diff --git a/audio/a2dp.h b/audio/a2dp.h
index 6d69189c..0a838b62 100644
--- a/audio/a2dp.h
+++ b/audio/a2dp.h
@@ -58,6 +58,8 @@ struct sbc_codec_cap {
uint8_t max_bitpool;
} __attribute__ ((packed));
+struct a2dp_sep;
+
typedef void (*a2dp_stream_cb_t) (struct avdtp *session, struct device *dev,
struct avdtp_stream *stream,
void *user_data);
@@ -69,7 +71,8 @@ void a2dp_exit(void);
unsigned int a2dp_source_request_stream(struct avdtp *session,
struct device *dev,
gboolean start, a2dp_stream_cb_t cb,
- void *user_data);
+ void *user_data,
+ struct a2dp_sep **sep);
gboolean a2dp_source_cancel_stream(int id);
gboolean a2dp_source_lock(struct device *dev, struct avdtp *session);
diff --git a/audio/avdtp.c b/audio/avdtp.c
index 0b56340f..99a929f4 100644
--- a/audio/avdtp.c
+++ b/audio/avdtp.c
@@ -219,7 +219,7 @@ struct avdtp_local_sep {
GSList *caps;
struct avdtp_sep_ind *ind;
struct avdtp_sep_cfm *cfm;
- void *data;
+ void *user_data;
};
struct stream_callback {
@@ -573,7 +573,7 @@ static void release_stream(struct avdtp_stream *stream, struct avdtp *session)
g_source_remove(stream->io);
if (sep->cfm && sep->cfm->abort)
- sep->cfm->abort(session, sep, stream, NULL);
+ sep->cfm->abort(session, sep, stream, NULL, sep->user_data);
avdtp_sep_set_state(session, sep, AVDTP_STATE_IDLE);
}
@@ -815,7 +815,8 @@ static gboolean avdtp_getcap_cmd(struct avdtp *session,
goto failed;
}
- if (!sep->ind->get_capability(session, sep, &caps, &err))
+ if (!sep->ind->get_capability(session, sep, &caps, &err,
+ sep->user_data))
goto failed;
init_response(&rsp->header, &req->header, TRUE);
@@ -882,7 +883,8 @@ static gboolean avdtp_setconf_cmd(struct avdtp *session,
if (sep->ind && sep->ind->set_configuration) {
if (!sep->ind->set_configuration(session, sep, stream,
stream->caps, &err,
- &category)) {
+ &category,
+ sep->user_data)) {
stream_free(stream);
goto failed;
}
@@ -949,7 +951,8 @@ static gboolean avdtp_open_cmd(struct avdtp *session, struct seid_req *req,
stream = sep->stream;
if (sep->ind && sep->ind->open) {
- if (!sep->ind->open(session, sep, stream, &err))
+ if (!sep->ind->open(session, sep, stream, &err,
+ sep->user_data))
goto failed;
}
@@ -1009,7 +1012,8 @@ static gboolean avdtp_start_cmd(struct avdtp *session, struct start_req *req,
}
if (sep->ind && sep->ind->start) {
- if (!sep->ind->start(session, sep, stream, &err))
+ if (!sep->ind->start(session, sep, stream, &err,
+ sep->user_data))
goto failed;
}
@@ -1057,7 +1061,8 @@ static gboolean avdtp_close_cmd(struct avdtp *session, struct seid_req *req,
stream = sep->stream;
if (sep->ind && sep->ind->close) {
- if (!sep->ind->close(session, sep, stream, &err))
+ if (!sep->ind->close(session, sep, stream, &err,
+ sep->user_data))
goto failed;
}
@@ -1116,7 +1121,8 @@ static gboolean avdtp_suspend_cmd(struct avdtp *session,
}
if (sep->ind && sep->ind->suspend) {
- if (!sep->ind->suspend(session, sep, stream, &err))
+ if (!sep->ind->suspend(session, sep, stream, &err,
+ sep->user_data))
goto failed;
}
@@ -1156,7 +1162,8 @@ static gboolean avdtp_abort_cmd(struct avdtp *session, struct seid_req *req,
}
if (sep->ind && sep->ind->abort) {
- if (!sep->ind->abort(session, sep, sep->stream, &err))
+ if (!sep->ind->abort(session, sep, sep->stream, &err,
+ sep->user_data))
goto failed;
}
@@ -1230,7 +1237,8 @@ static gboolean transport_cb(GIOChannel *chan, GIOCondition cond,
struct avdtp_local_sep *sep = stream->lsep;
if (stream->close_int && sep->cfm && sep->cfm->close)
- sep->cfm->close(stream->session, sep, stream, NULL);
+ sep->cfm->close(stream->session, sep, stream, NULL,
+ sep->user_data);
avdtp_sep_set_state(stream->session, sep, AVDTP_STATE_IDLE);
@@ -1255,7 +1263,7 @@ static void handle_transport_connect(struct avdtp *session, int sock,
stream->mtu = mtu;
if (!stream->open_acp && sep->cfm && sep->cfm->open)
- sep->cfm->open(session, sep, stream, NULL);
+ sep->cfm->open(session, sep, stream, NULL, sep->user_data);
channel = g_io_channel_unix_new(stream->sock);
@@ -1556,36 +1564,41 @@ static gboolean request_timeout(gpointer user_data)
case AVDTP_RECONFIGURE:
error("Reconfigure request timed out");
if (lsep && lsep->cfm && lsep->cfm->reconfigure)
- lsep->cfm->reconfigure(session, lsep, stream, &err);
+ lsep->cfm->reconfigure(session, lsep, stream, &err,
+ lsep->user_data);
break;
case AVDTP_OPEN:
error("Open request timed out");
if (lsep && lsep->cfm && lsep->cfm->open)
- lsep->cfm->open(session, lsep, stream, &err);
+ lsep->cfm->open(session, lsep, stream, &err,
+ lsep->user_data);
break;
case AVDTP_START:
error("Start request timed out");
if (lsep && lsep->cfm && lsep->cfm->start)
- lsep->cfm->start(session, lsep, stream, &err);
+ lsep->cfm->start(session, lsep, stream, &err,
+ lsep->user_data);
break;
case AVDTP_SUSPEND:
error("Suspend request timed out");
if (lsep && lsep->cfm && lsep->cfm->suspend)
- lsep->cfm->suspend(session, lsep, stream, &err);
+ lsep->cfm->suspend(session, lsep, stream, &err,
+ lsep->user_data);
break;
case AVDTP_CLOSE:
error("Close request timed out");
if (lsep && lsep->cfm && lsep->cfm->close)
- lsep->cfm->close(session, lsep, stream, &err);
+ lsep->cfm->close(session, lsep, stream, &err,
+ lsep->user_data);
break;
case AVDTP_SET_CONFIGURATION:
error("SetConfiguration request timed out");
if (lsep && lsep->cfm && lsep->cfm->set_configuration)
- lsep->cfm->set_configuration(session, lsep, stream, &err);
- /* fallthrough on purpose */
+ lsep->cfm->set_configuration(session, lsep, stream,
+ &err, lsep->user_data);
+ goto failed;
case AVDTP_DISCOVER:
error("Discover request timed out");
- if (lsep && lsep->cfm && lsep->cfm->set_configuration)
goto failed;
case AVDTP_GET_CAPABILITIES:
error("GetCapabilities request timed out");
@@ -1756,7 +1769,8 @@ static gboolean avdtp_set_configuration_resp(struct avdtp *session,
struct avdtp_local_sep *sep = stream->lsep;
if (sep->cfm && sep->cfm->set_configuration)
- sep->cfm->set_configuration(session, sep, stream, NULL);
+ sep->cfm->set_configuration(session, sep, stream, NULL,
+ sep->user_data);
avdtp_sep_set_state(session, sep, AVDTP_STATE_CONFIGURED);
@@ -1794,7 +1808,7 @@ static gboolean avdtp_start_resp(struct avdtp *session,
struct avdtp_local_sep *sep = stream->lsep;
if (sep->cfm && sep->cfm->start)
- sep->cfm->start(session, sep, stream, NULL);
+ sep->cfm->start(session, sep, stream, NULL, sep->user_data);
avdtp_sep_set_state(session, sep, AVDTP_STATE_STREAMING);
@@ -1825,7 +1839,7 @@ static gboolean avdtp_suspend_resp(struct avdtp *session,
avdtp_sep_set_state(session, sep, AVDTP_STATE_OPEN);
if (sep->cfm && sep->cfm->suspend)
- sep->cfm->suspend(session, sep, stream, NULL);
+ sep->cfm->suspend(session, sep, stream, NULL, sep->user_data);
return TRUE;
}
@@ -1837,7 +1851,7 @@ static gboolean avdtp_abort_resp(struct avdtp *session,
struct avdtp_local_sep *sep = stream->lsep;
if (sep->cfm && sep->cfm->suspend)
- sep->cfm->suspend(session, sep, stream, NULL);
+ sep->cfm->suspend(session, sep, stream, NULL, sep->user_data);
avdtp_sep_set_state(session, sep, AVDTP_STATE_IDLE);
@@ -1973,7 +1987,8 @@ static gboolean avdtp_parse_rej(struct avdtp *session, struct avdtp_stream *stre
error("OPEN request rejected: %s (%d)",
avdtp_strerror(&err), err.err.error_code);
if (sep && sep->cfm && sep->cfm->open)
- sep->cfm->open(session, sep, stream, &err);
+ sep->cfm->open(session, sep, stream, &err,
+ sep->user_data);
return TRUE;
case AVDTP_SET_CONFIGURATION:
if (!conf_rej_to_err((void *) header, size, &err, &category))
@@ -1981,7 +1996,8 @@ static gboolean avdtp_parse_rej(struct avdtp *session, struct avdtp_stream *stre
error("SET_CONFIGURATION request rejected: %s (%d)",
avdtp_strerror(&err), err.err.error_code);
if (sep && sep->cfm && sep->cfm->set_configuration)
- sep->cfm->set_configuration(session, sep, stream, &err);
+ sep->cfm->set_configuration(session, sep, stream,
+ &err, sep->user_data);
return TRUE;
case AVDTP_RECONFIGURE:
if (!conf_rej_to_err((void *) header, size, &err, &category))
@@ -1989,7 +2005,8 @@ static gboolean avdtp_parse_rej(struct avdtp *session, struct avdtp_stream *stre
error("RECONFIGURE request rejected: %s (%d)",
avdtp_strerror(&err), err.err.error_code);
if (sep && sep->cfm && sep->cfm->reconfigure)
- sep->cfm->reconfigure(session, sep, stream, &err);
+ sep->cfm->reconfigure(session, sep, stream, &err,
+ sep->user_data);
return TRUE;
case AVDTP_START:
if (!stream_rej_to_err((void *) header, size, &err, &acp_seid))
@@ -1997,7 +2014,8 @@ static gboolean avdtp_parse_rej(struct avdtp *session, struct avdtp_stream *stre
error("START request rejected: %s (%d)",
avdtp_strerror(&err), err.err.error_code);
if (sep && sep->cfm && sep->cfm->start)
- sep->cfm->start(session, sep, stream, &err);
+ sep->cfm->start(session, sep, stream, &err,
+ sep->user_data);
return TRUE;
case AVDTP_SUSPEND:
if (!stream_rej_to_err((void *) header, size, &err, &acp_seid))
@@ -2005,7 +2023,8 @@ static gboolean avdtp_parse_rej(struct avdtp *session, struct avdtp_stream *stre
error("SUSPEND request rejected: %s (%d)",
avdtp_strerror(&err), err.err.error_code);
if (sep && sep->cfm && sep->cfm->suspend)
- sep->cfm->suspend(session, sep, stream, &err);
+ sep->cfm->suspend(session, sep, stream, &err,
+ sep->user_data);
return TRUE;
case AVDTP_CLOSE:
if (!stream_rej_to_err((void *) header, size, &err, &acp_seid))
@@ -2013,7 +2032,8 @@ static gboolean avdtp_parse_rej(struct avdtp *session, struct avdtp_stream *stre
error("CLOSE request rejected: %s (%d)",
avdtp_strerror(&err), err.err.error_code);
if (sep && sep->cfm && sep->cfm->close)
- sep->cfm->close(session, sep, stream, &err);
+ sep->cfm->close(session, sep, stream, &err,
+ sep->user_data);
return TRUE;
case AVDTP_ABORT:
if (!stream_rej_to_err((void *) header, size, &err, &acp_seid))
@@ -2021,7 +2041,8 @@ static gboolean avdtp_parse_rej(struct avdtp *session, struct avdtp_stream *stre
error("ABORT request rejected: %s (%d)",
avdtp_strerror(&err), err.err.error_code);
if (sep && sep->cfm && sep->cfm->abort)
- sep->cfm->abort(session, sep, stream, &err);
+ sep->cfm->abort(session, sep, stream, &err,
+ sep->user_data);
return TRUE;
default:
error("Unknown reject response signal id: %u",
@@ -2298,6 +2319,9 @@ int avdtp_set_configuration(struct avdtp *session,
if (!(lsep && rsep))
return -EINVAL;
+ debug("avdtp_set_configuration(%p): int_seid=%u, acp_seid=%u",
+ session, lsep->info.seid, rsep->seid);
+
new_stream = g_new0(struct avdtp_stream, 1);
new_stream->session = session;
@@ -2314,8 +2338,8 @@ int avdtp_set_configuration(struct avdtp *session,
req = g_malloc0(sizeof(struct setconf_req) + caps_len);
init_request(&req->header, AVDTP_SET_CONFIGURATION);
- req->acp_seid = lsep->info.seid;
- req->int_seid = rsep->seid;
+ req->int_seid = lsep->info.seid;
+ req->acp_seid = rsep->seid;
/* Copy the capabilities into the request */
for (l = caps, ptr = req->caps; l != NULL; l = g_slist_next(l)) {
@@ -2457,7 +2481,8 @@ int avdtp_abort(struct avdtp *session, struct avdtp_stream *stream)
struct avdtp_local_sep *avdtp_register_sep(uint8_t type, uint8_t media_type,
struct avdtp_sep_ind *ind,
- struct avdtp_sep_cfm *cfm)
+ struct avdtp_sep_cfm *cfm,
+ void *user_data)
{
struct avdtp_local_sep *sep;
@@ -2472,6 +2497,7 @@ struct avdtp_local_sep *avdtp_register_sep(uint8_t type, uint8_t media_type,
sep->info.media_type = media_type;
sep->ind = ind;
sep->cfm = cfm;
+ sep->user_data = user_data;
local_seps = g_slist_append(local_seps, sep);
diff --git a/audio/avdtp.h b/audio/avdtp.h
index 49907cff..d759be48 100644
--- a/audio/avdtp.h
+++ b/audio/avdtp.h
@@ -97,28 +97,32 @@ struct avdtp_sep_cfm {
void (*set_configuration) (struct avdtp *session,
struct avdtp_local_sep *lsep,
struct avdtp_stream *stream,
- struct avdtp_error *err);
+ struct avdtp_error *err,
+ void *user_data);
void (*get_configuration) (struct avdtp *session,
struct avdtp_local_sep *lsep,
struct avdtp_stream *stream,
- struct avdtp_error *err);
+ struct avdtp_error *err,
+ void *user_data);
void (*open) (struct avdtp *session, struct avdtp_local_sep *lsep,
- struct avdtp_stream *stream, struct avdtp_error *err);
+ struct avdtp_stream *stream, struct avdtp_error *err,
+ void *user_data);
void (*start) (struct avdtp *session, struct avdtp_local_sep *lsep,
- struct avdtp_stream *stream, struct avdtp_error *err);
+ struct avdtp_stream *stream, struct avdtp_error *err,
+ void *user_data);
void (*suspend) (struct avdtp *session, struct avdtp_local_sep *lsep,
struct avdtp_stream *stream,
- struct avdtp_error *err);
+ struct avdtp_error *err, void *user_data);
void (*close) (struct avdtp *session, struct avdtp_local_sep *lsep,
struct avdtp_stream *stream,
- struct avdtp_error *err);
+ struct avdtp_error *err, void *user_data);
void (*abort) (struct avdtp *session, struct avdtp_local_sep *lsep,
struct avdtp_stream *stream,
- struct avdtp_error *err);
+ struct avdtp_error *err, void *user_data);
void (*reconfigure) (struct avdtp *session,
struct avdtp_local_sep *lsep,
struct avdtp_stream *stream,
- struct avdtp_error *err);
+ struct avdtp_error *err, void *user_data);
};
/* Callbacks for indicating when we received a new command. The return value
@@ -126,32 +130,35 @@ struct avdtp_sep_cfm {
struct avdtp_sep_ind {
gboolean (*get_capability) (struct avdtp *session,
struct avdtp_local_sep *sep,
- GSList **caps, uint8_t *err);
+ GSList **caps, uint8_t *err,
+ void *user_data);
gboolean (*set_configuration) (struct avdtp *session,
struct avdtp_local_sep *lsep,
struct avdtp_stream *stream,
GSList *caps, uint8_t *err,
- uint8_t *category);
+ uint8_t *category, void *user_data);
gboolean (*get_configuration) (struct avdtp *session,
struct avdtp_local_sep *lsep,
- uint8_t *err);
+ uint8_t *err, void *user_data);
gboolean (*open) (struct avdtp *session, struct avdtp_local_sep *lsep,
- struct avdtp_stream *stream, uint8_t *err);
+ struct avdtp_stream *stream, uint8_t *err,
+ void *user_data);
gboolean (*start) (struct avdtp *session, struct avdtp_local_sep *lsep,
- struct avdtp_stream *stream,
- uint8_t *err);
+ struct avdtp_stream *stream, uint8_t *err,
+ void *user_data);
gboolean (*suspend) (struct avdtp *session,
struct avdtp_local_sep *sep,
- struct avdtp_stream *stream,
- uint8_t *err);
+ struct avdtp_stream *stream, uint8_t *err,
+ void *user_data);
gboolean (*close) (struct avdtp *session, struct avdtp_local_sep *sep,
- struct avdtp_stream *stream,
- uint8_t *err);
+ struct avdtp_stream *stream, uint8_t *err,
+ void *user_data);
gboolean (*abort) (struct avdtp *session, struct avdtp_local_sep *sep,
- struct avdtp_stream *stream, uint8_t *err);
+ struct avdtp_stream *stream, uint8_t *err,
+ void *user_data);
gboolean (*reconfigure) (struct avdtp *session,
struct avdtp_local_sep *lsep,
- uint8_t *err);
+ uint8_t *err, void *user_data);
};
typedef void (*avdtp_discover_cb_t) (struct avdtp *session, GSList *seps,
@@ -200,7 +207,8 @@ int avdtp_abort(struct avdtp *session, struct avdtp_stream *stream);
struct avdtp_local_sep *avdtp_register_sep(uint8_t type, uint8_t media_type,
struct avdtp_sep_ind *ind,
- struct avdtp_sep_cfm *cfm);
+ struct avdtp_sep_cfm *cfm,
+ void *user_data);
/* Find a matching pair of local and remote SEP ID's */
int avdtp_get_seps(struct avdtp *session, uint8_t type, uint8_t media,
diff --git a/audio/sink.c b/audio/sink.c
index 8141eff5..0dc12eb3 100644
--- a/audio/sink.c
+++ b/audio/sink.c
@@ -149,11 +149,13 @@ static void stream_setup_complete(struct avdtp *session, struct device *dev,
DBusMessage *reply;
reply = dbus_message_new_method_return(pending->msg);
send_message_and_unref(pending->conn, reply);
+ debug("Stream successfully created");
}
else {
err_failed(pending->conn, pending->msg, "Stream setup failed");
avdtp_unref(sink->session);
sink->session = NULL;
+ debug("Stream setup failed");
}
pending_request_free(pending);
@@ -186,7 +188,7 @@ static DBusHandlerResult sink_connect(DBusConnection *conn,
sink->connect = pending;
id = a2dp_source_request_stream(sink->session, dev, FALSE,
- stream_setup_complete, pending);
+ stream_setup_complete, pending, NULL);
if (id == 0) {
pending_request_free(pending);
sink->connect = NULL;
@@ -196,6 +198,8 @@ static DBusHandlerResult sink_connect(DBusConnection *conn,
"Failed to request a stream");
}
+ debug("stream creation in progress");
+
pending->id = id;
return DBUS_HANDLER_RESULT_HANDLED;
diff --git a/audio/unix.c b/audio/unix.c
index 2b9b74f0..a04c5bfb 100644
--- a/audio/unix.c
+++ b/audio/unix.c
@@ -61,10 +61,12 @@ typedef void (*notify_cb_t) (struct device *dev, void *data);
struct a2dp_data {
struct avdtp *session;
struct avdtp_stream *stream;
+ struct a2dp_sep *sep;
};
struct unix_client {
struct device *dev;
+ struct avdtp_local_sep *sep;
service_type_t type;
union {
struct a2dp_data a2dp;
@@ -335,7 +337,7 @@ proceed:
id = a2dp_source_request_stream(a2dp->session, dev,
TRUE, a2dp_setup_complete,
- client);
+ client, &a2dp->sep);
if (id == 0) {
error("request_stream failed");
goto failed;
@@ -414,7 +416,7 @@ static gboolean client_cb(GIOChannel *chan, GIOCondition cond, gpointer data)
}
if (cond & (G_IO_HUP | G_IO_ERR)) {
- debug("Unix client disconnected");
+ debug("Unix client disconnected (fd=%d)", client->sock);
if (!client->dev)
goto failed;
if (client->disconnect)
@@ -488,7 +490,7 @@ static gboolean server_cb(GIOChannel *chan, GIOCondition cond, gpointer data)
return TRUE;
}
- debug("Accepted new client connection on unix socket");
+ debug("Accepted new client connection on unix socket (fd=%d)", cli_sk);
client = g_new0(struct unix_client, 1);
client->sock = cli_sk;