#include "gstbus.h"
+/* bus signals */
+enum
+{
+ SYNC_MESSAGE,
+ ASYNC_MESSAGE,
+ /* add more above */
+ LAST_SIGNAL
+};
static void gst_bus_class_init (GstBusClass * klass);
static void gst_bus_init (GstBus * bus);
GValue * value, GParamSpec * pspec);
static GstObjectClass *parent_class = NULL;
-
-/* static guint gst_bus_signals[LAST_SIGNAL] = { 0 }; */
+static guint gst_bus_signals[LAST_SIGNAL] = { 0 };
GType
gst_bus_get_type (void)
return bus_type;
}
+/* fixme: do something about this */
+static void
+marshal_VOID__MINIOBJECT (GClosure * closure, GValue * return_value,
+ guint n_param_values, const GValue * param_values, gpointer invocation_hint,
+ gpointer marshal_data)
+{
+ typedef void (*marshalfunc_VOID__MINIOBJECT) (gpointer obj, gpointer arg1,
+ gpointer data2);
+ register marshalfunc_VOID__MINIOBJECT callback;
+ register GCClosure *cc = (GCClosure *) closure;
+ register gpointer data1, data2;
+
+ g_return_if_fail (n_param_values == 2);
+
+ if (G_CCLOSURE_SWAP_DATA (closure)) {
+ data1 = closure->data;
+ data2 = g_value_peek_pointer (param_values + 0);
+ } else {
+ data1 = g_value_peek_pointer (param_values + 0);
+ data2 = closure->data;
+ }
+ callback =
+ (marshalfunc_VOID__MINIOBJECT) (marshal_data ? marshal_data : cc->
+ callback);
+
+ callback (data1, gst_value_get_mini_object (param_values + 1), data2);
+}
+
static void
gst_bus_class_init (GstBusClass * klass)
{
gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_bus_dispose);
gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_bus_set_property);
gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_bus_get_property);
+
+ /**
+ * GstBus::sync-message:
+ * @bus: the object which received the signal
+ * @message: the message that has been posted synchronously
+ *
+ * A message has been posted on the bus. This signal is emited from the
+ * thread that posted the message so one has to be carefull with locking.
+ */
+ gst_bus_signals[SYNC_MESSAGE] =
+ g_signal_new ("sync-message", G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
+ G_STRUCT_OFFSET (GstBusClass, sync_message), NULL, NULL,
+ marshal_VOID__MINIOBJECT, G_TYPE_NONE, 1, GST_TYPE_MESSAGE);
+
+ /**
+ * GstBus::async-message:
+ * @bus: the object which received the signal
+ * @message: the message that has been posted asynchronously
+ *
+ * A message has been posted on the bus. This signal is emited from a
+ * GSource added to the mainloop.
+ */
+ gst_bus_signals[ASYNC_MESSAGE] =
+ g_signal_new ("async-message", G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
+ G_STRUCT_OFFSET (GstBusClass, async_message), NULL, NULL,
+ marshal_VOID__MINIOBJECT, G_TYPE_NONE, 1, GST_TYPE_MESSAGE);
}
static void
g_return_val_if_fail (GST_IS_BUS (bus), FALSE);
g_return_val_if_fail (GST_IS_MESSAGE (message), FALSE);
- GST_DEBUG_OBJECT (bus, "[msg %p] posting on bus, type %d",
- message, GST_MESSAGE_TYPE (message));
+ GST_DEBUG_OBJECT (bus, "[msg %p] posting on bus, type %s",
+ message, gst_message_type_get_name (GST_MESSAGE_TYPE (message)));
GST_LOCK (bus);
/* check if the bus is flushing */
GST_UNLOCK (bus);
}
+
/**
* gst_bus_pop:
* @bus: a #GstBus to pop
poll_data->message = gst_message_ref (message);
GST_DEBUG ("mainloop %p quit", poll_data->loop);
g_main_loop_quit (poll_data->loop);
- } else {
- /* don't remove the source. */
}
+
/* we always keep the source alive so that we don't accidentialy
* free the poll_data */
return TRUE;
* specify a maximum time to poll with the @timeout parameter. If @timeout is
* negative, this function will block indefinitely.
*
+ * All messages not in @events will be popped off the bus and will be ignored.
+ *
* This function will enter the default mainloop while polling.
*
* Returns: The message that was received, or NULL if the poll timed out.
return ret;
}
+
+/**
+ * gst_bus_async_signal_func:
+ * @bus: a #GstBus
+ * @message: the message received
+ * @data: user data
+ *
+ * A helper GstBusFunc that can be used to convert all asynchronous messages
+ * into signals.
+ *
+ * Returns: TRUE
+ */
+gboolean
+gst_bus_async_signal_func (GstBus * bus, GstMessage * message, gpointer data)
+{
+ GQuark detail = 0;
+
+ detail = gst_message_type_to_quark (GST_MESSAGE_TYPE (message));
+
+ g_signal_emit (bus, gst_bus_signals[ASYNC_MESSAGE], detail, message);
+
+ /* we never remove this source based on signal emission return values */
+ return TRUE;
+}
+
+/**
+ * gst_bus_sync_signal_handler:
+ * @bus: a #GstBus
+ * @message: the message received
+ * @data: user data
+ *
+ * A helper GstBusSyncHandler that can be used to convert all synchronous
+ * messages into signals.
+ *
+ * Returns: GST_BUS_PASS
+ */
+GstBusSyncReply
+gst_bus_sync_signal_handler (GstBus * bus, GstMessage * message, gpointer data)
+{
+ GQuark detail = 0;
+
+ detail = gst_message_type_to_quark (GST_MESSAGE_TYPE (message));
+
+ g_signal_emit (bus, gst_bus_signals[SYNC_MESSAGE], detail, message);
+
+ return GST_BUS_PASS;
+}
{
GstObjectClass parent_class;
+ /* signals */
+ void (*sync_message) (GstBus *bus, GstMessage *message);
+ void (*async_message) (GstBus *bus, GstMessage *message);
+
/*< private > */
gpointer _gst_reserved[GST_PADDING];
};
GstMessage * gst_bus_pop (GstBus * bus);
void gst_bus_set_flushing (GstBus * bus, gboolean flushing);
+/* synchronous dispatching */
void gst_bus_set_sync_handler (GstBus * bus, GstBusSyncHandler func,
gpointer data);
-
+/* GSource based dispatching */
GSource * gst_bus_create_watch (GstBus * bus, GstMessageType events);
guint gst_bus_add_watch_full (GstBus * bus,
gint priority,
GstBusFunc func,
gpointer user_data);
+/* polling the bus */
GstMessage* gst_bus_poll (GstBus *bus, GstMessageType events,
GstClockTimeDiff timeout);
+/* signal based dispatching helper functions. */
+gboolean gst_bus_async_signal_func (GstBus *bus, GstMessage *message,
+ gpointer data);
+GstBusSyncReply gst_bus_sync_signal_handler (GstBus *bus, GstMessage *message,
+ gpointer data);
+
G_END_DECLS
#endif /* __GST_BUS_H__ */
static void gst_message_finalize (GstMessage * message);
static GstMessage *_gst_message_copy (GstMessage * message);
-
void
_gst_message_initialize (void)
{
g_type_class_unref (ptr);
}
+typedef struct
+{
+ gint type;
+ gchar *name;
+ GQuark quark;
+} GstMessageQuarks;
+
+static GstMessageQuarks message_quarks[] = {
+ {GST_MESSAGE_UNKNOWN, "unknown", 0},
+ {GST_MESSAGE_EOS, "eos", 0},
+ {GST_MESSAGE_ERROR, "error", 0},
+ {GST_MESSAGE_WARNING, "warning", 0},
+ {GST_MESSAGE_INFO, "info", 0},
+ {GST_MESSAGE_TAG, "tag", 0},
+ {GST_MESSAGE_BUFFERING, "buffering", 0},
+ {GST_MESSAGE_STATE_CHANGED, "state-changed", 0},
+ {GST_MESSAGE_STEP_DONE, "step-done", 0},
+ {GST_MESSAGE_NEW_CLOCK, "new-clock", 0},
+ {GST_MESSAGE_STRUCTURE_CHANGE, "structure-change", 0},
+ {GST_MESSAGE_STREAM_STATUS, "stream-status", 0},
+ {GST_MESSAGE_APPLICATION, "application", 0},
+ {GST_MESSAGE_SEGMENT_START, "segment-start", 0},
+ {GST_MESSAGE_SEGMENT_DONE, "segment-done", 0},
+ {0, NULL, 0}
+};
+
+const gchar *
+gst_message_type_get_name (GstMessageType type)
+{
+ gint i;
+
+ for (i = 0; message_quarks[i].name; i++) {
+ if (type == message_quarks[i].type)
+ return message_quarks[i].name;
+ }
+ return "unknown";
+}
+
+GQuark
+gst_message_type_to_quark (GstMessageType type)
+{
+ gint i;
+
+ for (i = 0; message_quarks[i].name; i++) {
+ if (type == message_quarks[i].type)
+ return message_quarks[i].quark;
+ }
+ return 0;
+}
+
GType
gst_message_get_type (void)
{
static GType _gst_message_type;
if (G_UNLIKELY (_gst_message_type == 0)) {
+ gint i;
static const GTypeInfo message_info = {
sizeof (GstMessageClass),
NULL,
_gst_message_type = g_type_register_static (GST_TYPE_MINI_OBJECT,
"GstMessage", &message_info, 0);
+
+ for (i = 0; message_quarks[i].name; i++) {
+ message_quarks[i].quark =
+ g_quark_from_static_string (message_quarks[i].name);
+ }
}
return _gst_message_type;
}