1
/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
3
* gvc-mixer-ui-device.c
4
* Copyright (C) Conor Curran 2011 <conor.curran@canonical.com>
6
* gvc-mixer-ui-device.c is free software: you can redistribute it and/or modify it
7
* under the terms of the GNU General Public License as published by the
8
* Free Software Foundation, either version 3 of the License, or
9
* (at your option) any later version.
11
* gvc-mixer-ui-device.c is distributed in the hope that it will be useful, but
12
* WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14
* See the GNU General Public License for more details.
16
* You should have received a copy of the GNU General Public License along
17
* with this program. If not, see <http://www.gnu.org/licenses/>.
21
#include "gvc-mixer-ui-device.h"
22
#include "gvc-mixer-card.h"
24
#define GVC_MIXER_UI_DEVICE_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GVC_TYPE_MIXER_UI_DEVICE, GvcMixerUIDevicePrivate))
26
static guint32 output_serial = 1;
28
struct GvcMixerUIDevicePrivate
30
gchar* first_line_desc;
31
gchar* second_line_desc;
36
gboolean port_available;
37
GList* supported_profiles;
38
UiDeviceDirection type;
40
gboolean disable_profile_swapping;
41
gchar* user_preferred_profile;
56
static void gvc_mixer_ui_device_class_init (GvcMixerUIDeviceClass *klass);
57
static void gvc_mixer_ui_device_init (GvcMixerUIDevice *op);
58
static void gvc_mixer_ui_device_finalize (GObject *object);
60
G_DEFINE_TYPE (GvcMixerUIDevice, gvc_mixer_ui_device, G_TYPE_OBJECT);
63
get_next_output_serial (void)
67
serial = output_serial++;
69
if ((gint32)output_serial < 0) {
76
gvc_mixer_ui_device_get_property (GObject *object,
81
GvcMixerUIDevice *self = GVC_MIXER_UI_DEVICE (object);
85
case PROP_DESC_LINE_1:
86
g_value_set_string (value, self->priv->first_line_desc);
88
case PROP_DESC_LINE_2:
89
g_value_set_string (value, self->priv->second_line_desc);
92
g_value_set_int (value, self->priv->card_id);
95
g_value_set_string (value, self->priv->port_name);
98
g_value_set_int (value, self->priv->stream_id);
100
case PROP_UI_DEVICE_TYPE:
101
g_value_set_uint (value, (guint)self->priv->type);
103
case PROP_PORT_AVAILABLE:
104
g_value_set_boolean (value, self->priv->port_available);
107
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
113
gvc_mixer_ui_device_set_property (GObject *object,
118
GvcMixerUIDevice *self = GVC_MIXER_UI_DEVICE (object);
122
case PROP_DESC_LINE_1:
123
g_free (self->priv->first_line_desc);
124
self->priv->first_line_desc = g_value_dup_string (value);
125
/*g_print ("gvc-mixer-output-set-property - 1st line: %s\n",
126
self->priv->first_line_desc);*/
128
case PROP_DESC_LINE_2:
129
g_free (self->priv->second_line_desc);
130
self->priv->second_line_desc = g_value_dup_string (value);
131
/*g_print ("gvc-mixer-output-set-property - 2nd line: %s\n",
132
self->priv->second_line_desc);*/
135
self->priv->card_id = g_value_get_int (value);
136
/*g_print ("gvc-mixer-output-set-property - card id: %i\n",
137
self->priv->gvc_card_id);*/
140
g_free (self->priv->port_name);
141
self->priv->port_name = g_value_dup_string (value);
142
/*g_print ("gvc-mixer-output-set-property - card port name: %s\n",
143
self->priv->card_port_name);*/
146
self->priv->stream_id = g_value_get_int (value);
147
/*g_print ("gvc-mixer-output-set-property - sink id: %i\n",
148
self->priv->stream_id);*/
150
case PROP_UI_DEVICE_TYPE:
151
self->priv->type = (UiDeviceDirection)g_value_get_uint (value);
153
case PROP_PORT_AVAILABLE:
154
self->priv->port_available = g_value_get_boolean (value);
155
/*g_print ("gvc-mixer-output-set-property - port available %i, value passed in %i \n",
156
self->priv->port_available, g_value_get_boolean (value));*/
159
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
165
gvc_mixer_ui_device_constructor (GType type,
166
guint n_construct_properties,
167
GObjectConstructParam *construct_params)
170
GvcMixerUIDevice *self;
172
object = G_OBJECT_CLASS (gvc_mixer_ui_device_parent_class)->constructor (type, n_construct_properties, construct_params);
174
self = GVC_MIXER_UI_DEVICE (object);
175
self->priv->id = get_next_output_serial ();
176
self->priv->profiles = g_hash_table_new_full (g_str_hash,
180
self->priv->stream_id = GVC_MIXER_UI_DEVICE_INVALID;
181
self->priv->card_id = GVC_MIXER_UI_DEVICE_INVALID;
182
self->priv->port_name = NULL;
183
self->priv->disable_profile_swapping = FALSE;
184
self->priv->user_preferred_profile = NULL;
189
gvc_mixer_ui_device_init (GvcMixerUIDevice *object)
191
object->priv = GVC_MIXER_UI_DEVICE_GET_PRIVATE (object);
195
gvc_mixer_ui_device_dispose (GObject *object)
197
g_return_if_fail (object != NULL);
198
g_return_if_fail (GVC_MIXER_UI_DEVICE (object));
200
GvcMixerUIDevice *device;
201
device = GVC_MIXER_UI_DEVICE (object);
203
if (device->priv->port_name != NULL){
204
g_free (device->priv->port_name);
205
device->priv->port_name = NULL;
207
if (device->priv->first_line_desc != NULL){
208
g_free (device->priv->first_line_desc);
209
device->priv->first_line_desc = NULL;
211
if (device->priv->second_line_desc != NULL){
212
g_free (device->priv->second_line_desc);
213
device->priv->second_line_desc = NULL;
215
if (device->priv->profiles != NULL){
216
g_hash_table_destroy (device->priv->profiles);
217
device->priv->profiles = NULL;
219
if (device->priv->user_preferred_profile != NULL){
220
g_free (device->priv->user_preferred_profile);
221
device->priv->user_preferred_profile = NULL;
223
G_OBJECT_CLASS (gvc_mixer_ui_device_parent_class)->dispose (object);
227
gvc_mixer_ui_device_finalize (GObject *object)
229
G_OBJECT_CLASS (gvc_mixer_ui_device_parent_class)->finalize (object);
233
gvc_mixer_ui_device_class_init (GvcMixerUIDeviceClass *klass)
235
GObjectClass* object_class = G_OBJECT_CLASS (klass);
237
object_class->constructor = gvc_mixer_ui_device_constructor;
238
object_class->dispose = gvc_mixer_ui_device_dispose;
239
object_class->finalize = gvc_mixer_ui_device_finalize;
240
object_class->set_property = gvc_mixer_ui_device_set_property;
241
object_class->get_property = gvc_mixer_ui_device_get_property;
245
pspec = g_param_spec_string ("description",
246
"Description construct prop",
247
"Set first line description",
250
g_object_class_install_property (object_class,
254
pspec = g_param_spec_string ("origin",
255
"origin construct prop",
256
"Set second line description name",
259
g_object_class_install_property (object_class,
263
pspec = g_param_spec_int ("card-id",
264
"Card id from pulse",
268
GVC_MIXER_UI_DEVICE_INVALID,
271
g_object_class_install_property (object_class,
275
pspec = g_param_spec_string ("port-name",
276
"port-name construct prop",
280
g_object_class_install_property (object_class,
284
pspec = g_param_spec_int ("stream-id",
285
"stream id assigned by gvc-stream",
289
GVC_MIXER_UI_DEVICE_INVALID,
291
g_object_class_install_property (object_class,
295
pspec = g_param_spec_uint ("type",
297
"determine whether its an input and output",
302
g_object_class_install_property (object_class,
306
pspec = g_param_spec_boolean ( "port-available",
308
"determine whether this port is available",
311
g_object_class_install_property (object_class,
315
g_type_class_add_private (klass, sizeof (GvcMixerUIDevicePrivate));
319
// Optimise so as on the first pass you can 'choose' which profiles to hold on to and
320
// which are useles because they are essentially duplicates.
322
gvc_mixer_ui_device_set_profiles (GvcMixerUIDevice *device, const GList *in_profiles)
326
GHashTable *profile_descriptions;
328
device->priv->supported_profiles = in_profiles;
330
profile_count = g_list_length (in_profiles);
331
profile_descriptions = g_hash_table_new_full (g_str_hash,
337
gboolean is_input = device->priv->type != UiDeviceOutput;
338
gboolean is_output = device->priv->type == UiDeviceOutput;
340
// Store each profile in a hash with the shortened relevant string as the key
341
for (t = in_profiles; t != NULL; t = t->next) {
343
GvcMixerCardProfile* p;
347
//g_print ("\n check if this %s has already passed %i", p->profile, g_hash_table_contains (profile_descriptions, p->profile));
351
modified = g_strsplit (p->profile, "+", 0);
354
count = g_strv_length (modified);
357
g_print ("\n Single profile, %i, key %s against value %s for device %s \n",
361
gvc_mixer_ui_device_get_description (device));
362
g_hash_table_insert (profile_descriptions,
363
g_strdup (p->profile),
364
g_strdup (modified[0]));
365
g_strfreev (modified);
369
if (device->priv->type == UiDeviceOutput) {
370
if (g_str_has_prefix (modified[0], "output")){
371
g_print ("\n Found an output profile - storing key %s against value %s for device %s \n",
372
p->profile, modified[0], gvc_mixer_ui_device_get_description (device));
373
g_hash_table_insert (profile_descriptions,
374
g_strdup (p->profile),
375
g_strdup (modified[0]));
379
if (g_str_has_prefix (modified[1], "input")){
380
g_print ("\n Found an input profile - storing key %s against value %s for device %s \n",
381
p->profile, modified[1], gvc_mixer_ui_device_get_description (device));
382
g_hash_table_insert (profile_descriptions,
383
g_strdup (p->profile),
384
g_strdup (modified[1]));
387
g_strfreev (modified);
390
// Determine if we want allow the user to change the profile from the device
391
// i.e. is there any actual choice or just much of the same thing from the
392
// context of the direction on this device.
393
gboolean identical = TRUE;
394
GList *shortened_profiles;
395
shortened_profiles = g_hash_table_get_values (profile_descriptions);
397
for (t = shortened_profiles; t != NULL; t = t->next) {
400
if (g_list_next (t) != NULL){
405
identical = g_strcmp0 (prof, next_prof) == 0;
411
g_list_free (shortened_profiles);
413
g_print ("\n device->priv->disable_profile_swapping = %i \n",
416
device->priv->disable_profile_swapping = identical;
421
for (y = in_profiles; y != NULL; y = y->next) {
422
GvcMixerCardProfile* p;
425
short_name = g_hash_table_lookup (profile_descriptions, p->profile);
427
g_print ("\n\n has this profile passed already- %s , %s \n\n", short_name, p->profile);
429
for (x = in_profiles; x != NULL; x = x->next) {
430
GvcMixerCardProfile* l;
432
gchar* other_modified;
434
if (g_strcmp0 (p->profile, "off") == 0){
435
g_print ("\n\n Bluetooth off profile - ignore it");
439
if (g_hash_table_contains (device->priv->profiles, short_name) == TRUE){
440
g_print ("\n\n SHORT NAME already populated move on - %s \n\n", p->profile);
444
other_modified = g_hash_table_lookup (profile_descriptions, l->profile);
446
if (g_strcmp0 (other_modified, short_name) == 0){
447
if (sort_profiles (p, l) > 0){
448
g_hash_table_insert (device->priv->profiles, short_name, p);
451
g_hash_table_insert (device->priv->profiles, short_name, l);
458
// If it's identical we want to find the profile that is relevant to the context of the device
459
// For the sake of the UI - avoid user confusion.
460
GList* profile_descriptions_keys;
461
profile_descriptions_keys = g_hash_table_get_keys (profile_descriptions);
463
gboolean matched = FALSE;
464
for (c = profile_descriptions_keys; c != NULL; c = c->next) {
467
gchar* shortened_value;
468
shortened_value = g_hash_table_lookup (profile_descriptions, prof);
469
if (g_strcmp0 (shortened_value, prof) == 0){
471
for (j = in_profiles; j != NULL; j = j->next) {
472
GvcMixerCardProfile* l;
474
if (g_strcmp0 (l->profile, prof) == 0){
475
g_hash_table_insert (device->priv->profiles,
483
// We can't find the ideal profile for the insensitive combo
484
// just pick the one with the highest priority.
486
GvcMixerCardProfile* p;
487
// Since the profile list was already sorted on card port creation
488
// we just need to take the last one as this will have the highest priority
489
p = g_list_last (in_profiles)->data;
490
g_hash_table_insert (device->priv->profiles,
498
final_keys = g_hash_table_get_keys (device->priv->profiles);
500
g_print ("\n\n Profile population \n FOR DEVICE %s", gvc_mixer_ui_device_get_description (device));
501
for (o = final_keys; o != NULL; o = o->next){
504
GvcMixerCardProfile* l;
505
l = g_hash_table_lookup (device->priv->profiles, key);
506
g_print ("\n key %s against \n profile %s \n",
510
g_hash_table_destroy (profile_descriptions);
514
gvc_mixer_ui_device_determine_profile_sensitivity (GvcMixerUIDevice *device)
516
return device->priv->disable_profile_swapping;
520
gvc_mixer_ui_device_get_profiles (GvcMixerUIDevice *device)
522
return g_hash_table_get_values (device->priv->profiles);
526
gvc_mixer_ui_device_get_supported_profiles (GvcMixerUIDevice *device)
528
return device->priv->supported_profiles;
532
gvc_mixer_ui_device_get_id (GvcMixerUIDevice *op)
534
g_return_val_if_fail (GVC_IS_MIXER_UI_DEVICE (op), 0);
539
gvc_mixer_ui_device_get_stream_id (GvcMixerUIDevice *op)
542
g_object_get (G_OBJECT (op),
543
"stream-id", &sink_id, NULL);
548
gvc_mixer_ui_device_invalidate_stream (GvcMixerUIDevice *self)
550
self->priv->stream_id = GVC_MIXER_UI_DEVICE_INVALID;
555
gvc_mixer_ui_device_get_description (GvcMixerUIDevice *op)
557
return op->priv->first_line_desc;
561
gvc_mixer_ui_device_get_user_preferred_profile (GvcMixerUIDevice *dev)
563
return dev->priv->user_preferred_profile;
567
gvc_mixer_ui_device_get_top_priority_profile (GvcMixerUIDevice *dev)
570
last = g_list_last (dev->priv->supported_profiles);
571
GvcMixerCardProfile *profile;
572
profile = last->data;
573
return profile->profile;
577
gvc_mixer_ui_device_set_user_preferred_profile (GvcMixerUIDevice *device, const gchar* profile)
579
if (device->priv->user_preferred_profile != NULL){
580
g_free (device->priv->user_preferred_profile);
581
device->priv->user_preferred_profile = NULL;
583
device->priv->user_preferred_profile = g_strdup (profile);
587
gvc_mixer_ui_device_get_port (GvcMixerUIDevice *op)
589
return op->priv->port_name;
593
gvc_mixer_ui_device_is_software (GvcMixerUIDevice *dev)
595
return dev->priv->port_name == NULL;
599
gvc_mixer_ui_device_is_output (GvcMixerUIDevice *dev)
601
return dev->priv->type == UiDeviceOutput;