mirror of
https://github.com/Rafostar/clapper.git
synced 2025-08-31 00:11:59 +02:00
clapper: Implement reactables manager
An object for managing instances of reactable type of enhancers. Based on/similar to features manager which along with Clapper features objects gets deprecated in favour of reactables.
This commit is contained in:
@@ -29,6 +29,7 @@
|
||||
#include "clapper-app-bus-private.h"
|
||||
#include "clapper-features-bus-private.h"
|
||||
#include "clapper-enhancer-proxy-list-private.h"
|
||||
#include "clapper-reactables-manager-private.h"
|
||||
#include "gst/clapper-plugin-private.h"
|
||||
|
||||
#include "clapper-functionalities-availability.h"
|
||||
@@ -56,6 +57,7 @@ clapper_init_check_internal (int *argc, char **argv[])
|
||||
clapper_playbin_bus_initialize ();
|
||||
clapper_app_bus_initialize ();
|
||||
clapper_features_bus_initialize ();
|
||||
clapper_reactables_manager_initialize ();
|
||||
|
||||
_proxies = clapper_enhancer_proxy_list_new_named ("global-proxy-list");
|
||||
|
||||
|
@@ -20,12 +20,14 @@
|
||||
#include "clapper-cache-private.h"
|
||||
#include "clapper-version.h"
|
||||
#include "clapper-extractable.h"
|
||||
#include "clapper-reactable.h"
|
||||
|
||||
#define CLAPPER_CACHE_HEADER "CLAPPER"
|
||||
|
||||
typedef enum
|
||||
{
|
||||
CLAPPER_CACHE_IFACE_EXTRACTABLE = 1,
|
||||
CLAPPER_CACHE_IFACE_REACTABLE,
|
||||
} ClapperCacheIfaces;
|
||||
|
||||
static GArray *enum_registry = NULL;
|
||||
@@ -243,6 +245,8 @@ clapper_cache_read_iface (const gchar **data)
|
||||
switch (iface_id) {
|
||||
case CLAPPER_CACHE_IFACE_EXTRACTABLE:
|
||||
return CLAPPER_TYPE_EXTRACTABLE;
|
||||
case CLAPPER_CACHE_IFACE_REACTABLE:
|
||||
return CLAPPER_TYPE_REACTABLE;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
@@ -433,6 +437,8 @@ clapper_cache_store_iface (GByteArray *bytes, GType iface)
|
||||
|
||||
if (iface == CLAPPER_TYPE_EXTRACTABLE)
|
||||
iface_id = CLAPPER_CACHE_IFACE_EXTRACTABLE;
|
||||
else if (iface == CLAPPER_TYPE_REACTABLE)
|
||||
iface_id = CLAPPER_CACHE_IFACE_REACTABLE;
|
||||
else
|
||||
return FALSE;
|
||||
|
||||
|
@@ -20,6 +20,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <glib.h>
|
||||
#include <glib-object.h>
|
||||
|
||||
#include "clapper-enhancer-proxy-list.h"
|
||||
#include "clapper-enhancer-proxy.h"
|
||||
@@ -38,4 +39,7 @@ void clapper_enhancer_proxy_list_fill_from_global_proxies (ClapperEnhancerProxyL
|
||||
G_GNUC_INTERNAL
|
||||
void clapper_enhancer_proxy_list_sort (ClapperEnhancerProxyList *list);
|
||||
|
||||
G_GNUC_INTERNAL
|
||||
gboolean clapper_enhancer_proxy_list_has_proxy_with_interface (ClapperEnhancerProxyList *list, GType iface_type);
|
||||
|
||||
G_END_DECLS
|
||||
|
@@ -161,6 +161,29 @@ clapper_enhancer_proxy_list_sort (ClapperEnhancerProxyList *self)
|
||||
g_ptr_array_sort_values (self->proxies, (GCompareFunc) _sort_values_by_name);
|
||||
}
|
||||
|
||||
/*
|
||||
* clapper_enhancer_proxy_list_has_proxy_with_interface:
|
||||
* @iface_type: an interface #GType
|
||||
*
|
||||
* Check if any enhancer implementing given interface type is available.
|
||||
*
|
||||
* Returns: whether any enhancer proxy was found.
|
||||
*/
|
||||
gboolean
|
||||
clapper_enhancer_proxy_list_has_proxy_with_interface (ClapperEnhancerProxyList *self, GType iface_type)
|
||||
{
|
||||
guint i;
|
||||
|
||||
for (i = 0; i < self->proxies->len; ++i) {
|
||||
ClapperEnhancerProxy *proxy = clapper_enhancer_proxy_list_peek_proxy (self, i);
|
||||
|
||||
if (clapper_enhancer_proxy_target_has_interface (proxy, iface_type))
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* clapper_enhancer_proxy_list_get_proxy:
|
||||
* @list: a #ClapperEnhancerProxyList
|
||||
|
@@ -45,6 +45,9 @@ void clapper_enhancer_proxy_export_to_cache (ClapperEnhancerProxy *proxy);
|
||||
G_GNUC_INTERNAL
|
||||
GObject * clapper_enhancer_proxy_get_peas_info (ClapperEnhancerProxy *proxy);
|
||||
|
||||
G_GNUC_INTERNAL
|
||||
gboolean clapper_enhancer_proxy_has_locally_set (ClapperEnhancerProxy *proxy, const gchar *property_name);
|
||||
|
||||
G_GNUC_INTERNAL
|
||||
GstStructure * clapper_enhancer_proxy_make_current_config (ClapperEnhancerProxy *proxy);
|
||||
|
||||
|
@@ -48,6 +48,9 @@
|
||||
#include "clapper-basic-functions.h"
|
||||
#include "clapper-cache-private.h"
|
||||
#include "clapper-extractable.h"
|
||||
#include "clapper-reactable.h"
|
||||
#include "clapper-player-private.h"
|
||||
#include "clapper-utils-private.h"
|
||||
#include "clapper-enums.h"
|
||||
|
||||
#include "clapper-functionalities-availability.h"
|
||||
@@ -454,7 +457,7 @@ clapper_enhancer_proxy_export_to_cache (ClapperEnhancerProxy *self)
|
||||
gboolean
|
||||
clapper_enhancer_proxy_fill_from_instance (ClapperEnhancerProxy *self, GObject *enhancer)
|
||||
{
|
||||
GType enhancer_types[1] = { CLAPPER_TYPE_EXTRACTABLE };
|
||||
const GType enhancer_types[] = { CLAPPER_TYPE_EXTRACTABLE, CLAPPER_TYPE_REACTABLE };
|
||||
GType *ifaces;
|
||||
GParamSpec **pspecs;
|
||||
GParamFlags enhancer_flags;
|
||||
@@ -500,6 +503,18 @@ clapper_enhancer_proxy_get_peas_info (ClapperEnhancerProxy *self)
|
||||
return self->peas_info;
|
||||
}
|
||||
|
||||
gboolean
|
||||
clapper_enhancer_proxy_has_locally_set (ClapperEnhancerProxy *self, const gchar *property_name)
|
||||
{
|
||||
gboolean has_field;
|
||||
|
||||
GST_OBJECT_LOCK (self);
|
||||
has_field = (self->local_config && gst_structure_has_field (self->local_config, property_name));
|
||||
GST_OBJECT_UNLOCK (self);
|
||||
|
||||
return has_field;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
_apply_config_cb (GQuark field_id, const GValue *value, GObject *enhancer)
|
||||
{
|
||||
@@ -527,6 +542,7 @@ clapper_enhancer_proxy_make_current_config (ClapperEnhancerProxy *self)
|
||||
|
||||
/* Using "has_field", as set value might be %NULL */
|
||||
if ((pspec->flags & CLAPPER_ENHANCER_PARAM_LOCAL)
|
||||
&& self->local_config
|
||||
&& gst_structure_has_field (self->local_config, pspec->name)) {
|
||||
if (!merged_config)
|
||||
merged_config = gst_structure_new_empty (CONFIG_STRUCTURE_NAME);
|
||||
@@ -540,44 +556,13 @@ clapper_enhancer_proxy_make_current_config (ClapperEnhancerProxy *self)
|
||||
GVariant *def = g_settings_get_default_value (settings, pspec->name);
|
||||
|
||||
if (!g_variant_equal (val, def)) {
|
||||
if (!merged_config)
|
||||
merged_config = gst_structure_new_empty (CONFIG_STRUCTURE_NAME);
|
||||
GValue value = G_VALUE_INIT;
|
||||
|
||||
switch (pspec->value_type) {
|
||||
case G_TYPE_BOOLEAN:
|
||||
gst_structure_set (merged_config, pspec->name,
|
||||
pspec->value_type, g_variant_get_boolean (val), NULL);
|
||||
break;
|
||||
case G_TYPE_INT:
|
||||
gst_structure_set (merged_config, pspec->name,
|
||||
pspec->value_type, g_variant_get_int32 (val), NULL);
|
||||
break;
|
||||
case G_TYPE_UINT:
|
||||
gst_structure_set (merged_config, pspec->name,
|
||||
pspec->value_type, g_variant_get_uint32 (val), NULL);
|
||||
break;
|
||||
case G_TYPE_DOUBLE:
|
||||
gst_structure_set (merged_config, pspec->name,
|
||||
pspec->value_type, g_variant_get_double (val), NULL);
|
||||
break;
|
||||
case G_TYPE_STRING:
|
||||
gst_structure_set (merged_config, pspec->name,
|
||||
pspec->value_type, g_variant_get_string (val, NULL), NULL);
|
||||
break;
|
||||
default:{
|
||||
if (G_IS_PARAM_SPEC_ENUM (pspec)) {
|
||||
gst_structure_set (merged_config, pspec->name,
|
||||
G_TYPE_INT, g_variant_get_int32 (val), NULL);
|
||||
break;
|
||||
} else if (G_IS_PARAM_SPEC_FLAGS (pspec)) {
|
||||
gst_structure_set (merged_config, pspec->name,
|
||||
G_TYPE_UINT, g_variant_get_uint32 (val), NULL);
|
||||
break;
|
||||
}
|
||||
GST_ERROR_OBJECT (self, "Unsupported enhancer \"%s\" setting type: %s",
|
||||
pspec->name, g_type_name (pspec->value_type));
|
||||
break;
|
||||
}
|
||||
if (G_LIKELY (clapper_utils_set_value_from_variant (&value, val))) {
|
||||
if (!merged_config)
|
||||
merged_config = gst_structure_new_empty (CONFIG_STRUCTURE_NAME);
|
||||
|
||||
gst_structure_take_value (merged_config, pspec->name, &value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -947,6 +932,20 @@ _structure_take_value_by_pspec (ClapperEnhancerProxy *self,
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
_trigger_reactable_configure_take (ClapperEnhancerProxy *self, GstStructure *structure)
|
||||
{
|
||||
ClapperPlayer *player = clapper_player_get_from_ancestor (GST_OBJECT_CAST (self));
|
||||
|
||||
if (G_LIKELY (player != NULL)) {
|
||||
clapper_reactables_manager_trigger_configure_take_config (
|
||||
player->reactables_manager, self, structure);
|
||||
gst_object_unref (player);
|
||||
} else {
|
||||
gst_structure_free (structure);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* clapper_enhancer_proxy_set_locally:
|
||||
* @proxy: a #ClapperEnhancerProxy
|
||||
@@ -1017,10 +1016,10 @@ clapper_enhancer_proxy_set_locally (ClapperEnhancerProxy *self, const gchar *fir
|
||||
|
||||
_update_local_config_from_structure (self, structure);
|
||||
|
||||
/* TODO: _post_local_config instead of free if managed
|
||||
* (for when managed interfaces are implemented) */
|
||||
|
||||
gst_structure_free (structure);
|
||||
if (clapper_enhancer_proxy_target_has_interface (self, CLAPPER_TYPE_REACTABLE))
|
||||
_trigger_reactable_configure_take (self, structure);
|
||||
else
|
||||
gst_structure_free (structure);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1084,10 +1083,10 @@ clapper_enhancer_proxy_set_locally_with_table (ClapperEnhancerProxy *self, GHash
|
||||
|
||||
_update_local_config_from_structure (self, structure);
|
||||
|
||||
/* TODO: _post_local_config instead of free if managed
|
||||
* (for when managed interfaces are implemented) */
|
||||
|
||||
gst_structure_free (structure);
|
||||
if (clapper_enhancer_proxy_target_has_interface (self, CLAPPER_TYPE_REACTABLE))
|
||||
_trigger_reactable_configure_take (self, structure);
|
||||
else
|
||||
gst_structure_free (structure);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@@ -33,6 +33,9 @@ static HMODULE _enhancers_dll_handle = NULL;
|
||||
|
||||
// Supported interfaces
|
||||
#include "clapper-extractable.h"
|
||||
#include "clapper-reactable.h"
|
||||
|
||||
#include <clapper-functionalities-availability.h>
|
||||
|
||||
#define GST_CAT_DEFAULT clapper_enhancers_loader_debug
|
||||
GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
|
||||
@@ -110,6 +113,36 @@ clapper_enhancers_loader_initialize (ClapperEnhancerProxyList *proxies)
|
||||
ClapperEnhancerProxy *proxy;
|
||||
gboolean filled;
|
||||
|
||||
/* FIXME: 1.0: Remove together with features code and manager.
|
||||
* These would clash with each other, so avoid loading these
|
||||
* as enhancers when also compiled as part of the library. */
|
||||
#if (CLAPPER_HAVE_MPRIS || CLAPPER_HAVE_DISCOVERER || CLAPPER_HAVE_SERVER)
|
||||
guint f_index;
|
||||
const gchar *module_name = peas_plugin_info_get_module_name (info);
|
||||
const gchar *ported_features[] = {
|
||||
#if CLAPPER_HAVE_MPRIS
|
||||
"clapper-mpris",
|
||||
#endif
|
||||
#if CLAPPER_HAVE_DISCOVERER
|
||||
"clapper-discoverer",
|
||||
#endif
|
||||
#if CLAPPER_HAVE_SERVER
|
||||
"clapper-server",
|
||||
#endif
|
||||
};
|
||||
|
||||
for (f_index = 0; f_index < G_N_ELEMENTS (ported_features); ++f_index) {
|
||||
if (strcmp (module_name, ported_features[f_index]) == 0) {
|
||||
GST_INFO ("Skipped \"%s\" enhancer module, since its"
|
||||
" loaded from deprecated feature object", module_name);
|
||||
g_clear_object (&info);
|
||||
}
|
||||
}
|
||||
|
||||
if (!info) // cleared when exists as feature
|
||||
continue;
|
||||
#endif
|
||||
|
||||
/* Clapper supports only 1 proxy per plugin. Each plugin can
|
||||
* ship 1 class, but it can implement more than 1 interface. */
|
||||
proxy = clapper_enhancer_proxy_new_global_take ((GObject *) info);
|
||||
@@ -118,7 +151,7 @@ clapper_enhancers_loader_initialize (ClapperEnhancerProxyList *proxies)
|
||||
* Otherwise make an instance and fill missing data from it (slow). */
|
||||
if (!(filled = clapper_enhancer_proxy_fill_from_cache (proxy))) {
|
||||
GObject *enhancer;
|
||||
GType main_types[1] = { CLAPPER_TYPE_EXTRACTABLE };
|
||||
const GType main_types[] = { CLAPPER_TYPE_EXTRACTABLE, CLAPPER_TYPE_REACTABLE };
|
||||
guint j;
|
||||
|
||||
/* We cannot ask libpeas for "any" of our main interfaces, so try each one until found */
|
||||
|
@@ -23,7 +23,7 @@
|
||||
#include <gst/pbutils/pbutils.h>
|
||||
|
||||
#include "clapper-media-item.h"
|
||||
#include "clapper-player-private.h"
|
||||
#include "clapper-player.h"
|
||||
#include "clapper-app-bus-private.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
@@ -30,6 +30,7 @@
|
||||
#include "clapper-timeline-private.h"
|
||||
#include "clapper-player-private.h"
|
||||
#include "clapper-playbin-bus-private.h"
|
||||
#include "clapper-reactables-manager-private.h"
|
||||
#include "clapper-features-manager-private.h"
|
||||
#include "clapper-utils-private.h"
|
||||
|
||||
@@ -565,6 +566,8 @@ clapper_media_item_populate_tags (ClapperMediaItem *self, const GstTagList *tags
|
||||
if (changed && player) {
|
||||
ClapperFeaturesManager *features_manager;
|
||||
|
||||
if (player->reactables_manager)
|
||||
clapper_reactables_manager_trigger_item_updated (player->reactables_manager, self);
|
||||
if ((features_manager = clapper_player_get_features_manager (player)))
|
||||
clapper_features_manager_trigger_item_updated (features_manager, self);
|
||||
}
|
||||
@@ -602,6 +605,8 @@ clapper_media_item_update_from_tag_list (ClapperMediaItem *self, const GstTagLis
|
||||
if (changed) {
|
||||
ClapperFeaturesManager *features_manager;
|
||||
|
||||
if (player->reactables_manager)
|
||||
clapper_reactables_manager_trigger_item_updated (player->reactables_manager, self);
|
||||
if ((features_manager = clapper_player_get_features_manager (player)))
|
||||
clapper_features_manager_trigger_item_updated (features_manager, self);
|
||||
}
|
||||
@@ -645,6 +650,8 @@ clapper_media_item_update_from_discoverer_info (ClapperMediaItem *self, GstDisco
|
||||
if (changed) {
|
||||
ClapperFeaturesManager *features_manager;
|
||||
|
||||
if (player->reactables_manager)
|
||||
clapper_reactables_manager_trigger_item_updated (player->reactables_manager, self);
|
||||
if ((features_manager = clapper_player_get_features_manager (player)))
|
||||
clapper_features_manager_trigger_item_updated (features_manager, self);
|
||||
}
|
||||
|
@@ -173,6 +173,8 @@ _update_current_duration (ClapperPlayer *player)
|
||||
if (clapper_media_item_set_duration (player->played_item, duration_dbl, player->app_bus)) {
|
||||
ClapperFeaturesManager *features_manager;
|
||||
|
||||
if (player->reactables_manager)
|
||||
clapper_reactables_manager_trigger_item_updated (player->reactables_manager, player->played_item);
|
||||
if ((features_manager = clapper_player_get_features_manager (player)))
|
||||
clapper_features_manager_trigger_item_updated (features_manager, player->played_item);
|
||||
}
|
||||
@@ -1046,6 +1048,8 @@ _handle_stream_start_msg (GstMessage *msg, ClapperPlayer *player)
|
||||
if (G_LIKELY (changed)) {
|
||||
clapper_queue_handle_played_item_changed (player->queue, player->played_item, player->app_bus);
|
||||
|
||||
if (player->reactables_manager)
|
||||
clapper_reactables_manager_trigger_played_item_changed (player->reactables_manager, player->played_item);
|
||||
if (clapper_player_get_have_features (player))
|
||||
clapper_features_manager_trigger_played_item_changed (player->features_manager, player->played_item);
|
||||
}
|
||||
|
@@ -27,6 +27,7 @@
|
||||
|
||||
#include "clapper-app-bus-private.h"
|
||||
#include "clapper-features-manager-private.h"
|
||||
#include "clapper-reactables-manager-private.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
@@ -47,6 +48,8 @@ struct _ClapperPlayer
|
||||
ClapperFeaturesManager *features_manager;
|
||||
gint have_features; // atomic integer
|
||||
|
||||
ClapperReactablesManager *reactables_manager;
|
||||
|
||||
ClapperEnhancerProxyList *enhancer_proxies;
|
||||
|
||||
/* This is different from queue current item as it is used/changed only
|
||||
|
@@ -50,6 +50,7 @@
|
||||
#include "clapper-audio-stream-private.h"
|
||||
#include "clapper-subtitle-stream-private.h"
|
||||
#include "clapper-enhancer-proxy-list-private.h"
|
||||
#include "clapper-reactable.h"
|
||||
#include "clapper-enums-private.h"
|
||||
#include "clapper-utils-private.h"
|
||||
#include "../shared/clapper-shared-utils-private.h"
|
||||
@@ -159,6 +160,8 @@ clapper_player_refresh_position (ClapperPlayer *self)
|
||||
|
||||
clapper_app_bus_post_prop_notify (self->app_bus,
|
||||
GST_OBJECT_CAST (self), param_specs[PROP_POSITION]);
|
||||
if (self->reactables_manager)
|
||||
clapper_reactables_manager_trigger_position_changed (self->reactables_manager, position_dbl);
|
||||
if (clapper_player_get_have_features (self))
|
||||
clapper_features_manager_trigger_position_changed (self->features_manager, position_dbl);
|
||||
}
|
||||
@@ -225,6 +228,8 @@ clapper_player_handle_playbin_state_changed (ClapperPlayer *self)
|
||||
|
||||
clapper_app_bus_post_prop_notify (self->app_bus,
|
||||
GST_OBJECT_CAST (self), param_specs[PROP_STATE]);
|
||||
if (self->reactables_manager)
|
||||
clapper_reactables_manager_trigger_state_changed (self->reactables_manager, state);
|
||||
if (clapper_player_get_have_features (self))
|
||||
clapper_features_manager_trigger_state_changed (self->features_manager, state);
|
||||
}
|
||||
@@ -256,6 +261,8 @@ clapper_player_handle_playbin_volume_changed (ClapperPlayer *self, const GValue
|
||||
|
||||
clapper_app_bus_post_prop_notify (self->app_bus,
|
||||
GST_OBJECT_CAST (self), param_specs[PROP_VOLUME]);
|
||||
if (self->reactables_manager)
|
||||
clapper_reactables_manager_trigger_volume_changed (self->reactables_manager, volume);
|
||||
if (clapper_player_get_have_features (self))
|
||||
clapper_features_manager_trigger_volume_changed (self->features_manager, volume);
|
||||
}
|
||||
@@ -280,6 +287,8 @@ clapper_player_handle_playbin_mute_changed (ClapperPlayer *self, const GValue *v
|
||||
|
||||
clapper_app_bus_post_prop_notify (self->app_bus,
|
||||
GST_OBJECT_CAST (self), param_specs[PROP_MUTE]);
|
||||
if (self->reactables_manager)
|
||||
clapper_reactables_manager_trigger_mute_changed (self->reactables_manager, mute);
|
||||
if (clapper_player_get_have_features (self))
|
||||
clapper_features_manager_trigger_mute_changed (self->features_manager, mute);
|
||||
}
|
||||
@@ -400,6 +409,8 @@ clapper_player_handle_playbin_rate_changed (ClapperPlayer *self, gdouble speed)
|
||||
|
||||
clapper_app_bus_post_prop_notify (self->app_bus,
|
||||
GST_OBJECT_CAST (self), param_specs[PROP_SPEED]);
|
||||
if (self->reactables_manager)
|
||||
clapper_reactables_manager_trigger_speed_changed (self->reactables_manager, speed);
|
||||
if (clapper_player_get_have_features (self))
|
||||
clapper_features_manager_trigger_speed_changed (self->features_manager, speed);
|
||||
}
|
||||
@@ -2326,6 +2337,13 @@ clapper_player_init (ClapperPlayer *self)
|
||||
|
||||
clapper_enhancer_proxy_list_fill_from_global_proxies (self->enhancer_proxies);
|
||||
|
||||
if (clapper_enhancer_proxy_list_has_proxy_with_interface (self->enhancer_proxies, CLAPPER_TYPE_REACTABLE)) {
|
||||
self->reactables_manager = clapper_reactables_manager_new ();
|
||||
gst_object_set_parent (GST_OBJECT_CAST (self->reactables_manager), GST_OBJECT_CAST (self));
|
||||
|
||||
clapper_reactables_manager_trigger_prepare (self->reactables_manager);
|
||||
}
|
||||
|
||||
self->position_query = gst_query_new_position (GST_FORMAT_TIME);
|
||||
|
||||
self->current_state = GST_STATE_NULL;
|
||||
@@ -2392,6 +2410,11 @@ clapper_player_finalize (GObject *object)
|
||||
gst_object_unparent (GST_OBJECT_CAST (self->subtitle_streams));
|
||||
gst_object_unref (self->subtitle_streams);
|
||||
|
||||
if (self->reactables_manager) {
|
||||
gst_object_unparent (GST_OBJECT_CAST (self->reactables_manager));
|
||||
gst_object_unref (self->reactables_manager);
|
||||
}
|
||||
|
||||
gst_object_unparent (GST_OBJECT_CAST (self->enhancer_proxies));
|
||||
gst_object_unref (self->enhancer_proxies);
|
||||
|
||||
|
@@ -29,6 +29,8 @@
|
||||
#include "clapper-media-item-private.h"
|
||||
#include "clapper-player-private.h"
|
||||
#include "clapper-playbin-bus-private.h"
|
||||
#include "clapper-reactables-manager-private.h"
|
||||
#include "clapper-features-manager-private.h"
|
||||
|
||||
#define CLAPPER_QUEUE_GET_REC_LOCK(obj) (&CLAPPER_QUEUE_CAST(obj)->rec_lock)
|
||||
#define CLAPPER_QUEUE_REC_LOCK(obj) g_rec_mutex_lock (CLAPPER_QUEUE_GET_REC_LOCK(obj))
|
||||
@@ -132,15 +134,27 @@ _announce_model_update (ClapperQueue *self, guint index, guint removed, guint ad
|
||||
if (removed != added) {
|
||||
ClapperPlayer *player = clapper_player_get_from_ancestor (GST_OBJECT_CAST (self));
|
||||
|
||||
if (player && clapper_player_get_have_features (player)) {
|
||||
if (added == 1) // addition
|
||||
clapper_features_manager_trigger_queue_item_added (player->features_manager, changed_item, index);
|
||||
else if (removed == 1) // removal
|
||||
clapper_features_manager_trigger_queue_item_removed (player->features_manager, changed_item, index);
|
||||
else if (removed > 1 && added == 0) // queue cleared
|
||||
clapper_features_manager_trigger_queue_cleared (player->features_manager);
|
||||
else
|
||||
if (player) {
|
||||
gboolean have_features = clapper_player_get_have_features (player);
|
||||
|
||||
if (added == 1) { // addition
|
||||
if (player->reactables_manager)
|
||||
clapper_reactables_manager_trigger_queue_item_added (player->reactables_manager, changed_item, index);
|
||||
if (have_features)
|
||||
clapper_features_manager_trigger_queue_item_added (player->features_manager, changed_item, index);
|
||||
} else if (removed == 1) { // removal
|
||||
if (player->reactables_manager)
|
||||
clapper_reactables_manager_trigger_queue_item_removed (player->reactables_manager, changed_item, index);
|
||||
if (have_features)
|
||||
clapper_features_manager_trigger_queue_item_removed (player->features_manager, changed_item, index);
|
||||
} else if (removed > 1 && added == 0) { // queue cleared
|
||||
if (player->reactables_manager)
|
||||
clapper_reactables_manager_trigger_queue_cleared (player->reactables_manager);
|
||||
if (have_features)
|
||||
clapper_features_manager_trigger_queue_cleared (player->features_manager);
|
||||
} else {
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
}
|
||||
|
||||
gst_clear_object (&player);
|
||||
@@ -160,6 +174,8 @@ _announce_reposition (ClapperQueue *self, guint before, guint after)
|
||||
GST_DEBUG_OBJECT (self, "Announcing item reposition: %u -> %u", before, after);
|
||||
|
||||
if ((player = clapper_player_get_from_ancestor (GST_OBJECT_CAST (self)))) {
|
||||
if (player->reactables_manager)
|
||||
clapper_reactables_manager_trigger_queue_item_repositioned (player->reactables_manager, before, after);
|
||||
if (clapper_player_get_have_features (player))
|
||||
clapper_features_manager_trigger_queue_item_repositioned (player->features_manager, before, after);
|
||||
|
||||
@@ -989,6 +1005,8 @@ clapper_queue_set_progression_mode (ClapperQueue *self, ClapperQueueProgressionM
|
||||
|
||||
clapper_app_bus_post_prop_notify (player->app_bus,
|
||||
GST_OBJECT_CAST (self), param_specs[PROP_PROGRESSION_MODE]);
|
||||
if (player->reactables_manager)
|
||||
clapper_reactables_manager_trigger_queue_progression_changed (player->reactables_manager, mode);
|
||||
if (clapper_player_get_have_features (player))
|
||||
clapper_features_manager_trigger_queue_progression_changed (player->features_manager, mode);
|
||||
|
||||
|
82
src/lib/clapper/clapper-reactables-manager-private.h
Normal file
82
src/lib/clapper/clapper-reactables-manager-private.h
Normal file
@@ -0,0 +1,82 @@
|
||||
/* Clapper Playback Library
|
||||
* Copyright (C) 2025 Rafał Dzięgiel <rafostar.github@gmail.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "clapper-enums.h"
|
||||
#include "clapper-threaded-object.h"
|
||||
#include "clapper-enhancer-proxy.h"
|
||||
#include "clapper-media-item.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define CLAPPER_TYPE_REACTABLES_MANAGER (clapper_reactables_manager_get_type())
|
||||
#define CLAPPER_REACTABLES_MANAGER_CAST(obj) ((ClapperReactablesManager *)(obj))
|
||||
|
||||
G_DECLARE_FINAL_TYPE (ClapperReactablesManager, clapper_reactables_manager, CLAPPER, REACTABLES_MANAGER, ClapperThreadedObject)
|
||||
|
||||
G_GNUC_INTERNAL
|
||||
void clapper_reactables_manager_initialize (void);
|
||||
|
||||
G_GNUC_INTERNAL
|
||||
ClapperReactablesManager * clapper_reactables_manager_new (void);
|
||||
|
||||
G_GNUC_INTERNAL
|
||||
void clapper_reactables_manager_trigger_prepare (ClapperReactablesManager *manager);
|
||||
|
||||
G_GNUC_INTERNAL
|
||||
void clapper_reactables_manager_trigger_configure_take_config (ClapperReactablesManager *manager, ClapperEnhancerProxy *proxy, GstStructure *config);
|
||||
|
||||
G_GNUC_INTERNAL
|
||||
void clapper_reactables_manager_trigger_state_changed (ClapperReactablesManager *manager, ClapperPlayerState state);
|
||||
|
||||
G_GNUC_INTERNAL
|
||||
void clapper_reactables_manager_trigger_position_changed (ClapperReactablesManager *manager, gdouble position);
|
||||
|
||||
G_GNUC_INTERNAL
|
||||
void clapper_reactables_manager_trigger_speed_changed (ClapperReactablesManager *manager, gdouble speed);
|
||||
|
||||
G_GNUC_INTERNAL
|
||||
void clapper_reactables_manager_trigger_volume_changed (ClapperReactablesManager *manager, gdouble volume);
|
||||
|
||||
G_GNUC_INTERNAL
|
||||
void clapper_reactables_manager_trigger_mute_changed (ClapperReactablesManager *manager, gboolean mute);
|
||||
|
||||
G_GNUC_INTERNAL
|
||||
void clapper_reactables_manager_trigger_played_item_changed (ClapperReactablesManager *manager, ClapperMediaItem *item);
|
||||
|
||||
G_GNUC_INTERNAL
|
||||
void clapper_reactables_manager_trigger_item_updated (ClapperReactablesManager *manager, ClapperMediaItem *item);
|
||||
|
||||
G_GNUC_INTERNAL
|
||||
void clapper_reactables_manager_trigger_queue_item_added (ClapperReactablesManager *manager, ClapperMediaItem *item, guint index);
|
||||
|
||||
G_GNUC_INTERNAL
|
||||
void clapper_reactables_manager_trigger_queue_item_removed (ClapperReactablesManager *manager, ClapperMediaItem *item, guint index);
|
||||
|
||||
G_GNUC_INTERNAL
|
||||
void clapper_reactables_manager_trigger_queue_item_repositioned (ClapperReactablesManager *manager, guint before, guint after);
|
||||
|
||||
G_GNUC_INTERNAL
|
||||
void clapper_reactables_manager_trigger_queue_cleared (ClapperReactablesManager *manager);
|
||||
|
||||
G_GNUC_INTERNAL
|
||||
void clapper_reactables_manager_trigger_queue_progression_changed (ClapperReactablesManager *manager, ClapperQueueProgressionMode mode);
|
||||
|
||||
G_END_DECLS
|
533
src/lib/clapper/clapper-reactables-manager.c
Normal file
533
src/lib/clapper/clapper-reactables-manager.c
Normal file
@@ -0,0 +1,533 @@
|
||||
/* Clapper Playback Library
|
||||
* Copyright (C) 2025 Rafał Dzięgiel <rafostar.github@gmail.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include <gst/gst.h>
|
||||
|
||||
#include "clapper-reactables-manager-private.h"
|
||||
#include "clapper-reactable.h"
|
||||
#include "clapper-bus-private.h"
|
||||
#include "clapper-player.h"
|
||||
#include "clapper-enhancer-proxy-list.h"
|
||||
#include "clapper-enhancer-proxy-private.h"
|
||||
#include "clapper-utils-private.h"
|
||||
|
||||
#include "clapper-functionalities-availability.h"
|
||||
|
||||
#if CLAPPER_WITH_ENHANCERS_LOADER
|
||||
#include "clapper-enhancers-loader-private.h"
|
||||
#endif
|
||||
|
||||
#define CONFIG_STRUCTURE_NAME "config"
|
||||
|
||||
#define GST_CAT_DEFAULT clapper_reactables_manager_debug
|
||||
GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
|
||||
|
||||
struct _ClapperReactablesManager
|
||||
{
|
||||
ClapperThreadedObject parent;
|
||||
|
||||
GstBus *bus;
|
||||
GPtrArray *array;
|
||||
};
|
||||
|
||||
#define parent_class clapper_reactables_manager_parent_class
|
||||
G_DEFINE_TYPE (ClapperReactablesManager, clapper_reactables_manager, CLAPPER_TYPE_THREADED_OBJECT);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
ClapperReactable *reactable;
|
||||
ClapperEnhancerProxy *proxy;
|
||||
GSettings *settings;
|
||||
} ClapperReactableManagerData;
|
||||
|
||||
enum
|
||||
{
|
||||
CLAPPER_REACTABLES_MANAGER_EVENT_INVALID = 0,
|
||||
CLAPPER_REACTABLES_MANAGER_EVENT_STATE_CHANGED,
|
||||
CLAPPER_REACTABLES_MANAGER_EVENT_POSITION_CHANGED,
|
||||
CLAPPER_REACTABLES_MANAGER_EVENT_SPEED_CHANGED,
|
||||
CLAPPER_REACTABLES_MANAGER_EVENT_VOLUME_CHANGED,
|
||||
CLAPPER_REACTABLES_MANAGER_EVENT_MUTE_CHANGED,
|
||||
CLAPPER_REACTABLES_MANAGER_EVENT_PLAYED_ITEM_CHANGED,
|
||||
CLAPPER_REACTABLES_MANAGER_EVENT_ITEM_UPDATED,
|
||||
CLAPPER_REACTABLES_MANAGER_EVENT_QUEUE_ITEM_ADDED,
|
||||
CLAPPER_REACTABLES_MANAGER_EVENT_QUEUE_ITEM_REMOVED,
|
||||
CLAPPER_REACTABLES_MANAGER_EVENT_QUEUE_ITEM_REPOSITIONED,
|
||||
CLAPPER_REACTABLES_MANAGER_EVENT_QUEUE_CLEARED,
|
||||
CLAPPER_REACTABLES_MANAGER_EVENT_QUEUE_PROGRESSION_CHANGED
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
CLAPPER_REACTABLES_MANAGER_QUARK_PREPARE = 0,
|
||||
CLAPPER_REACTABLES_MANAGER_QUARK_CONFIGURE,
|
||||
CLAPPER_REACTABLES_MANAGER_QUARK_EVENT,
|
||||
CLAPPER_REACTABLES_MANAGER_QUARK_VALUE,
|
||||
CLAPPER_REACTABLES_MANAGER_QUARK_EXTRA_VALUE
|
||||
};
|
||||
|
||||
static ClapperBusQuark _quarks[] = {
|
||||
{"prepare", 0},
|
||||
{"configure", 0},
|
||||
{"event", 0},
|
||||
{"value", 0},
|
||||
{"extra-value", 0},
|
||||
{NULL, 0}
|
||||
};
|
||||
|
||||
#define _EVENT(e) G_PASTE(CLAPPER_REACTABLES_MANAGER_EVENT_, e)
|
||||
#define _QUARK(q) (_quarks[CLAPPER_REACTABLES_MANAGER_QUARK_##q].quark)
|
||||
|
||||
#define _BUS_POST_EVENT_SINGLE(event_id,lower,type,val) { \
|
||||
GValue _value = G_VALUE_INIT; \
|
||||
g_value_init (&_value, type); \
|
||||
g_value_set_##lower (&_value, val); \
|
||||
_bus_post_event (self, event_id, &_value, NULL); }
|
||||
|
||||
#define _BUS_POST_EVENT_DUAL(event_id,lower1,type1,val1,lower2,type2,val2) { \
|
||||
GValue _value1 = G_VALUE_INIT; \
|
||||
GValue _value2 = G_VALUE_INIT; \
|
||||
g_value_init (&_value1, type1); \
|
||||
g_value_init (&_value2, type2); \
|
||||
g_value_set_##lower1 (&_value1, val1); \
|
||||
g_value_set_##lower2 (&_value2, val2); \
|
||||
_bus_post_event (self, event_id, &_value1, &_value2); }
|
||||
|
||||
void
|
||||
clapper_reactables_manager_initialize (void)
|
||||
{
|
||||
gint i;
|
||||
|
||||
for (i = 0; _quarks[i].name; ++i)
|
||||
_quarks[i].quark = g_quark_from_static_string (_quarks[i].name);
|
||||
}
|
||||
|
||||
static void
|
||||
_settings_changed_cb (GSettings *settings, const gchar *key, ClapperReactableManagerData *data)
|
||||
{
|
||||
GST_DEBUG_OBJECT (data->reactable, "Global setting \"%s\" changed", key);
|
||||
|
||||
/* Local settings are applied through bus events, so all that is
|
||||
* needed here is a check to not overwrite locally set setting */
|
||||
if (!clapper_enhancer_proxy_has_locally_set (data->proxy, key)) {
|
||||
GVariant *variant = g_settings_get_value (settings, key);
|
||||
GValue value = G_VALUE_INIT;
|
||||
|
||||
if (G_LIKELY (clapper_utils_set_value_from_variant (&value, variant))) {
|
||||
g_object_set_property (G_OBJECT (data->reactable), key, &value);
|
||||
g_value_unset (&value);
|
||||
}
|
||||
|
||||
g_variant_unref (variant);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
clapper_reactables_manager_handle_prepare (ClapperReactablesManager *self)
|
||||
{
|
||||
ClapperPlayer *player;
|
||||
|
||||
GST_INFO_OBJECT (self, "Preparing reactable enhancers");
|
||||
player = CLAPPER_PLAYER_CAST (gst_object_get_parent (GST_OBJECT_CAST (self)));
|
||||
|
||||
if (G_LIKELY (player != NULL)) {
|
||||
ClapperEnhancerProxyList *proxies = clapper_player_get_enhancer_proxies (player);
|
||||
guint i, n_proxies = clapper_enhancer_proxy_list_get_n_proxies (proxies);
|
||||
|
||||
for (i = 0; i < n_proxies; ++i) {
|
||||
ClapperEnhancerProxy *proxy = clapper_enhancer_proxy_list_peek_proxy (proxies, i);
|
||||
ClapperReactable *reactable = NULL;
|
||||
|
||||
if (!clapper_enhancer_proxy_target_has_interface (proxy, CLAPPER_TYPE_REACTABLE))
|
||||
continue;
|
||||
|
||||
#if CLAPPER_WITH_ENHANCERS_LOADER
|
||||
reactable = CLAPPER_REACTABLE_CAST (
|
||||
clapper_enhancers_loader_create_enhancer (proxy, CLAPPER_TYPE_REACTABLE));
|
||||
#endif
|
||||
|
||||
if (G_LIKELY (reactable != NULL)) {
|
||||
ClapperReactableManagerData *data;
|
||||
GstStructure *config;
|
||||
|
||||
if (g_object_is_floating (reactable))
|
||||
gst_object_ref_sink (reactable);
|
||||
|
||||
data = g_new (ClapperReactableManagerData, 1);
|
||||
data->reactable = reactable;
|
||||
data->proxy = gst_object_ref (proxy);
|
||||
data->settings = clapper_enhancer_proxy_get_settings (proxy);
|
||||
|
||||
GST_TRACE_OBJECT (self, "Created data for reactable: %" GST_PTR_FORMAT, data->reactable);
|
||||
|
||||
/* Settings are stored in data in order for this signal to keep working */
|
||||
if (data->settings)
|
||||
g_signal_connect (data->settings, "changed", G_CALLBACK (_settings_changed_cb), data);
|
||||
|
||||
if ((config = clapper_enhancer_proxy_make_current_config (proxy))) {
|
||||
clapper_enhancer_proxy_apply_config_to_enhancer (proxy, config, (GObject *) reactable);
|
||||
gst_structure_free (config);
|
||||
}
|
||||
|
||||
g_ptr_array_add (self->array, data);
|
||||
gst_object_set_parent (GST_OBJECT_CAST (data->reactable), GST_OBJECT_CAST (player));
|
||||
}
|
||||
}
|
||||
|
||||
GST_INFO_OBJECT (self, "Prepared %i reactable enhancers", self->array->len);
|
||||
gst_object_unref (player);
|
||||
} else {
|
||||
GST_ERROR_OBJECT (self, "Could not prepare reactable enhancers!");
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
clapper_reactables_manager_handle_configure (ClapperReactablesManager *self, const GstStructure *structure)
|
||||
{
|
||||
const GValue *proxy_val, *config_val;
|
||||
ClapperEnhancerProxy *proxy;
|
||||
const GstStructure *config;
|
||||
guint i;
|
||||
|
||||
proxy_val = gst_structure_id_get_value (structure, _QUARK (VALUE));
|
||||
config_val = gst_structure_id_get_value (structure, _QUARK (EXTRA_VALUE));
|
||||
|
||||
proxy = CLAPPER_ENHANCER_PROXY_CAST (g_value_get_object (proxy_val));
|
||||
config = gst_value_get_structure (config_val);
|
||||
|
||||
for (i = 0; i < self->array->len; ++i) {
|
||||
ClapperReactableManagerData *data = g_ptr_array_index (self->array, i);
|
||||
|
||||
if (data->proxy == proxy) {
|
||||
clapper_enhancer_proxy_apply_config_to_enhancer (data->proxy,
|
||||
config, (GObject *) data->reactable);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
GST_ERROR_OBJECT (self, "Triggered configure, but no matching enhancer proxy found");
|
||||
}
|
||||
|
||||
static inline void
|
||||
clapper_reactables_manager_handle_event (ClapperReactablesManager *self, const GstStructure *structure)
|
||||
{
|
||||
const GValue *value = gst_structure_id_get_value (structure, _QUARK (VALUE));
|
||||
const GValue *extra_value = gst_structure_id_get_value (structure, _QUARK (EXTRA_VALUE));
|
||||
guint i, event_id;
|
||||
|
||||
if (G_UNLIKELY (!gst_structure_id_get (structure,
|
||||
_QUARK (EVENT), G_TYPE_ENUM, &event_id, NULL))) {
|
||||
GST_ERROR_OBJECT (self, "Could not read event ID");
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < self->array->len; ++i) {
|
||||
ClapperReactableManagerData *data = g_ptr_array_index (self->array, i);
|
||||
ClapperReactableInterface *reactable_iface = CLAPPER_REACTABLE_GET_IFACE (data->reactable);
|
||||
|
||||
switch (event_id) {
|
||||
case _EVENT (STATE_CHANGED):
|
||||
if (reactable_iface->state_changed)
|
||||
reactable_iface->state_changed (data->reactable, g_value_get_int (value));
|
||||
break;
|
||||
case _EVENT (POSITION_CHANGED):
|
||||
if (reactable_iface->position_changed)
|
||||
reactable_iface->position_changed (data->reactable, g_value_get_double (value));
|
||||
break;
|
||||
case _EVENT (SPEED_CHANGED):
|
||||
if (reactable_iface->speed_changed)
|
||||
reactable_iface->speed_changed (data->reactable, g_value_get_double (value));
|
||||
break;
|
||||
case _EVENT (VOLUME_CHANGED):
|
||||
if (reactable_iface->volume_changed)
|
||||
reactable_iface->volume_changed (data->reactable, g_value_get_double (value));
|
||||
break;
|
||||
case _EVENT (MUTE_CHANGED):
|
||||
if (reactable_iface->mute_changed)
|
||||
reactable_iface->mute_changed (data->reactable, g_value_get_boolean (value));
|
||||
break;
|
||||
case _EVENT (PLAYED_ITEM_CHANGED):
|
||||
if (reactable_iface->played_item_changed) {
|
||||
reactable_iface->played_item_changed (data->reactable,
|
||||
CLAPPER_MEDIA_ITEM_CAST (g_value_get_object (value)));
|
||||
}
|
||||
break;
|
||||
case _EVENT (ITEM_UPDATED):
|
||||
if (reactable_iface->item_updated) {
|
||||
reactable_iface->item_updated (data->reactable,
|
||||
CLAPPER_MEDIA_ITEM_CAST (g_value_get_object (value)));
|
||||
}
|
||||
break;
|
||||
case _EVENT (QUEUE_ITEM_ADDED):
|
||||
if (reactable_iface->queue_item_added) {
|
||||
reactable_iface->queue_item_added (data->reactable,
|
||||
CLAPPER_MEDIA_ITEM_CAST (g_value_get_object (value)),
|
||||
g_value_get_uint (extra_value));
|
||||
}
|
||||
break;
|
||||
case _EVENT (QUEUE_ITEM_REMOVED):
|
||||
if (reactable_iface->queue_item_removed) {
|
||||
reactable_iface->queue_item_removed (data->reactable,
|
||||
CLAPPER_MEDIA_ITEM_CAST (g_value_get_object (value)),
|
||||
g_value_get_uint (extra_value));
|
||||
}
|
||||
break;
|
||||
case _EVENT (QUEUE_ITEM_REPOSITIONED):
|
||||
if (reactable_iface->queue_item_repositioned) {
|
||||
reactable_iface->queue_item_repositioned (data->reactable,
|
||||
g_value_get_uint (value),
|
||||
g_value_get_uint (extra_value));
|
||||
}
|
||||
break;
|
||||
case _EVENT (QUEUE_CLEARED):
|
||||
if (reactable_iface->queue_cleared)
|
||||
reactable_iface->queue_cleared (data->reactable);
|
||||
break;
|
||||
case _EVENT (QUEUE_PROGRESSION_CHANGED):
|
||||
if (reactable_iface->queue_progression_changed)
|
||||
reactable_iface->queue_progression_changed (data->reactable, g_value_get_int (value));
|
||||
break;
|
||||
default:
|
||||
GST_ERROR_OBJECT (self, "Invalid event ID on reactables bus: %u", event_id);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
_bus_message_func (GstBus *bus, GstMessage *msg, gpointer user_data G_GNUC_UNUSED)
|
||||
{
|
||||
if (G_LIKELY (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_APPLICATION)) {
|
||||
ClapperReactablesManager *self = CLAPPER_REACTABLES_MANAGER_CAST (GST_MESSAGE_SRC (msg));
|
||||
const GstStructure *structure = gst_message_get_structure (msg);
|
||||
GQuark quark = gst_structure_get_name_id (structure);
|
||||
|
||||
if (quark == _QUARK (EVENT)) {
|
||||
clapper_reactables_manager_handle_event (self, structure);
|
||||
} else if (quark == _QUARK (PREPARE)) {
|
||||
clapper_reactables_manager_handle_prepare (self);
|
||||
} else if (quark == _QUARK (CONFIGURE)) {
|
||||
clapper_reactables_manager_handle_configure (self, structure);
|
||||
} else {
|
||||
GST_ERROR_OBJECT (self, "Received invalid quark on reactables bus!");
|
||||
}
|
||||
}
|
||||
|
||||
return G_SOURCE_CONTINUE;
|
||||
}
|
||||
|
||||
static void
|
||||
_bus_post_event (ClapperReactablesManager *self, guint event_id,
|
||||
GValue *value, GValue *extra_value)
|
||||
{
|
||||
GstStructure *structure = gst_structure_new_id (_QUARK (EVENT),
|
||||
_QUARK (EVENT), G_TYPE_ENUM, event_id,
|
||||
NULL);
|
||||
|
||||
if (value)
|
||||
gst_structure_id_take_value (structure, _QUARK (VALUE), value);
|
||||
if (extra_value)
|
||||
gst_structure_id_take_value (structure, _QUARK (EXTRA_VALUE), extra_value);
|
||||
|
||||
gst_bus_post (self->bus, gst_message_new_application (
|
||||
GST_OBJECT_CAST (self), structure));
|
||||
}
|
||||
|
||||
/*
|
||||
* clapper_reactables_manager_new:
|
||||
*
|
||||
* Returns: (transfer full): a new #ClapperReactablesManager instance.
|
||||
*/
|
||||
ClapperReactablesManager *
|
||||
clapper_reactables_manager_new (void)
|
||||
{
|
||||
ClapperReactablesManager *reactables_manager;
|
||||
|
||||
reactables_manager = g_object_new (CLAPPER_TYPE_REACTABLES_MANAGER, NULL);
|
||||
gst_object_ref_sink (reactables_manager);
|
||||
|
||||
return reactables_manager;
|
||||
}
|
||||
|
||||
void
|
||||
clapper_reactables_manager_trigger_prepare (ClapperReactablesManager *self)
|
||||
{
|
||||
GstStructure *structure = gst_structure_new_id_empty (_QUARK (PREPARE));
|
||||
|
||||
gst_bus_post (self->bus, gst_message_new_application (
|
||||
GST_OBJECT_CAST (self), structure));
|
||||
}
|
||||
|
||||
void
|
||||
clapper_reactables_manager_trigger_configure_take_config (ClapperReactablesManager *self,
|
||||
ClapperEnhancerProxy *proxy, GstStructure *config)
|
||||
{
|
||||
GstStructure *structure = gst_structure_new_id (_QUARK (CONFIGURE),
|
||||
_QUARK (VALUE), G_TYPE_OBJECT, proxy, NULL);
|
||||
GValue extra_value = G_VALUE_INIT;
|
||||
|
||||
g_value_init (&extra_value, GST_TYPE_STRUCTURE);
|
||||
g_value_take_boxed (&extra_value, config);
|
||||
|
||||
gst_structure_id_take_value (structure, _QUARK (EXTRA_VALUE), &extra_value);
|
||||
|
||||
gst_bus_post (self->bus, gst_message_new_application (
|
||||
GST_OBJECT_CAST (self), structure));
|
||||
}
|
||||
|
||||
void
|
||||
clapper_reactables_manager_trigger_state_changed (ClapperReactablesManager *self, ClapperPlayerState state)
|
||||
{
|
||||
_BUS_POST_EVENT_SINGLE (_EVENT (STATE_CHANGED), int, G_TYPE_INT, state);
|
||||
}
|
||||
|
||||
void
|
||||
clapper_reactables_manager_trigger_position_changed (ClapperReactablesManager *self, gdouble position)
|
||||
{
|
||||
_BUS_POST_EVENT_SINGLE (_EVENT (POSITION_CHANGED), double, G_TYPE_DOUBLE, position);
|
||||
}
|
||||
|
||||
void
|
||||
clapper_reactables_manager_trigger_speed_changed (ClapperReactablesManager *self, gdouble speed)
|
||||
{
|
||||
_BUS_POST_EVENT_SINGLE (_EVENT (SPEED_CHANGED), double, G_TYPE_DOUBLE, speed);
|
||||
}
|
||||
|
||||
void
|
||||
clapper_reactables_manager_trigger_volume_changed (ClapperReactablesManager *self, gdouble volume)
|
||||
{
|
||||
_BUS_POST_EVENT_SINGLE (_EVENT (VOLUME_CHANGED), double, G_TYPE_DOUBLE, volume);
|
||||
}
|
||||
|
||||
void
|
||||
clapper_reactables_manager_trigger_mute_changed (ClapperReactablesManager *self, gboolean mute)
|
||||
{
|
||||
_BUS_POST_EVENT_SINGLE (_EVENT (MUTE_CHANGED), boolean, G_TYPE_BOOLEAN, mute);
|
||||
}
|
||||
|
||||
void
|
||||
clapper_reactables_manager_trigger_played_item_changed (ClapperReactablesManager *self, ClapperMediaItem *item)
|
||||
{
|
||||
_BUS_POST_EVENT_SINGLE (_EVENT (PLAYED_ITEM_CHANGED), object, CLAPPER_TYPE_MEDIA_ITEM, item);
|
||||
}
|
||||
|
||||
void
|
||||
clapper_reactables_manager_trigger_item_updated (ClapperReactablesManager *self, ClapperMediaItem *item)
|
||||
{
|
||||
_BUS_POST_EVENT_SINGLE (_EVENT (ITEM_UPDATED), object, CLAPPER_TYPE_MEDIA_ITEM, item);
|
||||
}
|
||||
|
||||
void
|
||||
clapper_reactables_manager_trigger_queue_item_added (ClapperReactablesManager *self, ClapperMediaItem *item, guint index)
|
||||
{
|
||||
_BUS_POST_EVENT_DUAL (_EVENT (QUEUE_ITEM_ADDED), object, CLAPPER_TYPE_MEDIA_ITEM, item, uint, G_TYPE_UINT, index);
|
||||
}
|
||||
|
||||
void
|
||||
clapper_reactables_manager_trigger_queue_item_removed (ClapperReactablesManager *self, ClapperMediaItem *item, guint index)
|
||||
{
|
||||
_BUS_POST_EVENT_DUAL (_EVENT (QUEUE_ITEM_REMOVED), object, CLAPPER_TYPE_MEDIA_ITEM, item, uint, G_TYPE_UINT, index);
|
||||
}
|
||||
|
||||
void
|
||||
clapper_reactables_manager_trigger_queue_item_repositioned (ClapperReactablesManager *self, guint before, guint after)
|
||||
{
|
||||
_BUS_POST_EVENT_DUAL (_EVENT (QUEUE_ITEM_REPOSITIONED), uint, G_TYPE_UINT, before, uint, G_TYPE_UINT, after);
|
||||
}
|
||||
|
||||
void
|
||||
clapper_reactables_manager_trigger_queue_cleared (ClapperReactablesManager *self)
|
||||
{
|
||||
_bus_post_event (self, _EVENT (QUEUE_CLEARED), NULL, NULL);
|
||||
}
|
||||
|
||||
void
|
||||
clapper_reactables_manager_trigger_queue_progression_changed (ClapperReactablesManager *self, ClapperQueueProgressionMode mode)
|
||||
{
|
||||
_BUS_POST_EVENT_SINGLE (_EVENT (QUEUE_PROGRESSION_CHANGED), int, G_TYPE_INT, mode);
|
||||
}
|
||||
|
||||
static void
|
||||
_data_remove_func (ClapperReactableManagerData *data)
|
||||
{
|
||||
GST_TRACE ("Removing data for reactable: %" GST_PTR_FORMAT, data->reactable);
|
||||
|
||||
g_clear_object (&data->settings);
|
||||
|
||||
gst_object_unparent (GST_OBJECT_CAST (data->reactable));
|
||||
gst_object_unref (data->reactable);
|
||||
|
||||
gst_object_unref (data->proxy);
|
||||
g_free (data);
|
||||
}
|
||||
|
||||
static void
|
||||
clapper_reactables_manager_thread_start (ClapperThreadedObject *threaded_object)
|
||||
{
|
||||
ClapperReactablesManager *self = CLAPPER_REACTABLES_MANAGER_CAST (threaded_object);
|
||||
|
||||
GST_TRACE_OBJECT (threaded_object, "Reactables manager thread start");
|
||||
|
||||
self->array = g_ptr_array_new_with_free_func (
|
||||
(GDestroyNotify) _data_remove_func);
|
||||
|
||||
self->bus = gst_bus_new ();
|
||||
gst_bus_add_watch (self->bus, (GstBusFunc) _bus_message_func, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
clapper_reactables_manager_thread_stop (ClapperThreadedObject *threaded_object)
|
||||
{
|
||||
ClapperReactablesManager *self = CLAPPER_REACTABLES_MANAGER_CAST (threaded_object);
|
||||
|
||||
GST_TRACE_OBJECT (self, "Reactables manager thread stop");
|
||||
|
||||
gst_bus_set_flushing (self->bus, TRUE);
|
||||
gst_bus_remove_watch (self->bus);
|
||||
gst_clear_object (&self->bus);
|
||||
|
||||
g_ptr_array_unref (self->array);
|
||||
}
|
||||
|
||||
static void
|
||||
clapper_reactables_manager_init (ClapperReactablesManager *self)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
clapper_reactables_manager_finalize (GObject *object)
|
||||
{
|
||||
GST_TRACE_OBJECT (object, "Finalize");
|
||||
G_OBJECT_CLASS (parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
clapper_reactables_manager_class_init (ClapperReactablesManagerClass *klass)
|
||||
{
|
||||
GObjectClass *gobject_class = (GObjectClass *) klass;
|
||||
ClapperThreadedObjectClass *threaded_object = (ClapperThreadedObjectClass *) klass;
|
||||
|
||||
GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "clapperreactablesmanager", 0,
|
||||
"Clapper Reactables Manager");
|
||||
|
||||
gobject_class->finalize = clapper_reactables_manager_finalize;
|
||||
|
||||
threaded_object->thread_start = clapper_reactables_manager_thread_start;
|
||||
threaded_object->thread_stop = clapper_reactables_manager_thread_stop;
|
||||
}
|
@@ -29,6 +29,8 @@
|
||||
#include "clapper-timeline-private.h"
|
||||
#include "clapper-marker-private.h"
|
||||
#include "clapper-player-private.h"
|
||||
#include "clapper-reactables-manager-private.h"
|
||||
#include "clapper-features-manager-private.h"
|
||||
|
||||
#define GST_CAT_DEFAULT clapper_timeline_debug
|
||||
GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
|
||||
@@ -106,15 +108,17 @@ clapper_timeline_post_item_updated (ClapperTimeline *self)
|
||||
ClapperPlayer *player;
|
||||
|
||||
if ((player = clapper_player_get_from_ancestor (GST_OBJECT_CAST (self)))) {
|
||||
ClapperFeaturesManager *features_manager;
|
||||
ClapperMediaItem *item;
|
||||
|
||||
if ((features_manager = clapper_player_get_features_manager (player))) {
|
||||
ClapperMediaItem *item;
|
||||
if ((item = CLAPPER_MEDIA_ITEM_CAST (gst_object_get_parent (GST_OBJECT_CAST (self))))) {
|
||||
ClapperFeaturesManager *features_manager;
|
||||
|
||||
if ((item = CLAPPER_MEDIA_ITEM (gst_object_get_parent (GST_OBJECT_CAST (self))))) {
|
||||
if (player->reactables_manager)
|
||||
clapper_reactables_manager_trigger_item_updated (player->reactables_manager, item);
|
||||
if ((features_manager = clapper_player_get_features_manager (player)))
|
||||
clapper_features_manager_trigger_item_updated (features_manager, item);
|
||||
gst_object_unref (item);
|
||||
}
|
||||
|
||||
gst_object_unref (item);
|
||||
}
|
||||
|
||||
gst_object_unref (player);
|
||||
|
@@ -54,4 +54,7 @@ gchar * clapper_utils_uri_from_file (GFile *file);
|
||||
G_GNUC_INTERNAL
|
||||
gchar * clapper_utils_title_from_uri (const gchar *uri);
|
||||
|
||||
G_GNUC_INTERNAL
|
||||
gboolean clapper_utils_set_value_from_variant (GValue *value, GVariant *variant);
|
||||
|
||||
G_END_DECLS
|
||||
|
@@ -271,3 +271,59 @@ clapper_utils_title_from_uri (const gchar *uri)
|
||||
|
||||
return title;
|
||||
}
|
||||
|
||||
gboolean
|
||||
clapper_utils_set_value_from_variant (GValue *value, GVariant *variant)
|
||||
{
|
||||
const gchar *var_type = g_variant_get_type_string (variant);
|
||||
GType val_type;
|
||||
|
||||
switch (var_type[0]) {
|
||||
case 'b':
|
||||
val_type = G_TYPE_BOOLEAN;
|
||||
break;
|
||||
case 'i':
|
||||
val_type = G_TYPE_INT;
|
||||
break;
|
||||
case 'u':
|
||||
val_type = G_TYPE_UINT;
|
||||
break;
|
||||
case 'd':
|
||||
val_type = G_TYPE_DOUBLE;
|
||||
break;
|
||||
case 's':
|
||||
val_type = G_TYPE_STRING;
|
||||
break;
|
||||
default:
|
||||
goto error;
|
||||
}
|
||||
|
||||
g_value_init (value, val_type);
|
||||
|
||||
switch (val_type) {
|
||||
case G_TYPE_BOOLEAN:
|
||||
g_value_set_boolean (value, g_variant_get_boolean (variant));
|
||||
break;
|
||||
case G_TYPE_INT:
|
||||
g_value_set_int (value, g_variant_get_int32 (variant));
|
||||
break;
|
||||
case G_TYPE_UINT:
|
||||
g_value_set_uint (value, g_variant_get_uint32 (variant));
|
||||
break;
|
||||
case G_TYPE_DOUBLE:
|
||||
g_value_set_double (value, g_variant_get_double (variant));
|
||||
break;
|
||||
case G_TYPE_STRING:
|
||||
g_value_set_string (value, g_variant_get_string (variant, NULL));
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
break;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
|
||||
error:
|
||||
GST_ERROR ("Unsupported conversion for variant type: %s", var_type);
|
||||
return FALSE;
|
||||
}
|
||||
|
@@ -23,36 +23,13 @@
|
||||
|
||||
#include "../clapper-basic-functions.h"
|
||||
#include "../clapper-enhancer-proxy.h"
|
||||
#include "../clapper-enhancer-proxy-list.h"
|
||||
#include "../clapper-enhancer-proxy-list-private.h"
|
||||
#include "../clapper-extractable.h"
|
||||
|
||||
#include "clapper-plugin-private.h"
|
||||
#include "clapper-extractable-src-private.h"
|
||||
#include "clapper-uri-list-demux-private.h"
|
||||
|
||||
/*
|
||||
* clapper_gst_plugin_has_enhancers:
|
||||
* @iface_type: an interface #GType
|
||||
*
|
||||
* Check if any enhancer implementing given interface type is available.
|
||||
*
|
||||
* Returns: whether any enhancer was found.
|
||||
*/
|
||||
static gboolean
|
||||
clapper_gst_plugin_has_enhancers (ClapperEnhancerProxyList *proxies, GType iface_type)
|
||||
{
|
||||
guint i, n_proxies = clapper_enhancer_proxy_list_get_n_proxies (proxies);
|
||||
|
||||
for (i = 0; i < n_proxies; ++i) {
|
||||
ClapperEnhancerProxy *proxy = clapper_enhancer_proxy_list_peek_proxy (proxies, i);
|
||||
|
||||
if (clapper_enhancer_proxy_target_has_interface (proxy, iface_type))
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
clapper_gst_plugin_init (GstPlugin *plugin)
|
||||
{
|
||||
@@ -66,7 +43,7 @@ clapper_gst_plugin_init (GstPlugin *plugin)
|
||||
global_proxies = clapper_get_global_enhancer_proxies ();
|
||||
|
||||
/* Avoid registering an URI handler without schemes */
|
||||
if (clapper_gst_plugin_has_enhancers (global_proxies, CLAPPER_TYPE_EXTRACTABLE))
|
||||
if (clapper_enhancer_proxy_list_has_proxy_with_interface (global_proxies, CLAPPER_TYPE_EXTRACTABLE))
|
||||
res |= GST_ELEMENT_REGISTER (clapperextractablesrc, plugin);
|
||||
|
||||
res |= GST_ELEMENT_REGISTER (clapperurilistdemux, plugin);
|
||||
|
@@ -149,6 +149,7 @@ clapper_sources = [
|
||||
'clapper-player.c',
|
||||
'clapper-queue.c',
|
||||
'clapper-reactable.c',
|
||||
'clapper-reactables-manager.c',
|
||||
'clapper-stream.c',
|
||||
'clapper-stream-list.c',
|
||||
'clapper-subtitle-stream.c',
|
||||
|
Reference in New Issue
Block a user