summaryrefslogtreecommitdiff
path: root/shell
diff options
context:
space:
mode:
authorJonny Lamb <jonny.lamb@collabora.co.uk>2014-04-02 12:21:16 +0200
committerJonny Lamb <jonny.lamb@collabora.co.uk>2014-04-02 12:21:16 +0200
commite41c9cacbd620d5cd94381a38b7e034c89055a6c (patch)
treecdf24e779ec15480d12c1e8bd3227a3582af58c3 /shell
parentce66ce9ded16457feb97dcbf6d41246cb441d1e8 (diff)
downloadgraynard-e41c9cacbd620d5cd94381a38b7e034c89055a6c.tar.gz
graynard-e41c9cacbd620d5cd94381a38b7e034c89055a6c.zip
clock: set volume using asoundlib
Diffstat (limited to 'shell')
-rw-r--r--shell/clock.c119
1 files changed, 103 insertions, 16 deletions
diff --git a/shell/clock.c b/shell/clock.c
index 0fc14c9..909ec90 100644
--- a/shell/clock.c
+++ b/shell/clock.c
@@ -21,11 +21,12 @@
#include "config.h"
-#include "clock.h"
-
+#include <alsa/asoundlib.h>
#define GNOME_DESKTOP_USE_UNSTABLE_API
#include <libgnome-desktop/gnome-wall-clock.h>
+#include "clock.h"
+
enum {
VOLUME_CHANGED,
N_SIGNALS
@@ -42,6 +43,10 @@ struct MaynardClockPrivate {
GtkWidget *volume_image;
GnomeWallClock *wall_clock;
+
+ snd_mixer_t *mixer_handle;
+ snd_mixer_elem_t *mixer;
+ glong min_volume, max_volume;
};
G_DEFINE_TYPE(MaynardClock, maynard_clock, GTK_TYPE_WINDOW)
@@ -54,30 +59,48 @@ maynard_clock_init (MaynardClock *self)
MaynardClockPrivate);
}
+static gdouble
+alsa_volume_to_percentage (MaynardClock *self,
+ glong value)
+{
+ glong range;
+
+ /* min volume isn't always zero unfortunately */
+ range = self->priv->max_volume - self->priv->min_volume;
+
+ value -= self->priv->min_volume;
+
+ return (value / (gdouble) range) * 100;
+}
+
+static glong
+percentage_to_alsa_volume (MaynardClock *self,
+ gdouble value)
+{
+ glong range;
+
+ /* min volume isn't always zero unfortunately */
+ range = self->priv->max_volume - self->priv->min_volume;
+
+ return (range * value / 100) + self->priv->min_volume;
+}
+
static void
volume_changed_cb (GtkRange *range,
MaynardClock *self)
{
- GError *error = NULL;
gdouble value;
- gchar *cmd;
const gchar *icon_name;
GtkWidget *box;
value = gtk_range_get_value (range);
- cmd = g_strdup_printf ("amixer set PCM %d%%", (int) value);
-
- g_spawn_command_line_async (cmd, &error);
-
- if (error)
+ if (self->priv->mixer != NULL)
{
- g_print ("failed to set volume: %s\n", error->message);
- g_clear_error (&error);
+ snd_mixer_selem_set_playback_volume_all (self->priv->mixer,
+ percentage_to_alsa_volume (self, value));
}
- g_free (cmd);
-
/* update the icon */
if (value > 75)
icon_name = "audio-volume-high-symbolic";
@@ -102,9 +125,17 @@ volume_changed_cb (GtkRange *range,
static gboolean
volume_idle_cb (gpointer data)
{
- GtkRange *range = GTK_RANGE (data);
+ MaynardClock *self = MAYNARD_CLOCK (data);
+ glong volume;
- gtk_range_set_value (range, 50);
+ if (self->priv->mixer != NULL)
+ {
+ snd_mixer_selem_get_playback_volume (self->priv->mixer,
+ SND_MIXER_SCHN_MONO, &volume);
+
+ gtk_range_set_value (GTK_RANGE (self->priv->volume_scale),
+ alsa_volume_to_percentage (self, volume));
+ }
return G_SOURCE_REMOVE;
}
@@ -134,7 +165,7 @@ create_volume_box (MaynardClock *self)
/* set the initial value in an idle so ::volume-changed is emitted
* when other widgets are connected to the signal and can react
* accordingly. */
- g_idle_add (volume_idle_cb, self->priv->volume_scale);
+ g_idle_add (volume_idle_cb, self);
return box;
}
@@ -159,6 +190,55 @@ wall_clock_notify_cb (GnomeWallClock *wall_clock,
}
static void
+setup_mixer (MaynardClock *self)
+{
+ snd_mixer_selem_id_t *sid;
+ gint ret;
+
+ /* this is all pretty specific to the rpi */
+
+ if ((ret = snd_mixer_open (&self->priv->mixer_handle, 0)) < 0)
+ goto error;
+
+ if ((ret = snd_mixer_attach (self->priv->mixer_handle, "default")) < 0)
+ goto error;
+
+ if ((ret = snd_mixer_selem_register (self->priv->mixer_handle, NULL, NULL)) < 0)
+ goto error;
+
+ if ((ret = snd_mixer_load (self->priv->mixer_handle)) < 0)
+ goto error;
+
+ snd_mixer_selem_id_alloca (&sid);
+ snd_mixer_selem_id_set_index (sid, 0);
+ snd_mixer_selem_id_set_name (sid, "PCM");
+ self->priv->mixer = snd_mixer_find_selem (self->priv->mixer_handle, sid);
+
+ /* fallback to mixer "Master" */
+ if (self->priv->mixer == NULL)
+ {
+ snd_mixer_selem_id_set_name (sid, "Master");
+ self->priv->mixer = snd_mixer_find_selem (self->priv->mixer_handle, sid);
+ if (self->priv->mixer == NULL)
+ goto error;
+ }
+
+ if ((ret = snd_mixer_selem_get_playback_volume_range (self->priv->mixer,
+ &self->priv->min_volume, &self->priv->max_volume)) < 0)
+ goto error;
+
+ return;
+
+error:
+ g_debug ("failed to setup mixer: %s", snd_strerror (ret));
+
+ if (self->priv->mixer_handle != NULL)
+ snd_mixer_close (self->priv->mixer_handle);
+ self->priv->mixer_handle = NULL;
+ self->priv->mixer = NULL;
+}
+
+static void
maynard_clock_constructed (GObject *object)
{
MaynardClock *self = MAYNARD_CLOCK (object);
@@ -211,6 +291,8 @@ maynard_clock_constructed (GObject *object)
gtk_container_add (GTK_CONTAINER (self->priv->revealer_clock),
self->priv->label);
+ setup_mixer (self);
+
wall_clock_notify_cb (self->priv->wall_clock, NULL, self);
}
@@ -221,6 +303,11 @@ maynard_clock_dispose (GObject *object)
g_clear_object (&self->priv->wall_clock);
+ if (self->priv->mixer_handle != NULL)
+ snd_mixer_close (self->priv->mixer_handle);
+ self->priv->mixer_handle = NULL;
+ self->priv->mixer = NULL;
+
G_OBJECT_CLASS (maynard_clock_parent_class)->dispose (object);
}