1 /*
2  * Copyright (C) 2014 Michal Ratajsky <michal.ratajsky@gmail.com>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the licence, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 #include <string.h>
19 #include <glib.h>
20 #include <glib-object.h>
21 
22 #include "matemixer-device.h"
23 #include "matemixer-enums.h"
24 #include "matemixer-enum-types.h"
25 #include "matemixer-stream.h"
26 #include "matemixer-stream-control.h"
27 #include "matemixer-stream-private.h"
28 #include "matemixer-stream-switch.h"
29 #include "matemixer-switch.h"
30 
31 /**
32  * SECTION:matemixer-stream
33  * @include: libmatemixer/matemixer.h
34  */
35 
36 struct _MateMixerStreamPrivate
37 {
38     gchar                  *name;
39     gchar                  *label;
40     MateMixerDirection      direction;
41     MateMixerDevice        *device;
42     MateMixerStreamControl *control;
43 };
44 
45 enum {
46     PROP_0,
47     PROP_NAME,
48     PROP_LABEL,
49     PROP_DIRECTION,
50     PROP_DEVICE,
51     PROP_DEFAULT_CONTROL,
52     N_PROPERTIES
53 };
54 
55 static GParamSpec *properties[N_PROPERTIES] = { NULL, };
56 
57 enum {
58     CONTROL_ADDED,
59     CONTROL_REMOVED,
60     SWITCH_ADDED,
61     SWITCH_REMOVED,
62     N_SIGNALS
63 };
64 
65 static guint signals[N_SIGNALS] = { 0, };
66 
67 static void mate_mixer_stream_get_property (GObject              *object,
68                                             guint                 param_id,
69                                             GValue               *value,
70                                             GParamSpec           *pspec);
71 static void mate_mixer_stream_set_property (GObject              *object,
72                                             guint                 param_id,
73                                             const GValue         *value,
74                                             GParamSpec           *pspec);
75 
76 static void mate_mixer_stream_dispose      (GObject              *object);
77 static void mate_mixer_stream_finalize     (GObject              *object);
78 
79 G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (MateMixerStream, mate_mixer_stream, G_TYPE_OBJECT)
80 
81 static MateMixerStreamControl *mate_mixer_stream_real_get_control (MateMixerStream *stream,
82                                                                    const gchar     *name);
83 static MateMixerStreamSwitch * mate_mixer_stream_real_get_switch  (MateMixerStream *stream,
84                                                                    const gchar     *name);
85 
86 static void
mate_mixer_stream_class_init(MateMixerStreamClass * klass)87 mate_mixer_stream_class_init (MateMixerStreamClass *klass)
88 {
89     GObjectClass *object_class;
90 
91     klass->get_control = mate_mixer_stream_real_get_control;
92     klass->get_switch  = mate_mixer_stream_real_get_switch;
93 
94     object_class = G_OBJECT_CLASS (klass);
95     object_class->dispose      = mate_mixer_stream_dispose;
96     object_class->finalize     = mate_mixer_stream_finalize;
97     object_class->get_property = mate_mixer_stream_get_property;
98     object_class->set_property = mate_mixer_stream_set_property;
99 
100     properties[PROP_NAME] =
101         g_param_spec_string ("name",
102                              "Name",
103                              "Name of the stream",
104                              NULL,
105                              G_PARAM_READWRITE |
106                              G_PARAM_CONSTRUCT_ONLY |
107                              G_PARAM_STATIC_STRINGS);
108 
109     properties[PROP_LABEL] =
110         g_param_spec_string ("label",
111                              "Label",
112                              "Label of the stream",
113                              NULL,
114                              G_PARAM_READWRITE |
115                              G_PARAM_CONSTRUCT_ONLY |
116                              G_PARAM_STATIC_STRINGS);
117 
118     properties[PROP_DIRECTION] =
119         g_param_spec_enum ("direction",
120                            "Direction",
121                            "Direction of the stream",
122                            MATE_MIXER_TYPE_DIRECTION,
123                            MATE_MIXER_DIRECTION_UNKNOWN,
124                            G_PARAM_READWRITE |
125                            G_PARAM_CONSTRUCT_ONLY |
126                            G_PARAM_STATIC_STRINGS);
127 
128     properties[PROP_DEVICE] =
129         g_param_spec_object ("device",
130                              "Device",
131                              "Device the stream belongs to",
132                              MATE_MIXER_TYPE_DEVICE,
133                              G_PARAM_READWRITE |
134                              G_PARAM_CONSTRUCT_ONLY |
135                              G_PARAM_STATIC_STRINGS);
136 
137     properties[PROP_DEFAULT_CONTROL] =
138         g_param_spec_object ("default-control",
139                              "Default control",
140                              "Default control of the stream",
141                              MATE_MIXER_TYPE_STREAM_CONTROL,
142                              G_PARAM_READWRITE |
143                              G_PARAM_CONSTRUCT_ONLY |
144                              G_PARAM_STATIC_STRINGS);
145 
146     g_object_class_install_properties (object_class, N_PROPERTIES, properties);
147 
148     signals[CONTROL_ADDED] =
149         g_signal_new ("control-added",
150                       G_TYPE_FROM_CLASS (object_class),
151                       G_SIGNAL_RUN_FIRST,
152                       G_STRUCT_OFFSET (MateMixerStreamClass, control_added),
153                       NULL,
154                       NULL,
155                       g_cclosure_marshal_VOID__STRING,
156                       G_TYPE_NONE,
157                       1,
158                       G_TYPE_STRING);
159 
160     signals[CONTROL_REMOVED] =
161         g_signal_new ("control-removed",
162                       G_TYPE_FROM_CLASS (object_class),
163                       G_SIGNAL_RUN_FIRST,
164                       G_STRUCT_OFFSET (MateMixerStreamClass, control_removed),
165                       NULL,
166                       NULL,
167                       g_cclosure_marshal_VOID__STRING,
168                       G_TYPE_NONE,
169                       1,
170                       G_TYPE_STRING);
171 
172     signals[SWITCH_ADDED] =
173         g_signal_new ("switch-added",
174                       G_TYPE_FROM_CLASS (object_class),
175                       G_SIGNAL_RUN_FIRST,
176                       G_STRUCT_OFFSET (MateMixerStreamClass, switch_added),
177                       NULL,
178                       NULL,
179                       g_cclosure_marshal_VOID__STRING,
180                       G_TYPE_NONE,
181                       1,
182                       G_TYPE_STRING);
183 
184     signals[SWITCH_REMOVED] =
185         g_signal_new ("switch-removed",
186                       G_TYPE_FROM_CLASS (object_class),
187                       G_SIGNAL_RUN_FIRST,
188                       G_STRUCT_OFFSET (MateMixerStreamClass, switch_removed),
189                       NULL,
190                       NULL,
191                       g_cclosure_marshal_VOID__STRING,
192                       G_TYPE_NONE,
193                       1,
194                       G_TYPE_STRING);
195 }
196 
197 static void
mate_mixer_stream_get_property(GObject * object,guint param_id,GValue * value,GParamSpec * pspec)198 mate_mixer_stream_get_property (GObject    *object,
199                                 guint       param_id,
200                                 GValue     *value,
201                                 GParamSpec *pspec)
202 {
203     MateMixerStream *stream;
204 
205     stream = MATE_MIXER_STREAM (object);
206 
207     switch (param_id) {
208     case PROP_NAME:
209         g_value_set_string (value, stream->priv->name);
210         break;
211     case PROP_LABEL:
212         g_value_set_string (value, stream->priv->label);
213         break;
214     case PROP_DIRECTION:
215         g_value_set_enum (value, stream->priv->direction);
216         break;
217     case PROP_DEVICE:
218         g_value_set_object (value, stream->priv->device);
219         break;
220     case PROP_DEFAULT_CONTROL:
221         g_value_set_object (value, stream->priv->control);
222         break;
223 
224     default:
225         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
226         break;
227     }
228 }
229 
230 static void
mate_mixer_stream_set_property(GObject * object,guint param_id,const GValue * value,GParamSpec * pspec)231 mate_mixer_stream_set_property (GObject      *object,
232                                 guint         param_id,
233                                 const GValue *value,
234                                 GParamSpec   *pspec)
235 {
236     MateMixerStream *stream;
237 
238     stream = MATE_MIXER_STREAM (object);
239 
240     switch (param_id) {
241     case PROP_NAME:
242         /* Construct-only string */
243         stream->priv->name = g_value_dup_string (value);
244         break;
245     case PROP_LABEL:
246         /* Construct-only string */
247         stream->priv->label = g_value_dup_string (value);
248         break;
249     case PROP_DIRECTION:
250         stream->priv->direction = g_value_get_enum (value);
251         break;
252     case PROP_DEVICE:
253         /* Construct-only object */
254         stream->priv->device = g_value_get_object (value);
255 
256         if (stream->priv->device != NULL)
257             g_object_add_weak_pointer (G_OBJECT (stream->priv->device),
258                                        (gpointer *) &stream->priv->device);
259         break;
260     case PROP_DEFAULT_CONTROL:
261         /* Construct-only object */
262         stream->priv->control = g_value_dup_object (value);
263         break;
264 
265     default:
266         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
267         break;
268     }
269 }
270 
271 static void
mate_mixer_stream_init(MateMixerStream * stream)272 mate_mixer_stream_init (MateMixerStream *stream)
273 {
274     stream->priv = mate_mixer_stream_get_instance_private (stream);
275 }
276 
277 static void
mate_mixer_stream_dispose(GObject * object)278 mate_mixer_stream_dispose (GObject *object)
279 {
280     MateMixerStream *stream;
281 
282     stream = MATE_MIXER_STREAM (object);
283 
284     g_clear_object (&stream->priv->control);
285 
286     G_OBJECT_CLASS (mate_mixer_stream_parent_class)->dispose (object);
287 }
288 
289 static void
mate_mixer_stream_finalize(GObject * object)290 mate_mixer_stream_finalize (GObject *object)
291 {
292     MateMixerStream *stream;
293 
294     stream = MATE_MIXER_STREAM (object);
295 
296     g_free (stream->priv->name);
297     g_free (stream->priv->label);
298 
299     G_OBJECT_CLASS (mate_mixer_stream_parent_class)->finalize (object);
300 }
301 
302 /**
303  * mate_mixer_stream_get_name:
304  * @stream: a #MateMixerStream
305  */
306 const gchar *
mate_mixer_stream_get_name(MateMixerStream * stream)307 mate_mixer_stream_get_name (MateMixerStream *stream)
308 {
309     g_return_val_if_fail (MATE_MIXER_IS_STREAM (stream), NULL);
310 
311     return stream->priv->name;
312 }
313 
314 /**
315  * mate_mixer_stream_get_label:
316  * @stream: a #MateMixerStream
317  */
318 const gchar *
mate_mixer_stream_get_label(MateMixerStream * stream)319 mate_mixer_stream_get_label (MateMixerStream *stream)
320 {
321     g_return_val_if_fail (MATE_MIXER_IS_STREAM (stream), NULL);
322 
323     return stream->priv->label;
324 }
325 
326 /**
327  * mate_mixer_stream_get_direction:
328  * @stream: a #MateMixerStream
329  */
330 MateMixerDirection
mate_mixer_stream_get_direction(MateMixerStream * stream)331 mate_mixer_stream_get_direction (MateMixerStream *stream)
332 {
333     g_return_val_if_fail (MATE_MIXER_IS_STREAM (stream), MATE_MIXER_DIRECTION_UNKNOWN);
334 
335     return stream->priv->direction;
336 }
337 
338 /**
339  * mate_mixer_stream_get_device:
340  * @stream: a #MateMixerStream
341  */
342 MateMixerDevice *
mate_mixer_stream_get_device(MateMixerStream * stream)343 mate_mixer_stream_get_device (MateMixerStream *stream)
344 {
345     g_return_val_if_fail (MATE_MIXER_IS_STREAM (stream), NULL);
346 
347     return stream->priv->device;
348 }
349 
350 /**
351  * mate_mixer_stream_get_control:
352  * @stream: a #MateMixerStream
353  * @name: the name of a stream control
354  */
355 MateMixerStreamControl *
mate_mixer_stream_get_control(MateMixerStream * stream,const gchar * name)356 mate_mixer_stream_get_control (MateMixerStream *stream, const gchar *name)
357 {
358     g_return_val_if_fail (MATE_MIXER_IS_STREAM (stream), NULL);
359     g_return_val_if_fail (name != NULL, NULL);
360 
361     return MATE_MIXER_STREAM_GET_CLASS (stream)->get_control (stream, name);
362 }
363 
364 /**
365  * mate_mixer_stream_get_switch:
366  * @stream: a #MateMixerStream
367  * @name: the name of a stream switch
368  *
369  * Gets the switch with the given name.
370  *
371  * Returns: a #MateMixerStreamSwitch or %NULL if there is no such switch.
372  */
373 MateMixerStreamSwitch *
mate_mixer_stream_get_switch(MateMixerStream * stream,const gchar * name)374 mate_mixer_stream_get_switch (MateMixerStream *stream, const gchar *name)
375 {
376     g_return_val_if_fail (MATE_MIXER_IS_STREAM (stream), NULL);
377     g_return_val_if_fail (name != NULL, NULL);
378 
379     return MATE_MIXER_STREAM_GET_CLASS (stream)->get_switch (stream, name);
380 }
381 
382 /**
383  * mate_mixer_stream_get_default_control:
384  * @stream: a #MateMixerStream
385  */
386 MateMixerStreamControl *
mate_mixer_stream_get_default_control(MateMixerStream * stream)387 mate_mixer_stream_get_default_control (MateMixerStream *stream)
388 {
389     const GList *list;
390 
391     g_return_val_if_fail (MATE_MIXER_IS_STREAM (stream), NULL);
392 
393     if (stream->priv->control != NULL)
394         return stream->priv->control;
395 
396     /* If the stream does not have a default control, just return the first one */
397     list = mate_mixer_stream_list_controls (stream);
398     if (list != NULL)
399         return MATE_MIXER_STREAM_CONTROL (list->data);
400 
401     return NULL;
402 }
403 
404 /**
405  * mate_mixer_stream_list_controls:
406  * @stream: a #MateMixerStream
407  */
408 const GList *
mate_mixer_stream_list_controls(MateMixerStream * stream)409 mate_mixer_stream_list_controls (MateMixerStream *stream)
410 {
411     MateMixerStreamClass *klass;
412 
413     g_return_val_if_fail (MATE_MIXER_IS_STREAM (stream), NULL);
414 
415     klass = MATE_MIXER_STREAM_GET_CLASS (stream);
416 
417     if (G_LIKELY (klass->list_controls != NULL))
418         return klass->list_controls (stream);
419 
420     return NULL;
421 }
422 
423 /**
424  * mate_mixer_stream_list_switches:
425  * @stream: a #MateMixerStream
426  */
427 const GList *
mate_mixer_stream_list_switches(MateMixerStream * stream)428 mate_mixer_stream_list_switches (MateMixerStream *stream)
429 {
430     MateMixerStreamClass *klass;
431 
432     g_return_val_if_fail (MATE_MIXER_IS_STREAM (stream), NULL);
433 
434     klass = MATE_MIXER_STREAM_GET_CLASS (stream);
435 
436     if (G_LIKELY (klass->list_switches != NULL))
437         return klass->list_switches (stream);
438 
439     return NULL;
440 }
441 
442 static MateMixerStreamControl *
mate_mixer_stream_real_get_control(MateMixerStream * stream,const gchar * name)443 mate_mixer_stream_real_get_control (MateMixerStream *stream, const gchar *name)
444 {
445     const GList *list;
446 
447     g_return_val_if_fail (MATE_MIXER_IS_STREAM (stream), NULL);
448     g_return_val_if_fail (name != NULL, NULL);
449 
450     list = mate_mixer_stream_list_controls (stream);
451     while (list != NULL) {
452         MateMixerStreamControl *control = MATE_MIXER_STREAM_CONTROL (list->data);
453 
454         if (strcmp (name, mate_mixer_stream_control_get_name (control)) == 0)
455             return control;
456 
457         list = list->next;
458     }
459     return NULL;
460 }
461 
462 static MateMixerStreamSwitch *
mate_mixer_stream_real_get_switch(MateMixerStream * stream,const gchar * name)463 mate_mixer_stream_real_get_switch (MateMixerStream *stream, const gchar *name)
464 {
465     const GList *list;
466 
467     g_return_val_if_fail (MATE_MIXER_IS_STREAM (stream), NULL);
468     g_return_val_if_fail (name != NULL, NULL);
469 
470     list = mate_mixer_stream_list_switches (stream);
471     while (list != NULL) {
472         MateMixerSwitch *swtch = MATE_MIXER_SWITCH (list->data);
473 
474         if (strcmp (name, mate_mixer_switch_get_name (swtch)) == 0)
475             return MATE_MIXER_STREAM_SWITCH (swtch);
476 
477         list = list->next;
478     }
479     return NULL;
480 }
481 
482 void
_mate_mixer_stream_set_default_control(MateMixerStream * stream,MateMixerStreamControl * control)483 _mate_mixer_stream_set_default_control (MateMixerStream        *stream,
484                                         MateMixerStreamControl *control)
485 {
486     g_return_if_fail (MATE_MIXER_IS_STREAM (stream));
487     g_return_if_fail (control == NULL || MATE_MIXER_IS_STREAM_CONTROL (control));
488 
489     if (stream->priv->control == control)
490         return;
491 
492     if (stream->priv->control != NULL)
493         g_object_unref (stream->priv->control);
494 
495     /* The default control is allowed to be NULL */
496     if (control != NULL) {
497         stream->priv->control = g_object_ref (control);
498 
499         g_debug ("Stream %s default control changed to %s",
500                  mate_mixer_stream_get_name (stream),
501                  mate_mixer_stream_control_get_name (control));
502     } else {
503         stream->priv->control = NULL;
504 
505         g_debug ("Stream %s default control unset",
506                  mate_mixer_stream_get_name (stream));
507     }
508 
509     g_object_notify_by_pspec (G_OBJECT (stream), properties[PROP_DEFAULT_CONTROL]);
510 }
511