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 a enumeraiton list are static. Crrently, 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.