diff options
author | Vito Caputo <vcaputo@pengaru.com> | 2022-04-01 17:47:19 -0700 |
---|---|---|
committer | Vito Caputo <vcaputo@pengaru.com> | 2022-04-01 17:59:03 -0700 |
commit | 6b8790a22c38e0d5419eb5a4dac5e30f684ae473 (patch) | |
tree | 444ac5369c34a705cd302862928ccad237d68bfe /src/modules/rtv/rtv.c | |
parent | 78c275b094b63e01a5f7bc71af80fe787911bbf4 (diff) |
modules/*: instantiate and use setups
Now modules allocate and return an opaque setup pointer in
res_setup when they implement a setup method.
Defaults are utilized when ${module}_create_context() receives a
NULL setup. The default setup used in this case should match the
defaults/preferred values emitted by the module's setup method.
But performing setup should always be optional, so a NULL setup
provided to create_context() is to be expected.
No cleanup of these setup instances is currently performed, so
it's a small memory leak for now. Since these are opaque and may
contain nested references to other allocations, simply using
free() somewhere in the frontend is insufficient. There will
probably need to be something like a til_module_t.setup_free()
method added in the future which modules may assign libc's free()
to when appropriate, or their own more elaborate version.
Lifecycle for the settings is very simple; the setup method
returns an instance, the caller is expected to free it when no
longer needed (once free is implemented). The create_context
consumer of a given setup must make its own copy of the settings
if necessary, and may not keep a reference - it must assume the
setup will be freed immediately after create_context() returns.
This enables the ability to reuse a setup instance across
multiple create_context() calls if desired, one can imagine
something like running the same module with the same settings
multiple times across multiple displays for instance. If the
module has significant entropy the output will differ despite
being configured identically...
With this commit one may change settings for any of the modules
*while* the modules are actively rendering a given context, and
the settings should *not* be visible. They should only affect
the context they're supplied to.
Diffstat (limited to 'src/modules/rtv/rtv.c')
-rw-r--r-- | src/modules/rtv/rtv.c | 159 |
1 files changed, 101 insertions, 58 deletions
diff --git a/src/modules/rtv/rtv.c b/src/modules/rtv/rtv.c index b49ac37..217368c 100644 --- a/src/modules/rtv/rtv.c +++ b/src/modules/rtv/rtv.c @@ -20,6 +20,7 @@ #define RTV_DURATION_SECS 15 #define RTV_CAPTION_DURATION_SECS 5 #define RTV_CONTEXT_DURATION_SECS 60 +#define RTV_DEFAULT_SNOW_MODULE "snow" typedef struct rtv_channel_t { const til_module_t *module; @@ -38,12 +39,26 @@ typedef struct rtv_context_t { rtv_channel_t *channel, *last_channel; txt_t *caption; + unsigned duration; + unsigned context_duration; + unsigned snow_duration; + unsigned caption_duration; + rtv_channel_t snow_channel; size_t n_channels; rtv_channel_t channels[]; } rtv_context_t; +typedef struct rtv_setup_t { + unsigned duration; + unsigned context_duration; + unsigned snow_duration; + unsigned caption_duration; + char *snow_module; + char *channels[]; +} rtv_setup_t; + static void setup_next_channel(rtv_context_t *ctxt, unsigned ticks); static void * rtv_create_context(unsigned ticks, unsigned num_cpus, void *setup); static void rtv_destroy_context(void *context); @@ -51,12 +66,14 @@ static void rtv_prepare_frame(void *context, unsigned ticks, unsigned n_cpus, ti static void rtv_finish_frame(void *context, unsigned ticks, til_fb_fragment_t *fragment); static int rtv_setup(const til_settings_t *settings, til_setting_t **res_setting, const til_setting_desc_t **res_desc, void **res_setup); -static unsigned rtv_duration = RTV_DURATION_SECS; -static unsigned rtv_context_duration = RTV_CONTEXT_DURATION_SECS; -static unsigned rtv_snow_duration = RTV_SNOW_DURATION_SECS; -static unsigned rtv_caption_duration = RTV_CAPTION_DURATION_SECS; -static char **rtv_channels; -static char *rtv_snow_module; +static rtv_setup_t rtv_default_setup = { + .duration = RTV_DURATION_SECS, + .context_duration = RTV_CONTEXT_DURATION_SECS, + .snow_duration = RTV_SNOW_DURATION_SECS, + .caption_duration = RTV_CAPTION_DURATION_SECS, + .snow_module = RTV_DEFAULT_SNOW_MODULE, + .channels = { NULL }, /* NULL == "all" */ +}; til_module_t rtv_module = { @@ -143,7 +160,7 @@ static void setup_next_channel(rtv_context_t *ctxt, unsigned ticks) */ if (ctxt->channel) { ctxt->channel->cumulative_time += now - ctxt->channel->last_on_time; - if (ctxt->channel->cumulative_time >= rtv_context_duration) { + if (ctxt->channel->cumulative_time >= ctxt->context_duration) { ctxt->channel->cumulative_time = 0; ctxt->channel->module_ctxt = til_module_destroy_context(ctxt->channel->module, ctxt->channel->module_ctxt); @@ -159,7 +176,7 @@ static void setup_next_channel(rtv_context_t *ctxt, unsigned ticks) ctxt->last_channel = ctxt->channel; ctxt->channel = &ctxt->snow_channel; ctxt->caption = NULL; - ctxt->next_switch = now + rtv_snow_duration; + ctxt->next_switch = now + ctxt->snow_duration; } else { size_t i; @@ -195,8 +212,8 @@ static void setup_next_channel(rtv_context_t *ctxt, unsigned ticks) ctxt->channel->settings = settings ? settings : strdup(""); } - ctxt->next_switch = now + rtv_duration; - ctxt->next_hide_caption = now + rtv_caption_duration; + ctxt->next_switch = now + ctxt->duration; + ctxt->next_hide_caption = now + ctxt->caption_duration; } if (!ctxt->channel->module_ctxt) @@ -206,16 +223,19 @@ static void setup_next_channel(rtv_context_t *ctxt, unsigned ticks) } -static int rtv_should_skip_module(const rtv_context_t *ctxt, const til_module_t *module) +static int rtv_should_skip_module(const rtv_setup_t *setup, const til_module_t *module) { if (module == &rtv_module || - module == ctxt->snow_channel.module) + (setup->snow_module && !strcmp(module->name, setup->snow_module))) return 1; - if (!rtv_channels) + /* An empty channels list is a special case for representing "all", an + * empty channels setting returns -EINVAL during _setup(). + */ + if (!setup->channels[0]) return 0; - for (char **channel = rtv_channels; *channel; channel++) { + for (char * const *channel = setup->channels; *channel; channel++) { if (!strcmp(module->name, *channel)) return 0; } @@ -228,28 +248,39 @@ static void * rtv_create_context(unsigned ticks, unsigned num_cpus, void *setup) { rtv_context_t *ctxt; const til_module_t **modules; - size_t n_modules; + size_t n_modules, n_channels = 0; static til_module_t none_module = {}; + if (!setup) + setup = &rtv_default_setup; + til_get_modules(&modules, &n_modules); - ctxt = calloc(1, sizeof(rtv_context_t) + n_modules * sizeof(rtv_channel_t)); + /* how many modules are in the setup? */ + for (size_t i = 0; i < n_modules; i++) { + if (!rtv_should_skip_module(setup, modules[i])) + n_channels++; + } + + ctxt = calloc(1, sizeof(rtv_context_t) + n_channels * sizeof(rtv_channel_t)); if (!ctxt) return NULL; ctxt->n_cpus = num_cpus; + ctxt->duration = ((rtv_setup_t *)setup)->duration; + ctxt->context_duration = ((rtv_setup_t *)setup)->context_duration; + ctxt->snow_duration = ((rtv_setup_t *)setup)->snow_duration; + ctxt->caption_duration = ((rtv_setup_t *)setup)->caption_duration; ctxt->snow_channel.module = &none_module; - if (rtv_snow_module) { - ctxt->snow_channel.module = til_lookup_module(rtv_snow_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, ticks, NULL, &ctxt->snow_channel.module_ctxt); } for (size_t i = 0; i < n_modules; i++) { - if (rtv_should_skip_module(ctxt, modules[i])) - continue; - - ctxt->channels[ctxt->n_channels++].module = modules[i]; + if (!rtv_should_skip_module(setup, modules[i])) + ctxt->channels[ctxt->n_channels++].module = modules[i]; } setup_next_channel(ctxt, ticks); @@ -400,52 +431,64 @@ static int rtv_setup(const til_settings_t *settings, til_setting_t **res_setting if (r) return r; - /* turn channels colon-separated list into a null-terminated array of strings */ - if (strcmp(channels, "all")) { - const til_module_t **modules; - size_t n_modules; - char *tokchannels, *channel; - int n = 2; - - til_get_modules(&modules, &n_modules); + if (res_setup) { + rtv_setup_t *setup; - tokchannels = strdup(channels); - if (!tokchannels) + setup = calloc(1, sizeof(*setup) + sizeof(setup->channels[0])); + if (!setup) return -ENOMEM; - channel = strtok(tokchannels, ":"); - do { - char **new; - size_t i; + /* turn channels colon-separated list into a null-terminated array of strings */ + if (strcmp(channels, "all")) { + const til_module_t **modules; + size_t n_modules; + char *tokchannels, *channel; + int n = 2; - for (i = 0; i < n_modules; i++) { - if (!strcmp(channel, modules[i]->name)) - break; - } - - if (i >= n_modules) - return -EINVAL; + til_get_modules(&modules, &n_modules); - new = realloc(rtv_channels, n * sizeof(*rtv_channels)); - if (!new) + tokchannels = strdup(channels); + if (!tokchannels) return -ENOMEM; - new[n - 2] = channel; - new[n - 1] = NULL; - n++; + channel = strtok(tokchannels, ":"); + do { + rtv_setup_t *new; + size_t i; - rtv_channels = new; - } while (channel = strtok(NULL, ":")); - } + for (i = 0; i < n_modules; i++) { + if (!strcmp(channel, modules[i]->name)) + break; + } + + if (i >= n_modules) + return -EINVAL; + + new = realloc(setup, sizeof(*setup) + n * sizeof(setup->channels[0])); + if (!new) { + free(setup); + return -ENOMEM; + } - if (strcmp(snow_module, "none")) - rtv_snow_module = strdup(snow_module); + new->channels[n - 2] = channel; + new->channels[n - 1] = NULL; + n++; - /* TODO FIXME: parse errors */ - sscanf(duration, "%u", &rtv_duration); - sscanf(context_duration, "%u", &rtv_context_duration); - sscanf(caption_duration, "%u", &rtv_caption_duration); - sscanf(snow_duration, "%u", &rtv_snow_duration); + setup = new; + } while (channel = strtok(NULL, ":")); + } + + if (strcmp(snow_module, "none")) + setup->snow_module = strdup(snow_module); + + /* TODO FIXME: parse errors */ + sscanf(duration, "%u", &setup->duration); + sscanf(context_duration, "%u", &setup->context_duration); + sscanf(caption_duration, "%u", &setup->caption_duration); + sscanf(snow_duration, "%u", &setup->snow_duration); + + *res_setup = setup; + } return 0; } |