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;
281
* gvc_mixer_card_get_ports:
283
* Return value: (transfer none) (element-type GvcMixerCardPort):
286
gvc_mixer_card_get_ports (GvcMixerCard *card)
288
g_return_val_if_fail (GVC_IS_MIXER_CARD (card), NULL);
289
return card->priv->ports;
293
* gvc_mixer_card_profile_compare:
295
* Return value: 1 if @a has a higher priority, -1 if @b has a higher
296
* priority, 0 if @a and @b have the same priority.
299
gvc_mixer_card_profile_compare (GvcMixerCardProfile *a,
300
GvcMixerCardProfile *b)
302
if (a->priority == b->priority)
304
if (a->priority > b->priority)
310
* gvc_mixer_card_set_profiles:
311
* @profiles: (transfer full) (element-type GvcMixerCardProfile):
314
gvc_mixer_card_set_profiles (GvcMixerCard *card,
317
g_return_val_if_fail (GVC_IS_MIXER_CARD (card), FALSE);
318
g_return_val_if_fail (card->priv->profiles == NULL, FALSE);
320
card->priv->profiles = g_list_sort (profiles, (GCompareFunc) gvc_mixer_card_profile_compare);
326
* gvc_mixer_card_get_gicon:
329
* Return value: (transfer full):
332
gvc_mixer_card_get_gicon (GvcMixerCard *card)
334
g_return_val_if_fail (GVC_IS_MIXER_CARD (card), NULL);
336
if (card->priv->icon_name == NULL)
339
return g_themed_icon_new_with_default_fallbacks (card->priv->icon_name);
343
* gvc_mixer_card_set_ports:
344
* @ports: (transfer full) (element-type GvcMixerCardPort):
347
gvc_mixer_card_set_ports (GvcMixerCard *card,
350
g_return_val_if_fail (GVC_IS_MIXER_CARD (card), FALSE);
351
g_return_val_if_fail (card->priv->ports == NULL, FALSE);
353
card->priv->ports = ports;
359
gvc_mixer_card_set_property (GObject *object,
364
GvcMixerCard *self = GVC_MIXER_CARD (object);
367
case PROP_PA_CONTEXT:
368
self->priv->pa_context = g_value_get_pointer (value);
371
self->priv->index = g_value_get_ulong (value);
374
self->priv->id = g_value_get_ulong (value);
377
gvc_mixer_card_set_name (self, g_value_get_string (value));
380
gvc_mixer_card_set_icon_name (self, g_value_get_string (value));
383
gvc_mixer_card_set_profile (self, g_value_get_string (value));
386
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
392
gvc_mixer_card_get_property (GObject *object,
397
GvcMixerCard *self = GVC_MIXER_CARD (object);
400
case PROP_PA_CONTEXT:
401
g_value_set_pointer (value, self->priv->pa_context);
404
g_value_set_ulong (value, self->priv->index);
407
g_value_set_ulong (value, self->priv->id);
410
g_value_set_string (value, self->priv->name);
413
g_value_set_string (value, self->priv->icon_name);
416
g_value_set_string (value, self->priv->profile);
418
case PROP_HUMAN_PROFILE:
419
g_value_set_string (value, self->priv->human_profile);
422
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
428
gvc_mixer_card_constructor (GType type,
429
guint n_construct_properties,
430
GObjectConstructParam *construct_params)
435
object = G_OBJECT_CLASS (gvc_mixer_card_parent_class)->constructor (type, n_construct_properties, construct_params);
437
self = GVC_MIXER_CARD (object);
439
self->priv->id = get_next_card_serial ();
445
gvc_mixer_card_class_init (GvcMixerCardClass *klass)
447
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
449
gobject_class->constructor = gvc_mixer_card_constructor;
450
gobject_class->finalize = gvc_mixer_card_finalize;
452
gobject_class->set_property = gvc_mixer_card_set_property;
453
gobject_class->get_property = gvc_mixer_card_get_property;
455
g_object_class_install_property (gobject_class,
457
g_param_spec_ulong ("index",
459
"The index for this card",
461
G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
462
g_object_class_install_property (gobject_class,
464
g_param_spec_ulong ("id",
466
"The id for this card",
468
G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
469
g_object_class_install_property (gobject_class,
471
g_param_spec_pointer ("pa-context",
472
"PulseAudio context",
473
"The PulseAudio context for this card",
474
G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
475
g_object_class_install_property (gobject_class,
477
g_param_spec_string ("name",
479
"Name to display for this card",
481
G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
482
g_object_class_install_property (gobject_class,
484
g_param_spec_string ("icon-name",
486
"Name of icon to display for this card",
488
G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
489
g_object_class_install_property (gobject_class,
491
g_param_spec_string ("profile",
493
"Name of current profile for this card",
496
g_object_class_install_property (gobject_class,
498
g_param_spec_string ("human-profile",
499
"Profile (Human readable)",
500
"Name of current profile for this card in human readable form",
504
g_type_class_add_private (klass, sizeof (GvcMixerCardPrivate));
508
gvc_mixer_card_init (GvcMixerCard *card)
510
card->priv = GVC_MIXER_CARD_GET_PRIVATE (card);
514
gvc_mixer_card_new (pa_context *context,
519
object = g_object_new (GVC_TYPE_MIXER_CARD,
521
"pa-context", context,
523
return GVC_MIXER_CARD (object);
527
free_profile (GvcMixerCardProfile *p)
530
g_free (p->human_profile);
536
gvc_mixer_card_finalize (GObject *object)
538
GvcMixerCard *mixer_card;
540
g_return_if_fail (object != NULL);
541
g_return_if_fail (GVC_IS_MIXER_CARD (object));
543
mixer_card = GVC_MIXER_CARD (object);
545
g_return_if_fail (mixer_card->priv != NULL);
547
g_free (mixer_card->priv->name);
548
mixer_card->priv->name = NULL;
550
g_free (mixer_card->priv->icon_name);
551
mixer_card->priv->icon_name = NULL;
553
g_free (mixer_card->priv->target_profile);
554
mixer_card->priv->target_profile = NULL;
556
g_free (mixer_card->priv->profile);
557
mixer_card->priv->profile = NULL;
559
g_free (mixer_card->priv->human_profile);
560
mixer_card->priv->human_profile = NULL;
562
g_list_foreach (mixer_card->priv->profiles, (GFunc) free_profile, NULL);
563
g_list_free (mixer_card->priv->profiles);
564
mixer_card->priv->profiles = NULL;
566
G_OBJECT_CLASS (gvc_mixer_card_parent_class)->finalize (object);