Skip to content

Commit

Permalink
media-keys: Add support for an audio device selection dialog
Browse files Browse the repository at this point in the history
  • Loading branch information
JosephMcc committed Oct 21, 2024
1 parent bcc2dc3 commit c39c483
Showing 1 changed file with 161 additions and 0 deletions.
161 changes: 161 additions & 0 deletions plugins/media-keys/csd-media-keys-manager.c
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,10 @@ static const gchar kb_introspection_xml[] =
#define LOGIND_DBUS_PATH "/org/freedesktop/login1"
#define LOGIND_DBUS_INTERFACE "org.freedesktop.login1.Manager"

#define AUDIO_SELECTION_DBUS_NAME "org.Cinnamon.AudioDeviceSelection"
#define AUDIO_SELECTION_DBUS_PATH "/org/Cinnamon/AudioDeviceSelection"
#define AUDIO_SELECTION_DBUS_INTERFACE "org.Cinnamon.AudioDeviceSelection"

#define CSD_MEDIA_KEYS_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), CSD_TYPE_MEDIA_KEYS_MANAGER, CsdMediaKeysManagerPrivate))

typedef struct {
Expand All @@ -147,6 +151,11 @@ struct CsdMediaKeysManagerPrivate
GHashTable *streams; /* key = X device ID, value = stream id */
GUdevClient *udev_client;
#endif /* HAVE_GUDEV */
guint audio_selection_watch_id;
guint audio_selection_signal_id;
GDBusConnection *audio_selection_conn;
gboolean audio_selection_requested;
guint audio_selection_device_id;

GtkWidget *dialog;

Expand Down Expand Up @@ -1777,6 +1786,140 @@ update_theme_settings (GSettings *settings,
}
}

typedef struct {
GvcHeadsetPortChoice choice;
gchar *name;
} AudioSelectionChoice;

static AudioSelectionChoice audio_selection_choices[] = {
{ GVC_HEADSET_PORT_CHOICE_HEADPHONES, "headphones" },
{ GVC_HEADSET_PORT_CHOICE_HEADSET, "headset" },
{ GVC_HEADSET_PORT_CHOICE_MIC, "microphone" },
};

static void
audio_selection_done (GDBusConnection *connection,
const gchar *sender_name,
const gchar *object_path,
const gchar *interface_name,
const gchar *signal_name,
GVariant *parameters,
gpointer data)
{
CsdMediaKeysManagerPrivate *priv = CSD_MEDIA_KEYS_MANAGER (data)->priv;
const gchar *choice;
guint i;

if (!priv->audio_selection_requested)
return;

choice = NULL;
g_variant_get_child (parameters, 0, "&s", &choice);
if (!choice)
return;

for (i = 0; i < G_N_ELEMENTS (audio_selection_choices); ++i) {
if (g_str_equal (choice, audio_selection_choices[i].name)) {
gvc_mixer_control_set_headset_port (priv->volume,
priv->audio_selection_device_id,
audio_selection_choices[i].choice);
break;
}
}

priv->audio_selection_requested = FALSE;
}

static void
audio_selection_needed (GvcMixerControl *control,
guint id,
gboolean show_dialog,
GvcHeadsetPortChoice choices,
CsdMediaKeysManager *manager)
{
CsdMediaKeysManagerPrivate *priv = manager->priv;
gchar *args[G_N_ELEMENTS (audio_selection_choices) + 1];
guint i, n;

if (!priv->audio_selection_conn)
return;

if (priv->audio_selection_requested) {
g_dbus_connection_call (priv->audio_selection_conn,
AUDIO_SELECTION_DBUS_NAME,
AUDIO_SELECTION_DBUS_PATH,
AUDIO_SELECTION_DBUS_INTERFACE,
"Close", NULL, NULL,
G_DBUS_CALL_FLAGS_NONE,
-1, NULL, NULL, NULL);
priv->audio_selection_requested = FALSE;
}

if (!show_dialog)
return;

n = 0;
for (i = 0; i < G_N_ELEMENTS (audio_selection_choices); ++i) {
if (choices & audio_selection_choices[i].choice)
args[n++] = audio_selection_choices[i].name;
}
args[n] = NULL;

priv->audio_selection_requested = TRUE;
priv->audio_selection_device_id = id;
g_dbus_connection_call (priv->audio_selection_conn,
AUDIO_SELECTION_DBUS_NAME,
AUDIO_SELECTION_DBUS_PATH,
AUDIO_SELECTION_DBUS_INTERFACE,
"Open",
g_variant_new ("(^as)", args),
NULL,
G_DBUS_CALL_FLAGS_NONE,
-1, NULL, NULL, NULL);
}

static void
audio_selection_appeared (GDBusConnection *connection,
const gchar *name,
const gchar *name_owner,
gpointer data)
{
CsdMediaKeysManager *manager = data;
manager->priv->audio_selection_conn = connection;
manager->priv->audio_selection_signal_id =
g_dbus_connection_signal_subscribe (connection,
AUDIO_SELECTION_DBUS_NAME,
AUDIO_SELECTION_DBUS_INTERFACE,
"DeviceSelected",
AUDIO_SELECTION_DBUS_PATH,
NULL,
G_DBUS_SIGNAL_FLAGS_NONE,
audio_selection_done,
manager,
NULL);
}

static void
clear_audio_selection (CsdMediaKeysManager *manager)
{
CsdMediaKeysManagerPrivate *priv = manager->priv;

if (priv->audio_selection_signal_id)
g_dbus_connection_signal_unsubscribe (priv->audio_selection_conn,
priv->audio_selection_signal_id);
priv->audio_selection_signal_id = 0;
priv->audio_selection_conn = NULL;
}

static void
audio_selection_vanished (GDBusConnection *connection,
const gchar *name,
gpointer data)
{
if (connection)
clear_audio_selection (data);
}

static gboolean
start_media_keys_idle_cb (CsdMediaKeysManager *manager)
{
Expand Down Expand Up @@ -1863,6 +2006,19 @@ csd_media_keys_manager_start (CsdMediaKeysManager *manager,
"stream-removed",
G_CALLBACK (on_control_stream_removed),
manager);
g_signal_connect (manager->priv->volume,
"audio-device-selection-needed",
G_CALLBACK (audio_selection_needed),
manager);

manager->priv->audio_selection_watch_id =
g_bus_watch_name (G_BUS_TYPE_SESSION,
AUDIO_SELECTION_DBUS_NAME,
G_BUS_NAME_WATCHER_FLAGS_NONE,
audio_selection_appeared,
audio_selection_vanished,
manager,
NULL);

cinnamon_settings_profile_end ("gvc_mixer_control_new");

Expand Down Expand Up @@ -2037,6 +2193,11 @@ csd_media_keys_manager_stop (CsdMediaKeysManager *manager)
g_list_free (priv->media_players);
priv->media_players = NULL;
}

if (priv->audio_selection_watch_id)
g_bus_unwatch_name (priv->audio_selection_watch_id);
priv->audio_selection_watch_id = 0;
clear_audio_selection (manager);
}

static GObject *
Expand Down

0 comments on commit c39c483

Please sign in to comment.