Merge branch 'master' into 0.11
[platform/upstream/gst-plugins-base.git] / gst-libs / gst / audio / 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 "audio-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 /* FIXME 0.11: check if we need to add API for sometimes-supportedness
54  * (aka making up for GstImplementsInterface removal) */
55
56 static void gst_mixer_class_init (GstMixerInterface * iface);
57
58 GType
59 gst_mixer_get_type (void)
60 {
61   static GType gst_mixer_type = 0;
62
63   if (!gst_mixer_type) {
64     static const GTypeInfo gst_mixer_info = {
65       sizeof (GstMixerInterface),
66       (GBaseInitFunc) gst_mixer_class_init,
67       NULL,
68       NULL,
69       NULL,
70       NULL,
71       0,
72       0,
73       NULL,
74     };
75
76     gst_mixer_type = g_type_register_static (G_TYPE_INTERFACE,
77         "GstMixer", &gst_mixer_info, 0);
78   }
79
80   return gst_mixer_type;
81 }
82
83 static void
84 gst_mixer_class_init (GstMixerInterface * iface)
85 {
86   /* default virtual functions */
87   iface->get_mixer_type = NULL;
88   iface->list_tracks = NULL;
89   iface->set_volume = NULL;
90   iface->get_volume = NULL;
91   iface->set_mute = NULL;
92   iface->set_record = NULL;
93   iface->set_option = NULL;
94   iface->get_option = NULL;
95 }
96
97 /**
98  * gst_mixer_list_tracks:
99  * @mixer: the #GstMixer (a #GstElement) to get the tracks from.
100  *
101  * Returns a list of available tracks for this mixer/element. Note
102  * that it is allowed for sink (output) elements to only provide
103  * the output tracks in this list. Likewise, for sources (inputs),
104  * it is allowed to only provide input elements in this list.
105  *
106  * Returns: A #GList consisting of zero or more #GstMixerTracks.
107  *          The list is owned by the #GstMixer instance and must not be freed
108  *          or modified.
109  */
110
111 const GList *
112 gst_mixer_list_tracks (GstMixer * mixer)
113 {
114   GstMixerInterface *iface;
115
116   g_return_val_if_fail (mixer != NULL, NULL);
117
118   iface = GST_MIXER_GET_INTERFACE (mixer);
119
120   if (iface->list_tracks) {
121     return iface->list_tracks (mixer);
122   }
123
124   return NULL;
125 }
126
127 /**
128  * gst_mixer_set_volume:
129  * @mixer: The #GstMixer (a #GstElement) that owns the track.
130  * @track: The #GstMixerTrack to set the volume on.
131  * @volumes: an array of integers (of size track->num_channels)
132  *           that gives the wanted volume for each channel in
133  *           this track.
134  *
135  * Sets the volume on each channel in a track. Short note about
136  * naming: a track is defined as one separate stream owned by
137  * the mixer/element, such as 'Line-in' or 'Microphone'. A
138  * channel is said to be a mono-stream inside this track. A
139  * stereo track thus contains two channels.
140  */
141
142 void
143 gst_mixer_set_volume (GstMixer * mixer, GstMixerTrack * track, gint * volumes)
144 {
145   GstMixerInterface *iface;
146
147   g_return_if_fail (mixer != NULL);
148   g_return_if_fail (track != NULL);
149   g_return_if_fail (volumes != NULL);
150
151   iface = GST_MIXER_GET_INTERFACE (mixer);
152
153   if (iface->set_volume) {
154     iface->set_volume (mixer, track, volumes);
155   }
156 }
157
158 /**
159  * gst_mixer_get_volume:
160  * @mixer: the #GstMixer (a #GstElement) that owns the track
161  * @track: the GstMixerTrack to get the volume from.
162  * @volumes: a pre-allocated array of integers (of size
163  *           track->num_channels) to store the current volume
164  *           of each channel in the given track in.
165  *
166  * Get the current volume(s) on the given track.
167  */
168
169 void
170 gst_mixer_get_volume (GstMixer * mixer, GstMixerTrack * track, gint * volumes)
171 {
172   GstMixerInterface *iface;
173
174   g_return_if_fail (mixer != NULL);
175   g_return_if_fail (track != NULL);
176   g_return_if_fail (volumes != NULL);
177
178   iface = GST_MIXER_GET_INTERFACE (mixer);
179
180   if (iface->get_volume) {
181     iface->get_volume (mixer, track, volumes);
182   } else {
183     gint i;
184
185     for (i = 0; i < track->num_channels; i++) {
186       volumes[i] = 0;
187     }
188   }
189 }
190
191 /**
192  * gst_mixer_set_mute:
193  * @mixer: the #GstMixer (a #GstElement) that owns the track.
194  * @track: the #GstMixerTrack to operate on.
195  * @mute: a boolean value indicating whether to turn on or off
196  *        muting.
197  *
198  * Mutes or unmutes the given channel. To find out whether a
199  * track is currently muted, use GST_MIXER_TRACK_HAS_FLAG ().
200  */
201
202 void
203 gst_mixer_set_mute (GstMixer * mixer, GstMixerTrack * track, gboolean mute)
204 {
205   GstMixerInterface *iface;
206
207   g_return_if_fail (mixer != NULL);
208   g_return_if_fail (track != NULL);
209
210   iface = GST_MIXER_GET_INTERFACE (mixer);
211
212   if (iface->set_mute) {
213     iface->set_mute (mixer, track, mute);
214   }
215 }
216
217 /**
218  * gst_mixer_set_record:
219  * @mixer: The #GstMixer (a #GstElement) that owns the track.
220  * @track: the #GstMixerTrack to operate on.
221  * @record: a boolean value that indicates whether to turn on
222  *          or off recording.
223  *
224  * Enables or disables recording on the given track. Note that
225  * this is only possible on input tracks, not on output tracks
226  * (see GST_MIXER_TRACK_HAS_FLAG () and the GST_MIXER_TRACK_INPUT
227  * flag).
228  */
229
230 void
231 gst_mixer_set_record (GstMixer * mixer, GstMixerTrack * track, gboolean record)
232 {
233   GstMixerInterface *iface = GST_MIXER_GET_INTERFACE (mixer);
234
235   if (iface->set_record) {
236     iface->set_record (mixer, track, record);
237   }
238 }
239
240 /**
241  * gst_mixer_set_option:
242  * @mixer: The #GstMixer (a #GstElement) that owns the optionlist.
243  * @opts: The #GstMixerOptions that we operate on.
244  * @value: The requested new option value.
245  *
246  * Sets a name/value option in the mixer to the requested value.
247  */
248
249 void
250 gst_mixer_set_option (GstMixer * mixer, GstMixerOptions * opts, gchar * value)
251 {
252   GstMixerInterface *iface;
253
254   g_return_if_fail (mixer != NULL);
255   g_return_if_fail (opts != NULL);
256
257   iface = GST_MIXER_GET_INTERFACE (mixer);
258
259   if (iface->set_option) {
260     iface->set_option (mixer, opts, value);
261   }
262 }
263
264 /**
265  * gst_mixer_get_option:
266  * @mixer: The #GstMixer (a #GstElement) that owns the optionlist.
267  * @opts: The #GstMixerOptions that we operate on.
268  *
269  * Get the current value of a name/value option in the mixer.
270  *
271  * Returns: current value of the name/value option.
272  */
273
274 const gchar *
275 gst_mixer_get_option (GstMixer * mixer, GstMixerOptions * opts)
276 {
277   GstMixerInterface *iface;
278
279   g_return_val_if_fail (mixer != NULL, NULL);
280   g_return_val_if_fail (opts != NULL, NULL);
281
282   iface = GST_MIXER_GET_INTERFACE (mixer);
283
284   if (iface->get_option) {
285     return iface->get_option (mixer, opts);
286   }
287
288   return NULL;
289 }
290
291 /**
292  * gst_mixer_get_mixer_type:
293  * @mixer: The #GstMixer implementation
294  *
295  * Get the #GstMixerType of this mixer implementation.
296  *
297  * Returns: A the #GstMixerType.
298  *
299  * Since: 0.10.24
300  */
301 GstMixerType
302 gst_mixer_get_mixer_type (GstMixer * mixer)
303 {
304   GstMixerInterface *iface = GST_MIXER_GET_INTERFACE (mixer);
305
306   g_return_val_if_fail (iface->get_mixer_type != NULL, GST_MIXER_SOFTWARE);
307   return iface->get_mixer_type (mixer);
308 }
309
310 /**
311  * gst_mixer_get_mixer_flags:
312  * @mixer: The #GstMixer implementation
313  *
314  * Get the set of supported flags for this mixer implementation.
315  *
316  * Returns: A set of or-ed GstMixerFlags for supported features.
317  */
318 GstMixerFlags
319 gst_mixer_get_mixer_flags (GstMixer * mixer)
320 {
321   GstMixerInterface *iface;
322
323   g_return_val_if_fail (mixer != NULL, FALSE);
324   iface = GST_MIXER_GET_INTERFACE (mixer);
325
326   if (iface->get_mixer_flags) {
327     return iface->get_mixer_flags (mixer);
328   }
329   return GST_MIXER_FLAG_NONE;
330 }
331
332 /**
333  * gst_mixer_mute_toggled:
334  * @mixer: the #GstMixer (a #GstElement) that owns the track
335  * @track: the GstMixerTrack that has change mute state.
336  * @mute: the new state of the mute flag on the track
337  *
338  * This function is called by the mixer implementation to produce
339  * a notification message on the bus indicating that the given track
340  * has changed mute state.
341  *
342  * This function only works for GstElements that are implementing the
343  * GstMixer interface, and the element needs to have been provided a bus.
344  */
345 void
346 gst_mixer_mute_toggled (GstMixer * mixer, GstMixerTrack * track, gboolean mute)
347 {
348   GstStructure *s;
349   GstMessage *m;
350
351   g_return_if_fail (mixer != NULL);
352   g_return_if_fail (GST_IS_ELEMENT (mixer));
353   g_return_if_fail (track != NULL);
354
355   s = gst_structure_new (GST_MIXER_MESSAGE_NAME,
356       "type", G_TYPE_STRING, "mute-toggled",
357       "track", GST_TYPE_MIXER_TRACK, track, "mute", G_TYPE_BOOLEAN, mute, NULL);
358
359   m = gst_message_new_element (GST_OBJECT (mixer), s);
360   if (gst_element_post_message (GST_ELEMENT (mixer), m) == FALSE) {
361     GST_WARNING ("This element has no bus, therefore no message sent!");
362   }
363 }
364
365 /**
366  * gst_mixer_record_toggled:
367  * @mixer: the #GstMixer (a #GstElement) that owns the track
368  * @track: the GstMixerTrack that has changed recording state.
369  * @record: the new state of the record flag on the track
370  *
371  * This function is called by the mixer implementation to produce
372  * a notification message on the bus indicating that the given track
373  * has changed recording state.
374  *
375  * This function only works for GstElements that are implementing the
376  * GstMixer interface, and the element needs to have been provided a bus.
377  */
378 void
379 gst_mixer_record_toggled (GstMixer * mixer,
380     GstMixerTrack * track, gboolean record)
381 {
382   GstStructure *s;
383   GstMessage *m;
384
385   g_return_if_fail (mixer != NULL);
386   g_return_if_fail (GST_IS_ELEMENT (mixer));
387   g_return_if_fail (track != NULL);
388
389   s = gst_structure_new (GST_MIXER_MESSAGE_NAME,
390       "type", G_TYPE_STRING, "record-toggled",
391       "track", GST_TYPE_MIXER_TRACK, track,
392       "record", G_TYPE_BOOLEAN, record, NULL);
393
394   m = gst_message_new_element (GST_OBJECT (mixer), s);
395   if (gst_element_post_message (GST_ELEMENT (mixer), m) == FALSE) {
396     GST_WARNING ("This element has no bus, therefore no message sent!");
397   }
398 }
399
400 /**
401  * gst_mixer_volume_changed:
402  * @mixer: the #GstMixer (a #GstElement) that owns the track
403  * @track: the GstMixerTrack that has changed.
404  * @volumes: Array of volume values, one per channel on the mixer track.
405  *
406  * This function is called by the mixer implementation to produce
407  * a notification message on the bus indicating that the volume(s) for the
408  * given track have changed.
409  *
410  * This function only works for GstElements that are implementing the
411  * GstMixer interface, and the element needs to have been provided a bus.
412  */
413 void
414 gst_mixer_volume_changed (GstMixer * mixer,
415     GstMixerTrack * track, gint * volumes)
416 {
417   GstStructure *s;
418   GstMessage *m;
419   GValue l = { 0, };
420   GValue v = { 0, };
421   gint i;
422
423   g_return_if_fail (mixer != NULL);
424   g_return_if_fail (GST_IS_ELEMENT (mixer));
425   g_return_if_fail (track != NULL);
426
427   s = gst_structure_new (GST_MIXER_MESSAGE_NAME,
428       "type", G_TYPE_STRING, "volume-changed",
429       "track", GST_TYPE_MIXER_TRACK, track, NULL);
430
431   g_value_init (&l, GST_TYPE_ARRAY);
432
433   g_value_init (&v, G_TYPE_INT);
434
435   /* FIXME 0.11: pass track->num_channels to the function */
436   for (i = 0; i < track->num_channels; ++i) {
437     g_value_set_int (&v, volumes[i]);
438     gst_value_array_append_value (&l, &v);
439   }
440   g_value_unset (&v);
441
442   gst_structure_set_value (s, "volumes", &l);
443   g_value_unset (&l);
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_option_changed:
453  * @mixer: the #GstMixer (a #GstElement) that owns the options 
454  * @opts: the GstMixerOptions that has changed value.
455  * @value: the new value of the GstMixerOptions.
456  *
457  * This function is called by the mixer implementation to produce
458  * a notification message on the bus indicating that the given options
459  * object has changed state. 
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_option_changed (GstMixer * mixer,
466     GstMixerOptions * opts, const gchar * value)
467 {
468   GstStructure *s;
469   GstMessage *m;
470
471   g_return_if_fail (mixer != NULL);
472   g_return_if_fail (GST_IS_ELEMENT (mixer));
473   g_return_if_fail (opts != NULL);
474
475   s = gst_structure_new (GST_MIXER_MESSAGE_NAME,
476       "type", G_TYPE_STRING, "option-changed",
477       "options", GST_TYPE_MIXER_OPTIONS, opts,
478       "value", G_TYPE_STRING, value, NULL);
479
480   m = gst_message_new_element (GST_OBJECT (mixer), s);
481   if (gst_element_post_message (GST_ELEMENT (mixer), m) == FALSE) {
482     GST_WARNING ("This element has no bus, therefore no message sent!");
483   }
484 }
485
486 /**
487  * gst_mixer_options_list_changed:
488  * @mixer: the #GstMixer (a #GstElement) that owns the options 
489  * @opts: the GstMixerOptions whose list of values has changed
490  *
491  * This function is called by the mixer implementation to produce
492  * a notification message on the bus indicating that the list of possible
493  * options of a given options object has changed.
494  *
495  * The new options are not contained in the message on purpose. Applications
496  * should call gst_mixer_options_get_values() on @opts to make @opts update
497  * its internal state and obtain the new list of values.
498  *
499  * This function only works for GstElements that are implementing the
500  * GstMixer interface, and the element needs to have been provided a bus
501  * for this to work.
502  *
503  * Since: 0.10.18
504  */
505 void
506 gst_mixer_options_list_changed (GstMixer * mixer, GstMixerOptions * opts)
507 {
508   GstStructure *s;
509   GstMessage *m;
510
511   g_return_if_fail (mixer != NULL);
512   g_return_if_fail (GST_IS_ELEMENT (mixer));
513   g_return_if_fail (opts != NULL);
514   g_return_if_fail (GST_IS_MIXER_OPTIONS (opts));
515
516   /* we do not include the new list here on purpose, so that the application
517    * has to use gst_mixer_options_get_values() to get the new list, which then
518    * allows the mixer options object to update the internal GList in a somewhat
519    * thread-safe way at least */
520   s = gst_structure_new (GST_MIXER_MESSAGE_NAME,
521       "type", G_TYPE_STRING, "options-list-changed",
522       "options", GST_TYPE_MIXER_OPTIONS, opts, NULL);
523
524   m = gst_message_new_element (GST_OBJECT (mixer), s);
525   if (gst_element_post_message (GST_ELEMENT (mixer), m) == FALSE) {
526     GST_WARNING ("This element has no bus, therefore no message sent!");
527   }
528 }
529
530 /**
531  * gst_mixer_mixer_changed:
532  * @mixer: the #GstMixer (a #GstElement) which has changed
533  *
534  * This function is called by the mixer implementation to produce
535  * a notification message on the bus indicating that the list of available
536  * mixer tracks for a given mixer object has changed. Applications should
537  * rebuild their interface when they receive this message.
538  *
539  * This function only works for GstElements that are implementing the
540  * GstMixer interface, and the element needs to have been provided a bus.
541  *
542  * Since: 0.10.18
543  */
544 void
545 gst_mixer_mixer_changed (GstMixer * mixer)
546 {
547   GstStructure *s;
548   GstMessage *m;
549
550   g_return_if_fail (mixer != NULL);
551   g_return_if_fail (GST_IS_ELEMENT (mixer));
552
553   s = gst_structure_new (GST_MIXER_MESSAGE_NAME,
554       "type", G_TYPE_STRING, "mixer-changed", NULL);
555
556   m = gst_message_new_element (GST_OBJECT (mixer), s);
557   if (gst_element_post_message (GST_ELEMENT (mixer), m) == FALSE) {
558     GST_WARNING ("This element has no bus, therefore no message sent!");
559   }
560 }
561
562 static gboolean
563 gst_mixer_message_is_mixer_message (GstMessage * message)
564 {
565   const GstStructure *s;
566
567   if (message == NULL)
568     return FALSE;
569   if (GST_MESSAGE_TYPE (message) != GST_MESSAGE_ELEMENT)
570     return FALSE;
571
572   s = gst_message_get_structure (message);
573   return gst_structure_has_name (s, GST_MIXER_MESSAGE_NAME);
574 }
575
576 /**
577  * gst_mixer_message_get_type:
578  * @message: A GstMessage to inspect.
579  *
580  * Check a bus message to see if it is a GstMixer notification
581  * message and return the GstMixerMessageType identifying which
582  * type of notification it is.
583  *
584  * Returns: The type of the GstMixerMessage, or GST_MIXER_MESSAGE_INVALID
585  * if the message is not a GstMixer notification.
586  *
587  * Since: 0.10.14
588  */
589 GstMixerMessageType
590 gst_mixer_message_get_type (GstMessage * message)
591 {
592   const GstStructure *s;
593   const gchar *m_type;
594
595   if (!gst_mixer_message_is_mixer_message (message))
596     return GST_MIXER_MESSAGE_INVALID;
597
598   s = gst_message_get_structure (message);
599   m_type = gst_structure_get_string (s, "type");
600   g_return_val_if_fail (m_type != NULL, GST_MIXER_MESSAGE_INVALID);
601
602   if (g_str_equal (m_type, "mute-toggled"))
603     return GST_MIXER_MESSAGE_MUTE_TOGGLED;
604   else if (g_str_equal (m_type, "record-toggled"))
605     return GST_MIXER_MESSAGE_RECORD_TOGGLED;
606   else if (g_str_equal (m_type, "volume-changed"))
607     return GST_MIXER_MESSAGE_VOLUME_CHANGED;
608   else if (g_str_equal (m_type, "option-changed"))
609     return GST_MIXER_MESSAGE_OPTION_CHANGED;
610   else if (g_str_equal (m_type, "options-list-changed"))
611     return GST_MIXER_MESSAGE_OPTIONS_LIST_CHANGED;
612   else if (g_str_equal (m_type, "mixer-changed"))
613     return GST_MIXER_MESSAGE_MIXER_CHANGED;
614
615   return GST_MIXER_MESSAGE_INVALID;
616 }
617
618 #define GST_MIXER_MESSAGE_HAS_TYPE(msg,msg_type) \
619 (gst_mixer_message_get_type (msg) == GST_MIXER_MESSAGE_ ## msg_type)
620
621 /**
622  * gst_mixer_message_parse_mute_toggled:
623  * @message: A mute-toggled change notification message.
624  * @track: Pointer to hold a GstMixerTrack object, or NULL.
625  * @mute: A pointer to a gboolean variable, or NULL.
626  *
627  * Extracts the contents of a mute-toggled bus message. Reads
628  * the GstMixerTrack that has changed, and the new value of the mute
629  * flag.
630  *
631  * The GstMixerTrack remains valid until the message is freed.
632  *
633  * Since: 0.10.14
634  */
635 void
636 gst_mixer_message_parse_mute_toggled (GstMessage * message,
637     GstMixerTrack ** track, gboolean * mute)
638 {
639   const GstStructure *s;
640
641   g_return_if_fail (gst_mixer_message_is_mixer_message (message));
642   g_return_if_fail (GST_MIXER_MESSAGE_HAS_TYPE (message, MUTE_TOGGLED));
643
644   s = gst_message_get_structure (message);
645
646   if (track) {
647     const GValue *v = gst_structure_get_value (s, "track");
648
649     g_return_if_fail (v != NULL);
650     *track = (GstMixerTrack *) g_value_get_object (v);
651     g_return_if_fail (GST_IS_MIXER_TRACK (*track));
652   }
653
654   if (mute)
655     g_return_if_fail (gst_structure_get_boolean (s, "mute", mute));
656 }
657
658 /**
659  * gst_mixer_message_parse_record_toggled:
660  * @message: A record-toggled change notification message.
661  * @track: Pointer to hold a GstMixerTrack object, or NULL.
662  * @record: A pointer to a gboolean variable, or NULL.
663  *
664  * Extracts the contents of a record-toggled bus message. Reads
665  * the GstMixerTrack that has changed, and the new value of the 
666  * recording flag.
667  *
668  * The GstMixerTrack remains valid until the message is freed.
669  *
670  * Since: 0.10.14
671  */
672 void
673 gst_mixer_message_parse_record_toggled (GstMessage * message,
674     GstMixerTrack ** track, gboolean * record)
675 {
676   const GstStructure *s;
677
678   g_return_if_fail (gst_mixer_message_is_mixer_message (message));
679   g_return_if_fail (GST_MIXER_MESSAGE_HAS_TYPE (message, RECORD_TOGGLED));
680
681   s = gst_message_get_structure (message);
682
683   if (track) {
684     const GValue *v = gst_structure_get_value (s, "track");
685
686     g_return_if_fail (v != NULL);
687     *track = (GstMixerTrack *) g_value_get_object (v);
688     g_return_if_fail (GST_IS_MIXER_TRACK (*track));
689   }
690
691   if (record)
692     g_return_if_fail (gst_structure_get_boolean (s, "record", record));
693 }
694
695 /**
696  * gst_mixer_message_parse_volume_changed:
697  * @message: A volume-changed change notification message.
698  * @track: Pointer to hold a GstMixerTrack object, or NULL.
699  * @volumes: A pointer to receive an array of gint values, or NULL.
700  * @num_channels: Result location to receive the number of channels, or NULL.
701  *
702  * Parses a volume-changed notification message and extracts the track object
703  * it refers to, as well as an array of volumes and the size of the volumes array.
704  *
705  * The track object remains valid until the message is freed.
706  *
707  * The caller must free the array returned in the volumes parameter using g_free
708  * when they are done with it.
709  *
710  * Since: 0.10.14
711  */
712 void
713 gst_mixer_message_parse_volume_changed (GstMessage * message,
714     GstMixerTrack ** track, gint ** volumes, gint * num_channels)
715 {
716   const GstStructure *s;
717
718   g_return_if_fail (gst_mixer_message_is_mixer_message (message));
719   g_return_if_fail (GST_MIXER_MESSAGE_HAS_TYPE (message, VOLUME_CHANGED));
720
721   s = gst_message_get_structure (message);
722
723   if (track) {
724     const GValue *v = gst_structure_get_value (s, "track");
725
726     g_return_if_fail (v != NULL);
727     *track = (GstMixerTrack *) g_value_get_object (v);
728     g_return_if_fail (GST_IS_MIXER_TRACK (*track));
729   }
730
731   if (volumes || num_channels) {
732     gint n_chans, i;
733     const GValue *v = gst_structure_get_value (s, "volumes");
734
735     g_return_if_fail (v != NULL);
736     g_return_if_fail (GST_VALUE_HOLDS_ARRAY (v));
737
738     n_chans = gst_value_array_get_size (v);
739     if (num_channels)
740       *num_channels = n_chans;
741
742     if (volumes) {
743       *volumes = g_new (gint, n_chans);
744       for (i = 0; i < n_chans; i++) {
745         const GValue *e = gst_value_array_get_value (v, i);
746
747         g_return_if_fail (e != NULL && G_VALUE_HOLDS_INT (e));
748         (*volumes)[i] = g_value_get_int (e);
749       }
750     }
751   }
752 }
753
754 /**
755  * gst_mixer_message_parse_option_changed:
756  * @message: A volume-changed change notification message.
757  * @options: Pointer to hold a GstMixerOptions object, or NULL.
758  * @value: Result location to receive the new options value, or NULL.
759  *
760  * Extracts the GstMixerOptions and new value from a option-changed bus notification
761  * message.
762  *
763  * The options and value returned remain valid until the message is freed.
764  *
765  * Since: 0.10.14
766  */
767 void
768 gst_mixer_message_parse_option_changed (GstMessage * message,
769     GstMixerOptions ** options, const gchar ** value)
770 {
771   const GstStructure *s;
772
773   g_return_if_fail (gst_mixer_message_is_mixer_message (message));
774   g_return_if_fail (GST_MIXER_MESSAGE_HAS_TYPE (message, OPTION_CHANGED));
775
776   s = gst_message_get_structure (message);
777
778   if (options) {
779     const GValue *v = gst_structure_get_value (s, "options");
780
781     g_return_if_fail (v != NULL);
782     *options = (GstMixerOptions *) g_value_get_object (v);
783     g_return_if_fail (GST_IS_MIXER_OPTIONS (*options));
784   }
785
786   if (value)
787     *value = gst_structure_get_string (s, "value");
788 }
789
790 /**
791  * gst_mixer_message_parse_options_list_changed:
792  * @message: A volume-changed change notification message.
793  * @options: Pointer to hold a GstMixerOptions object, or NULL.
794  *
795  * Extracts the GstMixerOptions whose value list has changed from an
796  * options-list-changed bus notification message.
797  *
798  * The options object returned remains valid until the message is freed. You
799  * do not need to unref it.
800  *
801  * Since: 0.10.18
802  */
803 void
804 gst_mixer_message_parse_options_list_changed (GstMessage * message,
805     GstMixerOptions ** options)
806 {
807   const GstStructure *s;
808
809   g_return_if_fail (gst_mixer_message_is_mixer_message (message));
810   g_return_if_fail (GST_MIXER_MESSAGE_HAS_TYPE (message, OPTIONS_LIST_CHANGED));
811
812   s = gst_message_get_structure (message);
813
814   if (options) {
815     const GValue *v = gst_structure_get_value (s, "options");
816
817     g_return_if_fail (v != NULL);
818     *options = (GstMixerOptions *) g_value_get_object (v);
819     g_return_if_fail (GST_IS_MIXER_OPTIONS (*options));
820   }
821 }