Thread (14 messages) flat view 14 messages, 3 authors, 2011-09-27

Re: [PATCH v5 2/6] Fix asynchronously run request stream cb

From: Luiz Augusto von Dentz <luiz.dentz@gmail.com>
Date: 2011-09-21 08:45:33

Hi Frédéric,

2011/9/6 Frédéric Dalleau [off-list ref]:
quoted hunk ↗ jump to hunk
Cancel pending callback if stream is canceled
Asynchronously run gateway_config_stream cb
Remove occurences of sco_start_cb
---
 audio/gateway.c |  148 +++++++++++++++++++++++++++++++++++++++----------------
 audio/gateway.h |   11 ++++-
 audio/unix.c    |   13 ++---
 3 files changed, 120 insertions(+), 52 deletions(-)
diff --git a/audio/gateway.c b/audio/gateway.c
index 59c91dd..4c28721 100644
--- a/audio/gateway.c
+++ b/audio/gateway.c
@@ -60,13 +60,18 @@ struct hf_agent {
       guint watch;    /* Disconnect watch */
 };

+struct connect_cb {
+       unsigned int id;
+       gateway_stream_cb_t cb;
+       void *cb_data;
+};
+
 struct gateway {
       gateway_state_t state;
       GIOChannel *rfcomm;
       GIOChannel *sco;
       GIOChannel *incoming;
-       gateway_stream_cb_t sco_start_cb;
-       void *sco_start_cb_data;
+       GSList *callbacks;
       struct hf_agent *agent;
       DBusMessage *msg;
       int version;
@@ -83,6 +88,11 @@ static GSList *gateway_callbacks = NULL;
 int gateway_close(struct audio_device *device);

+GQuark gateway_error_quark(void)
+{
+       return g_quark_from_static_string("gateway-error-quark");
+}
+
 static const char *state2str(gateway_state_t state)
 {
       switch (state) {
@@ -180,6 +190,41 @@ static gboolean agent_sendfd(struct hf_agent *agent, int fd,
       return TRUE;
 }

+static unsigned int connect_cb_new(struct gateway *gw,
+                                       gateway_stream_cb_t func,
+                                       void *user_data)
+{
+       struct connect_cb *cb;
+       static unsigned int free_cb_id = 1;
+
+       if (!func)
+               return 0;
+
+       cb = g_new(struct connect_cb, 1);
+
+       cb->cb = func;
+       cb->cb_data = user_data;
+       cb->id = free_cb_id++;
+
+       gw->callbacks = g_slist_append(gw->callbacks, cb);
+
+       return cb->id;
+}
+
+static void run_connect_cb(struct audio_device *dev, GError *err)
+{
+       struct gateway *gw = dev->gateway;
+       GSList *l;
+
+       for (l = gw->callbacks; l != NULL; l = l->next) {
+               struct connect_cb *cb = l->data;
+               cb->cb(dev, err, cb->cb_data);
+       }
+
+       g_slist_free_full(gw->callbacks, g_free);
+       gw->callbacks = NULL;
+}
+
 static gboolean sco_io_cb(GIOChannel *chan, GIOCondition cond,
                       struct audio_device *dev)
 {
@@ -206,9 +251,6 @@ static void sco_connect_cb(GIOChannel *chan, GError *err, gpointer user_data)
       gw->sco = g_io_channel_ref(chan);

-       if (gw->sco_start_cb)
-               gw->sco_start_cb(dev, err, gw->sco_start_cb_data);
-
       if (err) {
               error("sco_connect_cb(): %s", err->message);
               gateway_close(dev);
@@ -217,6 +259,8 @@ static void sco_connect_cb(GIOChannel *chan, GError *err, gpointer user_data)
       g_io_add_watch(gw->sco, G_IO_ERR | G_IO_HUP | G_IO_NVAL,
                               (GIOFunc) sco_io_cb, dev);
+
+       run_connect_cb(dev, NULL);
 }

 static gboolean rfcomm_disconnect_cb(GIOChannel *chan, GIOCondition cond,
@@ -270,8 +314,6 @@ static void rfcomm_connect_cb(GIOChannel *chan, GError *err,
       if (err) {
               error("connect(): %s", err->message);
-               if (gw->sco_start_cb)
-                       gw->sco_start_cb(dev, err, gw->sco_start_cb_data);
               goto fail;
       }
@@ -307,7 +349,7 @@ fail:
               g_dbus_send_message(dev->conn, reply);
       }

-       change_state(dev, GATEWAY_STATE_DISCONNECTED);
+       gateway_close(dev);
 }

 static int get_remote_profile_version(sdp_record_t *rec)
@@ -452,7 +494,6 @@ static void get_record_cb(sdp_list_t *recs, int err, gpointer user_data)
                               BT_IO_OPT_INVALID);
       if (!io) {
               error("Unable to connect: %s", gerr->message);
-               gateway_close(dev);
               goto fail;
       }
@@ -468,16 +509,10 @@ fail:
               g_dbus_send_message(dev->conn, reply);
       }

-       change_state(dev, GATEWAY_STATE_DISCONNECTED);
-
-       if (!gerr)
-               g_set_error(&gerr, BT_IO_ERROR, BT_IO_ERROR_FAILED,
-                               "connect: %s (%d)", strerror(-err), -err);
-
-       if (gw->sco_start_cb)
-               gw->sco_start_cb(dev, gerr, gw->sco_start_cb_data);
+       gateway_close(dev);

-       g_error_free(gerr);
+       if (gerr)
+               g_error_free(gerr);
 }

 static int get_records(struct audio_device *device)
@@ -510,6 +545,7 @@ static DBusMessage *ag_connect(DBusConnection *conn, DBusMessage *msg,
 int gateway_close(struct audio_device *device)
 {
+       GError *gerr = NULL;
       struct gateway *gw = device->gateway;
       int sock;
@@ -526,11 +562,13 @@ int gateway_close(struct audio_device *device)
               g_io_channel_shutdown(gw->sco, TRUE, NULL);
               g_io_channel_unref(gw->sco);
               gw->sco = NULL;
-               gw->sco_start_cb = NULL;
-               gw->sco_start_cb_data = NULL;
       }

       change_state(device, GATEWAY_STATE_DISCONNECTED);
+       g_set_error(&gerr, GATEWAY_ERROR,
+                       GATEWAY_ERROR_DISCONNECTED, "Disconnected");
+       run_connect_cb(device, gerr);
+       g_error_free(gerr);

       return 0;
 }
@@ -759,22 +797,27 @@ void gateway_start_service(struct audio_device *dev)
       }
 }

