fix up id's
[platform/upstream/gstreamer.git] / docs / pwg / advanced-interfaces.xml
1 <chapter id="chapter-advanced-interfaces">
2   <title>Interfaces</title>
3   <para>
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.
8   </para>
9   <para>
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
20     really possible.
21   </para>
22   <para>
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.
30   </para>
31   <para>
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>.
41   </para>
42   <para>
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>).
48   </para>
49
50   <sect1 id="section-iface-general" xreflabel="How to Implement Interfaces">
51     <title>How to Implement Interfaces</title>
52     <para>
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"/>.
68     </para>
69     <programlisting>
70 static void     gst_my_filter_some_interface_init       (GstSomeInterface *iface);
71
72 GType
73 gst_my_filter_get_type (void)
74 {
75   static GType my_filter_type = 0;
76                                                                                 
77   if (!my_filter_type) {
78     static const GTypeInfo my_filter_info = {
79       sizeof (GstMyFilterClass),
80       (GBaseInitFunc) gst_my_filter_base_init,
81       NULL,
82       (GClassInitFunc) gst_my_filter_class_init,
83       NULL,
84       NULL,
85       sizeof (GstMyFilter),
86       0,
87       (GInstanceInitFunc) gst_my_filter_init
88     };
89     static const GInterfaceInfo some_interface_info = {
90       (GInterfaceInitFunc) gst_my_filter_some_interface_init,
91       NULL,
92       NULL
93     };
94
95     my_filter_type =
96         g_type_register_static (GST_TYPE_MY_FILTER,
97                                 "GstMyFilter",
98                                 &amp;my_filter_info, 0);
99     g_type_add_interface_static (my_filter_type,
100                                  GST_TYPE_SOME_INTERFACE,
101                                  &amp;some_interface_info);
102   }
103
104   return my_filter_type;
105 }
106
107 static void
108 gst_my_filter_some_interface_init (GstSomeInterface *iface)
109 {
110   /* here, you would set virtual function pointers in the interface */
111 }
112     </programlisting>
113   </sect1>
114
115   <sect1 id="section-iface-mixer" xreflabel="Mixer Interface">
116     <title>Mixer Interface</title>
117     <para>
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.
128     </para>
129     <para>
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.
145     </para>
146     <programlisting>
147 #include &lt;gst/mixer/mixer.h&gt;
148
149 typedef struct _GstMyFilter {
150 [..]
151   gint volume;
152   GList *tracks;
153 } GstMyFilter;
154
155 static void     gst_my_filter_implements_interface_init (GstImplementsInterfaceClass *iface);
156 static void     gst_my_filter_mixer_interface_init      (GstMixerClass *iface);
157
158 GType
159 gst_my_filter_get_type (void)
160 {
161 [..]
162     static const GInterfaceInfo implements_interface_info = {
163       (GInterfaceInitFunc) gst_my_filter_implements_interface_init,
164       NULL,
165       NULL
166     };
167     static const GInterfaceInfo mixer_interface_info = {
168       (GInterfaceInitFunc) gst_my_filter_mixer_interface_init,
169       NULL,
170       NULL
171     };
172 [..]
173     g_type_add_interface_static (my_filter_type,
174                                  GST_TYPE_IMPLEMENTS_INTERFACE,
175                                  &amp;implements_interface_info);
176     g_type_add_interface_static (my_filter_type,
177                                  GST_TYPE_MIXER,
178                                  &amp;mixer_interface_info);
179 [..]
180 }
181
182 static void
183 gst_my_filter_init (GstMyFilter *filter)
184 {
185   GstMixerTrack *track = NULL;
186 [..]
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);
196 }
197
198 static gboolean
199 gst_my_filter_interface_supported (GstImplementsInterface *iface,
200                                    GType                   iface_type)
201 {
202   g_return_val_if_fail (iface_type == GST_TYPE_MIXER, FALSE);
203
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. */
206   return TRUE;
207 }
208
209 static void
210 gst_my_filter_implements_interface_init (GstImplementsInterfaceClass *iface)
211 {
212   iface->supported = gst_my_filter_interface_supported;
213 }
214
215 /*
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.
219  */
220
221 static const GList *
222 gst_my_filter_mixer_list_tracks (GstMixer *mixer)
223 {
224   GstMyFilter *filter = GST_MY_FILTER (mixer);
225
226   return filter->tracks;
227 }
228
229 /*
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
232  * on the track.
233  */
234
235 static void
236 gst_my_filter_mixer_set_volume (GstMixer      *mixer,
237                                 GstMixerTrack *track,
238                                 gint          *volumes)
239 {
240   GstMyFilter *filter = GST_MY_FILTER (mixer);
241
242   filter->volume = volumes[0];
243
244   g_print ("Volume set to %d\n", filter->volume);
245 }
246
247 static void
248 gst_my_filter_mixer_get_volume (GstMixer      *mixer,
249                                 GstMixerTrack *track,
250                                 gint          *volumes)
251 {
252   GstMyFilter *filter = GST_MY_FILTER (mixer);
253
254   volumes[0] = filter->volume;
255 }
256
257 static void
258 gst_my_filter_mixer_interface_init (GstMixerClass *iface)
259 {
260   /* the mixer interface requires a definition of the mixer type:
261    * hardware or software? */
262   GST_MIXER_TYPE (iface) = GST_MIXER_SOFTWARE;
263
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;
268 }
269     </programlisting>
270   </sect1>
271
272   <sect1 id="section-iface-tuner" xreflabel="Tuner Interface">
273     <title>Tuner Interface</title>
274     <para>
275       WRITEME
276     </para>
277   </sect1>
278
279   <sect1 id="section-iface-colorbalance" xreflabel="Color Balance Interface">
280     <title>Color Balance Interface</title>
281     <para>
282       WRITEME
283     </para>
284   </sect1>
285
286   <sect1 id="section-iface-propprobe" xreflabel="Property Probe Interface">
287     <title>Property Probe Interface</title>
288     <para>
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.
301     </para>
302     <para>
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.
314     </para>
315     <para>
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.
320     </para>
321     <programlisting>
322 #include &lt;gst/propertyprobe/propertyprobe.h&gt;
323
324 static void     gst_my_filter_probe_interface_init      (GstPropertyProbeInterface *iface);
325
326 GType
327 gst_my_filter_get_type (void)
328 {
329 [..]
330     static const GInterfaceInfo probe_interface_info = {
331       (GInterfaceInitFunc) gst_my_filter_probe_interface_init,
332       NULL,
333       NULL
334     };
335 [..]
336     g_type_add_interface_static (my_filter_type,
337                                  GST_TYPE_PROPERTY_PROBE,
338                                  &amp;probe_interface_info);
339 [..]
340 }
341
342 static const GList *
343 gst_my_filter_probe_get_properties (GstPropertyProbe *probe)
344 {
345   GObjectClass *klass = G_OBJECT_GET_CLASS (probe);
346   static GList *props = NULL;
347
348   if (!props) {
349     GParamSpec *pspec;
350
351     pspec = g_object_class_find_property (klass, "silent");
352     props = g_list_append (props, pspec);
353   }
354
355   return props;
356 }
357
358 static gboolean
359 gst_my_filter_probe_needs_probe (GstPropertyProbe *probe,
360                                  guint             prop_id,
361                                  const GParamSpec *pspec)
362 {
363   gboolean res = FALSE;
364
365   switch (prop_id) {
366     case ARG_SILENT:
367       res = FALSE;
368       break;
369     default:
370       G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec);
371       break;
372   }
373
374   return res;
375 }
376
377 static void
378 gst_my_filter_probe_probe_property (GstPropertyProbe *probe,
379                                     guint             prop_id,
380                                     const GParamSpec *pspec)
381 {
382   switch (prop_id) {
383     case ARG_SILENT:
384       /* don't need to do much here... */
385       break;
386     default:
387       G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec);
388       break;
389   }
390 }
391
392 static GValueArray *
393 gst_my_filter_get_silent_values (GstMyFilter *filter)
394 {
395   GValueArray *array = g_value_array_new (2);
396   GValue value = { 0 };
397
398   g_value_init (&amp;value, G_TYPE_BOOLEAN);
399
400   /* add TRUE */
401   g_value_set_boolean (&amp;value, TRUE);
402   g_value_array_append (array, &amp;value);
403
404   /* add FALSE */
405   g_value_set_boolean (&amp;value, FALSE);
406   g_value_array_append (array, &amp;value);
407
408   g_value_unset (&amp;value);
409
410   return array;
411 }
412
413 static GValueArray *
414 gst_my_filter_probe_get_values (GstPropertyProbe *probe,
415                                 guint             prop_id,
416                                 const GParamSpec *pspec)
417 {
418   GstMyFilter *filter = GST_MY_FILTER (probe);
419   GValueArray *array = NULL;
420
421   switch (prop_id) {
422     case ARG_SILENT:
423       array = gst_my_filter_get_silent_values (filter);
424       break;
425     default:
426       G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec);
427       break;
428   }
429
430   return array;
431 }
432
433 static void
434 gst_my_filter_probe_interface_init (GstPropertyProbeInterface *iface)
435 {
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;
440 }
441     </programlisting>
442     <para>
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>
446       functions.
447     </para>
448   </sect1>
449
450   <sect1 id="section-iface-profile" xreflabel="Profile Interface">
451     <title>Profile Interface</title>
452     <para>
453       WRITEME
454     </para>
455   </sect1>
456                                                                                 
457   <sect1 id="section-iface-xoverlay" xreflabel="X Overlay Interface">
458     <title>X Overlay Interface</title>
459     <para>
460       WRITEME
461     </para>
462   </sect1>
463
464   <sect1 id="section-iface-navigation" xreflabel="Navigation Interface">
465     <title>Navigation Interface</title>
466     <para>
467       WRITEME
468     </para>
469   </sect1>
470 </chapter>