Skip to content
Snippets Groups Projects
parser-streams.c 5.24 KiB
Newer Older
/* WirePlumber
 *
 * Copyright © 2019 Collabora Ltd.
 *    @author Julian Bouzas <julian.bouzas@collabora.com>
 *
 * SPDX-License-Identifier: MIT
 */

#include <wptoml/wptoml.h>

#include <pipewire/pipewire.h>

#include "parser-streams.h"

struct _WpParserStreams
{
  GObject parent;

  GPtrArray *datas;
};

const struct WpParserStreamsStreamData *
wp_parser_streams_find_stream (const struct WpParserStreamsData *data,
    const char *name)
{
  for (guint i = 0; i < data->n_streams; i++) {
    const struct WpParserStreamsStreamData *s = data->streams + i;
    if (g_strcmp0 (s->name, name) == 0)
      return s;
  }
  return NULL;
}

const struct WpParserStreamsStreamData *
wp_parser_streams_get_lowest_stream (const struct WpParserStreamsData *data)
{
  const struct WpParserStreamsStreamData *res = NULL;
  guint lowest = G_MAXUINT;
  for (guint i = 0; i < data->n_streams; i++) {
    const struct WpParserStreamsStreamData *s = data->streams + i;
    if (s->priority < lowest) {
      lowest = s->priority;
      res = s;
    }
  }
  return res;
}

static void wp_parser_streams_config_parser_init (gpointer iface,
    gpointer iface_data);

G_DEFINE_TYPE_WITH_CODE (WpParserStreams, wp_parser_streams,
    G_TYPE_OBJECT,
    G_IMPLEMENT_INTERFACE (WP_TYPE_CONFIG_PARSER,
                         wp_parser_streams_config_parser_init))

static void
wp_parser_streams_data_destroy (gpointer p)
{
  struct WpParserStreamsData *data = p;

  /* Clear the location */
  g_clear_pointer (&data->location, g_free);

  /* Clear the streams */
  for (guint i = 0; i < data->n_streams; i++) {
    struct WpParserStreamsStreamData *s = data->streams + i;
    g_clear_pointer (&s->name, g_free);
  }
  data->n_streams = 0;

  g_slice_free (struct WpParserStreamsData, data);
}

static void
streams_for_each (const WpTomlTable *table, gpointer user_data)
{
  struct WpParserStreamsData *data = user_data;
  struct WpParserStreamsStreamData *stream = NULL;
  g_return_if_fail (data);

  /* Make sure we don't parse more MAX_STREAMS streams */
  if (data->n_streams >= MAX_STREAMS)
    return;

  /* Skip unparsed tables */
  if (!table)
    return;

  /* Parse the mandatory name */
  stream = data->streams + data->n_streams;
  stream->name = wp_toml_table_get_string (table, "name");
  if (!stream->name)
    return;

  /* Parse the optional priority */
  stream->priority = 0;
  wp_toml_table_get_uint32 (table, "priority", &stream->priority);

  /* Increment the number of streams */
  data->n_streams++;
}


static struct WpParserStreamsData *
wp_parser_streams_data_new (const gchar *location)
{
  g_autoptr (WpTomlFile) file = NULL;
  g_autoptr (WpTomlTable) table = NULL;
  g_autoptr (WpTomlTableArray) streams = NULL;
  struct WpParserStreamsData *res = NULL;

  /* File format:
   * ------------
   * [[streams]]
   * name (string)
   * priority (uint32)
   */

  /* Get the TOML file */
  file = wp_toml_file_new (location);
  if (!file)
    return NULL;

  /* Get the file table */
  table = wp_toml_file_get_table (file);
  if (!table)
    return NULL;

  /* Create the streams data */
  res = g_slice_new0 (struct WpParserStreamsData);

  /* Set the location */
  res->location = g_strdup (location);

  /* Parse the streams */
  res->n_streams = 0;
  streams = wp_toml_table_get_array_table (table, "streams");
  if (streams)
    wp_toml_table_array_for_each (streams, streams_for_each, res);

  return res;
}

static gboolean
wp_parser_streams_add_file (WpConfigParser *parser,
    const gchar *name)
{
  WpParserStreams *self = WP_PARSER_STREAMS (parser);
  struct WpParserStreamsData *data;

  /* Parse the file */
  data = wp_parser_streams_data_new (name);
  if (!data) {
    g_warning ("Failed to parse configuration file '%s'", name);
    return FALSE;
  }

  /* Add the data to the array */
  g_ptr_array_add(self->datas, data);

  return TRUE;
}

static gconstpointer
wp_parser_streams_get_matched_data (WpConfigParser *parser, gpointer data)
{
  WpParserStreams *self = WP_PARSER_STREAMS (parser);
  const char *location = data;
  const struct WpParserStreamsData *d = NULL;

  /* Find the first data that matches location */
  for (guint i = 0; i < self->datas->len; i++) {
    d = g_ptr_array_index(self->datas, i);
    if (g_strrstr (d->location, location))
      return d;
  }

  return NULL;
}

static void
wp_parser_streams_reset (WpConfigParser *parser)
{
  WpParserStreams *self = WP_PARSER_STREAMS (parser);

  g_ptr_array_set_size (self->datas, 0);
}

static void
wp_parser_streams_config_parser_init (gpointer iface,
    gpointer iface_data)
{
  WpConfigParserInterface *cp_iface = iface;

  cp_iface->add_file = wp_parser_streams_add_file;
  cp_iface->get_matched_data = wp_parser_streams_get_matched_data;
  cp_iface->reset = wp_parser_streams_reset;
}

static void
wp_parser_streams_finalize (GObject * object)
{
  WpParserStreams *self = WP_PARSER_STREAMS (object);

  g_clear_pointer (&self->datas, g_ptr_array_unref);

  G_OBJECT_CLASS (wp_parser_streams_parent_class)->finalize (object);
}

static void
wp_parser_streams_init (WpParserStreams * self)
{
  self->datas = g_ptr_array_new_with_free_func (wp_parser_streams_data_destroy);
}

static void
wp_parser_streams_class_init (WpParserStreamsClass * klass)
{
  GObjectClass *object_class = (GObjectClass *) klass;

  object_class->finalize = wp_parser_streams_finalize;
}