Re: [PATCH v4 2/4] Fix asynchronously run request stream cb

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi Frédéric,

2011/8/31 Frédéric Dalleau <frederic.dalleau@xxxxxxxxxxxxxxx>:
> Cancel pending callback if stream is canceled
> Asynchronously run gateway_config_stream cb
> Remove occurences of sco_start_cb
> ---
>  audio/gateway.c |  138 +++++++++++++++++++++++++++++++++++++++---------------
>  audio/gateway.h |    2 +-
>  audio/unix.c    |   13 ++----
>  3 files changed, 104 insertions(+), 49 deletions(-)
>
> diff --git a/audio/gateway.c b/audio/gateway.c
> index 59c91dd..ee33d79 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;
> @@ -180,6 +185,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 +246,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 +254,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 +309,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 +344,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 +489,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 +504,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 +540,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 +557,12 @@ 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, BT_IO_ERROR, BT_IO_ERROR_FAILED, "Closed");
> +       run_connect_cb(device, gerr);
> +       g_error_free(gerr);

We should probably create its own error domain instead of reusing
BT_IO_ERROR, besides that it looks ok.

>
>        return 0;
>  }
> @@ -759,22 +791,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;
>
> +       id = connect_cb_new(gw, cb, user_data);
> +
>        if (!gw->rfcomm) {
> -               gw->sco_start_cb = cb;
> -               gw->sco_start_cb_data = user_data;
>                get_records(dev);
>        } else if (!gw->sco) {
> -               gw->sco_start_cb = cb;
> -               gw->sco_start_cb_data = user_data;
>                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 +819,55 @@ 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;
> +
> +       id = connect_cb_new(gw, cb, user_data);
>
>        if (!gw->rfcomm) {
> -               gw->sco_start_cb = sco_cb;
> -               gw->sco_start_cb_data = user_data;
> -               return get_records(dev);
> +               get_records(dev);
> +       } else if (cb) {
> +               g_idle_add(request_stream_cb, dev);
>        }
>
> -       if (sco_cb)
> -               sco_cb(dev, NULL, user_data);
> -
> -       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 +883,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 +892,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, BT_IO_ERROR, BT_IO_ERROR_FAILED, "GW 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..7012fc5 100644
> --- a/audio/gateway.h
> +++ b/audio/gateway.h
> @@ -52,7 +52,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@xxxxxxxxxxxxxxx
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>



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


[Index of Archives]     [Bluez Devel]     [Linux Wireless Networking]     [Linux Wireless Personal Area Networking]     [Linux ATH6KL]     [Linux USB Devel]     [Linux Media Drivers]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Big List of Linux Books]

  Powered by Linux