summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--audio/a2dp.c102
-rw-r--r--audio/a2dp.h3
-rw-r--r--audio/avdtp.c22
-rw-r--r--audio/avdtp.h17
-rw-r--r--audio/sink.c4
5 files changed, 91 insertions, 57 deletions
diff --git a/audio/a2dp.c b/audio/a2dp.c
index 5dd85a5e..cb43dce2 100644
--- a/audio/a2dp.c
+++ b/audio/a2dp.c
@@ -26,6 +26,7 @@
#endif
#include <stdlib.h>
+#include <errno.h>
#include <dbus/dbus.h>
#include <glib.h>
@@ -112,19 +113,29 @@ static struct device *a2dp_get_dev(struct avdtp *session)
return manager_device_connected(&addr, A2DP_SOURCE_UUID);
}
-static void setup_callback(struct a2dp_stream_cb *cb,
- struct a2dp_stream_setup *s)
+static gboolean finalize_stream_setup(struct a2dp_stream_setup *s, struct avdtp_error *err)
{
- cb->cb(s->session, s->sep, s->stream, cb->user_data);
-}
+ GSList *l;
+
+ for (l = s->cb; l != NULL; l = l->next) {
+ struct a2dp_stream_cb *cb = l->data;
+
+ cb->cb(s->session, s->sep, s->stream, cb->user_data, err);
+ }
-static gboolean finalize_stream_setup(struct a2dp_stream_setup *s)
-{
- g_slist_foreach(s->cb, (GFunc) setup_callback, s);
stream_setup_free(s);
return FALSE;
}
+static gboolean finalize_stream_setup_errno(struct a2dp_stream_setup *s, int err)
+{
+ struct avdtp_error avdtp_err;
+
+ avdtp_error_init(&avdtp_err, AVDTP_ERROR_ERRNO, -err);
+
+ return finalize_stream_setup(s, err ? &avdtp_err : NULL);
+}
+
static struct a2dp_stream_setup *find_setup_by_session(struct avdtp *session)
{
GSList *l;
@@ -324,22 +335,23 @@ static gboolean a2dp_select_capabilities(struct avdtp *session,
return TRUE;
}
-static void discovery_complete(struct avdtp *session, GSList *seps, int err,
+static void discovery_complete(struct avdtp *session, GSList *seps, struct avdtp_error *err,
void *user_data)
{
struct avdtp_local_sep *lsep;
struct avdtp_remote_sep *rsep;
struct a2dp_stream_setup *setup;
GSList *caps = NULL;
+ int posix_err;
setup = find_setup_by_session(session);
if (!setup)
return;
- if (err < 0 || setup->canceled) {
+ if (err || setup->canceled) {
setup->stream = NULL;
- finalize_stream_setup(setup);
+ finalize_stream_setup(setup, err);
return;
}
@@ -348,21 +360,21 @@ static void discovery_complete(struct avdtp *session, GSList *seps, int err,
if (avdtp_get_seps(session, AVDTP_SEP_TYPE_SINK, AVDTP_MEDIA_TYPE_AUDIO,
A2DP_CODEC_SBC, &lsep, &rsep) < 0) {
error("No matching ACP and INT SEPs found");
- finalize_stream_setup(setup);
+ finalize_stream_setup_errno(setup, -EINVAL);
return;
}
if (!a2dp_select_capabilities(session, rsep, &caps)) {
error("Unable to select remote SEP capabilities");
- finalize_stream_setup(setup);
+ finalize_stream_setup_errno(setup, -EINVAL);
return;
}
- err = avdtp_set_configuration(session, rsep, lsep, caps,
+ posix_err = avdtp_set_configuration(session, rsep, lsep, caps,
&setup->stream);
- if (err < 0) {
- error("avdtp_set_configuration: %s", strerror(-err));
- finalize_stream_setup(setup);
+ if (posix_err < 0) {
+ error("avdtp_set_configuration: %s", strerror(-posix_err));
+ finalize_stream_setup_errno(setup, posix_err);
}
}
@@ -490,7 +502,7 @@ static void setconf_cfm(struct avdtp *session, struct avdtp_local_sep *sep,
if (err) {
if (setup)
- finalize_stream_setup(setup);
+ finalize_stream_setup(setup, err);
return;
}
@@ -510,7 +522,7 @@ static void setconf_cfm(struct avdtp *session, struct avdtp_local_sep *sep,
error("Error on avdtp_open %s (%d)", strerror(-ret),
-ret);
setup->stream = NULL;
- finalize_stream_setup(setup);
+ finalize_stream_setup_errno(setup, ret);
}
}
@@ -557,6 +569,7 @@ static void open_cfm(struct avdtp *session, struct avdtp_local_sep *sep,
{
struct a2dp_sep *a2dp_sep = user_data;
struct a2dp_stream_setup *setup;
+ int posix_err;
if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)
debug("SBC Sink: Open_Cfm");
@@ -576,19 +589,22 @@ static void open_cfm(struct avdtp *session, struct avdtp_local_sep *sep,
if (err) {
setup->stream = NULL;
- goto finalize;
+ finalize_stream_setup(setup, err);
+ return;
}
if (setup->start) {
- if (avdtp_start(session, stream) == 0)
+ posix_err = avdtp_start(session, stream);
+ if (posix_err == 0)
return;
error("avdtp_start failed");
- setup->stream = NULL;
+ setup->stream = NULL;
}
+ else
+ posix_err = 0;
-finalize:
- finalize_stream_setup(setup);
+ finalize_stream_setup_errno(setup, -posix_err);
}
static gboolean suspend_timeout(struct a2dp_sep *sep)
@@ -646,10 +662,12 @@ static void start_cfm(struct avdtp *session, struct avdtp_local_sep *sep,
return;
}
- if (err)
+ if (err) {
setup->stream = NULL;
-
- finalize_stream_setup(setup);
+ finalize_stream_setup(setup, err);
+ }
+ else
+ finalize_stream_setup_errno(setup, 0);
}
static gboolean suspend_ind(struct avdtp *session, struct avdtp_local_sep *sep,
@@ -671,6 +689,7 @@ static void suspend_cfm(struct avdtp *session, struct avdtp_local_sep *sep,
{
struct a2dp_sep *a2dp_sep = user_data;
struct a2dp_stream_setup *setup;
+ int posix_err;
if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)
debug("SBC Sink: Suspend_Cfm");
@@ -684,13 +703,14 @@ static void suspend_cfm(struct avdtp *session, struct avdtp_local_sep *sep,
return;
if (err) {
- finalize_stream_setup(setup);
+ finalize_stream_setup(setup, err);
return;
}
if (setup->start) {
- if (avdtp_start(session, stream) < 0)
- finalize_stream_setup(setup);
+ posix_err = avdtp_start(session, stream);
+ if (posix_err < 0)
+ finalize_stream_setup_errno(setup, posix_err);
}
}
@@ -714,6 +734,7 @@ static void close_cfm(struct avdtp *session, struct avdtp_local_sep *sep,
{
struct a2dp_sep *a2dp_sep = user_data;
struct a2dp_stream_setup *setup;
+ int posix_err;
if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)
debug("SBC Sink: Close_Cfm");
@@ -731,19 +752,22 @@ static void close_cfm(struct avdtp *session, struct avdtp_local_sep *sep,
if (err) {
setup->stream = NULL;
- goto finalize;
+ finalize_stream_setup(setup, err);
+ return;
}
if (setup->start) {
- if (avdtp_discover(session, discovery_complete, setup) == 0)
+ posix_err = avdtp_discover(session, discovery_complete, setup);
+ if (posix_err == 0)
return;
error("avdtp_discover failed");
setup->stream = NULL;
}
+ else
+ posix_err = 0;
-finalize:
- finalize_stream_setup(setup);
+ finalize_stream_setup_errno(setup, -posix_err);
}
static gboolean abort_ind(struct avdtp *session, struct avdtp_local_sep *sep,
@@ -792,6 +816,7 @@ static void reconf_cfm(struct avdtp *session, struct avdtp_local_sep *sep,
{
struct a2dp_sep *a2dp_sep = user_data;
struct a2dp_stream_setup *setup;
+ int posix_err;
if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)
debug("SBC Sink: ReConfigure_Cfm");
@@ -811,19 +836,22 @@ static void reconf_cfm(struct avdtp *session, struct avdtp_local_sep *sep,
if (err) {
setup->stream = NULL;
- goto finalize;
+ finalize_stream_setup(setup, err);
+ return;
}
if (setup->start) {
- if (avdtp_start(session, stream) == 0)
+ posix_err = avdtp_start(session, stream);
+ if (posix_err == 0)
return;
error("avdtp_start failed");
setup->stream = NULL;
}
+ else
+ posix_err = 0;
-finalize:
- finalize_stream_setup(setup);
+ finalize_stream_setup_errno(setup, -posix_err);
}
static struct avdtp_sep_cfm cfm = {
diff --git a/audio/a2dp.h b/audio/a2dp.h
index e0d1c2f6..dffdf259 100644
--- a/audio/a2dp.h
+++ b/audio/a2dp.h
@@ -81,7 +81,8 @@ struct a2dp_sep;
typedef void (*a2dp_stream_cb_t) (struct avdtp *session, struct a2dp_sep *sep,
struct avdtp_stream *stream,
- void *user_data);
+ void *user_data,
+ struct avdtp_error *err);
int a2dp_init(DBusConnection *conn, int sources, int sinks);
void a2dp_exit(void);
diff --git a/audio/avdtp.c b/audio/avdtp.c
index 7907763a..ee1bd06d 100644
--- a/audio/avdtp.c
+++ b/audio/avdtp.c
@@ -77,11 +77,6 @@
#define STREAM_TIMEOUT 20000
typedef enum {
- AVDTP_ERROR_ERRNO,
- AVDTP_ERROR_ERROR_CODE
-} avdtp_error_type_t;
-
-typedef enum {
AVDTP_SESSION_STATE_DISCONNECTED,
AVDTP_SESSION_STATE_CONNECTING,
AVDTP_SESSION_STATE_CONNECTED
@@ -362,14 +357,6 @@ struct avdtp {
DBusPendingCall *pending_auth;
};
-struct avdtp_error {
- avdtp_error_type_t type;
- union {
- uint8_t error_code;
- int posix_errno;
- } err;
-};
-
static uint8_t free_seid = 1;
static GSList *local_seps = NULL;
@@ -499,7 +486,7 @@ static void set_disconnect_timer(struct avdtp *session)
disconnect_timeout, session);
}
-static void avdtp_error_init(struct avdtp_error *err, uint8_t type, int id)
+void avdtp_error_init(struct avdtp_error *err, uint8_t type, int id)
{
err->type = type;
switch (type) {
@@ -698,10 +685,15 @@ static void avdtp_sep_set_state(struct avdtp *session,
static void finalize_discovery(struct avdtp *session, int err)
{
+ struct avdtp_error avdtp_err;
+
+ avdtp_error_init(&avdtp_err, AVDTP_ERROR_ERRNO, -err);
+
if (!session->discov_cb)
return;
- session->discov_cb(session, session->seps, err,
+ session->discov_cb(session, session->seps,
+ err ? &avdtp_err : NULL,
session->user_data);
session->discov_cb = NULL;
diff --git a/audio/avdtp.h b/audio/avdtp.h
index e81bf496..6af47e57 100644
--- a/audio/avdtp.h
+++ b/audio/avdtp.h
@@ -21,11 +21,22 @@
*
*/
+typedef enum {
+ AVDTP_ERROR_ERRNO,
+ AVDTP_ERROR_ERROR_CODE
+} avdtp_error_type_t;
+
struct avdtp;
struct avdtp_stream;
struct avdtp_local_sep;
struct avdtp_remote_sep;
-struct avdtp_error;
+struct avdtp_error {
+ avdtp_error_type_t type;
+ union {
+ uint8_t error_code;
+ int posix_errno;
+ } err;
+};
/* SEP capability categories */
#define AVDTP_MEDIA_TRANSPORT 0x01
@@ -177,7 +188,7 @@ struct avdtp_sep_ind {
};
typedef void (*avdtp_discover_cb_t) (struct avdtp *session, GSList *seps,
- int err, void *user_data);
+ struct avdtp_error *err, void *user_data);
struct avdtp *avdtp_get(bdaddr_t *src, bdaddr_t *dst);
@@ -240,7 +251,9 @@ int avdtp_unregister_sep(struct avdtp_local_sep *sep);
avdtp_state_t avdtp_sep_get_state(struct avdtp_local_sep *sep);
+void avdtp_error_init(struct avdtp_error *err, uint8_t type, int id);
const char *avdtp_strerror(struct avdtp_error *err);
+int avdtp_error_code(struct avdtp_error *err);
void avdtp_get_peers(struct avdtp *session, bdaddr_t *src, bdaddr_t *dst);
diff --git a/audio/sink.c b/audio/sink.c
index ea95bcf7..e249af18 100644
--- a/audio/sink.c
+++ b/audio/sink.c
@@ -135,7 +135,7 @@ static void stream_state_changed(struct avdtp_stream *stream,
static void stream_setup_complete(struct avdtp *session, struct a2dp_sep *sep,
struct avdtp_stream *stream,
- void *user_data)
+ void *user_data, struct avdtp_error *err)
{
struct sink *sink = user_data;
struct pending_request *pending;
@@ -153,7 +153,7 @@ static void stream_setup_complete(struct avdtp *session, struct a2dp_sep *sep,
err_failed(pending->conn, pending->msg, "Stream setup failed");
avdtp_unref(sink->session);
sink->session = NULL;
- debug("Stream setup failed");
+ debug("Stream setup failed : %s", avdtp_strerror(err));
}
pending_request_free(pending);