Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

media-keys: Add support for an audio device selection dialog #401

Merged
merged 1 commit into from
Nov 4, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading