1
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
3
* Copyright (C) 2008 William Jon McCann
4
* Copyright (C) 2009 Bastien Nocera
5
* Copyright (C) Conor Curran 2011 <conor.curran@canonical.com>
7
* This program is free software; you can redistribute it and/or modify
8
* it under the terms of the GNU General Public License as published by
9
* the Free Software Foundation; either version 2 of the License, or
10
* (at your option) any later version.
12
* This program is distributed in the hope that it will be useful,
13
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
* GNU General Public License for more details.
17
* You should have received a copy of the GNU General Public License
18
* along with this program; if not, write to the Free Software
19
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
30
#include <glib/gi18n-lib.h>
32
#include <pulse/pulseaudio.h>
34
#include "gvc-mixer-card.h"
35
#include "gvc-mixer-card-private.h"
37
#define GVC_MIXER_CARD_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GVC_TYPE_MIXER_CARD, GvcMixerCardPrivate))
39
static guint32 card_serial = 1;
41
struct GvcMixerCardPrivate
43
pa_context *pa_context;
52
pa_operation *profile_op;
68
static void gvc_mixer_card_class_init (GvcMixerCardClass *klass);
69
static void gvc_mixer_card_init (GvcMixerCard *mixer_card);
70
static void gvc_mixer_card_finalize (GObject *object);
72
G_DEFINE_TYPE (GvcMixerCard, gvc_mixer_card, G_TYPE_OBJECT)
75
get_next_card_serial (void)
79
serial = card_serial++;
81
if ((gint32)card_serial < 0) {
89
gvc_mixer_card_get_pa_context (GvcMixerCard *card)
91
g_return_val_if_fail (GVC_IS_MIXER_CARD (card), 0);
92
return card->priv->pa_context;
96
gvc_mixer_card_get_index (GvcMixerCard *card)
98
g_return_val_if_fail (GVC_IS_MIXER_CARD (card), 0);
99
return card->priv->index;
103
gvc_mixer_card_get_id (GvcMixerCard *card)
105
g_return_val_if_fail (GVC_IS_MIXER_CARD (card), 0);
106
return card->priv->id;
110
gvc_mixer_card_get_name (GvcMixerCard *card)
112
g_return_val_if_fail (GVC_IS_MIXER_CARD (card), NULL);
113
return card->priv->name;
117
gvc_mixer_card_set_name (GvcMixerCard *card,
120
g_return_val_if_fail (GVC_IS_MIXER_CARD (card), FALSE);
122
g_free (card->priv->name);
123
card->priv->name = g_strdup (name);
124
g_object_notify (G_OBJECT (card), "name");
130
gvc_mixer_card_get_icon_name (GvcMixerCard *card)
132
g_return_val_if_fail (GVC_IS_MIXER_CARD (card), NULL);
133
return card->priv->icon_name;
137
gvc_mixer_card_set_icon_name (GvcMixerCard *card,
138
const char *icon_name)
140
g_return_val_if_fail (GVC_IS_MIXER_CARD (card), FALSE);
142
g_free (card->priv->icon_name);
143
card->priv->icon_name = g_strdup (icon_name);
144
g_object_notify (G_OBJECT (card), "icon-name");
150
* gvc_mixer_card_get_profile: (skip)
155
GvcMixerCardProfile *
156
gvc_mixer_card_get_profile (GvcMixerCard *card)
160
g_return_val_if_fail (GVC_IS_MIXER_CARD (card), NULL);
161
g_return_val_if_fail (card->priv->profiles != NULL, NULL);
163
for (l = card->priv->profiles; l != NULL; l = l->next) {
164
GvcMixerCardProfile *p = l->data;
165
if (g_str_equal (card->priv->profile, p->profile)) {
170
g_assert_not_reached ();
176
gvc_mixer_card_set_profile (GvcMixerCard *card,
181
g_return_val_if_fail (GVC_IS_MIXER_CARD (card), FALSE);
182
g_return_val_if_fail (card->priv->profiles != NULL, FALSE);
184
g_free (card->priv->profile);
185
card->priv->profile = g_strdup (profile);
187
g_free (card->priv->human_profile);
188
card->priv->human_profile = NULL;
190
for (l = card->priv->profiles; l != NULL; l = l->next) {
191
GvcMixerCardProfile *p = l->data;
192
if (g_str_equal (card->priv->profile, p->profile)) {
193
card->priv->human_profile = g_strdup (p->human_profile);
198
g_object_notify (G_OBJECT (card), "profile");
204
_pa_context_set_card_profile_by_index_cb (pa_context *context,
208
GvcMixerCard *card = GVC_MIXER_CARD (userdata);
210
g_assert (card->priv->target_profile);
213
gvc_mixer_card_set_profile (card, card->priv->target_profile);
215
g_debug ("Failed to switch profile on '%s' from '%s' to '%s'",
218
card->priv->target_profile);
220
g_free (card->priv->target_profile);
221
card->priv->target_profile = NULL;
223
pa_operation_unref (card->priv->profile_op);
224
card->priv->profile_op = NULL;
228
gvc_mixer_card_change_profile (GvcMixerCard *card,
231
g_return_val_if_fail (GVC_IS_MIXER_CARD (card), FALSE);
232
g_return_val_if_fail (card->priv->profiles != NULL, FALSE);
234
/* Same profile, or already requested? */
235
if (g_strcmp0 (card->priv->profile, profile) == 0)
237
if (g_strcmp0 (profile, card->priv->target_profile) == 0)
239
if (card->priv->profile_op != NULL) {
240
pa_operation_cancel (card->priv->profile_op);
241
pa_operation_unref (card->priv->profile_op);
242
card->priv->profile_op = NULL;
245
if (card->priv->profile != NULL) {
246
g_free (card->priv->target_profile);
247
card->priv->target_profile = g_strdup (profile);
249
card->priv->profile_op = pa_context_set_card_profile_by_index (card->priv->pa_context,
251
card->priv->target_profile,
252
_pa_context_set_card_profile_by_index_cb,
255
if (card->priv->profile_op == NULL) {
256
g_warning ("pa_context_set_card_profile_by_index() failed");
260
g_assert (card->priv->human_profile == NULL);
261
card->priv->profile = g_strdup (profile);
268
* gvc_mixer_card_get_profiles:
270
* Return value: (transfer none) (element-type GvcMixerCardProfile):
273
gvc_mixer_card_get_profiles (GvcMixerCard *card)
275
g_return_val_if_fail (GVC_IS_MIXER_CARD (card), NULL);
276
return card->priv->profiles;
280
* gvc_mixer_card_get_ports:
282
* Return value: (transfer none) (element-type GvcMixerCardPort):
285
gvc_mixer_card_get_ports (GvcMixerCard *card)
287
g_return_val_if_fail (GVC_IS_MIXER_CARD (card), NULL);
288
return card->priv->ports;
292
* gvc_mixer_card_profile_compare:
294
* Return value: 1 if @a has a higher priority, -1 if @b has a higher
295
* priority, 0 if @a and @b have the same priority.
298
gvc_mixer_card_profile_compare (GvcMixerCardProfile *a,
299
GvcMixerCardProfile *b)
301
if (a->priority == b->priority)
303
if (a->priority > b->priority)
309
* gvc_mixer_card_set_profiles:
310
* @profiles: (transfer full) (element-type GvcMixerCardProfile):
313
gvc_mixer_card_set_profiles (GvcMixerCard *card,
316
g_return_val_if_fail (GVC_IS_MIXER_CARD (card), FALSE);
317
g_return_val_if_fail (card->priv->profiles == NULL, FALSE);
319
card->priv->profiles = g_list_sort (profiles, (GCompareFunc) gvc_mixer_card_profile_compare);
325
* gvc_mixer_card_get_gicon:
328
* Return value: (transfer full):
331
gvc_mixer_card_get_gicon (GvcMixerCard *card)
333
g_return_val_if_fail (GVC_IS_MIXER_CARD (card), NULL);
335
if (card->priv->icon_name == NULL)
338
return g_themed_icon_new_with_default_fallbacks (card->priv->icon_name);
342
free_port (GvcMixerCardPort *port)
345
g_free (port->human_port);
346
g_free (port->icon_name);
347
g_list_free (port->profiles);
353
* gvc_mixer_card_set_ports:
354
* @ports: (transfer full) (element-type GvcMixerCardPort):
357
gvc_mixer_card_set_ports (GvcMixerCard *card,
360
g_return_val_if_fail (GVC_IS_MIXER_CARD (card), FALSE);
361
g_return_val_if_fail (card->priv->ports == NULL, FALSE);
363
g_list_free_full (card->priv->ports, (GDestroyNotify) free_port);
364
card->priv->ports = ports;
370
gvc_mixer_card_set_property (GObject *object,
375
GvcMixerCard *self = GVC_MIXER_CARD (object);
378
case PROP_PA_CONTEXT:
379
self->priv->pa_context = g_value_get_pointer (value);
382
self->priv->index = g_value_get_ulong (value);
385
self->priv->id = g_value_get_ulong (value);
388
gvc_mixer_card_set_name (self, g_value_get_string (value));
391
gvc_mixer_card_set_icon_name (self, g_value_get_string (value));
394
gvc_mixer_card_set_profile (self, g_value_get_string (value));
397
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
403
gvc_mixer_card_get_property (GObject *object,
408
GvcMixerCard *self = GVC_MIXER_CARD (object);
411
case PROP_PA_CONTEXT:
412
g_value_set_pointer (value, self->priv->pa_context);
415
g_value_set_ulong (value, self->priv->index);
418
g_value_set_ulong (value, self->priv->id);
421
g_value_set_string (value, self->priv->name);
424
g_value_set_string (value, self->priv->icon_name);
427
g_value_set_string (value, self->priv->profile);
429
case PROP_HUMAN_PROFILE:
430
g_value_set_string (value, self->priv->human_profile);
433
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
439
gvc_mixer_card_constructor (GType type,
440
guint n_construct_properties,
441
GObjectConstructParam *construct_params)
446
object = G_OBJECT_CLASS (gvc_mixer_card_parent_class)->constructor (type, n_construct_properties, construct_params);
448
self = GVC_MIXER_CARD (object);
450
self->priv->id = get_next_card_serial ();
456
gvc_mixer_card_class_init (GvcMixerCardClass *klass)
458
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
460
gobject_class->constructor = gvc_mixer_card_constructor;
461
gobject_class->finalize = gvc_mixer_card_finalize;
463
gobject_class->set_property = gvc_mixer_card_set_property;
464
gobject_class->get_property = gvc_mixer_card_get_property;
466
g_object_class_install_property (gobject_class,
468
g_param_spec_ulong ("index",
470
"The index for this card",
472
G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
473
g_object_class_install_property (gobject_class,
475
g_param_spec_ulong ("id",
477
"The id for this card",
479
G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
480
g_object_class_install_property (gobject_class,
482
g_param_spec_pointer ("pa-context",
483
"PulseAudio context",
484
"The PulseAudio context for this card",
485
G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
486
g_object_class_install_property (gobject_class,
488
g_param_spec_string ("name",
490
"Name to display for this card",
492
G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
493
g_object_class_install_property (gobject_class,
495
g_param_spec_string ("icon-name",
497
"Name of icon to display for this card",
499
G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
500
g_object_class_install_property (gobject_class,
502
g_param_spec_string ("profile",
504
"Name of current profile for this card",
507
g_object_class_install_property (gobject_class,
509
g_param_spec_string ("human-profile",
510
"Profile (Human readable)",
511
"Name of current profile for this card in human readable form",
515
g_type_class_add_private (klass, sizeof (GvcMixerCardPrivate));
519
gvc_mixer_card_init (GvcMixerCard *card)
521
card->priv = GVC_MIXER_CARD_GET_PRIVATE (card);
525
gvc_mixer_card_new (pa_context *context,
530
object = g_object_new (GVC_TYPE_MIXER_CARD,
532
"pa-context", context,
534
return GVC_MIXER_CARD (object);
538
free_profile (GvcMixerCardProfile *p)
541
g_free (p->human_profile);
547
gvc_mixer_card_finalize (GObject *object)
549
GvcMixerCard *mixer_card;
551
g_return_if_fail (object != NULL);
552
g_return_if_fail (GVC_IS_MIXER_CARD (object));
554
mixer_card = GVC_MIXER_CARD (object);
556
g_return_if_fail (mixer_card->priv != NULL);
558
g_free (mixer_card->priv->name);
559
mixer_card->priv->name = NULL;
561
g_free (mixer_card->priv->icon_name);
562
mixer_card->priv->icon_name = NULL;
564
g_free (mixer_card->priv->target_profile);
565
mixer_card->priv->target_profile = NULL;
567
g_free (mixer_card->priv->profile);
568
mixer_card->priv->profile = NULL;
570
g_free (mixer_card->priv->human_profile);
571
mixer_card->priv->human_profile = NULL;
573
g_list_foreach (mixer_card->priv->profiles, (GFunc) free_profile, NULL);
574
g_list_free (mixer_card->priv->profiles);
575
mixer_card->priv->profiles = NULL;
577
g_list_free_full (mixer_card->priv->ports, (GDestroyNotify) free_port);
578
mixer_card->priv->ports = NULL;
580
G_OBJECT_CLASS (gvc_mixer_card_parent_class)->finalize (object);