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
6
* This program is free software; you can redistribute it and/or modify
7
* it under the terms of the GNU General Public License as published by
8
* the Free Software Foundation; either version 2 of the License, or
9
* (at your option) any later version.
11
* This program 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
14
* GNU General Public License for more details.
16
* You should have received a copy of the GNU General Public License
17
* along with this program; if not, write to the Free Software
18
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
29
#include <glib/gi18n-lib.h>
31
#include <pulse/pulseaudio.h>
33
#include "gvc-mixer-card.h"
34
#include "gvc-mixer-card-private.h"
36
#define GVC_MIXER_CARD_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GVC_TYPE_MIXER_CARD, GvcMixerCardPrivate))
38
static guint32 card_serial = 1;
40
struct GvcMixerCardPrivate
42
pa_context *pa_context;
51
pa_operation *profile_op;
66
static void gvc_mixer_card_class_init (GvcMixerCardClass *klass);
67
static void gvc_mixer_card_init (GvcMixerCard *mixer_card);
68
static void gvc_mixer_card_finalize (GObject *object);
70
G_DEFINE_TYPE (GvcMixerCard, gvc_mixer_card, G_TYPE_OBJECT)
73
get_next_card_serial (void)
77
serial = card_serial++;
79
if ((gint32)card_serial < 0) {
87
gvc_mixer_card_get_pa_context (GvcMixerCard *card)
89
g_return_val_if_fail (GVC_IS_MIXER_CARD (card), 0);
90
return card->priv->pa_context;
94
gvc_mixer_card_get_index (GvcMixerCard *card)
96
g_return_val_if_fail (GVC_IS_MIXER_CARD (card), 0);
97
return card->priv->index;
101
gvc_mixer_card_get_id (GvcMixerCard *card)
103
g_return_val_if_fail (GVC_IS_MIXER_CARD (card), 0);
104
return card->priv->id;
108
gvc_mixer_card_get_name (GvcMixerCard *card)
110
g_return_val_if_fail (GVC_IS_MIXER_CARD (card), NULL);
111
return card->priv->name;
115
gvc_mixer_card_set_name (GvcMixerCard *card,
118
g_return_val_if_fail (GVC_IS_MIXER_CARD (card), FALSE);
120
g_free (card->priv->name);
121
card->priv->name = g_strdup (name);
122
g_object_notify (G_OBJECT (card), "name");
128
gvc_mixer_card_get_icon_name (GvcMixerCard *card)
130
g_return_val_if_fail (GVC_IS_MIXER_CARD (card), NULL);
131
return card->priv->icon_name;
135
gvc_mixer_card_set_icon_name (GvcMixerCard *card,
136
const char *icon_name)
138
g_return_val_if_fail (GVC_IS_MIXER_CARD (card), FALSE);
140
g_free (card->priv->icon_name);
141
card->priv->icon_name = g_strdup (icon_name);
142
g_object_notify (G_OBJECT (card), "icon-name");
148
* gvc_mixer_card_get_profile: (skip)
154
GvcMixerCardProfile *
155
gvc_mixer_card_get_profile (GvcMixerCard *card)
159
g_return_val_if_fail (GVC_IS_MIXER_CARD (card), NULL);
160
g_return_val_if_fail (card->priv->profiles != NULL, NULL);
162
for (l = card->priv->profiles; l != NULL; l = l->next) {
163
GvcMixerCardProfile *p = l->data;
164
if (g_str_equal (card->priv->profile, p->profile)) {
169
g_assert_not_reached ();
175
gvc_mixer_card_set_profile (GvcMixerCard *card,
180
g_return_val_if_fail (GVC_IS_MIXER_CARD (card), FALSE);
181
g_return_val_if_fail (card->priv->profiles != NULL, FALSE);
183
g_free (card->priv->profile);
184
card->priv->profile = g_strdup (profile);
186
g_free (card->priv->human_profile);
187
card->priv->human_profile = NULL;
189
for (l = card->priv->profiles; l != NULL; l = l->next) {
190
GvcMixerCardProfile *p = l->data;
191
if (g_str_equal (card->priv->profile, p->profile)) {
192
card->priv->human_profile = g_strdup (p->human_profile);
197
g_object_notify (G_OBJECT (card), "profile");
203
_pa_context_set_card_profile_by_index_cb (pa_context *context,
207
GvcMixerCard *card = GVC_MIXER_CARD (userdata);
209
g_assert (card->priv->target_profile);
212
gvc_mixer_card_set_profile (card, card->priv->target_profile);
214
g_debug ("Failed to switch profile on '%s' from '%s' to '%s'",
217
card->priv->target_profile);
219
g_free (card->priv->target_profile);
220
card->priv->target_profile = NULL;
222
pa_operation_unref (card->priv->profile_op);
223
card->priv->profile_op = NULL;
227
gvc_mixer_card_change_profile (GvcMixerCard *card,
230
g_return_val_if_fail (GVC_IS_MIXER_CARD (card), FALSE);
231
g_return_val_if_fail (card->priv->profiles != NULL, FALSE);
233
/* Same profile, or already requested? */
234
if (g_strcmp0 (card->priv->profile, profile) == 0)
236
if (g_strcmp0 (profile, card->priv->target_profile) == 0)
238
if (card->priv->profile_op != NULL) {
239
pa_operation_cancel (card->priv->profile_op);
240
pa_operation_unref (card->priv->profile_op);
241
card->priv->profile_op = NULL;
244
if (card->priv->profile != NULL) {
245
g_free (card->priv->target_profile);
246
card->priv->target_profile = g_strdup (profile);
248
card->priv->profile_op = pa_context_set_card_profile_by_index (card->priv->pa_context,
250
card->priv->target_profile,
251
_pa_context_set_card_profile_by_index_cb,
254
if (card->priv->profile_op == NULL) {
255
g_warning ("pa_context_set_card_profile_by_index() failed");
259
g_assert (card->priv->human_profile == NULL);
260
card->priv->profile = g_strdup (profile);
267
gvc_mixer_card_get_profiles (GvcMixerCard *card)
269
g_return_val_if_fail (GVC_IS_MIXER_CARD (card), NULL);
270
return card->priv->profiles;
274
sort_profiles (GvcMixerCardProfile *a,
275
GvcMixerCardProfile *b)
277
if (a->priority == b->priority)
279
if (a->priority > b->priority)
285
gvc_mixer_card_set_profiles (GvcMixerCard *card,
288
g_return_val_if_fail (GVC_IS_MIXER_CARD (card), FALSE);
289
g_return_val_if_fail (card->priv->profiles == NULL, FALSE);
291
card->priv->profiles = g_list_sort (profiles, (GCompareFunc) sort_profiles);
297
gvc_mixer_card_set_property (GObject *object,
302
GvcMixerCard *self = GVC_MIXER_CARD (object);
305
case PROP_PA_CONTEXT:
306
self->priv->pa_context = g_value_get_pointer (value);
309
self->priv->index = g_value_get_ulong (value);
312
self->priv->id = g_value_get_ulong (value);
315
gvc_mixer_card_set_name (self, g_value_get_string (value));
318
gvc_mixer_card_set_icon_name (self, g_value_get_string (value));
321
gvc_mixer_card_set_profile (self, g_value_get_string (value));
324
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
330
gvc_mixer_card_get_property (GObject *object,
335
GvcMixerCard *self = GVC_MIXER_CARD (object);
338
case PROP_PA_CONTEXT:
339
g_value_set_pointer (value, self->priv->pa_context);
342
g_value_set_ulong (value, self->priv->index);
345
g_value_set_ulong (value, self->priv->id);
348
g_value_set_string (value, self->priv->name);
351
g_value_set_string (value, self->priv->icon_name);
354
g_value_set_string (value, self->priv->profile);
356
case PROP_HUMAN_PROFILE:
357
g_value_set_string (value, self->priv->human_profile);
360
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
366
gvc_mixer_card_constructor (GType type,
367
guint n_construct_properties,
368
GObjectConstructParam *construct_params)
373
object = G_OBJECT_CLASS (gvc_mixer_card_parent_class)->constructor (type, n_construct_properties, construct_params);
375
self = GVC_MIXER_CARD (object);
377
self->priv->id = get_next_card_serial ();
383
gvc_mixer_card_class_init (GvcMixerCardClass *klass)
385
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
387
gobject_class->constructor = gvc_mixer_card_constructor;
388
gobject_class->finalize = gvc_mixer_card_finalize;
390
gobject_class->set_property = gvc_mixer_card_set_property;
391
gobject_class->get_property = gvc_mixer_card_get_property;
393
g_object_class_install_property (gobject_class,
395
g_param_spec_ulong ("index",
397
"The index for this card",
399
G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
400
g_object_class_install_property (gobject_class,
402
g_param_spec_ulong ("id",
404
"The id for this card",
406
G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
407
g_object_class_install_property (gobject_class,
409
g_param_spec_pointer ("pa-context",
410
"PulseAudio context",
411
"The PulseAudio context for this card",
412
G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
413
g_object_class_install_property (gobject_class,
415
g_param_spec_string ("name",
417
"Name to display for this card",
419
G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
420
g_object_class_install_property (gobject_class,
422
g_param_spec_string ("icon-name",
424
"Name of icon to display for this card",
426
G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
427
g_object_class_install_property (gobject_class,
429
g_param_spec_string ("profile",
431
"Name of current profile for this card",
434
g_object_class_install_property (gobject_class,
436
g_param_spec_string ("human-profile",
437
"Profile (Human readable)",
438
"Name of current profile for this card in human readable form",
442
g_type_class_add_private (klass, sizeof (GvcMixerCardPrivate));
446
gvc_mixer_card_init (GvcMixerCard *card)
448
card->priv = GVC_MIXER_CARD_GET_PRIVATE (card);
452
gvc_mixer_card_new (pa_context *context,
457
object = g_object_new (GVC_TYPE_MIXER_CARD,
459
"pa-context", context,
461
return GVC_MIXER_CARD (object);
465
free_profile (GvcMixerCardProfile *p)
468
g_free (p->human_profile);
474
gvc_mixer_card_finalize (GObject *object)
476
GvcMixerCard *mixer_card;
478
g_return_if_fail (object != NULL);
479
g_return_if_fail (GVC_IS_MIXER_CARD (object));
481
mixer_card = GVC_MIXER_CARD (object);
483
g_return_if_fail (mixer_card->priv != NULL);
485
g_free (mixer_card->priv->name);
486
mixer_card->priv->name = NULL;
488
g_free (mixer_card->priv->icon_name);
489
mixer_card->priv->icon_name = NULL;
491
g_free (mixer_card->priv->target_profile);
492
mixer_card->priv->target_profile = NULL;
494
g_free (mixer_card->priv->profile);
495
mixer_card->priv->profile = NULL;
497
g_free (mixer_card->priv->human_profile);
498
mixer_card->priv->human_profile = NULL;
500
g_list_foreach (mixer_card->priv->profiles, (GFunc) free_profile, NULL);
501
g_list_free (mixer_card->priv->profiles);
502
mixer_card->priv->profiles = NULL;
504
G_OBJECT_CLASS (gvc_mixer_card_parent_class)->finalize (object);