From 65b547658c1717024cf09715800451c70a565aca Mon Sep 17 00:00:00 2001
From: Vito Caputo <vcaputo@pengaru.com>
Date: Thu, 11 May 2023 02:51:29 -0700
Subject: modules/rtv: settings-ize snow_module=

first step towards settings-izing rtv, channels[] remains
---
 src/modules/rtv/rtv.c | 106 ++++++++++++++++++++++++++++++++++++++++----------
 1 file changed, 85 insertions(+), 21 deletions(-)

diff --git a/src/modules/rtv/rtv.c b/src/modules/rtv/rtv.c
index f2b92a4..35d968a 100644
--- a/src/modules/rtv/rtv.c
+++ b/src/modules/rtv/rtv.c
@@ -60,7 +60,8 @@ typedef struct rtv_setup_t {
 	unsigned		context_duration;
 	unsigned		snow_duration;
 	unsigned		caption_duration;
-	char			*snow_module;
+	char			*snow_module_name;
+	til_setup_t		*snow_module_setup;
 	unsigned		log_channels:1;
 	char			*channels[];
 } rtv_setup_t;
@@ -196,7 +197,7 @@ static void setup_next_channel(rtv_context_t *ctxt, unsigned ticks)
 static int rtv_should_skip_module(const rtv_setup_t *setup, const til_module_t *module)
 {
 	if (module == &rtv_module ||
-	    (setup->snow_module && !strcasecmp(module->name, setup->snow_module)))
+	    (setup->snow_module_name && !strcasecmp(module->name, setup->snow_module_name)))
 		return 1;
 
 	/* An empty channels list is a special case for representing "all", an
@@ -243,9 +244,13 @@ static til_module_context_t * rtv_create_context(const til_module_t *module, til
 	ctxt->caption_duration = ((rtv_setup_t *)setup)->caption_duration;
 
 	ctxt->snow_channel.module = &rtv_none_module;
-	if (((rtv_setup_t *)setup)->snow_module) {
-		ctxt->snow_channel.module = til_lookup_module(((rtv_setup_t *)setup)->snow_module);
-		(void) til_module_create_context(ctxt->snow_channel.module, stream, rand_r(&seed), ticks, 0, path, NULL, &ctxt->snow_channel.module_ctxt);
+	if (((rtv_setup_t *)setup)->snow_module_name) {
+		/* ctxt takes ownership of the snow_module_setup */
+		ctxt->snow_channel.module_setup = ((rtv_setup_t *)setup)->snow_module_setup;
+		((rtv_setup_t *)setup)->snow_module_setup = NULL;
+
+		ctxt->snow_channel.module = til_lookup_module(((rtv_setup_t *)setup)->snow_module_name);
+		(void) til_module_create_context(ctxt->snow_channel.module, stream, rand_r(&seed), ticks, 0, path, ctxt->snow_channel.module_setup, &ctxt->snow_channel.module_ctxt);
 	}
 
 	ctxt->log_channels = ((rtv_setup_t *)setup)->log_channels;
@@ -266,6 +271,7 @@ static void rtv_destroy_context(til_module_context_t *context)
 	rtv_context_t	*ctxt = (rtv_context_t *)context;
 
 	/* TODO FIXME: cleanup better, snow module etc */
+	til_setup_free(ctxt->snow_channel.module_setup);
 	cleanup_channel(ctxt);
 	free(context);
 }
