From 0a60cccf6d617e71d7fc6be218ddf45046ee0ce9 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 7 Jan 2016 12:15:57 +0100 Subject: [PATCH] introspect: improve introspection API Add GAsyncReadyCallback to the introspection API. This makes it possible to report errors in the future. Don't pass NULL in the callback anymore now that we have the Ready callback. We also don't need to have a return value from the callback because now we can cancel any iteration by using the GCancelable. Make pinos_context_info_finish() to get the final result/error of introspection. Update tools for new API --- src/client/introspect.c | 90 ++++++++++++++++++++++++++++---- src/client/introspect.h | 74 ++++++++++++++++++++++++-- src/gst/gstpinosdeviceprovider.c | 48 +++++++++-------- src/tools/pinos-monitor.c | 43 +++++++-------- 4 files changed, 193 insertions(+), 62 deletions(-) diff --git a/src/client/introspect.c b/src/client/introspect.c index 16b115ed4..da6093efc 100644 --- a/src/client/introspect.c +++ b/src/client/introspect.c @@ -27,6 +27,28 @@ #include "client/private.h" +/** + * pinos_context_info_finish: + * @object: a #GObject + * @res: a #GAsyncResult + * @error: location to place an error + * + * Call this function in the introspection GAsyncReadyCallback function + * to get the final result of the operation. + * + * Returns: %TRUE if the lookup was successful. If %FALSE is returned, @error + * will contain more details. + */ +gboolean +pinos_context_info_finish (GObject *object, + GAsyncResult *res, + GError **error) +{ + g_return_val_if_fail (g_task_is_valid (res, object), FALSE); + + return g_task_propagate_boolean (G_TASK (res), error); +} + #define SET_STRING(name, field, idx) \ G_STMT_START { \ GVariant *variant; \ @@ -123,17 +145,23 @@ pinos_context_get_daemon_info (PinosContext *context, PinosDaemonInfoFlags flags, PinosDaemonInfoCallback cb, GCancellable *cancellable, + GAsyncReadyCallback callback, gpointer user_data) { PinosDaemonInfo info; + GTask *task; g_return_if_fail (PINOS_IS_CONTEXT (context)); g_return_if_fail (cb != NULL); + task = g_task_new (context, cancellable, callback, user_data); + daemon_fill_info (&info, context->priv->daemon); cb (context, &info, user_data); daemon_clear_info (&info); - cb (context, NULL, user_data); + + g_task_return_boolean (task, TRUE); + g_object_unref (task); } static void @@ -176,14 +204,20 @@ pinos_context_list_client_info (PinosContext *context, PinosClientInfoFlags flags, PinosClientInfoCallback cb, GCancellable *cancellable, + GAsyncReadyCallback callback, gpointer user_data) { + PinosContextPrivate *priv; GList *walk; - PinosContextPrivate *priv = context->priv; + GTask *task; g_return_if_fail (PINOS_IS_CONTEXT (context)); g_return_if_fail (cb != NULL); + task = g_task_new (context, cancellable, callback, user_data); + + priv = context->priv; + for (walk = priv->clients; walk; walk = g_list_next (walk)) { GDBusProxy *proxy = walk->data; PinosClientInfo info; @@ -192,7 +226,9 @@ pinos_context_list_client_info (PinosContext *context, cb (context, &info, user_data); client_clear_info (&info); } - cb (context, NULL, user_data); + + g_task_return_boolean (task, TRUE); + g_object_unref (task); } /** @@ -212,21 +248,27 @@ pinos_context_get_client_info_by_id (PinosContext *context, PinosClientInfoFlags flags, PinosClientInfoCallback cb, GCancellable *cancellable, + GAsyncReadyCallback callback, gpointer user_data) { PinosClientInfo info; GDBusProxy *proxy; + GTask *task; g_return_if_fail (PINOS_IS_CONTEXT (context)); g_return_if_fail (id != NULL); g_return_if_fail (cb != NULL); + task = g_task_new (context, cancellable, callback, user_data); + proxy = G_DBUS_PROXY (id); client_fill_info (&info, proxy); cb (context, &info, user_data); client_clear_info (&info); - cb (context, NULL, user_data); + + g_task_return_boolean (task, TRUE); + g_object_unref (task); } /** @@ -291,14 +333,20 @@ pinos_context_list_source_info (PinosContext *context, PinosSourceInfoFlags flags, PinosSourceInfoCallback cb, GCancellable *cancellable, + GAsyncReadyCallback callback, gpointer user_data) { + PinosContextPrivate *priv; GList *walk; - PinosContextPrivate *priv = context->priv; + GTask *task; g_return_if_fail (PINOS_IS_CONTEXT (context)); g_return_if_fail (cb != NULL); + task = g_task_new (context, cancellable, callback, user_data); + + priv = context->priv; + for (walk = priv->sources; walk; walk = g_list_next (walk)) { GDBusProxy *proxy = walk->data; PinosSourceInfo info; @@ -307,7 +355,9 @@ pinos_context_list_source_info (PinosContext *context, cb (context, &info, user_data); source_clear_info (&info); } - cb (context, NULL, user_data); + + g_task_return_boolean (task, TRUE); + g_object_unref (task); } /** @@ -327,21 +377,27 @@ pinos_context_get_source_info_by_id (PinosContext *context, PinosSourceInfoFlags flags, PinosSourceInfoCallback cb, GCancellable *cancellable, + GAsyncReadyCallback callback, gpointer user_data) { PinosSourceInfo info; GDBusProxy *proxy; + GTask *task; g_return_if_fail (PINOS_IS_CONTEXT (context)); g_return_if_fail (id != NULL); g_return_if_fail (cb != NULL); + task = g_task_new (context, cancellable, callback, user_data); + proxy = G_DBUS_PROXY (id); source_fill_info (&info, proxy); cb (context, &info, user_data); source_clear_info (&info); - cb (context, NULL, user_data); + + g_task_return_boolean (task, TRUE); + g_object_unref (task); } /** @@ -408,14 +464,20 @@ pinos_context_list_source_output_info (PinosContext *context, PinosSourceOutputInfoFlags flags, PinosSourceOutputInfoCallback cb, GCancellable *cancellable, + GAsyncReadyCallback callback, gpointer user_data) { + PinosContextPrivate *priv; GList *walk; - PinosContextPrivate *priv = context->priv; + GTask *task; g_return_if_fail (PINOS_IS_CONTEXT (context)); g_return_if_fail (cb != NULL); + task = g_task_new (context, cancellable, callback, user_data); + + priv = context->priv; + for (walk = priv->source_outputs; walk; walk = g_list_next (walk)) { GDBusProxy *proxy = walk->data; PinosSourceOutputInfo info; @@ -424,7 +486,9 @@ pinos_context_list_source_output_info (PinosContext *context, cb (context, &info, user_data); source_output_clear_info (&info); } - cb (context, NULL, user_data); + + g_task_return_boolean (task, TRUE); + g_object_unref (task); } /** @@ -444,20 +508,26 @@ pinos_context_get_source_output_info_by_id (PinosContext *context, PinosSourceOutputInfoFlags flags, PinosSourceOutputInfoCallback cb, GCancellable *cancellable, + GAsyncReadyCallback callback, gpointer user_data) { PinosSourceOutputInfo info; GDBusProxy *proxy; + GTask *task; g_return_if_fail (PINOS_IS_CONTEXT (context)); g_return_if_fail (id != NULL); g_return_if_fail (cb != NULL); + task = g_task_new (context, cancellable, callback, user_data); + proxy = G_DBUS_PROXY (id); source_output_fill_info (&info, proxy); cb (context, &info, user_data); source_output_clear_info (&info); - cb (context, NULL, user_data); + + g_task_return_boolean (task, TRUE); + g_object_unref (task); } diff --git a/src/client/introspect.h b/src/client/introspect.h index c9c630f80..7f17901e2 100644 --- a/src/client/introspect.h +++ b/src/client/introspect.h @@ -28,6 +28,10 @@ G_BEGIN_DECLS +gboolean pinos_context_info_finish (GObject *object, + GAsyncResult *res, + GError **error); + /** * PinosDaemonInfo: * @id: generic id of the daemon @@ -55,16 +59,32 @@ typedef struct { PinosProperties *properties; } PinosDaemonInfo; +/**PinosDaemonInfoFlags: + * @PINOS_DAEMON_INFO_FLAGS_NONE: no flags + * + * Extra flags that can be passed to pinos_context_get_daemon_info() + */ typedef enum { PINOS_DAEMON_INFO_FLAGS_NONE = 0, } PinosDaemonInfoFlags; -typedef gboolean (*PinosDaemonInfoCallback) (PinosContext *c, const PinosDaemonInfo *info, gpointer userdata); +/** + * PinosDaemonInfoCallback: + * @c: a #PinosContext + * @info: a #PinosDaemonInfo + * @user_data: user data + * + * Callback with information about the Pinos daemon in @info. + */ +typedef void (*PinosDaemonInfoCallback) (PinosContext *c, + const PinosDaemonInfo *info, + gpointer user_data); void pinos_context_get_daemon_info (PinosContext *context, PinosDaemonInfoFlags flags, PinosDaemonInfoCallback cb, GCancellable *cancellable, + GAsyncReadyCallback callback, gpointer user_data); /** @@ -86,22 +106,41 @@ typedef struct { PinosProperties *properties; } PinosClientInfo; +/** + * PinosClientInfoFlags: + * @PINOS_CLIENT_INFO_FLAGS_NONE: no flags + * + * Extra flags for pinos_context_list_client_info() and + * pinos_context_get_client_info_by_id(). + */ typedef enum { PINOS_CLIENT_INFO_FLAGS_NONE = 0, } PinosClientInfoFlags; -typedef gboolean (*PinosClientInfoCallback) (PinosContext *c, const PinosClientInfo *info, gpointer userdata); +/** + * PinosClientInfoCallback: + * @c: a #PinosContext + * @info: a #PinosClientInfo + * @user_data: user data + * + * Callback with information about the Pinos client in @info. + */ +typedef void (*PinosClientInfoCallback) (PinosContext *c, + const PinosClientInfo *info, + gpointer user_data); void pinos_context_list_client_info (PinosContext *context, PinosClientInfoFlags flags, PinosClientInfoCallback cb, GCancellable *cancellable, + GAsyncReadyCallback callback, gpointer user_data); void pinos_context_get_client_info_by_id (PinosContext *context, gpointer id, PinosClientInfoFlags flags, PinosClientInfoCallback cb, GCancellable *cancellable, + GAsyncReadyCallback callback, gpointer user_data); /** @@ -162,18 +201,30 @@ typedef enum { PINOS_SOURCE_INFO_FLAGS_FORMATS = (1 << 0) } PinosSourceInfoFlags; -typedef gboolean (*PinosSourceInfoCallback) (PinosContext *c, const PinosSourceInfo *info, gpointer userdata); +/** + * PinosSourceInfoCallback: + * @c: a #PinosContext + * @info: a #PinosSourceInfo + * @user_data: user data + * + * Callback with information about the Pinos source in @info. + */ +typedef void (*PinosSourceInfoCallback) (PinosContext *c, + const PinosSourceInfo *info, + gpointer user_data); void pinos_context_list_source_info (PinosContext *context, PinosSourceInfoFlags flags, PinosSourceInfoCallback cb, GCancellable *cancellable, + GAsyncReadyCallback callback, gpointer user_data); void pinos_context_get_source_info_by_id (PinosContext *context, gpointer id, PinosSourceInfoFlags flags, PinosSourceInfoCallback cb, GCancellable *cancellable, + GAsyncReadyCallback callback, gpointer user_data); /** @@ -225,24 +276,37 @@ typedef struct { * PinosSourceOutputInfoFlags: * @PINOS_SOURCE_OUTPUT_INFO_FLAGS_NONE: no flags * - * Extra flags to pass to pinos_context_get_source_output_info_list. + * Extra flags to pass to pinos_context_list_source_output_info() and + * pinos_context_get_source_output_info_by_id(). */ typedef enum { PINOS_SOURCE_OUTPUT_INFO_FLAGS_NONE = 0, } PinosSourceOutputInfoFlags; -typedef gboolean (*PinosSourceOutputInfoCallback) (PinosContext *c, const PinosSourceOutputInfo *info, gpointer userdata); +/** + * PinosSourceOutputInfoCallback: + * @c: a #PinosContext + * @info: a #PinosSourceOutputInfo + * @user_data: user data + * + * Callback with information about the Pinos source output in @info. + */ +typedef void (*PinosSourceOutputInfoCallback) (PinosContext *c, + const PinosSourceOutputInfo *info, + gpointer user_data); void pinos_context_list_source_output_info (PinosContext *context, PinosSourceOutputInfoFlags flags, PinosSourceOutputInfoCallback cb, GCancellable *cancellable, + GAsyncReadyCallback callback, gpointer user_data); void pinos_context_get_source_output_info_by_id (PinosContext *context, gpointer id, PinosSourceOutputInfoFlags flags, PinosSourceOutputInfoCallback cb, GCancellable *cancellable, + GAsyncReadyCallback callback, gpointer user_data); G_END_DECLS diff --git a/src/gst/gstpinosdeviceprovider.c b/src/gst/gstpinosdeviceprovider.c index 0c3114cf9..3d6d00a27 100644 --- a/src/gst/gstpinosdeviceprovider.c +++ b/src/gst/gstpinosdeviceprovider.c @@ -229,7 +229,7 @@ new_source (const PinosSourceInfo *info) props); } -static gboolean +static void get_source_info_cb (PinosContext *context, const PinosSourceInfo *info, gpointer user_data) @@ -237,15 +237,9 @@ get_source_info_cb (PinosContext *context, GstPinosDeviceProvider *self = user_data; GstDevice *dev; - if (info == NULL) - return FALSE; - dev = new_source (info); - if (dev) gst_device_provider_device_add (GST_DEVICE_PROVIDER (self), dev); - - return TRUE; } static GstPinosDevice * @@ -291,6 +285,7 @@ context_subscribe_cb (PinosContext *context, PINOS_SOURCE_INFO_FLAGS_FORMATS, get_source_info_cb, NULL, + NULL, self); } else if (type == PINOS_SUBSCRIPTION_EVENT_REMOVE) { if (flags == PINOS_SUBSCRIPTION_FLAG_SOURCE && dev != NULL) { @@ -307,45 +302,49 @@ typedef struct { GList **devices; } InfoData; -static gboolean +static void list_source_info_cb (PinosContext *c, const PinosSourceInfo *info, gpointer user_data) { InfoData *data = user_data; - if (info == NULL) { - data->end = TRUE; - return FALSE; - } - *data->devices = g_list_prepend (*data->devices, gst_object_ref_sink (new_source (info))); - - return TRUE; } -static gboolean -get_daemon_info_cb (PinosContext *c, const PinosDaemonInfo *info, gpointer userdata) +static void +list_source_info_end_cb (GObject *source_object, + GAsyncResult *res, + gpointer user_data) { - GstDeviceProvider *provider = userdata; - const gchar *value; + InfoData *data = user_data; + GError *error = NULL; - if (info == NULL) - return TRUE; + if (!pinos_context_info_finish (source_object, res, &error)) { + GST_WARNING_OBJECT (source_object, "failed to list sources: %s", error->message); + g_clear_error (&error); + } + data->end = TRUE; +} + +static void +get_daemon_info_cb (PinosContext *c, const PinosDaemonInfo *info, gpointer user_data) +{ + GstDeviceProvider *provider = user_data; + const gchar *value; value = pinos_properties_get (info->properties, "gstreamer.deviceproviders"); if (value) { gchar **providers = g_strsplit (value, ",", -1); gint i; - GST_DEBUG_OBJECT (provider, "have hidden providers: %s\n", value); + GST_DEBUG_OBJECT (provider, "have hidden providers: %s", value); for (i = 0; providers[i]; i++) { gst_device_provider_hide_provider (provider, providers[i]); } g_strfreev (providers); } - return TRUE; } static GList * @@ -391,6 +390,7 @@ gst_pinos_device_provider_probe (GstDeviceProvider * provider) PINOS_DAEMON_INFO_FLAGS_NONE, get_daemon_info_cb, NULL, + NULL, self); @@ -400,6 +400,7 @@ gst_pinos_device_provider_probe (GstDeviceProvider * provider) PINOS_SOURCE_INFO_FLAGS_FORMATS, list_source_info_cb, NULL, + list_source_info_end_cb, &data); for (;;) { if (pinos_context_get_state (c) <= 0) @@ -520,6 +521,7 @@ gst_pinos_device_provider_start (GstDeviceProvider * provider) PINOS_DAEMON_INFO_FLAGS_NONE, get_daemon_info_cb, NULL, + NULL, self); pinos_main_loop_unlock (self->loop); diff --git a/src/tools/pinos-monitor.c b/src/tools/pinos-monitor.c index 709823743..212e78bb3 100644 --- a/src/tools/pinos-monitor.c +++ b/src/tools/pinos-monitor.c @@ -80,12 +80,20 @@ print_properties (PinosProperties *props) } } -static gboolean +static void +info_ready (GObject *o, GAsyncResult *res, gpointer user_data) +{ + GError *error = NULL; + + if (!pinos_context_info_finish (o, res, &error)) { + g_printerr ("introspection failure: %s\n", error->message); + g_clear_error (&error); + } +} + +static void dump_daemon_info (PinosContext *c, const PinosDaemonInfo *info, gpointer userdata) { - if (info == NULL) - return FALSE; - g_print ("\tid: %p\n", info->id); g_print ("\tdaemon-path: \"%s\"\n", info->daemon_path); if (info->change_mask & (1 << 0)) @@ -100,32 +108,22 @@ dump_daemon_info (PinosContext *c, const PinosDaemonInfo *info, gpointer userdat g_print ("\tcookie: %d\n", info->cookie); if (info->change_mask & (1 << 5)) print_properties (info->properties); - - return TRUE; } -static gboolean +static void dump_client_info (PinosContext *c, const PinosClientInfo *info, gpointer userdata) { - if (info == NULL) - return FALSE; - g_print ("\tid: %p\n", info->id); g_print ("\tclient-path: \"%s\"\n", info->client_path); if (info->change_mask & (1 << 0)) g_print ("\tname: \"%s\"\n", info->name); if (info->change_mask & (1 << 1)) print_properties (info->properties); - - return TRUE; } -static gboolean +static void dump_source_info (PinosContext *c, const PinosSourceInfo *info, gpointer userdata) { - if (info == NULL) - return FALSE; - g_print ("\tid: %p\n", info->id); g_print ("\tsource-path: \"%s\"\n", info->source_path); if (info->change_mask & (1 << 0)) @@ -136,16 +134,11 @@ dump_source_info (PinosContext *c, const PinosSourceInfo *info, gpointer userdat g_print ("\tstate: \"%s\"\n", pinos_source_state_as_string (info->state)); if (info->change_mask & (1 << 3)) print_formats ("possible formats", info->possible_formats); - - return TRUE; } -static gboolean +static void dump_source_output_info (PinosContext *c, const PinosSourceOutputInfo *info, gpointer userdata) { - if (info == NULL) - return FALSE; - g_print ("\tid: %p\n", info->id); g_print ("\toutput-path: \"%s\"\n", info->output_path); if (info->change_mask & (1 << 0)) @@ -160,8 +153,6 @@ dump_source_output_info (PinosContext *c, const PinosSourceOutputInfo *info, gpo print_formats ("format", info->format); if (info->change_mask & (1 << 5)) print_properties (info->properties); - - return TRUE; } static void @@ -172,6 +163,7 @@ dump_object (PinosContext *context, gpointer id, PinosSubscriptionFlags flags) PINOS_DAEMON_INFO_FLAGS_NONE, dump_daemon_info, NULL, + info_ready, NULL); } else if (flags & PINOS_SUBSCRIPTION_FLAG_CLIENT) { @@ -180,6 +172,7 @@ dump_object (PinosContext *context, gpointer id, PinosSubscriptionFlags flags) PINOS_CLIENT_INFO_FLAGS_NONE, dump_client_info, NULL, + info_ready, NULL); } else if (flags & PINOS_SUBSCRIPTION_FLAG_SOURCE) { @@ -188,6 +181,7 @@ dump_object (PinosContext *context, gpointer id, PinosSubscriptionFlags flags) PINOS_SOURCE_INFO_FLAGS_FORMATS, dump_source_info, NULL, + info_ready, NULL); } else if (flags & PINOS_SUBSCRIPTION_FLAG_SOURCE_OUTPUT) { @@ -196,6 +190,7 @@ dump_object (PinosContext *context, gpointer id, PinosSubscriptionFlags flags) PINOS_SOURCE_OUTPUT_INFO_FLAGS_NONE, dump_source_output_info, NULL, + info_ready, NULL); } }