No issues found
Tool | Failure ID | Location | Function | Message | Data |
---|---|---|---|---|---|
clang-analyzer | no-output-found | gvc/gvc-mixer-stream.c | Message(text='Unable to locate XML output from invoke-clang-analyzer') | None |
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
2 *
3 * Copyright (C) 2008 William Jon McCann
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18 *
19 */
20
21 #include "config.h"
22
23 #include <stdlib.h>
24 #include <stdio.h>
25 #include <unistd.h>
26
27 #include <glib.h>
28 #include <glib/gi18n-lib.h>
29
30 #include <pulse/pulseaudio.h>
31
32 #include "gvc-mixer-stream.h"
33 #include "gvc-mixer-stream-private.h"
34 #include "gvc-channel-map-private.h"
35
36 #define GVC_MIXER_STREAM_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GVC_TYPE_MIXER_STREAM, GvcMixerStreamPrivate))
37
38 static guint32 stream_serial = 1;
39
40 struct GvcMixerStreamPrivate
41 {
42 pa_context *pa_context;
43 guint id;
44 guint index;
45 gint card_index;
46 GvcChannelMap *channel_map;
47 char *name;
48 char *description;
49 char *application_id;
50 char *icon_name;
51 gboolean is_muted;
52 gboolean can_decibel;
53 gboolean is_event_stream;
54 gboolean is_virtual;
55 pa_volume_t base_volume;
56 pa_operation *change_volume_op;
57 char *port;
58 char *human_port;
59 GList *ports;
60 };
61
62 enum
63 {
64 PROP_0,
65 PROP_ID,
66 PROP_PA_CONTEXT,
67 PROP_CHANNEL_MAP,
68 PROP_INDEX,
69 PROP_NAME,
70 PROP_DESCRIPTION,
71 PROP_APPLICATION_ID,
72 PROP_ICON_NAME,
73 PROP_VOLUME,
74 PROP_DECIBEL,
75 PROP_IS_MUTED,
76 PROP_CAN_DECIBEL,
77 PROP_IS_EVENT_STREAM,
78 PROP_IS_VIRTUAL,
79 PROP_CARD_INDEX,
80 PROP_PORT,
81 };
82
83 static void gvc_mixer_stream_class_init (GvcMixerStreamClass *klass);
84 static void gvc_mixer_stream_init (GvcMixerStream *mixer_stream);
85 static void gvc_mixer_stream_finalize (GObject *object);
86
87 G_DEFINE_ABSTRACT_TYPE (GvcMixerStream, gvc_mixer_stream, G_TYPE_OBJECT)
88
89 static guint32
90 get_next_stream_serial (void)
91 {
92 guint32 serial;
93
94 serial = stream_serial++;
95
96 if ((gint32)stream_serial < 0) {
97 stream_serial = 1;
98 }
99
100 return serial;
101 }
102
103 pa_context *
104 gvc_mixer_stream_get_pa_context (GvcMixerStream *stream)
105 {
106 g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), 0);
107 return stream->priv->pa_context;
108 }
109
110 guint
111 gvc_mixer_stream_get_index (GvcMixerStream *stream)
112 {
113 g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), 0);
114 return stream->priv->index;
115 }
116
117 guint
118 gvc_mixer_stream_get_id (GvcMixerStream *stream)
119 {
120 g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), 0);
121 return stream->priv->id;
122 }
123
124 const GvcChannelMap *
125 gvc_mixer_stream_get_channel_map (GvcMixerStream *stream)
126 {
127 g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), NULL);
128 return stream->priv->channel_map;
129 }
130
131 /**
132 * gvc_mixer_stream_get_volume:
133 * @stream:
134 *
135 * Returns: (type guint32) (transfer none):
136 */
137 pa_volume_t
138 gvc_mixer_stream_get_volume (GvcMixerStream *stream)
139 {
140 g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), 0);
141
142 return (pa_volume_t) gvc_channel_map_get_volume(stream->priv->channel_map)[VOLUME];
143 }
144
145 gdouble
146 gvc_mixer_stream_get_decibel (GvcMixerStream *stream)
147 {
148 g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), 0);
149
150 return pa_sw_volume_to_dB(
151 (pa_volume_t) gvc_channel_map_get_volume(stream->priv->channel_map)[VOLUME]);
152 }
153
154 /**
155 * gvc_mixer_stream_set_volume:
156 * @stream:
157 * @volume: (type guint32):
158 *
159 * Returns:
160 */
161 gboolean
162 gvc_mixer_stream_set_volume (GvcMixerStream *stream,
163 pa_volume_t volume)
164 {
165 pa_cvolume cv;
166
167 g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE);
168
169 cv = *gvc_channel_map_get_cvolume(stream->priv->channel_map);
170 pa_cvolume_scale(&cv, volume);
171
172 if (!pa_cvolume_equal(gvc_channel_map_get_cvolume(stream->priv->channel_map), &cv)) {
173 gvc_channel_map_volume_changed(stream->priv->channel_map, &cv, FALSE);
174 g_object_notify (G_OBJECT (stream), "volume");
175 return TRUE;
176 }
177
178 return FALSE;
179 }
180
181 gboolean
182 gvc_mixer_stream_set_decibel (GvcMixerStream *stream,
183 gdouble db)
184 {
185 pa_cvolume cv;
186
187 g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE);
188
189 cv = *gvc_channel_map_get_cvolume(stream->priv->channel_map);
190 pa_cvolume_scale(&cv, pa_sw_volume_from_dB(db));
191
192 if (!pa_cvolume_equal(gvc_channel_map_get_cvolume(stream->priv->channel_map), &cv)) {
193 gvc_channel_map_volume_changed(stream->priv->channel_map, &cv, FALSE);
194 g_object_notify (G_OBJECT (stream), "volume");
195 }
196
197 return TRUE;
198 }
199
200 gboolean
201 gvc_mixer_stream_get_is_muted (GvcMixerStream *stream)
202 {
203 g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE);
204 return stream->priv->is_muted;
205 }
206
207 gboolean
208 gvc_mixer_stream_get_can_decibel (GvcMixerStream *stream)
209 {
210 g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE);
211 return stream->priv->can_decibel;
212 }
213
214 gboolean
215 gvc_mixer_stream_set_is_muted (GvcMixerStream *stream,
216 gboolean is_muted)
217 {
218 g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE);
219
220 if (is_muted != stream->priv->is_muted) {
221 stream->priv->is_muted = is_muted;
222 g_object_notify (G_OBJECT (stream), "is-muted");
223 }
224
225 return TRUE;
226 }
227
228 gboolean
229 gvc_mixer_stream_set_can_decibel (GvcMixerStream *stream,
230 gboolean can_decibel)
231 {
232 g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE);
233
234 if (can_decibel != stream->priv->can_decibel) {
235 stream->priv->can_decibel = can_decibel;
236 g_object_notify (G_OBJECT (stream), "can-decibel");
237 }
238
239 return TRUE;
240 }
241
242 const char *
243 gvc_mixer_stream_get_name (GvcMixerStream *stream)
244 {
245 g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), NULL);
246 return stream->priv->name;
247 }
248
249 const char *
250 gvc_mixer_stream_get_description (GvcMixerStream *stream)
251 {
252 g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), NULL);
253 return stream->priv->description;
254 }
255
256 gboolean
257 gvc_mixer_stream_set_name (GvcMixerStream *stream,
258 const char *name)
259 {
260 g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE);
261
262 g_free (stream->priv->name);
263 stream->priv->name = g_strdup (name);
264 g_object_notify (G_OBJECT (stream), "name");
265
266 return TRUE;
267 }
268
269 gboolean
270 gvc_mixer_stream_set_description (GvcMixerStream *stream,
271 const char *description)
272 {
273 g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE);
274
275 g_free (stream->priv->description);
276 stream->priv->description = g_strdup (description);
277 g_object_notify (G_OBJECT (stream), "description");
278
279 return TRUE;
280 }
281
282 gboolean
283 gvc_mixer_stream_is_event_stream (GvcMixerStream *stream)
284 {
285 g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE);
286
287 return stream->priv->is_event_stream;
288 }
289
290 gboolean
291 gvc_mixer_stream_set_is_event_stream (GvcMixerStream *stream,
292 gboolean is_event_stream)
293 {
294 g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE);
295
296 stream->priv->is_event_stream = is_event_stream;
297 g_object_notify (G_OBJECT (stream), "is-event-stream");
298
299 return TRUE;
300 }
301
302 gboolean
303 gvc_mixer_stream_is_virtual (GvcMixerStream *stream)
304 {
305 g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE);
306
307 return stream->priv->is_virtual;
308 }
309
310 gboolean
311 gvc_mixer_stream_set_is_virtual (GvcMixerStream *stream,
312 gboolean is_virtual)
313 {
314 g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE);
315
316 stream->priv->is_virtual = is_virtual;
317 g_object_notify (G_OBJECT (stream), "is-virtual");
318
319 return TRUE;
320 }
321
322 const char *
323 gvc_mixer_stream_get_application_id (GvcMixerStream *stream)
324 {
325 g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), NULL);
326 return stream->priv->application_id;
327 }
328
329 gboolean
330 gvc_mixer_stream_set_application_id (GvcMixerStream *stream,
331 const char *application_id)
332 {
333 g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE);
334
335 g_free (stream->priv->application_id);
336 stream->priv->application_id = g_strdup (application_id);
337 g_object_notify (G_OBJECT (stream), "application-id");
338
339 return TRUE;
340 }
341
342 static void
343 on_channel_map_volume_changed (GvcChannelMap *channel_map,
344 gboolean set,
345 GvcMixerStream *stream)
346 {
347 if (set == TRUE)
348 gvc_mixer_stream_push_volume (stream);
349
350 g_object_notify (G_OBJECT (stream), "volume");
351 }
352
353 static gboolean
354 gvc_mixer_stream_set_channel_map (GvcMixerStream *stream,
355 GvcChannelMap *channel_map)
356 {
357 g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE);
358
359 if (channel_map != NULL) {
360 g_object_ref (channel_map);
361 }
362
363 if (stream->priv->channel_map != NULL) {
364 g_signal_handlers_disconnect_by_func (stream->priv->channel_map,
365 on_channel_map_volume_changed,
366 stream);
367 g_object_unref (stream->priv->channel_map);
368 }
369
370 stream->priv->channel_map = channel_map;
371
372 if (stream->priv->channel_map != NULL) {
373 g_signal_connect (stream->priv->channel_map,
374 "volume-changed",
375 G_CALLBACK (on_channel_map_volume_changed),
376 stream);
377
378 g_object_notify (G_OBJECT (stream), "channel-map");
379 }
380
381 return TRUE;
382 }
383
384 const char *
385 gvc_mixer_stream_get_icon_name (GvcMixerStream *stream)
386 {
387 g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), NULL);
388 return stream->priv->icon_name;
389 }
390
391 /**
392 * gvc_mixer_stream_get_gicon:
393 * @stream: a #GvcMixerStream
394 *
395 * Returns: (transfer full): a new #GIcon
396 */
397 GIcon *
398 gvc_mixer_stream_get_gicon (GvcMixerStream *stream)
399 {
400 g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), NULL);
401 if (stream->priv->icon_name == NULL)
402 return NULL;
403 return g_themed_icon_new_with_default_fallbacks (stream->priv->icon_name);
404 }
405
406 gboolean
407 gvc_mixer_stream_set_icon_name (GvcMixerStream *stream,
408 const char *icon_name)
409 {
410 g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE);
411
412 g_free (stream->priv->icon_name);
413 stream->priv->icon_name = g_strdup (icon_name);
414 g_object_notify (G_OBJECT (stream), "icon-name");
415
416 return TRUE;
417 }
418
419 /**
420 * gvc_mixer_stream_get_base_volume:
421 * @stream:
422 *
423 * Returns: (type guint32) (transfer none):
424 */
425 pa_volume_t
426 gvc_mixer_stream_get_base_volume (GvcMixerStream *stream)
427 {
428 g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), 0);
429
430 return stream->priv->base_volume;
431 }
432
433 /**
434 * gvc_mixer_stream_set_base_volume:
435 * @stream:
436 * @base_volume: (type guint32):
437 *
438 * Returns:
439 */
440 gboolean
441 gvc_mixer_stream_set_base_volume (GvcMixerStream *stream,
442 pa_volume_t base_volume)
443 {
444 g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE);
445
446 stream->priv->base_volume = base_volume;
447
448 return TRUE;
449 }
450
451 const GvcMixerStreamPort *
452 gvc_mixer_stream_get_port (GvcMixerStream *stream)
453 {
454 GList *l;
455
456 g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), NULL);
457 g_return_val_if_fail (stream->priv->ports != NULL, NULL);
458
459 for (l = stream->priv->ports; l != NULL; l = l->next) {
460 GvcMixerStreamPort *p = l->data;
461 if (g_strcmp0 (stream->priv->port, p->port) == 0) {
462 return p;
463 }
464 }
465
466 g_assert_not_reached ();
467
468 return NULL;
469 }
470
471 gboolean
472 gvc_mixer_stream_set_port (GvcMixerStream *stream,
473 const char *port)
474 {
475 GList *l;
476
477 g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE);
478 g_return_val_if_fail (stream->priv->ports != NULL, FALSE);
479
480 g_free (stream->priv->port);
481 stream->priv->port = g_strdup (port);
482
483 g_free (stream->priv->human_port);
484 stream->priv->human_port = NULL;
485
486 for (l = stream->priv->ports; l != NULL; l = l->next) {
487 GvcMixerStreamPort *p = l->data;
488 if (g_str_equal (stream->priv->port, p->port)) {
489 stream->priv->human_port = g_strdup (p->human_port);
490 break;
491 }
492 }
493
494 g_object_notify (G_OBJECT (stream), "port");
495
496 return TRUE;
497 }
498
499 gboolean
500 gvc_mixer_stream_change_port (GvcMixerStream *stream,
501 const char *port)
502 {
503 g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE);
504 return GVC_MIXER_STREAM_GET_CLASS (stream)->change_port (stream, port);
505 }
506
507 /**
508 * gvc_mixer_stream_get_ports:
509 *
510 * Return value: (transfer none) (element-type GvcMixerStreamPort):
511 */
512 const GList *
513 gvc_mixer_stream_get_ports (GvcMixerStream *stream)
514 {
515 g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), NULL);
516 return stream->priv->ports;
517 }
518
519 static int
520 sort_ports (GvcMixerStreamPort *a,
521 GvcMixerStreamPort *b)
522 {
523 if (a->priority == b->priority)
524 return 0;
525 if (a->priority > b->priority)
526 return 1;
527 return -1;
528 }
529
530 /**
531 * gvc_mixer_stream_set_ports:
532 * @ports: (transfer full) (element-type GvcMixerStreamPort):
533 */
534 gboolean
535 gvc_mixer_stream_set_ports (GvcMixerStream *stream,
536 GList *ports)
537 {
538 g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE);
539 g_return_val_if_fail (stream->priv->ports == NULL, FALSE);
540
541 stream->priv->ports = g_list_sort (ports, (GCompareFunc) sort_ports);
542
543 return TRUE;
544 }
545
546 gint
547 gvc_mixer_stream_get_card_index (GvcMixerStream *stream)
548 {
549 g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), PA_INVALID_INDEX);
550 return stream->priv->card_index;
551 }
552
553 gboolean
554 gvc_mixer_stream_set_card_index (GvcMixerStream *stream,
555 gint card_index)
556 {
557 g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE);
558
559 stream->priv->card_index = card_index;
560 g_object_notify (G_OBJECT (stream), "card-index");
561
562 return TRUE;
563 }
564
565 static void
566 gvc_mixer_stream_set_property (GObject *object,
567 guint prop_id,
568 const GValue *value,
569 GParamSpec *pspec)
570 {
571 GvcMixerStream *self = GVC_MIXER_STREAM (object);
572
573 switch (prop_id) {
574 case PROP_PA_CONTEXT:
575 self->priv->pa_context = g_value_get_pointer (value);
576 break;
577 case PROP_INDEX:
578 self->priv->index = g_value_get_ulong (value);
579 break;
580 case PROP_ID:
581 self->priv->id = g_value_get_ulong (value);
582 break;
583 case PROP_CHANNEL_MAP:
584 gvc_mixer_stream_set_channel_map (self, g_value_get_object (value));
585 break;
586 case PROP_NAME:
587 gvc_mixer_stream_set_name (self, g_value_get_string (value));
588 break;
589 case PROP_DESCRIPTION:
590 gvc_mixer_stream_set_description (self, g_value_get_string (value));
591 break;
592 case PROP_APPLICATION_ID:
593 gvc_mixer_stream_set_application_id (self, g_value_get_string (value));
594 break;
595 case PROP_ICON_NAME:
596 gvc_mixer_stream_set_icon_name (self, g_value_get_string (value));
597 break;
598 case PROP_VOLUME:
599 gvc_mixer_stream_set_volume (self, g_value_get_ulong (value));
600 break;
601 case PROP_DECIBEL:
602 gvc_mixer_stream_set_decibel (self, g_value_get_double (value));
603 break;
604 case PROP_IS_MUTED:
605 gvc_mixer_stream_set_is_muted (self, g_value_get_boolean (value));
606 break;
607 case PROP_IS_EVENT_STREAM:
608 gvc_mixer_stream_set_is_event_stream (self, g_value_get_boolean (value));
609 break;
610 case PROP_IS_VIRTUAL:
611 gvc_mixer_stream_set_is_virtual (self, g_value_get_boolean (value));
612 break;
613 case PROP_CAN_DECIBEL:
614 gvc_mixer_stream_set_can_decibel (self, g_value_get_boolean (value));
615 break;
616 case PROP_PORT:
617 gvc_mixer_stream_set_port (self, g_value_get_string (value));
618 break;
619 case PROP_CARD_INDEX:
620 self->priv->card_index = g_value_get_long (value);
621 break;
622 default:
623 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
624 break;
625 }
626 }
627
628 static void
629 gvc_mixer_stream_get_property (GObject *object,
630 guint prop_id,
631 GValue *value,
632 GParamSpec *pspec)
633 {
634 GvcMixerStream *self = GVC_MIXER_STREAM (object);
635
636 switch (prop_id) {
637 case PROP_PA_CONTEXT:
638 g_value_set_pointer (value, self->priv->pa_context);
639 break;
640 case PROP_INDEX:
641 g_value_set_ulong (value, self->priv->index);
642 break;
643 case PROP_ID:
644 g_value_set_ulong (value, self->priv->id);
645 break;
646 case PROP_CHANNEL_MAP:
647 g_value_set_object (value, self->priv->channel_map);
648 break;
649 case PROP_NAME:
650 g_value_set_string (value, self->priv->name);
651 break;
652 case PROP_DESCRIPTION:
653 g_value_set_string (value, self->priv->description);
654 break;
655 case PROP_APPLICATION_ID:
656 g_value_set_string (value, self->priv->application_id);
657 break;
658 case PROP_ICON_NAME:
659 g_value_set_string (value, self->priv->icon_name);
660 break;
661 case PROP_VOLUME:
662 g_value_set_ulong (value,
663 pa_cvolume_max(gvc_channel_map_get_cvolume(self->priv->channel_map)));
664 break;
665 case PROP_DECIBEL:
666 g_value_set_double (value,
667 pa_sw_volume_to_dB(pa_cvolume_max(gvc_channel_map_get_cvolume(self->priv->channel_map))));
668 break;
669 case PROP_IS_MUTED:
670 g_value_set_boolean (value, self->priv->is_muted);
671 break;
672 case PROP_IS_EVENT_STREAM:
673 g_value_set_boolean (value, self->priv->is_event_stream);
674 break;
675 case PROP_IS_VIRTUAL:
676 g_value_set_boolean (value, self->priv->is_virtual);
677 break;
678 case PROP_CAN_DECIBEL:
679 g_value_set_boolean (value, self->priv->can_decibel);
680 break;
681 case PROP_PORT:
682 g_value_set_string (value, self->priv->port);
683 break;
684 case PROP_CARD_INDEX:
685 g_value_set_long (value, self->priv->card_index);
686 break;
687 default:
688 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
689 break;
690 }
691 }
692
693 static GObject *
694 gvc_mixer_stream_constructor (GType type,
695 guint n_construct_properties,
696 GObjectConstructParam *construct_params)
697 {
698 GObject *object;
699 GvcMixerStream *self;
700
701 object = G_OBJECT_CLASS (gvc_mixer_stream_parent_class)->constructor (type, n_construct_properties, construct_params);
702
703 self = GVC_MIXER_STREAM (object);
704
705 self->priv->id = get_next_stream_serial ();
706
707 return object;
708 }
709
710 static gboolean
711 gvc_mixer_stream_real_change_port (GvcMixerStream *stream,
712 const char *port)
713 {
714 return FALSE;
715 }
716
717 static gboolean
718 gvc_mixer_stream_real_push_volume (GvcMixerStream *stream, gpointer *op)
719 {
720 return FALSE;
721 }
722
723 static gboolean
724 gvc_mixer_stream_real_change_is_muted (GvcMixerStream *stream,
725 gboolean is_muted)
726 {
727 return FALSE;
728 }
729
730 gboolean
731 gvc_mixer_stream_push_volume (GvcMixerStream *stream)
732 {
733 pa_operation *op;
734 gboolean ret;
735
736 g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE);
737
738 if (stream->priv->is_event_stream != FALSE)
739 return TRUE;
740
741 g_debug ("Pushing new volume to stream '%s' (%s)",
742 stream->priv->description, stream->priv->name);
743
744 ret = GVC_MIXER_STREAM_GET_CLASS (stream)->push_volume (stream, (gpointer *) &op);
745 if (ret) {
746 if (stream->priv->change_volume_op != NULL)
747 pa_operation_unref (stream->priv->change_volume_op);
748 stream->priv->change_volume_op = op;
749 }
750 return ret;
751 }
752
753 gboolean
754 gvc_mixer_stream_change_is_muted (GvcMixerStream *stream,
755 gboolean is_muted)
756 {
757 gboolean ret;
758 g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE);
759 ret = GVC_MIXER_STREAM_GET_CLASS (stream)->change_is_muted (stream, is_muted);
760 return ret;
761 }
762
763 gboolean
764 gvc_mixer_stream_is_running (GvcMixerStream *stream)
765 {
766 if (stream->priv->change_volume_op == NULL)
767 return FALSE;
768
769 if ((pa_operation_get_state(stream->priv->change_volume_op) == PA_OPERATION_RUNNING))
770 return TRUE;
771
772 pa_operation_unref(stream->priv->change_volume_op);
773 stream->priv->change_volume_op = NULL;
774
775 return FALSE;
776 }
777
778 static void
779 gvc_mixer_stream_class_init (GvcMixerStreamClass *klass)
780 {
781 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
782
783 gobject_class->constructor = gvc_mixer_stream_constructor;
784 gobject_class->finalize = gvc_mixer_stream_finalize;
785 gobject_class->set_property = gvc_mixer_stream_set_property;
786 gobject_class->get_property = gvc_mixer_stream_get_property;
787
788 klass->push_volume = gvc_mixer_stream_real_push_volume;
789 klass->change_port = gvc_mixer_stream_real_change_port;
790 klass->change_is_muted = gvc_mixer_stream_real_change_is_muted;
791
792 g_object_class_install_property (gobject_class,
793 PROP_INDEX,
794 g_param_spec_ulong ("index",
795 "Index",
796 "The index for this stream",
797 0, G_MAXULONG, 0,
798 G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
799 g_object_class_install_property (gobject_class,
800 PROP_ID,
801 g_param_spec_ulong ("id",
802 "id",
803 "The id for this stream",
804 0, G_MAXULONG, 0,
805 G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
806 g_object_class_install_property (gobject_class,
807 PROP_CHANNEL_MAP,
808 g_param_spec_object ("channel-map",
809 "channel map",
810 "The channel map for this stream",
811 GVC_TYPE_CHANNEL_MAP,
812 G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
813 g_object_class_install_property (gobject_class,
814 PROP_PA_CONTEXT,
815 g_param_spec_pointer ("pa-context",
816 "PulseAudio context",
817 "The PulseAudio context for this stream",
818 G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
819 g_object_class_install_property (gobject_class,
820 PROP_VOLUME,
821 g_param_spec_ulong ("volume",
822 "Volume",
823 "The volume for this stream",
824 0, G_MAXULONG, 0,
825 G_PARAM_READWRITE));
826 g_object_class_install_property (gobject_class,
827 PROP_DECIBEL,
828 g_param_spec_double ("decibel",
829 "Decibel",
830 "The decibel level for this stream",
831 -G_MAXDOUBLE, G_MAXDOUBLE, 0,
832 G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
833
834 g_object_class_install_property (gobject_class,
835 PROP_NAME,
836 g_param_spec_string ("name",
837 "Name",
838 "Name to display for this stream",
839 NULL,
840 G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
841 g_object_class_install_property (gobject_class,
842 PROP_DESCRIPTION,
843 g_param_spec_string ("description",
844 "Description",
845 "Description to display for this stream",
846 NULL,
847 G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
848 g_object_class_install_property (gobject_class,
849 PROP_APPLICATION_ID,
850 g_param_spec_string ("application-id",
851 "Application identifier",
852 "Application identifier for this stream",
853 NULL,
854 G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
855 g_object_class_install_property (gobject_class,
856 PROP_ICON_NAME,
857 g_param_spec_string ("icon-name",
858 "Icon Name",
859 "Name of icon to display for this stream",
860 NULL,
861 G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
862 g_object_class_install_property (gobject_class,
863 PROP_IS_MUTED,
864 g_param_spec_boolean ("is-muted",
865 "is muted",
866 "Whether stream is muted",
867 FALSE,
868 G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
869 g_object_class_install_property (gobject_class,
870 PROP_CAN_DECIBEL,
871 g_param_spec_boolean ("can-decibel",
872 "can decibel",
873 "Whether stream volume can be converted to decibel units",
874 FALSE,
875 G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
876 g_object_class_install_property (gobject_class,
877 PROP_IS_EVENT_STREAM,
878 g_param_spec_boolean ("is-event-stream",
879 "is event stream",
880 "Whether stream's role is to play an event",
881 FALSE,
882 G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
883 g_object_class_install_property (gobject_class,
884 PROP_IS_VIRTUAL,
885 g_param_spec_boolean ("is-virtual",
886 "is virtual stream",
887 "Whether the stream is virtual",
888 FALSE,
889 G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
890 g_object_class_install_property (gobject_class,
891 PROP_PORT,
892 g_param_spec_string ("port",
893 "Port",
894 "The name of the current port for this stream",
895 NULL,
896 G_PARAM_READWRITE));
897 g_object_class_install_property (gobject_class,
898 PROP_CARD_INDEX,
899 g_param_spec_long ("card-index",
900 "Card index",
901 "The index of the card for this stream",
902 PA_INVALID_INDEX, G_MAXLONG, PA_INVALID_INDEX,
903 G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
904 g_type_class_add_private (klass, sizeof (GvcMixerStreamPrivate));
905 }
906
907 static void
908 gvc_mixer_stream_init (GvcMixerStream *stream)
909 {
910 stream->priv = GVC_MIXER_STREAM_GET_PRIVATE (stream);
911 }
912
913 static void
914 free_port (GvcMixerStreamPort *p)
915 {
916 g_free (p->port);
917 g_free (p->human_port);
918 g_free (p);
919 }
920
921 static void
922 gvc_mixer_stream_finalize (GObject *object)
923 {
924 GvcMixerStream *mixer_stream;
925
926 g_return_if_fail (object != NULL);
927 g_return_if_fail (GVC_IS_MIXER_STREAM (object));
928
929 mixer_stream = GVC_MIXER_STREAM (object);
930
931 g_return_if_fail (mixer_stream->priv != NULL);
932
933 g_object_unref (mixer_stream->priv->channel_map);
934 mixer_stream->priv->channel_map = NULL;
935
936 g_free (mixer_stream->priv->name);
937 mixer_stream->priv->name = NULL;
938
939 g_free (mixer_stream->priv->description);
940 mixer_stream->priv->description = NULL;
941
942 g_free (mixer_stream->priv->application_id);
943 mixer_stream->priv->application_id = NULL;
944
945 g_free (mixer_stream->priv->icon_name);
946 mixer_stream->priv->icon_name = NULL;
947
948 g_free (mixer_stream->priv->port);
949 mixer_stream->priv->port = NULL;
950
951 g_free (mixer_stream->priv->human_port);
952 mixer_stream->priv->human_port = NULL;
953
954 g_list_foreach (mixer_stream->priv->ports, (GFunc) free_port, NULL);
955 g_list_free (mixer_stream->priv->ports);
956 mixer_stream->priv->ports = NULL;
957
958 if (mixer_stream->priv->change_volume_op) {
959 pa_operation_unref(mixer_stream->priv->change_volume_op);
960 mixer_stream->priv->change_volume_op = NULL;
961 }
962
963 G_OBJECT_CLASS (gvc_mixer_stream_parent_class)->finalize (object);
964 }