Property Probe Interface

Property probing is a generic solution to the problem that properties' value lists in an enumeration are static. We've shown enumerations in Adding Arguments. Property probing tries to accomplish a goal similar to enumeration lists: to have a limited, explicit list of allowed values for a property. There are two differences between enumeration lists and probing. Firstly, enumerations only allow strings as values; property probing works for any value type. Secondly, the contents of a probed list of allowed values may change during the life of an element. The contents of an enumeration list are static. Currently, property probing is being used for detection of devices (e.g. for OSS elements, Video4linux elements, etc.). It could - in theory - be used for any property, though.

Property probing stores the list of allowed (or recommended) values in a GValueArray and returns that to the user. NULL is a valid return value, too. The process of property probing is separated over two virtual functions: one for probing the property to create a GValueArray, and one to retrieve the current GValueArray. Those two are separated because probing might take a long time (several seconds). Also, this simpliies interface implementation in elements. For the application, there are functions that wrap those two. For more information on this, have a look at the API reference for the GstPropertyProbe interface.

Below is a example of property probing for the audio filter element; it will probe for allowed values for the "silent" property. Indeed, this value is a gboolean so it doesn't make much sense. Then again, it's only an example.


#include <gst/propertyprobe/propertyprobe.h>

static void	gst_my_filter_probe_interface_init	(GstPropertyProbeInterface *iface);

GType
gst_my_filter_get_type (void)
{
[..]
    static const GInterfaceInfo probe_interface_info = {
      (GInterfaceInitFunc) gst_my_filter_probe_interface_init,
      NULL,
      NULL
    };
[..]
    g_type_add_interface_static (my_filter_type,
				 GST_TYPE_PROPERTY_PROBE,
				 &probe_interface_info);
[..]
}

static const GList *
gst_my_filter_probe_get_properties (GstPropertyProbe *probe)
{
  GObjectClass *klass = G_OBJECT_GET_CLASS (probe);
  static GList *props = NULL;

  if (!props) {
    GParamSpec *pspec;

    pspec = g_object_class_find_property (klass, "silent");
    props = g_list_append (props, pspec);
  }

  return props;
}

static gboolean
gst_my_filter_probe_needs_probe (GstPropertyProbe *probe,
				 guint             prop_id,
				 const GParamSpec *pspec)
{
  gboolean res = FALSE;

  switch (prop_id) {
    case ARG_SILENT:
      res = FALSE;
      break;
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec);
      break;
  }

  return res;
}

static void
gst_my_filter_probe_probe_property (GstPropertyProbe *probe,
				    guint             prop_id,
				    const GParamSpec *pspec)
{
  switch (prop_id) {
    case ARG_SILENT:
      /* don't need to do much here... */
      break;
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec);
      break;
  }
}

static GValueArray *
gst_my_filter_get_silent_values (GstMyFilter *filter)
{
  GValueArray *array = g_value_array_new (2);
  GValue value = { 0 };

  g_value_init (&value, G_TYPE_BOOLEAN);

  /* add TRUE */
  g_value_set_boolean (&value, TRUE);
  g_value_array_append (array, &value);

  /* add FALSE */
  g_value_set_boolean (&value, FALSE);
  g_value_array_append (array, &value);

  g_value_unset (&value);

  return array;
}

static GValueArray *
gst_my_filter_probe_get_values (GstPropertyProbe *probe,
				guint             prop_id,
				const GParamSpec *pspec)
{
  GstMyFilter *filter = GST_MY_FILTER (probe);
  GValueArray *array = NULL;

  switch (prop_id) {
    case ARG_SILENT:
      array = gst_my_filter_get_silent_values (filter);
      break;
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec);
      break;
  }

  return array;
}

static void
gst_my_filter_probe_interface_init (GstPropertyProbeInterface *iface)
{
  iface->get_properties = gst_my_filter_probe_get_properties;
  iface->needs_probe    = gst_my_filter_probe_needs_probe;
  iface->probe_property = gst_my_filter_probe_probe_property;
  iface->get_values     = gst_my_filter_probe_get_values;
}
    

You don't need to support any functions for getting or setting values. All that is handled via the standard GObject _set_property () and _get_property () functions.