@@ -311,20 +317,34 @@ static void rtv_finish_frame(til_module_context_t *context, til_stream_t *stream
 
 static int rtv_setup(const til_settings_t *settings, til_setting_t **res_setting, const til_setting_desc_t **res_desc, til_setup_t **res_setup)
 {
-	const char	*channels;
-	const char	*duration;
-	const char	*context_duration;
-	const char	*caption_duration;
-	const char	*snow_duration;
-	const char	*snow_module;
-	const char	*log_channels;
-	const char	*log_channels_values[] = {
-				"no",
-				"yes",
-				NULL
-			};
-	int		r;
+	const til_settings_t	*snow_module_settings;
+	const char		*channels;
+	const char		*duration;
+	const char		*context_duration;
+	const char		*caption_duration;
+	const char		*snow_duration;
+	const char		*snow_module;
+	const char		*log_channels;
+	const char		*log_channels_values[] = {
+					"no",
+					"yes",
+					NULL
+				};
+	int			r;
+
+	/* TODO: turn channels[] into settings instances full of settings instances, like modules/compose::layers */
+	/* except the difference here is, we don't want to _require_ the setup process to fill out all the settings.
+	 * We'd like to allow leaving any to be randomized by rototiller on channel switch as unset or something.
+	 * But if we're calling down into the per-channel-module .setup() to
+	 * get the settings populated, it's out of our hands on if that setting
+	 * is required to be present or not.  The per-channel-module will
+	 * refuse to proceed to the next setting unless it's present and
+	 * described etc.  So it's like the front-end needs a way to set the
+	 * setting with a "randomize" attribute or somesuch, and rtv needs a way
+	 * to make that an available thing like we're in some kind of deferred
+	 * setup preparation phase for a settings instance that will be re-evaluated
 
+	 */
 	r = til_settings_get_and_describe_value(settings,
 						&(til_setting_spec_t){
 							.name = "Colon-separated list of channel modules, \"all\" for all",
@@ -399,7 +419,8 @@ static int rtv_setup(const til_settings_t *settings, til_setting_t **res_setting
 							.name = "Module for snow (\"blank\" for blanking, \"none\" to disable)",
 							.key = "snow_module",
 							.preferred = RTV_DEFAULT_SNOW_MODULE,
-							.annotations = NULL
+							.annotations = NULL,
+							.as_nested_settings = 1,
 						},
 						&snow_module,
 						res_setting,
@@ -407,6 +428,24 @@ static int rtv_setup(const til_settings_t *settings, til_setting_t **res_setting
 	if (r)
 		return r;
 
+	assert(res_setting && *res_setting && (*res_setting)->value_as_nested_settings);
+	snow_module_settings = (*res_setting)->value_as_nested_settings;
+	if (strcasecmp(snow_module, "none")) {
+		const char		*snow_module_name = til_settings_get_value_by_idx(snow_module_settings, 0, NULL);
+		const til_module_t	*snow_module = til_lookup_module(snow_module_name);
+
+		if (!snow_module)
+			return -EINVAL;
+
+		if (snow_module->setup) {
+			r = snow_module->setup(snow_module_settings, res_setting, res_desc, NULL);
+			if (r)
+				return r;
+		}
+
+		/* now snow_module settings are complete, but not yet baked (no res_setup) */
+	}
+
 	r = til_settings_get_and_describe_value(settings,
 						&(til_setting_spec_t){
 							.name = "Log channel settings to stderr",
@@ -476,8 +515,33 @@ static int rtv_setup(const til_settings_t *settings, til_setting_t **res_setting
 			} while ((channel = strtok(NULL, ":")));
 		}
 
-		if (strcasecmp(snow_module, "none"))
-			setup->snow_module = strdup(snow_module);
+		if (strcasecmp(snow_module, "none")) {
+			const char		*snow_module_name = til_settings_get_value_by_idx(snow_module_settings, 0, NULL);
+			const til_module_t	*snow_module = til_lookup_module(snow_module_name);
+
+			if (!snow_module) {
+				til_setup_free(&setup->til_setup);
+
+				return -EINVAL;
+			}
+
+			setup->snow_module_name = strdup(snow_module_name);
+			if (!setup->snow_module_name) {
+				til_setup_free(&setup->til_setup);
+
+				return -ENOMEM;
+			}
+
+			if (snow_module->setup) {
+				/* bake the snow_module settings */
+				r = snow_module->setup(snow_module_settings, res_setting, res_desc, &setup->snow_module_setup);
+				if (r < 0) {
+					til_setup_free(&setup->til_setup);
+
+					return r;
+				}
+			}
+		}
 
 		/* TODO FIXME: parse errors */
 		sscanf(duration, "%u", &setup->duration);
-- 
cgit v1.2.3