diff options
author | Johan Hedberg <johan.hedberg@nokia.com> | 2009-02-02 19:26:23 -0800 |
---|---|---|
committer | Johan Hedberg <johan.hedberg@nokia.com> | 2009-02-02 19:32:14 -0800 |
commit | 38ca09be34dbb514fa1194b9a164d1b63a74069b (patch) | |
tree | 8a5e533c31a9e1d286801adafd09aefb3cf6a6c1 | |
parent | 8b3e4cf9d9eaba3cfc5ec5361d136ebb84ab749f (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.c | 16 | ||||
-rw-r--r-- | audio/sink.c | 79 | ||||
-rw-r--r-- | audio/sink.h | 1 |
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); |