From b0b15cec5c360d69e7d3c7730eb9709f48f90f6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Dzi=C4=99giel?= Date: Sat, 2 Aug 2025 20:21:52 +0200 Subject: [PATCH] clapper: Add "message" signal to the player A detailed signal that allows for applications to receive element messages posted on the pipeline bus. Useful if app cares about some custom message that player normally does not handle. For example audio player might want to read "level" messages in order to show current audio level or implement visualizations. --- src/lib/clapper/clapper-app-bus-private.h | 2 + src/lib/clapper/clapper-app-bus.c | 51 +++++++++++++++++++++++ src/lib/clapper/clapper-playbin-bus.c | 5 +++ src/lib/clapper/clapper-player.c | 23 ++++++++++ 4 files changed, 81 insertions(+) diff --git a/src/lib/clapper/clapper-app-bus-private.h b/src/lib/clapper/clapper-app-bus-private.h index 6f53dee4..b3c03d4d 100644 --- a/src/lib/clapper/clapper-app-bus-private.h +++ b/src/lib/clapper/clapper-app-bus-private.h @@ -52,6 +52,8 @@ void clapper_app_bus_post_object_desc_signal (ClapperAppBus *app_bus, GstObject void clapper_app_bus_post_desc_with_details_signal (ClapperAppBus *app_bus, GstObject *src, guint signal_id, const gchar *desc, const gchar *details); +void clapper_app_bus_post_message_signal (ClapperAppBus *app_bus, GstObject *src, guint signal_id, GstMessage *msg); + void clapper_app_bus_post_error_signal (ClapperAppBus *app_bus, GstObject *src, guint signal_id, GError *error, const gchar *debug_info); G_END_DECLS diff --git a/src/lib/clapper/clapper-app-bus.c b/src/lib/clapper/clapper-app-bus.c index b70e4fd1..b1d961af 100644 --- a/src/lib/clapper/clapper-app-bus.c +++ b/src/lib/clapper/clapper-app-bus.c @@ -46,6 +46,7 @@ enum CLAPPER_APP_BUS_STRUCTURE_SIMPLE_SIGNAL, CLAPPER_APP_BUS_STRUCTURE_OBJECT_DESC_SIGNAL, CLAPPER_APP_BUS_STRUCTURE_DESC_WITH_DETAILS_SIGNAL, + CLAPPER_APP_BUS_STRUCTURE_MESSAGE_SIGNAL, CLAPPER_APP_BUS_STRUCTURE_ERROR_SIGNAL }; @@ -58,6 +59,7 @@ static ClapperBusQuark _structure_quarks[] = { {"simple-signal", 0}, {"object-desc-signal", 0}, {"desc-with-details-signal", 0}, + {"message", 0}, {"error-signal", 0}, {NULL, 0} }; @@ -276,6 +278,53 @@ _handle_desc_with_details_signal_msg (GstMessage *msg, const GstStructure *struc g_free (details); } +void +clapper_app_bus_post_message_signal (ClapperAppBus *self, + GstObject *src, guint signal_id, GstMessage *msg) +{ + /* Check for any "message" signal connection */ + if (g_signal_handler_find (src, G_SIGNAL_MATCH_ID, + signal_id, 0, NULL, NULL, NULL) != 0) { + const GstStructure *structure = gst_message_get_structure (msg); + GQuark detail; + + if (G_UNLIKELY (structure == NULL)) + return; + + detail = g_quark_from_string (gst_structure_get_name (structure)); + + /* If specific detail is connected or ALL "message" handler */ + if (g_signal_handler_find (src, G_SIGNAL_MATCH_ID | G_SIGNAL_MATCH_DETAIL, + signal_id, detail, NULL, NULL, NULL) != 0 + || g_signal_handler_find (src, G_SIGNAL_MATCH_ID | G_SIGNAL_MATCH_DETAIL, + signal_id, 0, NULL, NULL, NULL) != 0) { + GstStructure *structure = gst_structure_new_id (_STRUCTURE_QUARK (MESSAGE_SIGNAL), + _FIELD_QUARK (SIGNAL_ID), G_TYPE_UINT, signal_id, + _FIELD_QUARK (DETAILS), G_TYPE_UINT, detail, + _FIELD_QUARK (OBJECT), GST_TYPE_MESSAGE, msg, + NULL); + gst_bus_post (GST_BUS_CAST (self), gst_message_new_application (src, structure)); + } + } +} + +static inline void +_handle_message_signal_msg (GstMessage *msg, const GstStructure *structure) +{ + guint signal_id = 0; + GQuark detail = 0; + GstMessage *fwd_message = NULL; + + gst_structure_id_get (structure, + _FIELD_QUARK (SIGNAL_ID), G_TYPE_UINT, &signal_id, + _FIELD_QUARK (DETAILS), G_TYPE_UINT, &detail, + _FIELD_QUARK (OBJECT), GST_TYPE_MESSAGE, &fwd_message, + NULL); + g_signal_emit (_MESSAGE_SRC_GOBJECT (msg), signal_id, detail, fwd_message); + + gst_message_unref (fwd_message); +} + void clapper_app_bus_post_error_signal (ClapperAppBus *self, GstObject *src, guint signal_id, @@ -326,6 +375,8 @@ clapper_app_bus_message_func (GstBus *bus, GstMessage *msg, gpointer user_data G _handle_simple_signal_msg (msg, structure); else if (quark == _STRUCTURE_QUARK (OBJECT_DESC_SIGNAL)) _handle_object_desc_signal_msg (msg, structure); + else if (quark == _STRUCTURE_QUARK (MESSAGE_SIGNAL)) + _handle_message_signal_msg (msg, structure); else if (quark == _STRUCTURE_QUARK (ERROR_SIGNAL)) _handle_error_signal_msg (msg, structure); else if (quark == _STRUCTURE_QUARK (DESC_WITH_DETAILS_SIGNAL)) diff --git a/src/lib/clapper/clapper-playbin-bus.c b/src/lib/clapper/clapper-playbin-bus.c index 4cb6a1c5..706d080b 100644 --- a/src/lib/clapper/clapper-playbin-bus.c +++ b/src/lib/clapper/clapper-playbin-bus.c @@ -930,6 +930,11 @@ _handle_element_msg (GstMessage *msg, ClapperPlayer *player) GST_OBJECT_CAST (downloaded_item), location); gst_object_unref (downloaded_item); + } else { + guint signal_id = g_signal_lookup ("message", CLAPPER_TYPE_PLAYER); + + clapper_app_bus_post_message_signal (player->app_bus, + GST_OBJECT_CAST (player), signal_id, msg); } } diff --git a/src/lib/clapper/clapper-player.c b/src/lib/clapper/clapper-player.c index d01868c5..39dee096 100644 --- a/src/lib/clapper/clapper-player.c +++ b/src/lib/clapper/clapper-player.c @@ -111,6 +111,7 @@ enum SIGNAL_SEEK_DONE, SIGNAL_DOWNLOAD_COMPLETE, SIGNAL_MISSING_PLUGIN, + SIGNAL_MESSAGE, SIGNAL_WARNING, SIGNAL_ERROR, SIGNAL_LAST @@ -2985,6 +2986,28 @@ clapper_player_class_init (ClapperPlayerClass *klass) G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, 0, NULL, NULL, NULL, G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_STRING); + /** + * ClapperPlayer::message: + * @player: a #ClapperPlayer + * @msg: a #GstMessage + * + * Allows for applications to receive element messages posted + * on the underlaying pipeline bus. + * + * This is a detailed signal. Connect to it via `message::name` + * to only receive messages with a certain `name`. + * + * Player will only forward messages to the main app thread (from which + * this signal is emitted) that have a matching signal handler, thus + * it is more efficient to listen only for specific messages instead + * of connecting to simply `message` with no details (without message name). + * + * Since: 0.10 + */ + signals[SIGNAL_MESSAGE] = g_signal_new ("message", G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS | G_SIGNAL_DETAILED, + 0, NULL, NULL, NULL, G_TYPE_NONE, 1, GST_TYPE_MESSAGE); + /** * ClapperPlayer::warning: * @player: a #ClapperPlayer