tizen 2.3 release
[framework/multimedia/gst-plugins-base0.10.git] / gst-libs / gst / interfaces / mixer.c
1 /* GStreamer Mixer
2  * Copyright (C) 2003 Ronald Bultje <rbultje@ronald.bitfreak.net>
3  *
4  * mixer.c: mixer design virtual class function wrappers
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public
17  * License along with this library; if not, write to the
18  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19  * Boston, MA 02111-1307, USA.
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25
26 #include "mixer.h"
27 #include "interfaces-marshal.h"
28
29 #define GST_MIXER_MESSAGE_NAME "gst-mixer-message"
30
31 /**
32  * SECTION:gstmixer
33  * @short_description: Interface for elements that provide mixer operations
34  * @see_also: alsamixer, oss4mixer, sunaudiomixer
35  *
36  * Basic interface for hardware mixer controls.
37  *
38  * Applications rarely need to use this interface, it is provided mainly
39  * for system-level mixer applets and the like. Volume control in playback
40  * applications should be done using a <classname>volume</classname>
41  * element or, if available, using the <quote>volume</quote> property of
42  * the audio sink element used (as provided by <classname>pulsesink</classname>
43  * for example), or even better: just use the <classname>playbin2</classname>
44  * element's <quote>volume</quote> property.
45  *
46  * Usage: In order to use the <classname>GstMixer</classname> interface, the
47  * element needs to be at least in READY state (so that the element has opened
48  * the mixer device). Once the element has been set to READY state or higher,
49  * it can be cast to a <classname>GstMixer</classname> using the GST_MIXER
50  * macro (in C) and the mixer API can be used.
51  */
52
53 #ifndef GST_DISABLE_DEPRECATED
54 enum
55 {
56   SIGNAL_MUTE_TOGGLED,
57   SIGNAL_RECORD_TOGGLED,
58   SIGNAL_VOLUME_CHANGED,
59   SIGNAL_OPTION_CHANGED,
60   LAST_SIGNAL
61 };
62
63 static guint gst_mixer_signals[LAST_SIGNAL] = { 0 };
64
65 #endif
66
67 static void gst_mixer_class_init (GstMixerClass * klass);
68
69 GType
70 gst_mixer_get_type (void)
71 {
72   static GType gst_mixer_type = 0;
73
74   if (!gst_mixer_type) {
75     static const GTypeInfo gst_mixer_info = {
76       sizeof (GstMixerClass),
77       (GBaseInitFunc) gst_mixer_class_init,
78       NULL,
79       NULL,
80       NULL,
81       NULL,
82       0,
83       0,
84       NULL,
85     };
86
87     gst_mixer_type = g_type_register_static (G_TYPE_INTERFACE,
88         "GstMixer", &gst_mixer_info, 0);
89     g_type_interface_add_prerequisite (gst_mixer_type,
90         GST_TYPE_IMPLEMENTS_INTERFACE);
91   }
92
93   return gst_mixer_type;
94 }
95
96 static void
97 gst_mixer_class_init (GstMixerClass * klass)
98 {
99 #ifndef GST_DISABLE_DEPRECATED
100   static gboolean initialized = FALSE;
101
102   /* signals (deprecated) */
103   if (!initialized) {
104     gst_mixer_signals[SIGNAL_RECORD_TOGGLED] =
105         g_signal_new ("record-toggled",
106         GST_TYPE_MIXER, G_SIGNAL_RUN_LAST,
107         G_STRUCT_OFFSET (GstMixerClass, record_toggled),
108         NULL, NULL,
109         gst_interfaces_marshal_VOID__OBJECT_BOOLEAN, G_TYPE_NONE, 2,
110         GST_TYPE_MIXER_TRACK, G_TYPE_BOOLEAN);
111     gst_mixer_signals[SIGNAL_MUTE_TOGGLED] =
112         g_signal_new ("mute-toggled",
113         GST_TYPE_MIXER, G_SIGNAL_RUN_LAST,
114         G_STRUCT_OFFSET (GstMixerClass, mute_toggled),
115         NULL, NULL,
116         gst_interfaces_marshal_VOID__OBJECT_BOOLEAN, G_TYPE_NONE, 2,
117         GST_TYPE_MIXER_TRACK, G_TYPE_BOOLEAN);
118     gst_mixer_signals[SIGNAL_VOLUME_CHANGED] =
119         g_signal_new ("volume-changed",
120         GST_TYPE_MIXER, G_SIGNAL_RUN_LAST,
121         G_STRUCT_OFFSET (GstMixerClass, volume_changed),
122         NULL, NULL,
123         gst_interfaces_marshal_VOID__OBJECT_POINTER, G_TYPE_NONE, 2,
124         GST_TYPE_MIXER_TRACK, G_TYPE_POINTER);
125     gst_mixer_signals[SIGNAL_OPTION_CHANGED] =
126         g_signal_new ("option-changed",
127         GST_TYPE_MIXER, G_SIGNAL_RUN_LAST,
128         G_STRUCT_OFFSET (GstMixerClass, option_changed),
129         NULL, NULL,
130         gst_interfaces_marshal_VOID__OBJECT_STRING, G_TYPE_NONE, 2,
131         GST_TYPE_MIXER_OPTIONS, G_TYPE_STRING);
132
133     initialized = TRUE;
134   }
135 #endif
136
137   klass->mixer_type = GST_MIXER_SOFTWARE;
138
139   /* default virtual functions */
140   klass->list_tracks = NULL;
141   klass->set_volume = NULL;
142   klass->get_volume = NULL;
143   klass->set_mute = NULL;
144   klass->set_record = NULL;
145   klass->set_option = NULL;
146   klass->get_option = NULL;
147 }
148
149 /**
150  * gst_mixer_list_tracks:
151  * @mixer: the #GstMixer (a #GstElement) to get the tracks from.
152  *
153  * Returns a list of available tracks for this mixer/element. Note
154  * that it is allowed for sink (output) elements to only provide
155  * the output tracks in this list. Likewise, for sources (inputs),
156  * it is allowed to only provide input elements in this list.
157  *
158  * Returns: A #GList consisting of zero or more #GstMixerTracks.
159  *          The list is owned by the #GstMixer instance and must not be freed
160  *          or modified.
161  */
162
163 const GList *
164 gst_mixer_list_tracks (GstMixer * mixer)
165 {
166   GstMixerClass *klass;
167
168   g_return_val_if_fail (mixer != NULL, NULL);
169
170   klass = GST_MIXER_GET_CLASS (mixer);
171
172   if (klass->list_tracks) {
173     return klass->list_tracks (mixer);
174   }
175
176   return NULL;
177 }
178
179 /**
180  * gst_mixer_set_volume:
181  * @mixer: The #GstMixer (a #GstElement) that owns the track.
182  * @track: The #GstMixerTrack to set the volume on.
183  * @volumes: an array of integers (of size track->num_channels)
184  *           that gives the wanted volume for each channel in
185  *           this track.
186  *
187  * Sets the volume on each channel in a track. Short note about
188  * naming: a track is defined as one separate stream owned by
189  * the mixer/element, such as 'Line-in' or 'Microphone'. A
190  * channel is said to be a mono-stream inside this track. A
191  * stereo track thus contains two channels.
192  */
193
194 void
195 gst_mixer_set_volume (GstMixer * mixer, GstMixerTrack * track, gint * volumes)
196 {
197   GstMixerClass *klass;
198
199   g_return_if_fail (mixer != NULL);
200   g_return_if_fail (track != NULL);
201   g_return_if_fail (volumes != NULL);
202
203   klass = GST_MIXER_GET_CLASS (mixer);
204
205   if (klass->set_volume) {
206     klass->set_volume (mixer, track, volumes);
207   }
208 }
209
210 /**
211  * gst_mixer_get_volume:
212  * @mixer: the #GstMixer (a #GstElement) that owns the track
213  * @track: the GstMixerTrack to get the volume from.
214  * @volumes: a pre-allocated array of integers (of size
215  *           track->num_channels) to store the current volume
216  *           of each channel in the given track in.
217  *
218  * Get the current volume(s) on the given track.
219  */
220
221 void
222 gst_mixer_get_volume (GstMixer * mixer, GstMixerTrack * track, gint * volumes)
223 {
224   GstMixerClass *klass;
225
226   g_return_if_fail (mixer != NULL);
227   g_return_if_fail (track != NULL);
228   g_return_if_fail (volumes != NULL);
229
230   klass = GST_MIXER_GET_CLASS (mixer);
231
232   if (klass->get_volume) {
233     klass->get_volume (mixer, track, volumes);
234   } else {
235     gint i;
236
237     for (i = 0; i < track->num_channels; i++) {
238       volumes[i] = 0;
239     }
240   }
241 }
242
243 /**
244  * gst_mixer_set_mute:
245  * @mixer: the #GstMixer (a #GstElement) that owns the track.
246  * @track: the #GstMixerTrack to operate on.
247  * @mute: a boolean value indicating whether to turn on or off
248  *        muting.
249  *
250  * Mutes or unmutes the given channel. To find out whether a
251  * track is currently muted, use GST_MIXER_TRACK_HAS_FLAG ().
252  */
253
254 void
255 gst_mixer_set_mute (GstMixer * mixer, GstMixerTrack * track, gboolean mute)
256 {
257   GstMixerClass *klass;
258
259   g_return_if_fail (mixer != NULL);
260   g_return_if_fail (track != NULL);
261
262   klass = GST_MIXER_GET_CLASS (mixer);
263
264   if (klass->set_mute) {
265     klass->set_mute (mixer, track, mute);
266   }
267 }
268
269 /**
270  * gst_mixer_set_record:
271  * @mixer: The #GstMixer (a #GstElement) that owns the track.
272  * @track: the #GstMixerTrack to operate on.
273  * @record: a boolean value that indicates whether to turn on
274  *          or off recording.
275  *
276  * Enables or disables recording on the given track. Note that
277  * this is only possible on input tracks, not on output tracks
278  * (see GST_MIXER_TRACK_HAS_FLAG () and the GST_MIXER_TRACK_INPUT
279  * flag).
280  */
281
282 void
283 gst_mixer_set_record (GstMixer * mixer, GstMixerTrack * track, gboolean record)
284 {
285   GstMixerClass *klass = GST_MIXER_GET_CLASS (mixer);
286
287   if (klass->set_record) {
288     klass->set_record (mixer, track, record);
289   }
290 }
291
292 /**
293  * gst_mixer_set_option:
294  * @mixer: The #GstMixer (a #GstElement) that owns the optionlist.
295  * @opts: The #GstMixerOptions that we operate on.
296  * @value: The requested new option value.
297  *
298  * Sets a name/value option in the mixer to the requested value.
299  */
300
301 void
302 gst_mixer_set_option (GstMixer * mixer, GstMixerOptions * opts, gchar * value)
303 {
304   GstMixerClass *klass;
305
306   g_return_if_fail (mixer != NULL);
307   g_return_if_fail (opts != NULL);
308
309   klass = GST_MIXER_GET_CLASS (mixer);
310
311   if (klass->set_option) {
312     klass->set_option (mixer, opts, value);
313   }
314 }
315
316 /**
317  * gst_mixer_get_option:
318  * @mixer: The #GstMixer (a #GstElement) that owns the optionlist.
319  * @opts: The #GstMixerOptions that we operate on.
320  *
321  * Get the current value of a name/value option in the mixer.
322  *
323  * Returns: current value of the name/value option.
324  */
325
326 const gchar *
327 gst_mixer_get_option (GstMixer * mixer, GstMixerOptions * opts)
328 {
329   GstMixerClass *klass;
330
331   g_return_val_if_fail (mixer != NULL, NULL);
332   g_return_val_if_fail (opts != NULL, NULL);
333
334   klass = GST_MIXER_GET_CLASS (mixer);
335
336   if (klass->get_option) {
337     return klass->get_option (mixer, opts);
338   }
339
340   return NULL;
341 }
342
343 /**
344  * gst_mixer_get_mixer_type:
345  * @mixer: The #GstMixer implementation
346  *
347  * Get the #GstMixerType of this mixer implementation.
348  *
349  * Returns: A the #GstMixerType.
350  *
351  * Since: 0.10.24
352  */
353 GstMixerType
354 gst_mixer_get_mixer_type (GstMixer * mixer)
355 {
356   GstMixerClass *klass = GST_MIXER_GET_CLASS (mixer);
357
358   return klass->mixer_type;
359 }
360
361 /**
362  * gst_mixer_get_mixer_flags:
363  * @mixer: The #GstMixer implementation
364  *
365  * Get the set of supported flags for this mixer implementation.
366  *
367  * Returns: A set of or-ed GstMixerFlags for supported features.
368  */
369 GstMixerFlags
370 gst_mixer_get_mixer_flags (GstMixer * mixer)
371 {
372   GstMixerClass *klass;
373
374   g_return_val_if_fail (mixer != NULL, FALSE);
375   klass = GST_MIXER_GET_CLASS (mixer);
376
377   if (klass->get_mixer_flags) {
378     return klass->get_mixer_flags (mixer);
379   }
380   return GST_MIXER_FLAG_NONE;
381 }
382
383 /**
384  * gst_mixer_mute_toggled:
385  * @mixer: the #GstMixer (a #GstElement) that owns the track
386  * @track: the GstMixerTrack that has change mute state.
387  * @mute: the new state of the mute flag on the track
388  *
389  * This function is called by the mixer implementation to produce
390  * a notification message on the bus indicating that the given track
391  * has changed mute state.
392  *
393  * This function only works for GstElements that are implementing the
394  * GstMixer interface, and the element needs to have been provided a bus.
395  */
396 void
397 gst_mixer_mute_toggled (GstMixer * mixer, GstMixerTrack * track, gboolean mute)
398 {
399   GstStructure *s;
400   GstMessage *m;
401
402   g_return_if_fail (mixer != NULL);
403   g_return_if_fail (GST_IS_ELEMENT (mixer));
404   g_return_if_fail (track != NULL);
405
406   s = gst_structure_new (GST_MIXER_MESSAGE_NAME,
407       "type", G_TYPE_STRING, "mute-toggled",
408       "track", GST_TYPE_MIXER_TRACK, track, "mute", G_TYPE_BOOLEAN, mute, NULL);
409
410   m = gst_message_new_element (GST_OBJECT (mixer), s);
411   if (gst_element_post_message (GST_ELEMENT (mixer), m) == FALSE) {
412     GST_WARNING ("This element has no bus, therefore no message sent!");
413   }
414 }
415
416 /**
417  * gst_mixer_record_toggled:
418  * @mixer: the #GstMixer (a #GstElement) that owns the track
419  * @track: the GstMixerTrack that has changed recording state.
420  * @record: the new state of the record flag on the track
421  *
422  * This function is called by the mixer implementation to produce
423  * a notification message on the bus indicating that the given track
424  * has changed recording state.
425  *
426  * This function only works for GstElements that are implementing the
427  * GstMixer interface, and the element needs to have been provided a bus.
428  */
429 void
430 gst_mixer_record_toggled (GstMixer * mixer,
431     GstMixerTrack * track, gboolean record)
432 {
433   GstStructure *s;
434   GstMessage *m;
435
436   g_return_if_fail (mixer != NULL);
437   g_return_if_fail (GST_IS_ELEMENT (mixer));
438   g_return_if_fail (track != NULL);
439
440   s = gst_structure_new (GST_MIXER_MESSAGE_NAME,
441       "type", G_TYPE_STRING, "record-toggled",
442       "track", GST_TYPE_MIXER_TRACK, track,
443       "record", G_TYPE_BOOLEAN, record, NULL);
444
445   m = gst_message_new_element (GST_OBJECT (mixer), s);
446   if (gst_element_post_message (GST_ELEMENT (mixer), m) == FALSE) {
447     GST_WARNING ("This element has no bus, therefore no message sent!");
448   }
449 }
450
451 /**
452  * gst_mixer_volume_changed:
453  * @mixer: the #GstMixer (a #GstElement) that owns the track
454  * @track: the GstMixerTrack that has changed.
455  * @volumes: Array of volume values, one per channel on the mixer track.
456  *
457  * This function is called by the mixer implementation to produce
458  * a notification message on the bus indicating that the volume(s) for the
459  * given track have changed.
460  *
461  * This function only works for GstElements that are implementing the
462  * GstMixer interface, and the element needs to have been provided a bus.
463  */
464 void
465 gst_mixer_volume_changed (GstMixer * mixer,
466     GstMixerTrack * track, gint * volumes)
467 {
468   GstStructure *s;
469   GstMessage *m;
470   GValue l = { 0, };
471   GValue v = { 0, };
472   gint i;
473
474   g_return_if_fail (mixer != NULL);
475   g_return_if_fail (GST_IS_ELEMENT (mixer));
476   g_return_if_fail (track != NULL);
477
478   s = gst_structure_new (GST_MIXER_MESSAGE_NAME,
479       "type", G_TYPE_STRING, "volume-changed",
480       "track", GST_TYPE_MIXER_TRACK, track, NULL);
481
482   g_value_init (&l, GST_TYPE_ARRAY);
483
484   g_value_init (&v, G_TYPE_INT);
485
486   /* FIXME 0.11: pass track->num_channels to the function */
487   for (i = 0; i < track->num_channels; ++i) {
488     g_value_set_int (&v, volumes[i]);
489     gst_value_array_append_value (&l, &v);
490   }
491   g_value_unset (&v);
492
493   gst_structure_set_value (s, "volumes", &l);
494   g_value_unset (&l);
495
496   m = gst_message_new_element (GST_OBJECT (mixer), s);
497   if (gst_element_post_message (GST_ELEMENT (mixer), m) == FALSE) {
498     GST_WARNING ("This element has no bus, therefore no message sent!");
499   }
500 }
501
502 /**
503  * gst_mixer_option_changed:
504  * @mixer: the #GstMixer (a #GstElement) that owns the options 
505  * @opts: the GstMixerOptions that has changed value.
506  * @value: the new value of the GstMixerOptions.
507  *
508  * This function is called by the mixer implementation to produce
509  * a notification message on the bus indicating that the given options
510  * object has changed state. 
511  *
512  * This function only works for GstElements that are implementing the
513  * GstMixer interface, and the element needs to have been provided a bus.
514  */
515 void
516 gst_mixer_option_changed (GstMixer * mixer,
517     GstMixerOptions * opts, const gchar * value)
518 {
519   GstStructure *s;
520   GstMessage *m;
521
522   g_return_if_fail (mixer != NULL);
523   g_return_if_fail (GST_IS_ELEMENT (mixer));
524   g_return_if_fail (opts != NULL);
525
526   s = gst_structure_new (GST_MIXER_MESSAGE_NAME,
527       "type", G_TYPE_STRING, "option-changed",
528       "options", GST_TYPE_MIXER_OPTIONS, opts,
529       "value", G_TYPE_STRING, value, NULL);
530
531   m = gst_message_new_element (GST_OBJECT (mixer), s);
532   if (gst_element_post_message (GST_ELEMENT (mixer), m) == FALSE) {
533     GST_WARNING ("This element has no bus, therefore no message sent!");
534   }
535 }
536
537 /**
538  * gst_mixer_options_list_changed:
539  * @mixer: the #GstMixer (a #GstElement) that owns the options 
540  * @opts: the GstMixerOptions whose list of values has changed
541  *
542  * This function is called by the mixer implementation to produce
543  * a notification message on the bus indicating that the list of possible
544  * options of a given options object has changed.
545  *
546  * The new options are not contained in the message on purpose. Applications
547  * should call gst_mixer_options_get_values() on @opts to make @opts update
548  * its internal state and obtain the new list of values.
549  *
550  * This function only works for GstElements that are implementing the
551  * GstMixer interface, and the element needs to have been provided a bus
552  * for this to work.
553  *
554  * Since: 0.10.18
555  */
556 void
557 gst_mixer_options_list_changed (GstMixer * mixer, GstMixerOptions * opts)
558 {
559   GstStructure *s;
560   GstMessage *m;
561
562   g_return_if_fail (mixer != NULL);
563   g_return_if_fail (GST_IS_ELEMENT (mixer));
564   g_return_if_fail (opts != NULL);
565   g_return_if_fail (GST_IS_MIXER_OPTIONS (opts));
566
567   /* we do not include the new list here on purpose, so that the application
568    * has to use gst_mixer_options_get_values() to get the new list, which then
569    * allows the mixer options object to update the internal GList in a somewhat
570    * thread-safe way at least */
571   s = gst_structure_new (GST_MIXER_MESSAGE_NAME,
572       "type", G_TYPE_STRING, "options-list-changed",
573       "options", GST_TYPE_MIXER_OPTIONS, opts, NULL);
574
575   m = gst_message_new_element (GST_OBJECT (mixer), s);
576   if (gst_element_post_message (GST_ELEMENT (mixer), m) == FALSE) {
577     GST_WARNING ("This element has no bus, therefore no message sent!");
578   }
579 }
580
581 /**
582  * gst_mixer_mixer_changed:
583  * @mixer: the #GstMixer (a #GstElement) which has changed
584  *
585  * This function is called by the mixer implementation to produce
586  * a notification message on the bus indicating that the list of available
587  * mixer tracks for a given mixer object has changed. Applications should
588  * rebuild their interface when they receive this message.
589  *
590  * This function only works for GstElements that are implementing the
591  * GstMixer interface, and the element needs to have been provided a bus.
592  *
593  * Since: 0.10.18
594  */
595 void
596 gst_mixer_mixer_changed (GstMixer * mixer)
597 {
598   GstStructure *s;
599   GstMessage *m;
600
601   g_return_if_fail (mixer != NULL);
602   g_return_if_fail (GST_IS_ELEMENT (mixer));
603
604   s = gst_structure_new (GST_MIXER_MESSAGE_NAME,
605       "type", G_TYPE_STRING, "mixer-changed", NULL);
606
607   m = gst_message_new_element (GST_OBJECT (mixer), s);
608   if (gst_element_post_message (GST_ELEMENT (mixer), m) == FALSE) {
609     GST_WARNING ("This element has no bus, therefore no message sent!");
610   }
611 }
612
613 static gboolean
614 gst_mixer_message_is_mixer_message (GstMessage * message)
615 {
616   const GstStructure *s;
617
618   if (message == NULL)
619     return FALSE;
620   if (GST_MESSAGE_TYPE (message) != GST_MESSAGE_ELEMENT)
621     return FALSE;
622
623   s = gst_message_get_structure (message);
624   return gst_structure_has_name (s, GST_MIXER_MESSAGE_NAME);
625 }
626
627 /**
628  * gst_mixer_message_get_type:
629  * @message: A GstMessage to inspect.
630  *
631  * Check a bus message to see if it is a GstMixer notification
632  * message and return the GstMixerMessageType identifying which
633  * type of notification it is.
634  *
635  * Returns: The type of the GstMixerMessage, or GST_MIXER_MESSAGE_INVALID
636  * if the message is not a GstMixer notification.
637  *
638  * Since: 0.10.14
639  */
640 GstMixerMessageType
641 gst_mixer_message_get_type (GstMessage * message)
642 {
643   const GstStructure *s;
644   const gchar *m_type;
645
646   if (!gst_mixer_message_is_mixer_message (message))
647     return GST_MIXER_MESSAGE_INVALID;
648
649   s = gst_message_get_structure (message);
650   m_type = gst_structure_get_string (s, "type");
651   g_return_val_if_fail (m_type != NULL, GST_MIXER_MESSAGE_INVALID);
652
653   if (g_str_equal (m_type, "mute-toggled"))
654     return GST_MIXER_MESSAGE_MUTE_TOGGLED;
655   else if (g_str_equal (m_type, "record-toggled"))
656     return GST_MIXER_MESSAGE_RECORD_TOGGLED;
657   else if (g_str_equal (m_type, "volume-changed"))
658     return GST_MIXER_MESSAGE_VOLUME_CHANGED;
659   else if (g_str_equal (m_type, "option-changed"))
660     return GST_MIXER_MESSAGE_OPTION_CHANGED;
661   else if (g_str_equal (m_type, "options-list-changed"))
662     return GST_MIXER_MESSAGE_OPTIONS_LIST_CHANGED;
663   else if (g_str_equal (m_type, "mixer-changed"))
664     return GST_MIXER_MESSAGE_MIXER_CHANGED;
665
666   return GST_MIXER_MESSAGE_INVALID;
667 }
668
669 #define GST_MIXER_MESSAGE_HAS_TYPE(msg,msg_type) \
670 (gst_mixer_message_get_type (msg) == GST_MIXER_MESSAGE_ ## msg_type)
671
672 /**
673  * gst_mixer_message_parse_mute_toggled:
674  * @message: A mute-toggled change notification message.
675  * @track: Pointer to hold a GstMixerTrack object, or NULL.
676  * @mute: A pointer to a gboolean variable, or NULL.
677  *
678  * Extracts the contents of a mute-toggled bus message. Reads
679  * the GstMixerTrack that has changed, and the new value of the mute
680  * flag.
681  *
682  * The GstMixerTrack remains valid until the message is freed.
683  *
684  * Since: 0.10.14
685  */
686 void
687 gst_mixer_message_parse_mute_toggled (GstMessage * message,
688     GstMixerTrack ** track, gboolean * mute)
689 {
690   const GstStructure *s;
691
692   g_return_if_fail (gst_mixer_message_is_mixer_message (message));
693   g_return_if_fail (GST_MIXER_MESSAGE_HAS_TYPE (message, MUTE_TOGGLED));
694
695   s = gst_message_get_structure (message);
696
697   if (track) {
698     const GValue *v = gst_structure_get_value (s, "track");
699
700     g_return_if_fail (v != NULL);
701     *track = (GstMixerTrack *) g_value_get_object (v);
702     g_return_if_fail (GST_IS_MIXER_TRACK (*track));
703   }
704
705   if (mute)
706     g_return_if_fail (gst_structure_get_boolean (s, "mute", mute));
707 }
708
709 /**
710  * gst_mixer_message_parse_record_toggled:
711  * @message: A record-toggled change notification message.
712  * @track: Pointer to hold a GstMixerTrack object, or NULL.
713  * @record: A pointer to a gboolean variable, or NULL.
714  *
715  * Extracts the contents of a record-toggled bus message. Reads
716  * the GstMixerTrack that has changed, and the new value of the 
717  * recording flag.
718  *
719  * The GstMixerTrack remains valid until the message is freed.
720  *
721  * Since: 0.10.14
722  */
723 void
724 gst_mixer_message_parse_record_toggled (GstMessage * message,
725     GstMixerTrack ** track, gboolean * record)
726 {
727   const GstStructure *s;
728
729   g_return_if_fail (gst_mixer_message_is_mixer_message (message));
730   g_return_if_fail (GST_MIXER_MESSAGE_HAS_TYPE (message, RECORD_TOGGLED));
731
732   s = gst_message_get_structure (message);
733
734   if (track) {
735     const GValue *v = gst_structure_get_value (s, "track");
736
737     g_return_if_fail (v != NULL);
738     *track = (GstMixerTrack *) g_value_get_object (v);
739     g_return_if_fail (GST_IS_MIXER_TRACK (*track));
740   }
741
742   if (record)
743     g_return_if_fail (gst_structure_get_boolean (s, "record", record));
744 }
745
746 /**
747  * gst_mixer_message_parse_volume_changed:
748  * @message: A volume-changed change notification message.
749  * @track: Pointer to hold a GstMixerTrack object, or NULL.
750  * @volumes: A pointer to receive an array of gint values, or NULL.
751  * @num_channels: Result location to receive the number of channels, or NULL.
752  *
753  * Parses a volume-changed notification message and extracts the track object
754  * it refers to, as well as an array of volumes and the size of the volumes array.
755  *
756  * The track object remains valid until the message is freed.
757  *
758  * The caller must free the array returned in the volumes parameter using g_free
759  * when they are done with it.
760  *
761  * Since: 0.10.14
762  */
763 void
764 gst_mixer_message_parse_volume_changed (GstMessage * message,
765     GstMixerTrack ** track, gint ** volumes, gint * num_channels)
766 {
767   const GstStructure *s;
768
769   g_return_if_fail (gst_mixer_message_is_mixer_message (message));
770   g_return_if_fail (GST_MIXER_MESSAGE_HAS_TYPE (message, VOLUME_CHANGED));
771
772   s = gst_message_get_structure (message);
773
774   if (track) {
775     const GValue *v = gst_structure_get_value (s, "track");
776
777     g_return_if_fail (v != NULL);
778     *track = (GstMixerTrack *) g_value_get_object (v);
779     g_return_if_fail (GST_IS_MIXER_TRACK (*track));
780   }
781
782   if (volumes || num_channels) {
783     gint n_chans, i;
784     const GValue *v = gst_structure_get_value (s, "volumes");
785
786     g_return_if_fail (v != NULL);
787     g_return_if_fail (GST_VALUE_HOLDS_ARRAY (v));
788
789     n_chans = gst_value_array_get_size (v);
790     if (num_channels)
791       *num_channels = n_chans;
792
793     if (volumes) {
794       *volumes = g_new (gint, n_chans);
795       for (i = 0; i < n_chans; i++) {
796         const GValue *e = gst_value_array_get_value (v, i);
797
798         g_return_if_fail (e != NULL && G_VALUE_HOLDS_INT (e));
799         (*volumes)[i] = g_value_get_int (e);
800       }
801     }
802   }
803 }
804
805 /**
806  * gst_mixer_message_parse_option_changed:
807  * @message: A volume-changed change notification message.
808  * @options: Pointer to hold a GstMixerOptions object, or NULL.
809  * @value: Result location to receive the new options value, or NULL.
810  *
811  * Extracts the GstMixerOptions and new value from a option-changed bus notification
812  * message.
813  *
814  * The options and value returned remain valid until the message is freed.
815  *
816  * Since: 0.10.14
817  */
818 void
819 gst_mixer_message_parse_option_changed (GstMessage * message,
820     GstMixerOptions ** options, const gchar ** value)
821 {
822   const GstStructure *s;
823
824   g_return_if_fail (gst_mixer_message_is_mixer_message (message));
825   g_return_if_fail (GST_MIXER_MESSAGE_HAS_TYPE (message, OPTION_CHANGED));
826
827   s = gst_message_get_structure (message);
828
829   if (options) {
830     const GValue *v = gst_structure_get_value (s, "options");
831
832     g_return_if_fail (v != NULL);
833     *options = (GstMixerOptions *) g_value_get_object (v);
834     g_return_if_fail (GST_IS_MIXER_OPTIONS (*options));
835   }
836
837   if (value)
838     *value = gst_structure_get_string (s, "value");
839 }
840
841 /**
842  * gst_mixer_message_parse_options_list_changed:
843  * @message: A volume-changed change notification message.
844  * @options: Pointer to hold a GstMixerOptions object, or NULL.
845  *
846  * Extracts the GstMixerOptions whose value list has changed from an
847  * options-list-changed bus notification message.
848  *
849  * The options object returned remains valid until the message is freed. You
850  * do not need to unref it.
851  *
852  * Since: 0.10.18
853  */
854 void
855 gst_mixer_message_parse_options_list_changed (GstMessage * message,
856     GstMixerOptions ** options)
857 {
858   const GstStructure *s;
859
860   g_return_if_fail (gst_mixer_message_is_mixer_message (message));
861   g_return_if_fail (GST_MIXER_MESSAGE_HAS_TYPE (message, OPTIONS_LIST_CHANGED));
862
863   s = gst_message_get_structure (message);
864
865   if (options) {
866     const GValue *v = gst_structure_get_value (s, "options");
867
868     g_return_if_fail (v != NULL);
869     *options = (GstMixerOptions *) g_value_get_object (v);
870     g_return_if_fail (GST_IS_MIXER_OPTIONS (*options));
871   }
872 }