164
g_debug ("Changed default device for %s to %s", info->name, info->device);
184
g_debug ("Changed default device for %s to %s", info->name, new_info.device);
166
186
pa_operation_unref (o);
190
gvc_mixer_control_stream_restore_sink_cb (pa_context *c,
191
const pa_ext_stream_restore_info *info,
195
GvcMixerControl *control = (GvcMixerControl *) userdata;
196
if (eol || info == NULL || !g_str_has_prefix(info->name, "sink-input-by"))
198
gvc_mixer_control_stream_restore_cb (c, control->priv->new_default_sink_stream, info, control);
202
gvc_mixer_control_stream_restore_source_cb (pa_context *c,
203
const pa_ext_stream_restore_info *info,
207
GvcMixerControl *control = (GvcMixerControl *) userdata;
208
if (eol || info == NULL || !g_str_has_prefix(info->name, "source-output-by"))
210
gvc_mixer_control_stream_restore_cb (c, control->priv->new_default_source_stream, info, control);
214
* gvc_mixer_control_lookup_device_from_stream:
218
* Returns: (transfer none): a #GvcUIDevice or %NULL
221
gvc_mixer_control_lookup_device_from_stream (GvcMixerControl *control,
222
GvcMixerStream *stream)
225
gboolean is_network_stream;
227
GvcMixerUIDevice *ret;
229
if (GVC_IS_MIXER_SOURCE (stream))
230
devices = g_hash_table_get_values (control->priv->ui_inputs);
232
devices = g_hash_table_get_values (control->priv->ui_outputs);
235
ports = gvc_mixer_stream_get_ports (stream);
236
is_network_stream = (ports == NULL);
238
for (d = devices; d != NULL; d = d->next) {
239
GvcMixerUIDevice *device = d->data;
240
gint stream_id = G_MAXINT;
242
g_object_get (G_OBJECT (device),
243
"stream-id", &stream_id,
246
if (is_network_stream &&
247
stream_id == gvc_mixer_stream_get_id (stream)) {
248
g_debug ("lookup device from stream - %s - it is a network_stream ",
249
gvc_mixer_ui_device_get_description (device));
252
} else if (!is_network_stream) {
253
const GvcMixerStreamPort *port;
254
port = gvc_mixer_stream_get_port (stream);
256
if (stream_id == gvc_mixer_stream_get_id (stream) &&
257
g_strcmp0 (gvc_mixer_ui_device_get_port (device),
259
g_debug ("lookup-device-from-stream found device: device description '%s', device port = '%s', device stream id %i AND stream port = '%s' stream id '%u' and stream description '%s'",
260
gvc_mixer_ui_device_get_description (device),
261
gvc_mixer_ui_device_get_port (device),
264
gvc_mixer_stream_get_id (stream),
265
gvc_mixer_stream_get_description (stream));
272
g_debug ("gvc_mixer_control_lookup_device_from_stream - Could not find a device for stream '%s'",gvc_mixer_stream_get_description (stream));
274
g_list_free (devices);
170
280
gvc_mixer_control_set_default_sink (GvcMixerControl *control,
171
281
GvcMixerStream *stream)
314
448
return gvc_mixer_control_lookup_id (control->priv->cards, id);
452
* gvc_mixer_control_lookup_output_id:
456
* Returns: (transfer none):
459
gvc_mixer_control_lookup_output_id (GvcMixerControl *control,
462
g_return_val_if_fail (GVC_IS_MIXER_CONTROL (control), NULL);
464
return gvc_mixer_control_lookup_id (control->priv->ui_outputs, id);
468
* gvc_mixer_control_lookup_input_id:
472
* Returns: (transfer none):
475
gvc_mixer_control_lookup_input_id (GvcMixerControl *control,
478
g_return_val_if_fail (GVC_IS_MIXER_CONTROL (control), NULL);
480
return gvc_mixer_control_lookup_id (control->priv->ui_inputs, id);
484
* gvc_mixer_control_get_stream_from_device:
488
* Returns: (transfer none):
491
gvc_mixer_control_get_stream_from_device (GvcMixerControl *control,
492
GvcMixerUIDevice *device)
496
g_return_val_if_fail (GVC_IS_MIXER_CONTROL (control), NULL);
497
g_return_val_if_fail (GVC_IS_MIXER_UI_DEVICE (device), NULL);
499
stream_id = gvc_mixer_ui_device_get_stream_id (device);
501
if (stream_id == GVC_MIXER_UI_DEVICE_INVALID) {
502
g_debug ("gvc_mixer_control_get_stream_from_device - device has a null stream");
505
return gvc_mixer_control_lookup_stream_id (control, stream_id);
509
* gvc_mixer_control_change_profile_on_selected_device:
512
* @profile: Can be null if any profile present on this port is okay
514
* Returns: This method will attempt to swap the profile on the card of
515
* the device with given profile name. If successfull it will set the
516
* preferred profile on that device so as we know the next time the user
517
* moves to that device it should have this profile active.
520
gvc_mixer_control_change_profile_on_selected_device (GvcMixerControl *control,
521
GvcMixerUIDevice *device,
522
const gchar *profile)
524
const gchar *best_profile;
525
GvcMixerCardProfile *current_profile;
528
g_object_get (G_OBJECT (device), "card", &card, NULL);
529
current_profile = gvc_mixer_card_get_profile (card);
532
best_profile = gvc_mixer_ui_device_get_best_profile (device, profile, current_profile->profile);
534
best_profile = profile;
536
g_assert (best_profile);
538
g_debug ("Selected '%s', moving to profile '%s' on card '%s' on stream id %i",
539
profile ? profile : "(any)", best_profile,
540
gvc_mixer_card_get_name (card),
541
gvc_mixer_ui_device_get_stream_id (device));
543
g_debug ("default sink name = %s and default sink id %u",
544
control->priv->default_sink_name,
545
control->priv->default_sink_id);
547
control->priv->profile_swapping_device_id = gvc_mixer_ui_device_get_id (device);
549
if (gvc_mixer_card_change_profile (card, best_profile)) {
550
gvc_mixer_ui_device_set_user_preferred_profile (device, best_profile);
557
* gvc_mixer_control_change_output:
560
* This method is called from the UI when the user selects a previously unselected device.
561
* - Firstly it queries the stream from the device.
562
* - It assumes that if the stream is null that it cannot be a bluetooth or network stream (they never show unless they have valid sinks and sources)
563
* In the scenario of a NULL stream on the device
564
* - It fetches the device's preferred profile or if NUll the profile with the highest priority on that device.
565
* - It then caches this device in control->priv->cached_desired_output_id so that when the update_sink triggered
566
* from when we attempt to change profile we will know exactly what device to highlight on that stream.
567
* - It attempts to swap the profile on the card from that device and returns.
568
* - Next, it handles network or bluetooth streams that only require their stream to be made the default.
569
* - Next it deals with port changes so if the stream's active port is not the same as the port on the device
570
* it will attempt to change the port on that stream to be same as the device. If this fails it will return.
571
* - Finally it will set this new stream to be the default stream and emit a signal for the UI confirming the active output device.
574
gvc_mixer_control_change_output (GvcMixerControl *control,
575
GvcMixerUIDevice* output)
577
GvcMixerStream *stream;
578
GvcMixerStream *default_stream;
579
const GvcMixerStreamPort *active_port;
580
const gchar *output_port;
582
g_debug ("control change output");
584
stream = gvc_mixer_control_get_stream_from_device (control, output);
585
if (stream == NULL) {
586
gvc_mixer_control_change_profile_on_selected_device (control,
591
/* Handle a network sink as a portless or cardless device */
592
if (!gvc_mixer_ui_device_has_ports (output)) {
593
g_debug ("Did we try to move to a software/bluetooth sink ?");
594
if (gvc_mixer_control_set_default_sink (control, stream)) {
595
/* sink change was successful, update the UI.*/
596
g_signal_emit (G_OBJECT (control),
597
signals[ACTIVE_OUTPUT_UPDATE],
599
gvc_mixer_ui_device_get_id (output));
602
g_warning ("Failed to set default sink with stream from output %s",
603
gvc_mixer_ui_device_get_description (output));
608
active_port = gvc_mixer_stream_get_port (stream);
609
output_port = gvc_mixer_ui_device_get_port (output);
610
/* First ensure the correct port is active on the sink */
611
if (g_strcmp0 (active_port->port, output_port) != 0) {
612
g_debug ("Port change, switch to = %s", output_port);
613
if (gvc_mixer_stream_change_port (stream, output_port) == FALSE) {
614
g_warning ("Could not change port !");
619
default_stream = gvc_mixer_control_get_default_sink (control);
621
/* Finally if we are not on the correct stream, swap over. */
622
if (stream != default_stream) {
623
GvcMixerUIDevice* output;
625
g_debug ("Attempting to swap over to stream %s ",
626
gvc_mixer_stream_get_description (stream));
627
if (gvc_mixer_control_set_default_sink (control, stream)) {
628
output = gvc_mixer_control_lookup_device_from_stream (control, stream);
629
g_signal_emit (G_OBJECT (control),
630
signals[ACTIVE_OUTPUT_UPDATE],
632
gvc_mixer_ui_device_get_id (output));
634
/* If the move failed for some reason reset the UI. */
635
output = gvc_mixer_control_lookup_device_from_stream (control, default_stream);
636
g_signal_emit (G_OBJECT (control),
637
signals[ACTIVE_OUTPUT_UPDATE],
639
gvc_mixer_ui_device_get_id (output));
646
* gvc_mixer_control_change_input:
649
* This method is called from the UI when the user selects a previously unselected device.
650
* - Firstly it queries the stream from the device.
651
* - It assumes that if the stream is null that it cannot be a bluetooth or network stream (they never show unless they have valid sinks and sources)
652
* In the scenario of a NULL stream on the device
653
* - It fetches the device's preferred profile or if NUll the profile with the highest priority on that device.
654
* - It then caches this device in control->priv->cached_desired_input_id so that when the update_source triggered
655
* from when we attempt to change profile we will know exactly what device to highlight on that stream.
656
* - It attempts to swap the profile on the card from that device and returns.
657
* - Next, it handles network or bluetooth streams that only require their stream to be made the default.
658
* - Next it deals with port changes so if the stream's active port is not the same as the port on the device
659
* it will attempt to change the port on that stream to be same as the device. If this fails it will return.
660
* - Finally it will set this new stream to be the default stream and emit a signal for the UI confirming the active input device.
663
gvc_mixer_control_change_input (GvcMixerControl *control,
664
GvcMixerUIDevice* input)
666
GvcMixerStream *stream;
667
GvcMixerStream *default_stream;
668
const GvcMixerStreamPort *active_port;
669
const gchar *input_port;
671
stream = gvc_mixer_control_get_stream_from_device (control, input);
672
if (stream == NULL) {
673
gvc_mixer_control_change_profile_on_selected_device (control,
678
/* Handle a network sink as a portless/cardless device */
679
if (!gvc_mixer_ui_device_has_ports (input)) {
680
g_debug ("Did we try to move to a software/bluetooth source ?");
681
if (! gvc_mixer_control_set_default_source (control, stream)) {
682
g_warning ("Failed to set default source with stream from input %s",
683
gvc_mixer_ui_device_get_description (input));
688
active_port = gvc_mixer_stream_get_port (stream);
689
input_port = gvc_mixer_ui_device_get_port (input);
690
/* First ensure the correct port is active on the sink */
691
if (g_strcmp0 (active_port->port, input_port) != 0) {
692
g_debug ("Port change, switch to = %s", input_port);
693
if (gvc_mixer_stream_change_port (stream, input_port) == FALSE) {
694
g_warning ("Could not change port!");
699
default_stream = gvc_mixer_control_get_default_source (control);
701
/* Finally if we are not on the correct stream, swap over. */
702
if (stream != default_stream) {
703
g_debug ("change-input - attempting to swap over to stream %s",
704
gvc_mixer_stream_get_description (stream));
705
gvc_mixer_control_set_default_source (control, stream);
318
711
listify_hash_values_hfunc (gpointer key,
531
948
new_id = gvc_mixer_stream_get_id (stream);
533
950
if (control->priv->default_source_id != new_id) {
951
GvcMixerUIDevice *input;
534
952
control->priv->default_source_id = new_id;
535
953
control->priv->default_source_is_set = TRUE;
536
954
g_signal_emit (control,
537
955
signals[DEFAULT_SOURCE_CHANGED],
959
if (control->priv->default_source_is_set) {
960
g_signal_handlers_disconnect_by_func (gvc_mixer_control_get_default_source (control),
961
on_default_source_port_notify,
965
g_signal_connect (stream,
967
G_CALLBACK (on_default_source_port_notify),
970
input = gvc_mixer_control_lookup_device_from_stream (control, stream);
972
g_signal_emit (G_OBJECT (control),
973
signals[ACTIVE_INPUT_UPDATE],
975
gvc_mixer_ui_device_get_id (input));
980
on_default_sink_port_notify (GObject *object,
982
GvcMixerControl *control)
985
GvcMixerUIDevice *output;
987
g_object_get (object, "port", &port, NULL);
989
output = gvc_mixer_control_lookup_device_from_stream (control,
990
GVC_MIXER_STREAM (object));
991
if (output != NULL) {
992
g_debug ("on_default_sink_port_notify - moved to port %s - which SHOULD correspond to output %s",
994
gvc_mixer_ui_device_get_description (output));
995
g_signal_emit (G_OBJECT (control),
996
signals[ACTIVE_OUTPUT_UPDATE],
998
gvc_mixer_ui_device_get_id (output));
701
1184
gvc_mixer_stream_get_id (stream));
1187
/* This method will match individual stream ports against its corresponding device
1189
* - iterates through our devices and finds the one where the card-id on the device is the same as the card-id on the stream
1190
* and the port-name on the device is the same as the streamport-name.
1191
* This should always find a match and is used exclusively by sync_devices().
1194
match_stream_with_devices (GvcMixerControl *control,
1195
GvcMixerStreamPort *stream_port,
1196
GvcMixerStream *stream)
1199
guint stream_card_id;
1201
gboolean in_possession = FALSE;
1203
stream_id = gvc_mixer_stream_get_id (stream);
1204
stream_card_id = gvc_mixer_stream_get_card_index (stream);
1206
devices = g_hash_table_get_values (GVC_IS_MIXER_SOURCE (stream) ? control->priv->ui_inputs : control->priv->ui_outputs);
1208
for (d = devices; d != NULL; d = d->next) {
1209
GvcMixerUIDevice *device;
1210
gint device_stream_id;
1211
gchar *device_port_name;
1218
g_object_get (G_OBJECT (device),
1219
"stream-id", &device_stream_id,
1222
"description", &description,
1223
"port-name", &device_port_name,
1226
card_id = gvc_mixer_card_get_index (card);
1228
g_debug ("Attempt to match_stream update_with_existing_outputs - Try description : '%s', origin : '%s', device port name : '%s', card : %p, AGAINST stream port: '%s', sink card id %i",
1236
if (stream_card_id == card_id &&
1237
g_strcmp0 (device_port_name, stream_port->port) == 0) {
1238
g_debug ("Match device with stream: We have a match with description: '%s', origin: '%s', cached already with device id %u, so set stream id to %i",
1241
gvc_mixer_ui_device_get_id (device),
1244
g_object_set (G_OBJECT (device),
1245
"stream-id", (gint)stream_id,
1247
in_possession = TRUE;
1250
g_free (device_port_name);
1252
g_free (description);
1254
if (in_possession == TRUE)
1258
g_list_free (devices);
1259
return in_possession;
1263
* This method attempts to match a sink or source with its relevant UI device.
1264
* GvcMixerStream can represent both a sink or source.
1265
* Using static card port introspection implies that we know beforehand what
1266
* outputs and inputs are available to the user.
1267
* But that does not mean that all of these inputs and outputs are available to be used.
1268
* For instance we might be able to see that there is a HDMI port available but if
1269
* we are on the default analog stereo output profile there is no valid sink for
1270
* that HDMI device. We first need to change profile and when update_sink() is called
1271
* only then can we match the new hdmi sink with its corresponding device.
1273
* Firstly it checks to see if the incoming stream has no ports.
1274
* - If a stream has no ports but has a valid card ID (bluetooth), it will attempt
1275
* to match the device with the stream using the card id.
1276
* - If a stream has no ports and no valid card id, it goes ahead and makes a new
1277
* device (software/network devices are only detectable at the sink/source level)
1278
* If the stream has ports it will match each port against the stream using match_stream_with_devices().
1280
* This method should always find a match.
1283
sync_devices (GvcMixerControl *control,
1284
GvcMixerStream* stream)
1286
/* Go through ports to see what outputs can be created. */
1287
const GList *stream_ports;
1288
const GList *n = NULL;
1289
gboolean is_output = !GVC_IS_MIXER_SOURCE (stream);
1290
gint stream_port_count = 0;
1292
stream_ports = gvc_mixer_stream_get_ports (stream);
1294
if (stream_ports == NULL) {
1295
GvcMixerUIDevice *device;
1296
/* Bluetooth, no ports but a valid card */
1297
if (gvc_mixer_stream_get_card_index (stream) != PA_INVALID_INDEX) {
1299
gboolean in_possession = FALSE;
1301
devices = g_hash_table_get_values (is_output ? control->priv->ui_outputs : control->priv->ui_inputs);
1303
for (d = devices; d != NULL; d = d->next) {
1309
g_object_get (G_OBJECT (device),
1312
card_id = gvc_mixer_card_get_index (card);
1313
g_debug ("sync devices, device description - '%s', device card id - %i, stream description - %s, stream card id - %i",
1314
gvc_mixer_ui_device_get_description (device),
1316
gvc_mixer_stream_get_description (stream),
1317
gvc_mixer_stream_get_card_index (stream));
1318
if (card_id == gvc_mixer_stream_get_card_index (stream)) {
1319
in_possession = TRUE;
1323
g_list_free (devices);
1325
if (!in_possession) {
1326
g_warning ("Couldn't match the portless stream (with card) - '%s' is it an input ? -> %i, streams card id -> %i",
1327
gvc_mixer_stream_get_description (stream),
1328
GVC_IS_MIXER_SOURCE (stream),
1329
gvc_mixer_stream_get_card_index (stream));
1333
g_object_set (G_OBJECT (device),
1334
"stream-id", (gint)gvc_mixer_stream_get_id (stream),
1335
"description", gvc_mixer_stream_get_description (stream),
1336
"origin", "", /*Leave it empty for these special cases*/
1338
"port-available", TRUE,
1340
} else { /* Network sink/source has no ports and no card. */
1343
object = g_object_new (GVC_TYPE_MIXER_UI_DEVICE,
1344
"stream-id", (gint)gvc_mixer_stream_get_id (stream),
1345
"description", gvc_mixer_stream_get_description (stream),
1346
"origin", "", /* Leave it empty for these special cases */
1348
"port-available", TRUE,
1350
device = GVC_MIXER_UI_DEVICE (object);
1352
g_hash_table_insert (is_output ? control->priv->ui_outputs : control->priv->ui_inputs,
1353
GUINT_TO_POINTER (gvc_mixer_ui_device_get_id (device)),
1354
g_object_ref (device));
1357
g_signal_emit (G_OBJECT (control),
1358
signals[is_output ? OUTPUT_ADDED : INPUT_ADDED],
1360
gvc_mixer_ui_device_get_id (device));
1365
/* Go ahead and make sure to match each port against a previously created device */
1366
for (n = stream_ports; n != NULL; n = n->next) {
1368
GvcMixerStreamPort *stream_port;
1369
stream_port = n->data;
1370
stream_port_count ++;
1372
if (match_stream_with_devices (control, stream_port, stream))
1375
g_warning ("Sync_devices: Failed to match stream id: %u, description: '%s', origin: '%s'",
1376
gvc_mixer_stream_get_id (stream),
1377
stream_port->human_port,
1378
gvc_mixer_stream_get_description (stream));
705
1383
set_icon_name_from_proplist (GvcMixerStream *stream,
811
1494
gvc_mixer_stream_set_card_index (stream, info->card);
812
1495
gvc_mixer_stream_set_description (stream, info->description);
813
1496
set_icon_name_from_proplist (stream, info->proplist, "audio-card");
1497
gvc_mixer_stream_set_form_factor (stream, pa_proplist_gets (info->proplist, PA_PROP_DEVICE_FORM_FACTOR));
1498
gvc_mixer_stream_set_sysfs_path (stream, pa_proplist_gets (info->proplist, "sysfs.path"));
814
1499
gvc_mixer_stream_set_volume (stream, (guint)max_volume);
815
1500
gvc_mixer_stream_set_is_muted (stream, info->mute);
816
1501
gvc_mixer_stream_set_can_decibel (stream, !!(info->flags & PA_SINK_DECIBEL_VOLUME));
817
1502
gvc_mixer_stream_set_base_volume (stream, (guint32) info->base_volume);
819
if (info->active_port != NULL)
820
gvc_mixer_stream_set_port (stream, info->active_port->name);
821
#endif /* PA_MICRO > 15 */
1504
/* Messy I know but to set the port everytime regardless of whether it has changed will cost us a
1505
* port change notify signal which causes the frontend to resync.
1506
* Only update the UI when something has changed. */
1507
if (info->active_port != NULL) {
1509
gvc_mixer_stream_set_port (stream, info->active_port->name);
1511
const GvcMixerStreamPort *active_port;
1512
active_port = gvc_mixer_stream_get_port (stream);
1513
if (active_port == NULL ||
1514
g_strcmp0 (active_port->port, info->active_port->name) != 0) {
1515
g_debug ("update sink - apparently a port update");
1516
gvc_mixer_stream_set_port (stream, info->active_port->name);
1522
g_debug ("update sink - is new");
824
1524
g_hash_table_insert (control->priv->sinks,
825
1525
GUINT_TO_POINTER (info->index),
826
1526
g_object_ref (stream));
827
1527
add_stream (control, stream);
1528
/* Always sink on a new stream to able to assign the right stream id
1529
* to the appropriate outputs (multiple potential outputs per stream). */
1530
sync_devices (control, stream);
1534
* When we change profile on a device that is not the server default sink,
1535
* it will jump back to the default sink set by the server to prevent the audio setup from being 'outputless'.
1536
* All well and good but then when we get the new stream created for the new profile how do we know
1537
* that this is the intended default or selected device the user wishes to use.
1538
* This is messy but it's the only reliable way that it can be done without ripping the whole thing apart.
1540
if (control->priv->profile_swapping_device_id != GVC_MIXER_UI_DEVICE_INVALID) {
1541
GvcMixerUIDevice *dev = NULL;
1542
dev = gvc_mixer_control_lookup_output_id (control, control->priv->profile_swapping_device_id);
1544
/* now check to make sure this new stream is the same stream just matched and set on the device object */
1545
if (gvc_mixer_ui_device_get_stream_id (dev) == gvc_mixer_stream_get_id (stream)) {
1546
g_debug ("Looks like we profile swapped on a non server default sink");
1547
gvc_mixer_control_set_default_sink (control, stream);
1550
control->priv->profile_swapping_device_id = GVC_MIXER_UI_DEVICE_INVALID;
830
1553
if (control->priv->default_sink_name != NULL
900
1621
gvc_mixer_stream_set_card_index (stream, info->card);
901
1622
gvc_mixer_stream_set_description (stream, info->description);
902
1623
set_icon_name_from_proplist (stream, info->proplist, "audio-input-microphone");
1624
gvc_mixer_stream_set_form_factor (stream, pa_proplist_gets (info->proplist, PA_PROP_DEVICE_FORM_FACTOR));
903
1625
gvc_mixer_stream_set_volume (stream, (guint)max_volume);
904
1626
gvc_mixer_stream_set_is_muted (stream, info->mute);
905
1627
gvc_mixer_stream_set_can_decibel (stream, !!(info->flags & PA_SOURCE_DECIBEL_VOLUME));
906
1628
gvc_mixer_stream_set_base_volume (stream, (guint32) info->base_volume);
908
if (info->active_port != NULL)
909
gvc_mixer_stream_set_port (stream, info->active_port->name);
910
#endif /* PA_MICRO > 15 */
1629
g_debug ("update source");
1631
if (info->active_port != NULL) {
1633
gvc_mixer_stream_set_port (stream, info->active_port->name);
1635
const GvcMixerStreamPort *active_port;
1636
active_port = gvc_mixer_stream_get_port (stream);
1637
if (active_port == NULL ||
1638
g_strcmp0 (active_port->port, info->active_port->name) != 0) {
1639
g_debug ("update source - apparently a port update");
1640
gvc_mixer_stream_set_port (stream, info->active_port->name);
913
1646
g_hash_table_insert (control->priv->sources,
914
1647
GUINT_TO_POINTER (info->index),
915
1648
g_object_ref (stream));
916
1649
add_stream (control, stream);
1650
sync_devices (control, stream);
1653
if (control->priv->profile_swapping_device_id != GVC_MIXER_UI_DEVICE_INVALID) {
1654
GvcMixerUIDevice *dev = NULL;
1656
dev = gvc_mixer_control_lookup_input_id (control, control->priv->profile_swapping_device_id);
1659
/* now check to make sure this new stream is the same stream just matched and set on the device object */
1660
if (gvc_mixer_ui_device_get_stream_id (dev) == gvc_mixer_stream_get_id (stream)) {
1661
g_debug ("Looks like we profile swapped on a non server default sink");
1662
gvc_mixer_control_set_default_source (control, stream);
1665
control->priv->profile_swapping_device_id = GVC_MIXER_UI_DEVICE_INVALID;
919
1667
if (control->priv->default_source_name != NULL
920
1668
&& info->name != NULL
921
1669
&& strcmp (control->priv->default_source_name, info->name) == 0) {
1863
* A utility method to gather which card profiles are relevant to the port .
1866
determine_profiles_for_port (pa_card_port_info *port,
1867
GList* card_profiles)
1870
GList *supported_profiles = NULL;
1872
for (i = 0; i < port->n_profiles; i++) {
1873
for (p = card_profiles; p != NULL; p = p->next) {
1874
GvcMixerCardProfile *prof;
1876
if (g_strcmp0 (port->profiles[i]->name, prof->profile) == 0)
1877
supported_profiles = g_list_append (supported_profiles, prof);
1880
g_debug ("%i profiles supported on port %s",
1881
g_list_length (supported_profiles),
1883
return g_list_sort (supported_profiles, (GCompareFunc) gvc_mixer_card_profile_compare);
1887
is_card_port_an_output (GvcMixerCardPort* port)
1889
return port->direction == PA_DIRECTION_OUTPUT ? TRUE : FALSE;
1893
* This method will create a ui device for the given port.
1896
create_ui_device_from_port (GvcMixerControl* control,
1897
GvcMixerCardPort* port,
1900
GvcMixerUIDeviceDirection direction;
1902
GvcMixerUIDevice *uidevice;
1903
gboolean available = port->available != PA_PORT_AVAILABLE_NO;
1905
direction = (is_card_port_an_output (port) == TRUE) ? UIDeviceOutput : UIDeviceInput;
1907
object = g_object_new (GVC_TYPE_MIXER_UI_DEVICE,
1908
"type", (uint)direction,
1910
"port-name", port->port,
1911
"description", port->human_port,
1912
"origin", gvc_mixer_card_get_name (card),
1913
"port-available", available,
1916
uidevice = GVC_MIXER_UI_DEVICE (object);
1917
gvc_mixer_ui_device_set_profiles (uidevice, port->profiles);
1919
g_hash_table_insert (is_card_port_an_output (port) ? control->priv->ui_outputs : control->priv->ui_inputs,
1920
GUINT_TO_POINTER (gvc_mixer_ui_device_get_id (uidevice)),
1921
g_object_ref (uidevice));
1925
g_signal_emit (G_OBJECT (control),
1926
signals[is_card_port_an_output (port) ? OUTPUT_ADDED : INPUT_ADDED],
1928
gvc_mixer_ui_device_get_id (uidevice));
1931
g_debug ("create_ui_device_from_port, direction %u, description '%s', origin '%s', port available %i",
1934
gvc_mixer_card_get_name (card),
1939
* This method will match up GvcMixerCardPorts with existing devices.
1940
* A match is achieved if the device's card-id and the port's card-id are the same
1941
* && the device's port-name and the card-port's port member are the same.
1942
* A signal is then sent adding or removing that device from the UI depending on the availability of the port.
1945
match_card_port_with_existing_device (GvcMixerControl *control,
1946
GvcMixerCardPort *card_port,
1952
GvcMixerUIDevice *device;
1953
gboolean is_output = is_card_port_an_output (card_port);
1955
devices = g_hash_table_get_values (is_output ? control->priv->ui_outputs : control->priv->ui_inputs);
1957
for (d = devices; d != NULL; d = d->next) {
1958
GvcMixerCard *device_card;
1959
gchar *device_port_name;
1962
g_object_get (G_OBJECT (device),
1963
"card", &device_card,
1964
"port-name", &device_port_name,
1967
if (g_strcmp0 (card_port->port, device_port_name) == 0 &&
1968
device_card == card) {
1969
g_debug ("Found the relevant device %s, update its port availability flag to %i, is_output %i",
1973
g_object_set (G_OBJECT (device),
1974
"port-available", available, NULL);
1975
g_signal_emit (G_OBJECT (control),
1976
is_output ? signals[available ? OUTPUT_ADDED : OUTPUT_REMOVED] : signals[available ? INPUT_ADDED : INPUT_REMOVED],
1978
gvc_mixer_ui_device_get_id (device));
1980
g_free (device_port_name);
1983
g_list_free (devices);
1987
create_ui_device_from_card (GvcMixerControl *control,
1991
GvcMixerUIDevice *in;
1992
GvcMixerUIDevice *out;
1993
const GList *profiles;
1995
/* For now just create two devices and presume this device is multi directional
1996
* Ensure to remove both on card removal (available to false by default) */
1997
profiles = gvc_mixer_card_get_profiles (card);
1999
g_debug ("Portless card just registered - %i", gvc_mixer_card_get_index (card));
2001
object = g_object_new (GVC_TYPE_MIXER_UI_DEVICE,
2002
"type", UIDeviceInput,
2003
"description", gvc_mixer_card_get_name (card),
2004
"origin", "", /* Leave it empty for these special cases */
2006
"port-available", FALSE,
2009
in = GVC_MIXER_UI_DEVICE (object);
2010
gvc_mixer_ui_device_set_profiles (in, profiles);
2012
g_hash_table_insert (control->priv->ui_inputs,
2013
GUINT_TO_POINTER (gvc_mixer_ui_device_get_id (in)),
2015
object = g_object_new (GVC_TYPE_MIXER_UI_DEVICE,
2016
"type", UIDeviceOutput,
2017
"description", gvc_mixer_card_get_name (card),
2018
"origin", "", /* Leave it empty for these special cases */
2020
"port-available", FALSE,
2023
out = GVC_MIXER_UI_DEVICE (object);
2024
gvc_mixer_ui_device_set_profiles (out, profiles);
2026
g_hash_table_insert (control->priv->ui_outputs,
2027
GUINT_TO_POINTER (gvc_mixer_ui_device_get_id (out)),
2028
g_object_ref (out));
2032
* At this point we can determine all devices available to us (besides network 'ports')
2033
* This is done by the following:
2035
* - gvc_mixer_card and gvc_mixer_card_ports are created and relevant setters are called.
2036
* - First it checks to see if it's a portless card. Bluetooth devices are portless AFAIHS.
2037
* If so it creates two devices, an input and an output.
2038
* - If it's a 'normal' card with ports it will create a new ui-device or
2039
* synchronise port availability with the existing device cached for that port on this card. */
1115
2042
update_card (GvcMixerControl *control,
1116
2043
const pa_card_info *info)
2045
const GList *card_ports = NULL;
2046
const GList *m = NULL;
1118
2047
GvcMixerCard *card;
1119
2048
gboolean is_new = FALSE;
2126
3187
G_TYPE_FROM_CLASS (klass),
2127
3188
G_SIGNAL_RUN_LAST,
2128
3189
G_STRUCT_OFFSET (GvcMixerControlClass, state_changed),
3191
g_cclosure_marshal_VOID__UINT,
2130
3192
G_TYPE_NONE, 1, G_TYPE_UINT);
2131
3193
signals [STREAM_ADDED] =
2132
3194
g_signal_new ("stream-added",
2133
3195
G_TYPE_FROM_CLASS (klass),
2134
3196
G_SIGNAL_RUN_LAST,
2135
3197
G_STRUCT_OFFSET (GvcMixerControlClass, stream_added),
3199
g_cclosure_marshal_VOID__UINT,
2137
3200
G_TYPE_NONE, 1, G_TYPE_UINT);
2138
3201
signals [STREAM_REMOVED] =
2139
3202
g_signal_new ("stream-removed",
2140
3203
G_TYPE_FROM_CLASS (klass),
2141
3204
G_SIGNAL_RUN_LAST,
2142
3205
G_STRUCT_OFFSET (GvcMixerControlClass, stream_removed),
3207
g_cclosure_marshal_VOID__UINT,
2144
3208
G_TYPE_NONE, 1, G_TYPE_UINT);
2145
3209
signals [CARD_ADDED] =
2146
3210
g_signal_new ("card-added",
2147
3211
G_TYPE_FROM_CLASS (klass),
2148
3212
G_SIGNAL_RUN_LAST,
2149
3213
G_STRUCT_OFFSET (GvcMixerControlClass, card_added),
3215
g_cclosure_marshal_VOID__UINT,
2151
3216
G_TYPE_NONE, 1, G_TYPE_UINT);
2152
3217
signals [CARD_REMOVED] =
2153
3218
g_signal_new ("card-removed",
2154
3219
G_TYPE_FROM_CLASS (klass),
2155
3220
G_SIGNAL_RUN_LAST,
2156
3221
G_STRUCT_OFFSET (GvcMixerControlClass, card_removed),
3223
g_cclosure_marshal_VOID__UINT,
2158
3224
G_TYPE_NONE, 1, G_TYPE_UINT);
2159
3225
signals [DEFAULT_SINK_CHANGED] =
2160
3226
g_signal_new ("default-sink-changed",
2161
3227
G_TYPE_FROM_CLASS (klass),
2162
3228
G_SIGNAL_RUN_LAST,
2163
3229
G_STRUCT_OFFSET (GvcMixerControlClass, default_sink_changed),
3231
g_cclosure_marshal_VOID__UINT,
2165
3232
G_TYPE_NONE, 1, G_TYPE_UINT);
2166
3233
signals [DEFAULT_SOURCE_CHANGED] =
2167
3234
g_signal_new ("default-source-changed",
2168
3235
G_TYPE_FROM_CLASS (klass),
2169
3236
G_SIGNAL_RUN_LAST,
2170
3237
G_STRUCT_OFFSET (GvcMixerControlClass, default_source_changed),
2172
G_TYPE_NONE, 1, G_TYPE_UINT);
3239
g_cclosure_marshal_VOID__UINT,
3240
G_TYPE_NONE, 1, G_TYPE_UINT);
3241
signals [ACTIVE_OUTPUT_UPDATE] =
3242
g_signal_new ("active-output-update",
3243
G_TYPE_FROM_CLASS (klass),
3245
G_STRUCT_OFFSET (GvcMixerControlClass, active_output_update),
3247
g_cclosure_marshal_VOID__UINT,
3248
G_TYPE_NONE, 1, G_TYPE_UINT);
3249
signals [ACTIVE_INPUT_UPDATE] =
3250
g_signal_new ("active-input-update",
3251
G_TYPE_FROM_CLASS (klass),
3253
G_STRUCT_OFFSET (GvcMixerControlClass, active_input_update),
3255
g_cclosure_marshal_VOID__UINT,
3256
G_TYPE_NONE, 1, G_TYPE_UINT);
3257
signals [OUTPUT_ADDED] =
3258
g_signal_new ("output-added",
3259
G_TYPE_FROM_CLASS (klass),
3261
G_STRUCT_OFFSET (GvcMixerControlClass, output_added),
3263
g_cclosure_marshal_VOID__UINT,
3264
G_TYPE_NONE, 1, G_TYPE_UINT);
3265
signals [INPUT_ADDED] =
3266
g_signal_new ("input-added",
3267
G_TYPE_FROM_CLASS (klass),
3269
G_STRUCT_OFFSET (GvcMixerControlClass, input_added),
3271
g_cclosure_marshal_VOID__UINT,
3272
G_TYPE_NONE, 1, G_TYPE_UINT);
3273
signals [OUTPUT_REMOVED] =
3274
g_signal_new ("output-removed",
3275
G_TYPE_FROM_CLASS (klass),
3277
G_STRUCT_OFFSET (GvcMixerControlClass, output_removed),
3279
g_cclosure_marshal_VOID__UINT,
3280
G_TYPE_NONE, 1, G_TYPE_UINT);
3281
signals [INPUT_REMOVED] =
3282
g_signal_new ("input-removed",
3283
G_TYPE_FROM_CLASS (klass),
3285
G_STRUCT_OFFSET (GvcMixerControlClass, input_removed),
3287
g_cclosure_marshal_VOID__UINT,
3288
G_TYPE_NONE, 1, G_TYPE_UINT);
2174
3289
g_type_class_add_private (klass, sizeof (GvcMixerControlPrivate));
2178
3294
gvc_mixer_control_init (GvcMixerControl *control)