+static gboolean request_stream_cb(gpointer data)
+{
+       run_connect_cb(data, NULL);
+       return FALSE;
+}
+
 /* These are functions to be called from unix.c for audio system
 * ifaces (alsa, gstreamer, etc.) */
-gboolean gateway_request_stream(struct audio_device *dev,
+unsigned int gateway_request_stream(struct audio_device *dev,
                               gateway_stream_cb_t cb, void *user_data)
 {
       struct gateway *gw = dev->gateway;
+       unsigned int id;
       GError *err = NULL;
       GIOChannel *io;

-       if (!gw->rfcomm) {
-               gw->sco_start_cb = cb;
-               gw->sco_start_cb_data = user_data;
+       id = connect_cb_new(gw, cb, user_data);
+
+       if (!gw->rfcomm)
               get_records(dev);
-       } else if (!gw->sco) {
-               gw->sco_start_cb = cb;
-               gw->sco_start_cb_data = user_data;
+       else if (!gw->sco) {
               io = bt_io_connect(BT_IO_SCO, sco_connect_cb, dev, NULL, &err,
                               BT_IO_OPT_SOURCE_BDADDR, &dev->src,
                               BT_IO_OPT_DEST_BDADDR, &dev->dst,
@@ -782,34 +825,53 @@ gboolean gateway_request_stream(struct audio_device *dev,
               if (!io) {
                       error("%s", err->message);
                       g_error_free(err);
-                       return FALSE;
+                       return 0;
               }
-       } else if (cb)
-               cb(dev, err, user_data);
+       } else
+               g_idle_add(request_stream_cb, dev);

-       return TRUE;
+       return id;
 }

-int gateway_config_stream(struct audio_device *dev, gateway_stream_cb_t sco_cb,
+int gateway_config_stream(struct audio_device *dev, gateway_stream_cb_t cb,
                               void *user_data)
 {
       struct gateway *gw = dev->gateway;
+       unsigned int id;

-       if (!gw->rfcomm) {
-               gw->sco_start_cb = sco_cb;
-               gw->sco_start_cb_data = user_data;
-               return get_records(dev);
-       }
+       id = connect_cb_new(gw, cb, user_data);

-       if (sco_cb)
-               sco_cb(dev, NULL, user_data);
+       if (!gw->rfcomm)
+               get_records(dev);
+       else if (cb)
+               g_idle_add(request_stream_cb, dev);

-       return 0;
+       return id;
 }

 gboolean gateway_cancel_stream(struct audio_device *dev, unsigned int id)
 {
+       struct gateway *gw = dev->gateway;
+       GSList *l;
+       struct connect_cb *cb = NULL;
+
+       for (l = gw->callbacks; l != NULL; l = l->next) {
+               struct connect_cb *tmp = l->data;
+
+               if (tmp->id == id) {
+                       cb = tmp;
+                       break;
+               }
+       }
+
+       if (!cb)
+               return FALSE;
+
+       gw->callbacks = g_slist_remove(gw->callbacks, cb);
+       g_free(cb);
+
       gateway_suspend_stream(dev);
+
       return TRUE;
 }
@@ -825,6 +887,7 @@ int gateway_get_sco_fd(struct audio_device *dev)
 void gateway_suspend_stream(struct audio_device *dev)
 {
+       GError *gerr = NULL;
       struct gateway *gw = dev->gateway;

       if (!gw || !gw->sco)
@@ -833,8 +896,9 @@ void gateway_suspend_stream(struct audio_device *dev)
       g_io_channel_shutdown(gw->sco, TRUE, NULL);
       g_io_channel_unref(gw->sco);
       gw->sco = NULL;
-       gw->sco_start_cb = NULL;
-       gw->sco_start_cb_data = NULL;
+       g_set_error(&gerr, GATEWAY_ERROR, GATEWAY_ERROR_SUSPENDED, "Suspended");
+       run_connect_cb(dev, gerr);
+       g_error_free(gerr);
       change_state(dev, GATEWAY_STATE_CONNECTED);
 }
diff --git a/audio/gateway.h b/audio/gateway.h
index 2dca32a..a8ed2f2 100644
--- a/audio/gateway.h
+++ b/audio/gateway.h
@@ -38,6 +38,15 @@ typedef enum {
       GATEWAY_LOCK_WRITE = 1 << 1,
 } gateway_lock_t;

+typedef enum {
+       GATEWAY_ERROR_DISCONNECTED,
+       GATEWAY_ERROR_SUSPENDED,
+} gateway_error_t;
+
+#define GATEWAY_ERROR gateway_error_quark()
+
+GQuark gateway_error_quark(void);
+
 typedef void (*gateway_state_cb) (struct audio_device *dev,
                                       gateway_state_t old_state,
                                       gateway_state_t new_state,
@@ -52,7 +61,7 @@ gboolean gateway_is_connected(struct audio_device *dev);
 int gateway_connect_rfcomm(struct audio_device *dev, GIOChannel *io);
 int gateway_connect_sco(struct audio_device *dev, GIOChannel *chan);
 void gateway_start_service(struct audio_device *device);
-gboolean gateway_request_stream(struct audio_device *dev,
+unsigned int gateway_request_stream(struct audio_device *dev,
                       gateway_stream_cb_t cb, void *user_data);
 int gateway_config_stream(struct audio_device *dev, gateway_stream_cb_t cb,
                       void *user_data);
diff --git a/audio/unix.c b/audio/unix.c
index 1e0ab30..c2d6d4a 100644
--- a/audio/unix.c
+++ b/audio/unix.c
@@ -1045,11 +1045,8 @@ static void start_config(struct audio_device *dev, struct unix_client *client)
               client->cancel = headset_cancel_stream;
               break;
       case TYPE_GATEWAY:
-               if (gateway_config_stream(dev, gateway_setup_complete, client) >= 0) {
-                       client->cancel = gateway_cancel_stream;
-                       id = 1;
-               } else
-                       id = 0;
+               id = gateway_config_stream(dev, gateway_setup_complete, client);
+               client->cancel = gateway_cancel_stream;
               break;

       default:
@@ -1118,10 +1115,8 @@ static void start_resume(struct audio_device *dev, struct unix_client *client)
               break;

       case TYPE_GATEWAY:
-               if (gateway_request_stream(dev, gateway_resume_complete, client))
-                       id = 1;
-               else
-                       id = 0;
+               id = gateway_request_stream(dev, gateway_resume_complete,
+                                               client);
               client->cancel = gateway_cancel_stream;
               break;

--
1.7.1

--
To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Ack

-- 
Luiz Augusto von Dentz
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help