1 <chapter id="chapter-advanced-interfaces">
2 <title>Interfaces</title>
4 Previously, in the chapter <xref linkend="chapter-building-args"/>, we have
5 introduced the concept of GObject properties of controlling an element's
6 behaviour. This is a very powerful, but has two big disadvantage: firstly,
7 it is too generic, and secondly, it isn't dynamic.
10 The first disadvantage has to do with customizability of the end-user
11 interface that will be built to control the element. Some properties are
12 more important than others. Some integer properties are better shown in a
13 spin-button widget, whereas others would be better represented by a slider
14 widget. Such things are not possible because the UI has no actual meaning
15 in the application. A UI widget that stands for a bitrate property is the
16 same as an UI widget that stands for the size of a video, as long as both
17 are of the same <classname>GParamSpec</classname> type. Another problem,
18 related to the one about parameter important, is that things like parameter
19 grouping, function grouping or anything to make parameters coherent, is not
23 The second argument against parameters are that they are not dynamic. In
24 many cases, the allowed values for a property are not fixed, but depend
25 on things that can only be detected at run-time. The names of inputs for
26 a TV card in a video4linux source element, for example, can only be
27 retrieved from the kernel driver when we've opened the device; this only
28 happens when the element goes into the READY state. This means that we
29 cannot create an enum property type to show this to the user.
32 The solution to those problems is to create very specialized types of
33 controls for certain often-used controls. We use the concept of interfaces
34 to achieve this. The basis of this all is the glib
35 <classname>GTypeInterface</classname> type. For each case where we think
36 it's useful, we've created interfaces which can be implemented by elements
37 at their own will. We've also created a small extension to
38 <classname>GTypeInterface</classname> (which is static itself, too) which
39 allows us to query for interface availability based on runtime properties.
40 This extension is called <classname>GstImplementsInterface</classname>.
43 One important note: interfaces do <emphasis>not</emphasis> replace
44 properties. Rather, interfaces should be built <emphasis>next to</emphasis>
45 properties. There are two important reasons for this. Firstly, properties
46 can be saved in XML files. Secondly, properties can be specified on the
47 commandline (<filename>gst-launch</filename>).
50 <sect1 id="section-iface-general" xreflabel="How to Implement Interfaces">
51 <title>How to Implement Interfaces</title>
53 Implementing interfaces is intiated in the <function>_get_type ()</function>
54 of your element. You can register one or more interfaces after having
55 registered the type itself. Some interfaces have dependencies on other
56 interfaces or can only be registered by certain types of elements. You
57 will be notified of doing that wrongly when using the element: it will
58 quit with failed assertions, which will explain what went wrong. In the
59 case of GStreamer, the only dependency that <emphasis>some</emphasis>
60 interfaces have is <classname>GstImplementsInterface</classname>. Per
61 interface, we will indicate clearly when it depends on this extension.
62 If it does, you need to register support for <emphasis>that</emphasis>
63 interface before registering support for the interface that you're
64 wanting to support. The example below explains how to add support for a
65 simple interface with no further dependencies. For a small explanation
66 on <classname>GstImplementsInterface</classname>, see the next section
67 about the mixer interface: <xref linkend="section-iface-mixer"/>.
70 static void gst_my_filter_some_interface_init (GstSomeInterface *iface);
73 gst_my_filter_get_type (void)
75 static GType my_filter_type = 0;
77 if (!my_filter_type) {
78 static const GTypeInfo my_filter_info = {
79 sizeof (GstMyFilterClass),
80 (GBaseInitFunc) gst_my_filter_base_init,
82 (GClassInitFunc) gst_my_filter_class_init,
87 (GInstanceInitFunc) gst_my_filter_init
89 static const GInterfaceInfo some_interface_info = {
90 (GInterfaceInitFunc) gst_my_filter_some_interface_init,
96 g_type_register_static (GST_TYPE_MY_FILTER,
98 &my_filter_info, 0);
99 g_type_add_interface_static (my_filter_type,
100 GST_TYPE_SOME_INTERFACE,
101 &some_interface_info);
104 return my_filter_type;
108 gst_my_filter_some_interface_init (GstSomeInterface *iface)
110 /* here, you would set virtual function pointers in the interface */
115 <sect1 id="section-iface-mixer" xreflabel="Mixer Interface">
116 <title>Mixer Interface</title>
118 The goal of the mixer interface is to provide a simple yet powerful API
119 to applications for audio hardware mixer/volume control. Most soundcards
120 have hardware mixers, where volume can be changed, they can be muted,
121 inputs can be modified to mix their content into what will be read from
122 the device by applications (in our case: audio source plugins). The
123 mixer interface is the way to control those. The mixer interface can
124 also be used for volume control in software (e.g. the <quote>volume</quote>
125 element). The end goal of this interface is to allow development of
126 hardware volume control applications and for the control of audio volume
127 and input/output settings.
130 The mixer interface requires the <classname>GstImplementsInterface</classname>
131 interface to be implemented by the element. The example below will
132 feature both, so it serves as an example for the
133 <classname>GstImplementsInterface</classname>, too. In the
134 <classname>GstImplementsInterface</classname>, it is required to set a
135 function pointer for the <function>supported ()</function> function. If
136 you don't, this function will always return FALSE (default
137 implementation) and the mixer interface implementation will not work. For
138 the mixer interface, the only required function is
139 <function>list_tracks ()</function>. All other function pointers in the
140 mixer interface are optional, although it is strongly recommended to set
141 function pointers for at least the <function>get_volume ()</function> and
142 <function>set_volume ()</function> functions. The API reference for this
143 interface documents the goal of each function, so we will limit ourselves
144 to the implementation here.
147 #include <gst/mixer/mixer.h>
149 typedef struct _GstMyFilter {
155 static void gst_my_filter_implements_interface_init (GstImplementsInterfaceClass *iface);
156 static void gst_my_filter_mixer_interface_init (GstMixerClass *iface);
159 gst_my_filter_get_type (void)
162 static const GInterfaceInfo implements_interface_info = {
163 (GInterfaceInitFunc) gst_my_filter_implements_interface_init,
167 static const GInterfaceInfo mixer_interface_info = {
168 (GInterfaceInitFunc) gst_my_filter_mixer_interface_init,
173 g_type_add_interface_static (my_filter_type,
174 GST_TYPE_IMPLEMENTS_INTERFACE,
175 &implements_interface_info);
176 g_type_add_interface_static (my_filter_type,
178 &mixer_interface_info);
183 gst_my_filter_init (GstMyFilter *filter)
185 GstMixerTrack *track = NULL;
187 filter->volume = 100;
188 filter->tracks = NULL;
189 track = g_object_new (GST_TYPE_MIXER_TRACK, NULL);
190 track->label = g_strdup ("MyTrack");
191 track->num_channels = 1;
192 track->min_volume = 0;
193 track->max_volume = 100;
194 track->flags = GST_MIXER_TRACK_SOFTWARE;
195 filter->tracks = g_list_append (filter->tracks, track);
199 gst_my_filter_interface_supported (GstImplementsInterface *iface,
202 g_return_val_if_fail (iface_type == GST_TYPE_MIXER, FALSE);
204 /* for the sake of this example, we'll always support it. However, normally,
205 * you would check whether the device you've opened supports mixers. */
210 gst_my_filter_implements_interface_init (GstImplementsInterfaceClass *iface)
212 iface->supported = gst_my_filter_interface_supported;
216 * This function returns the list of support tracks (inputs, outputs)
217 * on this element instance. Elements usually build this list during
218 * _init () or when going from NULL to READY.
222 gst_my_filter_mixer_list_tracks (GstMixer *mixer)
224 GstMyFilter *filter = GST_MY_FILTER (mixer);
226 return filter->tracks;
230 * Set volume. volumes is an array of size track->num_channels, and
231 * each value in the array gives the wanted volume for one channel
236 gst_my_filter_mixer_set_volume (GstMixer *mixer,
237 GstMixerTrack *track,
240 GstMyFilter *filter = GST_MY_FILTER (mixer);
242 filter->volume = volumes[0];
244 g_print ("Volume set to %d\n", filter->volume);
248 gst_my_filter_mixer_get_volume (GstMixer *mixer,
249 GstMixerTrack *track,
252 GstMyFilter *filter = GST_MY_FILTER (mixer);
254 volumes[0] = filter->volume;
258 gst_my_filter_mixer_interface_init (GstMixerClass *iface)
260 /* the mixer interface requires a definition of the mixer type:
261 * hardware or software? */
262 GST_MIXER_TYPE (iface) = GST_MIXER_SOFTWARE;
264 /* virtual function pointers */
265 iface->list_tracks = gst_my_filter_mixer_list_tracks;
266 iface->set_volume = gst_my_filter_mixer_set_volume;
267 iface->get_volume = gst_my_filter_mixer_get_volume;
272 <sect1 id="section-iface-tuner" xreflabel="Tuner Interface">
273 <title>Tuner Interface</title>
279 <sect1 id="section-iface-colorbalance" xreflabel="Color Balance Interface">
280 <title>Color Balance Interface</title>
286 <sect1 id="section-iface-propprobe" xreflabel="Property Probe Interface">
287 <title>Property Probe Interface</title>
289 Property probing is a generic solution to the problem that properties'
290 value lists in an enumeration are static. We've shown enumerations in
291 <xref linkend="chapter-building-args"/>. Property probing tries to accomplish
292 a goal similar to enumeration lists: to have a limited, explicit list of
293 allowed values for a property. There are two differences between
294 enumeration lists and probing. Firstly, enumerations only allow strings
295 as values; property probing works for any value type. Secondly, the
296 contents of a probed list of allowed values may change during the life
297 of an element. The contents of a enumeraiton list are static. Crrently,
298 property probing is being used for detection of devices (e.g. for OSS
299 elements, Video4linux elements, etc.). It could - in theory - be used
300 for any property, though.
303 Property probing stores the list of allowed (or recommended) values in a
304 <classname>GValueArray</classname> and returns that to the user.
305 <classname>NULL</classname> is a valid return value, too. The process of
306 property probing is separated over two virtual functions: one for probing
307 the property to create a <classname>GValueArray</classname>, and one to
308 retrieve the current <classname>GValueArray</classname>. Those two are
309 separated because probing might take a long time (several seconds). Also,
310 this simpliies interface implementation in elements. For the application,
311 there are functions that wrap those two. For more information on this,
312 have a look at the API reference for the
313 <classname>GstPropertyProbe</classname> interface.
316 Below is a example of property probing for the audio filter element; it
317 will probe for allowed values for the <quote>silent</quote> property.
318 Indeed, this value is a <classname>gboolean</classname> so it doesn't
319 make much sense. Then again, it's only an example.
322 #include <gst/propertyprobe/propertyprobe.h>
324 static void gst_my_filter_probe_interface_init (GstPropertyProbeInterface *iface);
327 gst_my_filter_get_type (void)
330 static const GInterfaceInfo probe_interface_info = {
331 (GInterfaceInitFunc) gst_my_filter_probe_interface_init,
336 g_type_add_interface_static (my_filter_type,
337 GST_TYPE_PROPERTY_PROBE,
338 &probe_interface_info);
343 gst_my_filter_probe_get_properties (GstPropertyProbe *probe)
345 GObjectClass *klass = G_OBJECT_GET_CLASS (probe);
346 static GList *props = NULL;
351 pspec = g_object_class_find_property (klass, "silent");
352 props = g_list_append (props, pspec);
359 gst_my_filter_probe_needs_probe (GstPropertyProbe *probe,
361 const GParamSpec *pspec)
363 gboolean res = FALSE;
370 G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec);
378 gst_my_filter_probe_probe_property (GstPropertyProbe *probe,
380 const GParamSpec *pspec)
384 /* don't need to do much here... */
387 G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec);
393 gst_my_filter_get_silent_values (GstMyFilter *filter)
395 GValueArray *array = g_value_array_new (2);
396 GValue value = { 0 };
398 g_value_init (&value, G_TYPE_BOOLEAN);
401 g_value_set_boolean (&value, TRUE);
402 g_value_array_append (array, &value);
405 g_value_set_boolean (&value, FALSE);
406 g_value_array_append (array, &value);
408 g_value_unset (&value);
414 gst_my_filter_probe_get_values (GstPropertyProbe *probe,
416 const GParamSpec *pspec)
418 GstMyFilter *filter = GST_MY_FILTER (probe);
419 GValueArray *array = NULL;
423 array = gst_my_filter_get_silent_values (filter);
426 G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec);
434 gst_my_filter_probe_interface_init (GstPropertyProbeInterface *iface)
436 iface->get_properties = gst_my_filter_probe_get_properties;
437 iface->needs_probe = gst_my_filter_probe_needs_probe;
438 iface->probe_property = gst_my_filter_probe_probe_property;
439 iface->get_values = gst_my_filter_probe_get_values;
443 You don't need to support any functions for getting or setting values.
444 All that is handled via the standard <classname>GObject</classname>
445 <function>_set_property ()</function> and <function>_get_property ()</function>
450 <sect1 id="section-iface-profile" xreflabel="Profile Interface">
451 <title>Profile Interface</title>
457 <sect1 id="section-iface-xoverlay" xreflabel="X Overlay Interface">
458 <title>X Overlay Interface</title>
464 <sect1 id="section-iface-navigation" xreflabel="Navigation Interface">
465 <title>Navigation Interface</title>