summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohan Hedberg <johan.hedberg@nokia.com>2007-08-28 12:22:29 +0000
committerJohan Hedberg <johan.hedberg@nokia.com>2007-08-28 12:22:29 +0000
commitd1fb0b25a9882016de70f102408f10101b348e57 (patch)
treee9a28f98b63eec38c78e8df150198d63635a50de
parent10abd63aeb3665b2dcade32b6397a485579638ec (diff)
Fix unix client disconnects before headset has been successfully connected
-rw-r--r--audio/a2dp.c2
-rw-r--r--audio/a2dp.h2
-rw-r--r--audio/headset.c42
-rw-r--r--audio/headset.h1
-rw-r--r--audio/unix.c9
5 files changed, 49 insertions, 7 deletions
diff --git a/audio/a2dp.c b/audio/a2dp.c
index fad9bd25..5e08b25b 100644
--- a/audio/a2dp.c
+++ b/audio/a2dp.c
@@ -880,7 +880,7 @@ static void discovery_complete(struct avdtp *session, GSList *seps, int err,
sink_new_stream(setup->dev, session, setup->stream);
}
-gboolean a2dp_source_cancel_stream(int id)
+gboolean a2dp_source_cancel_stream(struct device *dev, unsigned int id)
{
struct a2dp_stream_cb *cb_data;
GSList *l;
diff --git a/audio/a2dp.h b/audio/a2dp.h
index 4804c5f1..7358473e 100644
--- a/audio/a2dp.h
+++ b/audio/a2dp.h
@@ -72,7 +72,7 @@ unsigned int a2dp_source_request_stream(struct avdtp *session,
gboolean start, a2dp_stream_cb_t cb,
void *user_data,
struct a2dp_sep **sep);
-gboolean a2dp_source_cancel_stream(int id);
+gboolean a2dp_source_cancel_stream(struct device *dev, unsigned int id);
gboolean a2dp_source_lock(struct device *dev, struct avdtp *session);
gboolean a2dp_source_unlock(struct device *dev, struct avdtp *session);
diff --git a/audio/headset.c b/audio/headset.c
index 0ccd9d2e..5a626c17 100644
--- a/audio/headset.c
+++ b/audio/headset.c
@@ -68,6 +68,7 @@ static char *str_state[] = {"DISCONNECTED", "CONNECTING", "CONNECTED",
struct pending_connect {
DBusMessage *msg;
+ DBusPendingCall *call;
GIOChannel *io;
guint io_id;
int sock;
@@ -114,6 +115,11 @@ static void pending_connect_free(struct pending_connect *c)
}
if (c->msg)
dbus_message_unref(c->msg);
+ if (c->call) {
+ dbus_pending_call_cancel(c->call);
+ dbus_pending_call_unref(c->call);
+ }
+
g_free(c);
}
@@ -780,7 +786,7 @@ failed:
headset_set_state(device, HEADSET_STATE_DISCONNECTED);
}
-static int get_handles(struct device *device)
+static int get_handles(struct device *device, struct pending_connect *c)
{
DBusPendingCall *pending;
struct headset *hs = device->headset;
@@ -816,7 +822,10 @@ static int get_handles(struct device *device)
}
dbus_pending_call_set_notify(pending, get_handles_reply, device, NULL);
- dbus_pending_call_unref(pending);
+ if (c)
+ c->call = pending;
+ else
+ dbus_pending_call_unref(pending);
dbus_message_unref(msg);
return 0;
@@ -836,7 +845,7 @@ static int rfcomm_connect(struct device *device, struct pending_connect *c)
hs->type = hs->hfp_handle ? SVC_HANDSFREE : SVC_HEADSET;
if (hs->state == HEADSET_STATE_DISCONNECTED)
- return get_handles(device);
+ return get_handles(device, c);
else
return 0;
}
@@ -1399,6 +1408,33 @@ void headset_free(struct device *dev)
dev->headset = NULL;
}
+gboolean headset_cancel_stream(struct device *dev, unsigned int id)
+{
+ struct headset *hs = dev->headset;
+ GSList *l;
+ struct pending_connect *pending = NULL;
+
+ for (l = hs->pending; l != NULL; l = l->next) {
+ struct pending_connect *tmp = l->data;
+
+ if (tmp->id == id) {
+ pending = tmp;
+ break;
+ }
+ }
+
+ if (!pending)
+ return FALSE;
+
+ hs->pending = g_slist_remove(hs->pending, pending);
+ pending_connect_free(pending);
+
+ if (!hs->pending)
+ headset_set_state(dev, HEADSET_STATE_DISCONNECTED);
+
+ return TRUE;
+}
+
unsigned int headset_request_stream(struct device *dev, headset_stream_cb_t cb,
void *user_data)
{
diff --git a/audio/headset.h b/audio/headset.h
index 31486834..3f762815 100644
--- a/audio/headset.h
+++ b/audio/headset.h
@@ -57,6 +57,7 @@ void headset_update(struct device *dev, sdp_record_t *record, uint16_t svc);
unsigned int headset_request_stream(struct device *dev, headset_stream_cb_t cb,
void *user_data);
+gboolean headset_cancel_stream(struct device *dev, unsigned int id);
headset_type_t headset_get_type(struct device *dev);
void headset_set_type(struct device *dev, headset_type_t type);
diff --git a/audio/unix.c b/audio/unix.c
index 1d1a0b6a..71bb480c 100644
--- a/audio/unix.c
+++ b/audio/unix.c
@@ -79,6 +79,7 @@ struct unix_client {
notify_cb_t disconnect;
notify_cb_t suspend;
notify_cb_t play;
+ gboolean (*cancel_stream) (struct device *dev, unsigned int id);
};
static GSList *clients = NULL;
@@ -248,6 +249,8 @@ static void headset_setup_complete(struct device *dev, void *user_data)
return;
}
+ headset_lock(dev, NULL);
+
memset(&cfg, 0, sizeof(cfg));
cfg.fd_opt = CFG_FD_OPT_READWRITE;
@@ -401,10 +404,12 @@ static void create_stream(struct device *dev, struct unix_client *client)
id = a2dp_source_request_stream(a2dp->session, dev,
TRUE, a2dp_setup_complete,
client, &a2dp->sep);
+ client->cancel_stream = a2dp_source_cancel_stream;
break;
case TYPE_HEADSET:
id = headset_request_stream(dev, headset_setup_complete,
client);
+ client->cancel_stream = headset_cancel_stream;
break;
default:
error("No known services for device");
@@ -525,8 +530,8 @@ static gboolean client_cb(GIOChannel *chan, GIOCondition cond, gpointer data)
goto failed;
if (client->disconnect)
client->disconnect(client->dev, cb_data);
- if (client->type == TYPE_SINK && client->req_id > 0)
- a2dp_source_cancel_stream(client->req_id);
+ if (client->cancel_stream && client->req_id > 0)
+ client->cancel_stream(client->dev, client->req_id);
goto failed;
}