summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohan Hedberg <johan.hedberg@nokia.com>2009-02-02 19:26:23 -0800
committerJohan Hedberg <johan.hedberg@nokia.com>2009-02-02 19:32:14 -0800
commit38ca09be34dbb514fa1194b9a164d1b63a74069b (patch)
tree8a5e533c31a9e1d286801adafd09aefb3cf6a6c1
parent8b3e4cf9d9eaba3cfc5ec5361d136ebb84ab749f (diff)
Set up a stream for incoming connections if the sink doesn't do it
Some headsets when acting as initiators of an AVDTP connection create the AVDTP signaling channel but don't do anything else over it (i.e. they expect us to set up a stream when needed). This patch makes bluetoothd do the same as AudioSink.Connect() if no AVDTP commands have been received from the sink within one second after it has created the AVDTP signaling channel to us. Setting up a stream is also important because the AudioSink Connected property is bound to the existence of a configured stream (which makes sense since an AVDTP connection as such tells us nothing about what sinks and sources there are or even if audio or video will be used).
-rw-r--r--audio/avdtp.c16
-rw-r--r--audio/sink.c79
-rw-r--r--audio/sink.h1
3 files changed, 70 insertions, 26 deletions
diff --git a/audio/avdtp.c b/audio/avdtp.c
index d1cb5ef3..a45b7d28 100644
--- a/audio/avdtp.c
+++ b/audio/avdtp.c
@@ -391,6 +391,9 @@ struct avdtp {
guint dc_timer;
+ /* Attempt stream setup instead of disconnecting */
+ gboolean stream_setup;
+
DBusPendingCall *pending_auth;
};
@@ -597,12 +600,21 @@ static gboolean stream_open_timeout(gpointer user_data)
static gboolean disconnect_timeout(gpointer user_data)
{
struct avdtp *session = user_data;
+ struct audio_device *dev;
+ gboolean stream_setup;
assert(session->ref == 1);
session->dc_timer = 0;
+ stream_setup = session->stream_setup;
+ session->stream_setup = FALSE;
- connection_lost(session, -ETIMEDOUT);
+ dev = manager_get_device(&session->server->src, &session->dst);
+
+ if (dev && dev->sink && stream_setup)
+ sink_setup_stream(dev->sink, session);
+ else
+ connection_lost(session, -ETIMEDOUT);
return FALSE;
}
@@ -611,6 +623,7 @@ static void remove_disconnect_timer(struct avdtp *session)
{
g_source_remove(session->dc_timer);
session->dc_timer = 0;
+ session->stream_setup = FALSE;
}
static void set_disconnect_timer(struct avdtp *session)
@@ -2963,6 +2976,7 @@ static void auth_cb(DBusError *derr, void *user_data)
/* Here we set the disconnect timer so we don't stay in IDLE state
* indefinitely but set auto_dc to FALSE so that when a stream is
* finally opened it doesn't get closed due to a timeout */
+ session->stream_setup = TRUE;
set_disconnect_timer(session);
avdtp_set_auto_disconnect(session, FALSE);
diff --git a/audio/sink.c b/audio/sink.c
index 347e3f69..44faacf0 100644
--- a/audio/sink.c
+++ b/audio/sink.c
@@ -164,13 +164,16 @@ static gboolean stream_setup_retry(gpointer user_data)
struct pending_request *pending = sink->connect;
if (sink->state >= AVDTP_STATE_OPEN) {
- DBusMessage *reply;
debug("Stream successfully created, after XCASE connect:connect");
- reply = dbus_message_new_method_return(pending->msg);
- g_dbus_send_message(pending->conn, reply);
+ if (pending->msg) {
+ DBusMessage *reply;
+ reply = dbus_message_new_method_return(pending->msg);
+ g_dbus_send_message(pending->conn, reply);
+ }
} else {
debug("Stream setup failed, after XCASE connect:connect");
- error_failed(pending->conn, pending->msg, "Stream setup failed");
+ if (pending->msg)
+ error_failed(pending->conn, pending->msg, "Stream setup failed");
}
sink->connect = NULL;
@@ -189,26 +192,33 @@ static void stream_setup_complete(struct avdtp *session, struct a2dp_sep *sep,
pending = sink->connect;
if (stream) {
- DBusMessage *reply;
+ debug("Stream successfully created");
+
+ if (pending->msg) {
+ DBusMessage *reply;
+ reply = dbus_message_new_method_return(pending->msg);
+ g_dbus_send_message(pending->conn, reply);
+ }
+
sink->connect = NULL;
- reply = dbus_message_new_method_return(pending->msg);
- g_dbus_send_message(pending->conn, reply);
pending_request_free(pending);
- debug("Stream successfully created");
+
+ return;
+ }
+
+ avdtp_unref(sink->session);
+ sink->session = NULL;
+ if (avdtp_error_type(err) == AVDTP_ERROR_ERRNO
+ && avdtp_error_posix_errno(err) != EHOSTDOWN) {
+ debug("connect:connect XCASE detected");
+ g_timeout_add_seconds(STREAM_SETUP_RETRY_TIMER,
+ stream_setup_retry, sink);
} else {
- avdtp_unref(sink->session);
- sink->session = NULL;
- if (avdtp_error_type(err) == AVDTP_ERROR_ERRNO
- && avdtp_error_posix_errno(err) != EHOSTDOWN) {
- debug("connect:connect XCASE detected");
- g_timeout_add_seconds(STREAM_SETUP_RETRY_TIMER,
- stream_setup_retry, sink);
- } else {
- sink->connect = NULL;
+ if (pending->msg)
error_failed(pending->conn, pending->msg, "Stream setup failed");
- pending_request_free(pending);
- debug("Stream setup failed : %s", avdtp_strerror(err));
- }
+ sink->connect = NULL;
+ pending_request_free(pending);
+ debug("Stream setup failed : %s", avdtp_strerror(err));
}
}
@@ -395,13 +405,30 @@ static void discovery_complete(struct avdtp *session, GSList *seps, struct avdtp
return;
failed:
- error_failed(pending->conn, pending->msg, "Stream setup failed");
+ if (pending->msg)
+ error_failed(pending->conn, pending->msg, "Stream setup failed");
pending_request_free(pending);
sink->connect = NULL;
avdtp_unref(sink->session);
sink->session = NULL;
}
+gboolean sink_setup_stream(struct sink *sink, struct avdtp *session)
+{
+ if (sink->connect || sink->disconnect)
+ return FALSE;
+
+ if (session && !sink->session)
+ sink->session = avdtp_ref(session);
+
+ if (avdtp_discover(sink->session, discovery_complete, sink) < 0)
+ return FALSE;
+
+ sink->connect = g_new0(struct pending_request, 1);
+
+ return TRUE;
+}
+
static DBusMessage *sink_connect(DBusConnection *conn,
DBusMessage *msg, void *data)
{
@@ -427,12 +454,14 @@ static DBusMessage *sink_connect(DBusConnection *conn,
avdtp_set_auto_disconnect(sink->session, FALSE);
- pending = g_new0(struct pending_request, 1);
+ if (!sink_setup_stream(sink, NULL))
+ return g_dbus_create_error(msg, ERROR_INTERFACE ".Failed",
+ "Failed to create a stream");
+
+ pending = sink->connect;
+
pending->conn = dbus_connection_ref(conn);
pending->msg = dbus_message_ref(msg);
- sink->connect = pending;
-
- avdtp_discover(sink->session, discovery_complete, sink);
debug("stream creation in progress");
diff --git a/audio/sink.h b/audio/sink.h
index a665e560..8bd6bef1 100644
--- a/audio/sink.h
+++ b/audio/sink.h
@@ -30,3 +30,4 @@ gboolean sink_is_active(struct audio_device *dev);
avdtp_state_t sink_get_state(struct audio_device *dev);
gboolean sink_new_stream(struct audio_device *dev, struct avdtp *session,
struct avdtp_stream *stream);
+gboolean sink_setup_stream(struct sink *sink, struct avdtp *session);