Send commitlog mailing list submissions to
        [email protected]

To subscribe or unsubscribe via the World Wide Web, visit
        http://lists.openmoko.org/mailman/listinfo/commitlog
or, via email, send a message with subject or body 'help' to
        [EMAIL PROTECTED]

You can reach the person managing the list at
        [EMAIL PROTECTED]

When replying, please edit your Subject line so it is more specific
than "Re: Contents of commitlog digest..."
Today's Topics:

   1. r3814 - in
      trunk/src/target/OM-2007.2/applications/openmoko-dialer2: .
      src/dialer ([EMAIL PROTECTED])
   2. r3815 - in
      trunk/src/target/OM-2007.2/applications/openmoko-dialer2: .
      src/dialer ([EMAIL PROTECTED])
--- Begin Message ---
Author: chris
Date: 2008-01-11 14:50:29 +0100 (Fri, 11 Jan 2008)
New Revision: 3814

Added:
   
trunk/src/target/OM-2007.2/applications/openmoko-dialer2/src/dialer/moko-alsa-volume-button.c
   
trunk/src/target/OM-2007.2/applications/openmoko-dialer2/src/dialer/moko-alsa-volume-button.h
Modified:
   trunk/src/target/OM-2007.2/applications/openmoko-dialer2/ChangeLog
Log:
        * src/dialer/moko-alsa-volume-button.[ch]: 
        Add an alsa volume control widget (requires refactoring)


Modified: trunk/src/target/OM-2007.2/applications/openmoko-dialer2/ChangeLog
===================================================================
--- trunk/src/target/OM-2007.2/applications/openmoko-dialer2/ChangeLog  
2008-01-10 16:07:39 UTC (rev 3813)
+++ trunk/src/target/OM-2007.2/applications/openmoko-dialer2/ChangeLog  
2008-01-11 13:50:29 UTC (rev 3814)
@@ -1,3 +1,8 @@
+2008-01-11  Chris Lord  <[EMAIL PROTECTED]>
+
+       * src/dialer/moko-alsa-volume-button.[ch]:
+       Add an alsa volume control widget (requires refactoring)
+
 2008-01-09  Chris Lord  <[EMAIL PROTECTED]>
 
        * data/org.openmoko.Dialer.service.in:

Added: 
trunk/src/target/OM-2007.2/applications/openmoko-dialer2/src/dialer/moko-alsa-volume-button.c
===================================================================
--- 
trunk/src/target/OM-2007.2/applications/openmoko-dialer2/src/dialer/moko-alsa-volume-button.c
       2008-01-10 16:07:39 UTC (rev 3813)
+++ 
trunk/src/target/OM-2007.2/applications/openmoko-dialer2/src/dialer/moko-alsa-volume-button.c
       2008-01-11 13:50:29 UTC (rev 3814)
@@ -0,0 +1,523 @@
+
+#include "moko-alsa-volume-button.h"
+#include <gtk/gtk.h>
+#include <alsa/asoundlib.h>
+
+G_DEFINE_TYPE (MokoAlsaVolumeButton, moko_alsa_volume_button, \
+       GTK_TYPE_SCALE_BUTTON)
+
+#define ALSA_VOLUME_BUTTON_PRIVATE(o) \
+       (G_TYPE_INSTANCE_GET_PRIVATE ((o), MOKO_TYPE_ALSA_VOLUME_BUTTON, \
+        MokoAlsaVolumeButtonPrivate))
+
+typedef struct _MokoAlsaVolumeButtonPrivate MokoAlsaVolumeButtonPrivate;
+
+struct _MokoAlsaVolumeButtonPrivate {
+       gchar *device;
+       snd_mixer_selem_id_t *element;
+       
+       snd_mixer_t *mixer_handle;
+       snd_mixer_elem_t *mixer_elem;
+       gint control_type;
+       
+       glong min;
+       glong max;
+};
+
+enum {
+       PROP_DEVICE = 1,
+       PROP_ELEMENT,
+};
+
+enum {
+       PLAYBACK,
+       CAPTURE,
+       CONTROL
+};
+
+static gboolean
+io_func (GIOChannel *source, GIOCondition condition, MokoAlsaVolumeButton 
*self)
+{
+       switch (condition) {
+           case G_IO_IN : {
+               MokoAlsaVolumeButtonPrivate *priv =
+                       ALSA_VOLUME_BUTTON_PRIVATE (self);
+               snd_mixer_handle_events (priv->mixer_handle);
+               
+               break;
+           }
+           case G_IO_ERR :
+           case G_IO_NVAL :
+               g_warning ("Encountered an error, stopping IO watch");
+               return FALSE;
+           default :
+               g_warning ("Unhandled IO condition");
+               break;
+       }
+       
+       return TRUE;
+}
+
+static void
+update_adjustment (MokoAlsaVolumeButton *button)
+{
+       long volume, old_volume;
+       MokoAlsaVolumeButtonPrivate *priv = ALSA_VOLUME_BUTTON_PRIVATE (button);
+       
+       /* TODO: Average out volume across channels? */
+       
+       switch (priv->control_type) {
+           case PLAYBACK :
+               snd_mixer_selem_get_playback_volume (
+                       priv->mixer_elem, 0, &volume);
+               break;
+           case CAPTURE :
+               snd_mixer_selem_get_capture_volume (
+                       priv->mixer_elem, 0, &volume);
+               break;
+           case CONTROL :
+           default :
+               /* TODO: Handle switches? */
+               g_warning ("Unhandled control type");
+               return;
+       }
+       
+       old_volume = (long)((gtk_scale_button_get_value (
+               GTK_SCALE_BUTTON (button)) / 100.0) *
+               (gdouble)(priv->max-priv->min)) + priv->min;
+       if (volume != old_volume)
+               gtk_scale_button_set_value (GTK_SCALE_BUTTON (button),
+                       ((gdouble)(volume-priv->min)) /
+                               ((gdouble)priv->max-priv->min) * 100.0);
+}
+
+static int
+mixer_event_cb (snd_mixer_t *mixer, unsigned int mask, snd_mixer_elem_t *elem)
+{
+       /*MokoAlsaVolumeButton *button = MOKO_ALSA_VOLUME_BUTTON (
+               snd_mixer_get_callback_private (mixer));
+       MokoAlsaVolumeButtonPrivate *priv = ALSA_VOLUME_BUTTON_PRIVATE 
(button);*/
+       
+       return 0;
+}
+
+static int
+mixer_elem_event_cb (snd_mixer_elem_t *elem, unsigned int mask)
+{
+       MokoAlsaVolumeButton *button = MOKO_ALSA_VOLUME_BUTTON (
+               snd_mixer_elem_get_callback_private (elem));
+
+       update_adjustment (button);
+
+       return 0;
+}
+
+static void
+open_mixer (MokoAlsaVolumeButton *self)
+{
+       MokoAlsaVolumeButtonPrivate *priv = ALSA_VOLUME_BUTTON_PRIVATE (self);
+       
+       if (snd_mixer_open (&priv->mixer_handle, 0) != 0) {
+               g_warning ("Failed to get mixer handle");
+               priv->mixer_handle = NULL;
+               return;
+       }
+       
+       snd_mixer_set_callback (priv->mixer_handle, mixer_event_cb);
+       snd_mixer_set_callback_private (priv->mixer_handle, self);
+       
+       g_debug ("Opened mixer");
+}
+
+static void
+start_polling (MokoAlsaVolumeButton *self)
+{
+       struct pollfd *fds;
+       gint i, nfds;
+
+       MokoAlsaVolumeButtonPrivate *priv = ALSA_VOLUME_BUTTON_PRIVATE (self);
+       
+       if ((nfds = snd_mixer_poll_descriptors_count (priv->mixer_handle)) <= 
0){
+               g_warning ("No poll descriptors on mixer?");
+               return;
+       }
+       
+       fds = g_new0 (struct pollfd, nfds);
+       if (snd_mixer_poll_descriptors (priv->mixer_handle, fds, nfds) < 0) {
+               g_warning ("Error getting polling descriptors for sound mixer");
+               g_free (fds);
+               return;
+       }
+       
+       for (i = 0; i < nfds; i++) {
+               GIOChannel *channel = g_io_channel_unix_new (fds[i].fd);
+               g_debug ("Adding IO watch (IN: %d, OUT: %d)",
+                       fds[i].events & POLLIN, fds[i].events & POLLOUT);
+               g_io_add_watch (channel,
+                       ((fds[i].events & POLLIN) ? G_IO_IN : 0) |
+                       ((fds[i].events & POLLOUT) ? G_IO_OUT : 0) |
+                       ((fds[i].events & POLLPRI) ? G_IO_PRI : 0) |
+                       ((fds[i].events & POLLERR) ? G_IO_ERR : 0) |
+                       ((fds[i].events & POLLHUP) ? G_IO_HUP : 0) |
+                       ((fds[i].events & POLLNVAL) ? G_IO_NVAL : 0),
+                       (GIOFunc)io_func, self);
+       }
+       g_free (fds);
+       
+       g_debug ("Polling for events...");
+}
+
+static void
+close_mixer (MokoAlsaVolumeButton *self)
+{
+       MokoAlsaVolumeButtonPrivate *priv = ALSA_VOLUME_BUTTON_PRIVATE (self);
+       
+       if (!priv->mixer_handle) return;
+       
+       snd_mixer_close (priv->mixer_handle);
+       priv->mixer_handle = NULL;
+       g_debug ("Closed mixer");
+}
+
+static void
+detach_mixer (MokoAlsaVolumeButton *self)
+{
+       MokoAlsaVolumeButtonPrivate *priv = ALSA_VOLUME_BUTTON_PRIVATE (self);
+       
+       if (priv->mixer_handle && priv->device &&
+           priv->element && priv->mixer_elem) {
+               snd_mixer_detach (priv->mixer_handle, priv->device);
+               priv->mixer_elem = NULL;
+               g_debug ("Detached from mixer");
+               close_mixer (self);
+       }
+}
+
+static void
+attach_mixer (MokoAlsaVolumeButton *self)
+{
+       MokoAlsaVolumeButtonPrivate *priv = ALSA_VOLUME_BUTTON_PRIVATE (self);
+       
+       g_debug ("Trying to attach... %p, %s, %p", priv->mixer_handle,
+               priv->device, priv->element);
+       
+       open_mixer (self);
+       
+       if (priv->mixer_handle && priv->device && priv->element &&
+           (snd_mixer_attach (priv->mixer_handle, priv->device) == 0) &&
+           (snd_mixer_selem_register (priv->mixer_handle, NULL, NULL) == 0) &&
+           (snd_mixer_load (priv->mixer_handle) == 0)) {
+               priv->mixer_elem = snd_mixer_find_selem (
+                       priv->mixer_handle, priv->element);
+               if (!priv->mixer_elem) {
+                       g_warning ("Unable to find mixer element");
+                       snd_mixer_detach (priv->mixer_handle, priv->device);
+                       close_mixer (self);
+               } else {
+                       g_debug ("Attached to mixer");
+                       
+                       if (snd_mixer_selem_has_playback_volume (
+                           priv->mixer_elem)) {
+                               priv->control_type = PLAYBACK;
+                               snd_mixer_selem_get_playback_volume_range (
+                                       priv->mixer_elem,
+                                       &priv->min, &priv->max);
+                       } else if (snd_mixer_selem_has_capture_volume (
+                                priv->mixer_elem)) {
+                               priv->control_type = CAPTURE;
+                               snd_mixer_selem_get_capture_volume_range (
+                                       priv->mixer_elem,
+                                       &priv->min, &priv->max);
+                       } else
+                               priv->control_type = CONTROL;
+                       
+                       snd_mixer_elem_set_callback (
+                               priv->mixer_elem, mixer_elem_event_cb);
+                       snd_mixer_elem_set_callback_private (
+                               priv->mixer_elem, self);
+                       
+                       start_polling (self);
+                       update_adjustment (self);
+               }
+       } else {
+               close_mixer (self);
+       }
+}
+
+static void
+moko_alsa_volume_button_get_property (GObject *object, guint property_id,
+                                     GValue *value, GParamSpec *pspec)
+{
+       MokoAlsaVolumeButtonPrivate *priv = ALSA_VOLUME_BUTTON_PRIVATE (object);
+       
+       switch (property_id) {
+           case PROP_DEVICE :
+               g_value_set_string (value, priv->device);
+               break;
+           case PROP_ELEMENT :
+               g_value_set_pointer (value, priv->element);
+               break;
+           default:
+               G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+       }
+}
+
+static void
+moko_alsa_volume_button_set_property (GObject *object, guint property_id,
+                              const GValue *value, GParamSpec *pspec)
+{
+       switch (property_id) {
+           case PROP_DEVICE :
+               moko_alsa_volume_button_set_device (
+                       MOKO_ALSA_VOLUME_BUTTON (object),
+                       g_value_get_string (value));
+               break;
+               
+           case PROP_ELEMENT :
+               moko_alsa_volume_button_set_element (
+                       MOKO_ALSA_VOLUME_BUTTON (object),
+                       (snd_mixer_selem_id_t *)g_value_get_pointer (value));
+               break;
+           default:
+               G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+       }
+}
+
+static void
+moko_alsa_volume_button_finalize (GObject *object)
+{
+       MokoAlsaVolumeButton *button = MOKO_ALSA_VOLUME_BUTTON (object);
+       MokoAlsaVolumeButtonPrivate *priv = ALSA_VOLUME_BUTTON_PRIVATE (button);
+       
+       detach_mixer (button);
+       
+       g_free (priv->device);
+       if (priv->element) {
+               snd_mixer_selem_id_free (priv->element);
+       }
+       
+       G_OBJECT_CLASS (moko_alsa_volume_button_parent_class)->
+               finalize (object);
+}
+
+static void
+moko_alsa_volume_button_value_changed (GtkScaleButton *button, gdouble value)
+{
+       long volume;
+       
+       MokoAlsaVolumeButtonPrivate *priv = ALSA_VOLUME_BUTTON_PRIVATE (button);
+       
+       if (!priv->mixer_elem) return;
+       
+       if (GTK_SCALE_BUTTON_CLASS (moko_alsa_volume_button_parent_class)->
+           value_changed)
+               GTK_SCALE_BUTTON_CLASS (moko_alsa_volume_button_parent_class)->
+                       value_changed (button, value);
+       
+       volume = (long)((gtk_scale_button_get_value (
+               GTK_SCALE_BUTTON (button)) / 100.0) *
+               (gdouble)(priv->max-priv->min)) + priv->min;
+
+       switch (priv->control_type) {
+           case PLAYBACK :
+               snd_mixer_selem_set_playback_volume_all (
+                       priv->mixer_elem, volume);
+               break;
+           case CAPTURE :
+               snd_mixer_selem_set_capture_volume_all (
+                       priv->mixer_elem, volume);
+               break;
+           default :
+               g_warning ("Unhandled control type");
+       }
+}
+
+static void
+moko_alsa_volume_button_class_init (MokoAlsaVolumeButtonClass *klass)
+{
+       GObjectClass *object_class = G_OBJECT_CLASS (klass);
+       GtkScaleButtonClass *button_class = GTK_SCALE_BUTTON_CLASS (klass);
+
+       g_type_class_add_private (klass, sizeof (MokoAlsaVolumeButtonPrivate));
+
+       object_class->get_property = moko_alsa_volume_button_get_property;
+       object_class->set_property = moko_alsa_volume_button_set_property;
+       object_class->finalize = moko_alsa_volume_button_finalize;
+       
+       button_class->value_changed = moko_alsa_volume_button_value_changed;
+
+       g_object_class_install_property (
+               object_class,
+               PROP_DEVICE,
+               g_param_spec_string (
+                       "device",
+                       "gchar *",
+                       "The alsa device name.",
+                       "default",
+                       G_PARAM_READWRITE));
+
+       g_object_class_install_property (
+               object_class,
+               PROP_ELEMENT,
+               g_param_spec_pointer (
+                       "element",
+                       "snd_mixer_selem_id_t",
+                       "The alsa simple mixer element ID.",
+                       G_PARAM_READWRITE));
+}
+
+static void
+moko_alsa_volume_button_init (MokoAlsaVolumeButton *self)
+{
+       MokoAlsaVolumeButtonPrivate *priv = ALSA_VOLUME_BUTTON_PRIVATE (self);
+       
+       priv->device = g_strdup ("default");
+}
+
+GtkWidget *
+moko_alsa_volume_button_new (void)
+{
+       return GTK_WIDGET (g_object_new (MOKO_TYPE_ALSA_VOLUME_BUTTON, NULL));
+}
+
+void
+moko_alsa_volume_button_set_device (MokoAlsaVolumeButton *button,
+                                   const gchar *device)
+{
+       MokoAlsaVolumeButtonPrivate *priv = ALSA_VOLUME_BUTTON_PRIVATE (button);
+
+       detach_mixer (button);
+       g_free (priv->device);
+       priv->device = g_strdup (device);
+       g_debug ("Device set: %s", device);
+       attach_mixer (button);
+}
+
+void
+moko_alsa_volume_button_set_element (MokoAlsaVolumeButton *button,
+                                    snd_mixer_selem_id_t *element)
+{
+       MokoAlsaVolumeButtonPrivate *priv = ALSA_VOLUME_BUTTON_PRIVATE (button);
+
+       detach_mixer (button);
+       if (priv->element) {
+               snd_mixer_selem_id_free (priv->element);
+               priv->element = NULL;
+       }
+       
+       if (snd_mixer_selem_id_malloc (&priv->element) != 0) {
+               g_warning ("Unable to allocate mixer element id");
+       } else if (element) {
+               snd_mixer_selem_id_copy (priv->element, element);
+               g_debug ("Element set");
+               attach_mixer (button);
+       }
+}
+
+void
+moko_alsa_volume_button_set_device_from_card_number (
+       MokoAlsaVolumeButton *button, gint number)
+{
+       void **hints;
+       
+       if (snd_device_name_hint (number, "pcm", &hints) == 0) {
+               gchar *device = strdup (snd_device_name_get_hint (
+                       hints[0], "NAME"));
+               snd_device_name_free_hint (hints);
+               strchr (device, ':')[0] = '\0';
+               
+               moko_alsa_volume_button_set_device (button, device);
+               g_free (device);
+       } else
+               g_warning ("Unable to find card number %d", number);
+}
+
+void
+moko_alsa_volume_button_set_device_from_name (MokoAlsaVolumeButton *button,
+                                             const gchar *name)
+{
+       gint i = -1;
+       
+       if (!name) {
+               moko_alsa_volume_button_set_device (button, NULL);
+               return;
+       }
+
+       while (snd_card_next (&i) == 0) {
+               void **hints;
+       
+               if (snd_device_name_hint (i, "pcm", &hints) == 0) {
+                       gchar *device = strdup (snd_device_name_get_hint (
+                               hints[0], "NAME"));
+                       snd_device_name_free_hint (hints);
+                       strchr (device, ':')[0] = '\0';
+                       
+                       if (strcmp (device, name) == 0) {
+                               moko_alsa_volume_button_set_device (
+                                       button, device);
+                               g_free (device);
+                               return;
+                       }
+                       g_free (device);
+               }
+       }
+       
+       g_warning ("Card '%s' not found", name);
+}
+
+void
+moko_alsa_volume_button_set_element_from_name (MokoAlsaVolumeButton *button,
+                                              const gchar *name)
+{
+       MokoAlsaVolumeButtonPrivate *priv = ALSA_VOLUME_BUTTON_PRIVATE (button);
+
+       if (!priv->device) return;
+       
+       detach_mixer (button);
+       
+       if (!name) {
+               moko_alsa_volume_button_set_element (button, NULL);
+               return;
+       }
+       
+       open_mixer (button);
+       if ((snd_mixer_attach (priv->mixer_handle, priv->device) == 0) &&
+           (snd_mixer_selem_register (priv->mixer_handle, NULL, NULL) == 0) &&
+           (snd_mixer_load (priv->mixer_handle) == 0)) {
+               snd_mixer_elem_t *elem;
+               
+               elem = snd_mixer_first_elem (priv->mixer_handle);
+               while (elem) {
+                       const char *elem_name = snd_mixer_selem_get_name (elem);
+                       if (strcmp (elem_name, name) == 0)
+                               break;
+                       elem = snd_mixer_elem_next (elem);
+               }
+               
+               if (!elem) {
+                       snd_mixer_detach (priv->mixer_handle, priv->device);
+                       close_mixer (button);
+                       g_warning ("Mixer element '%s' not found", name);
+                       attach_mixer (button);
+               } else {
+                       snd_mixer_selem_id_t *id;
+                       if (snd_mixer_selem_id_malloc (&id) != 0) {
+                               g_warning ("Unable to allocate element id");
+                               snd_mixer_detach (
+                                       priv->mixer_handle, priv->device);
+                               close_mixer (button);
+                       } else {
+                               snd_mixer_selem_get_id (elem, id);
+                               snd_mixer_detach (
+                                       priv->mixer_handle, priv->device);
+                               close_mixer (button);
+                               g_debug ("Setting element ID");
+                               moko_alsa_volume_button_set_element (
+                                       button, id);
+                               snd_mixer_selem_id_free (id);
+                       }
+               }
+       } else
+               g_warning ("Unable to open mixer on card '%s'", priv->device);
+}
+

Added: 
trunk/src/target/OM-2007.2/applications/openmoko-dialer2/src/dialer/moko-alsa-volume-button.h
===================================================================
--- 
trunk/src/target/OM-2007.2/applications/openmoko-dialer2/src/dialer/moko-alsa-volume-button.h
       2008-01-10 16:07:39 UTC (rev 3813)
+++ 
trunk/src/target/OM-2007.2/applications/openmoko-dialer2/src/dialer/moko-alsa-volume-button.h
       2008-01-11 13:50:29 UTC (rev 3814)
@@ -0,0 +1,62 @@
+#ifndef _MOKO_ALSA_VOLUME_BUTTON
+#define _MOKO_ALSA_VOLUME_BUTTON
+
+#include <glib-object.h>
+#include <gtk/gtk.h>
+#include <alsa/asoundlib.h>
+
+G_BEGIN_DECLS
+
+#define MOKO_TYPE_ALSA_VOLUME_BUTTON moko_alsa_volume_button_get_type()
+
+#define MOKO_ALSA_VOLUME_BUTTON(obj) \
+       (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+       MOKO_TYPE_ALSA_VOLUME_BUTTON, MokoAlsaVolumeButton))
+
+#define MOKO_ALSA_VOLUME_BUTTON_CLASS(klass) \
+       (G_TYPE_CHECK_CLASS_CAST ((klass), \
+       MOKO_TYPE_ALSA_VOLUME_BUTTON, MokoAlsaVolumeButtonClass))
+
+#define MOKO_IS_ALSA_VOLUME_BUTTON(obj) \
+       (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+       MOKO_TYPE_ALSA_VOLUME_BUTTON))
+
+#define MOKO_IS_ALSA_VOLUME_BUTTON_CLASS(klass) \
+       (G_TYPE_CHECK_CLASS_TYPE ((klass), \
+       MOKO_TYPE_ALSA_VOLUME_BUTTON))
+
+#define MOKO_ALSA_VOLUME_BUTTON_GET_CLASS(obj) \
+       (G_TYPE_INSTANCE_GET_CLASS ((obj), \
+       MOKO_TYPE_ALSA_VOLUME_BUTTON, MokoAlsaVolumeButtonClass))
+
+typedef struct {
+       GtkScaleButton parent;
+} MokoAlsaVolumeButton;
+
+typedef struct {
+       GtkScaleButtonClass parent_class;
+} MokoAlsaVolumeButtonClass;
+
+GType moko_alsa_volume_button_get_type (void);
+
+GtkWidget *moko_alsa_volume_button_new (void);
+
+void moko_alsa_volume_button_set_device (MokoAlsaVolumeButton *button,
+                                        const gchar *device);
+
+void moko_alsa_volume_button_set_element (MokoAlsaVolumeButton *button,
+                                         snd_mixer_selem_id_t *element);
+
+void moko_alsa_volume_button_set_device_from_card_number (
+                       MokoAlsaVolumeButton *button, gint number);
+
+void moko_alsa_volume_button_set_device_from_name (MokoAlsaVolumeButton 
*button,
+                                                  const gchar *name);
+
+void moko_alsa_volume_button_set_element_from_name (
+                       MokoAlsaVolumeButton *button, const gchar *name);
+
+G_END_DECLS
+
+#endif /* _MOKO_ALSA_VOLUME_BUTTON */
+




--- End Message ---
--- Begin Message ---
Author: chris
Date: 2008-01-11 15:25:55 +0100 (Fri, 11 Jan 2008)
New Revision: 3815

Added:
   
trunk/src/target/OM-2007.2/applications/openmoko-dialer2/src/dialer/moko-alsa-volume-control.c
   
trunk/src/target/OM-2007.2/applications/openmoko-dialer2/src/dialer/moko-alsa-volume-control.h
Modified:
   trunk/src/target/OM-2007.2/applications/openmoko-dialer2/ChangeLog
   
trunk/src/target/OM-2007.2/applications/openmoko-dialer2/src/dialer/moko-alsa-volume-button.c
   
trunk/src/target/OM-2007.2/applications/openmoko-dialer2/src/dialer/moko-alsa-volume-button.h
Log:
        * src/dialer/moko-alsa-volume-button.[ch]:
        * src/dialer/moko-alsa-volume-control.[ch]:
        Refactor into separate control a widget objects for flexibility


Modified: trunk/src/target/OM-2007.2/applications/openmoko-dialer2/ChangeLog
===================================================================
--- trunk/src/target/OM-2007.2/applications/openmoko-dialer2/ChangeLog  
2008-01-11 13:50:29 UTC (rev 3814)
+++ trunk/src/target/OM-2007.2/applications/openmoko-dialer2/ChangeLog  
2008-01-11 14:25:55 UTC (rev 3815)
@@ -1,6 +1,12 @@
 2008-01-11  Chris Lord  <[EMAIL PROTECTED]>
 
        * src/dialer/moko-alsa-volume-button.[ch]:
+       * src/dialer/moko-alsa-volume-control.[ch]:
+       Refactor into separate control a widget objects for flexibility
+
+2008-01-11  Chris Lord  <[EMAIL PROTECTED]>
+
+       * src/dialer/moko-alsa-volume-button.[ch]:
        Add an alsa volume control widget (requires refactoring)
 
 2008-01-09  Chris Lord  <[EMAIL PROTECTED]>

Modified: 
trunk/src/target/OM-2007.2/applications/openmoko-dialer2/src/dialer/moko-alsa-volume-button.c
===================================================================
--- 
trunk/src/target/OM-2007.2/applications/openmoko-dialer2/src/dialer/moko-alsa-volume-button.c
       2008-01-11 13:50:29 UTC (rev 3814)
+++ 
trunk/src/target/OM-2007.2/applications/openmoko-dialer2/src/dialer/moko-alsa-volume-button.c
       2008-01-11 14:25:55 UTC (rev 3815)
@@ -1,7 +1,5 @@
 
 #include "moko-alsa-volume-button.h"
-#include <gtk/gtk.h>
-#include <alsa/asoundlib.h>
 
 G_DEFINE_TYPE (MokoAlsaVolumeButton, moko_alsa_volume_button, \
        GTK_TYPE_SCALE_BUTTON)
@@ -13,250 +11,23 @@
 typedef struct _MokoAlsaVolumeButtonPrivate MokoAlsaVolumeButtonPrivate;
 
 struct _MokoAlsaVolumeButtonPrivate {
-       gchar *device;
-       snd_mixer_selem_id_t *element;
-       
-       snd_mixer_t *mixer_handle;
-       snd_mixer_elem_t *mixer_elem;
-       gint control_type;
-       
-       glong min;
-       glong max;
+       MokoAlsaVolumeControl *control;
 };
 
 enum {
-       PROP_DEVICE = 1,
-       PROP_ELEMENT,
+       PROP_CONTROL = 1,
 };
 
-enum {
-       PLAYBACK,
-       CAPTURE,
-       CONTROL
-};
-
-static gboolean
-io_func (GIOChannel *source, GIOCondition condition, MokoAlsaVolumeButton 
*self)
-{
-       switch (condition) {
-           case G_IO_IN : {
-               MokoAlsaVolumeButtonPrivate *priv =
-                       ALSA_VOLUME_BUTTON_PRIVATE (self);
-               snd_mixer_handle_events (priv->mixer_handle);
-               
-               break;
-           }
-           case G_IO_ERR :
-           case G_IO_NVAL :
-               g_warning ("Encountered an error, stopping IO watch");
-               return FALSE;
-           default :
-               g_warning ("Unhandled IO condition");
-               break;
-       }
-       
-       return TRUE;
-}
-
 static void
-update_adjustment (MokoAlsaVolumeButton *button)
-{
-       long volume, old_volume;
-       MokoAlsaVolumeButtonPrivate *priv = ALSA_VOLUME_BUTTON_PRIVATE (button);
-       
-       /* TODO: Average out volume across channels? */
-       
-       switch (priv->control_type) {
-           case PLAYBACK :
-               snd_mixer_selem_get_playback_volume (
-                       priv->mixer_elem, 0, &volume);
-               break;
-           case CAPTURE :
-               snd_mixer_selem_get_capture_volume (
-                       priv->mixer_elem, 0, &volume);
-               break;
-           case CONTROL :
-           default :
-               /* TODO: Handle switches? */
-               g_warning ("Unhandled control type");
-               return;
-       }
-       
-       old_volume = (long)((gtk_scale_button_get_value (
-               GTK_SCALE_BUTTON (button)) / 100.0) *
-               (gdouble)(priv->max-priv->min)) + priv->min;
-       if (volume != old_volume)
-               gtk_scale_button_set_value (GTK_SCALE_BUTTON (button),
-                       ((gdouble)(volume-priv->min)) /
-                               ((gdouble)priv->max-priv->min) * 100.0);
-}
-
-static int
-mixer_event_cb (snd_mixer_t *mixer, unsigned int mask, snd_mixer_elem_t *elem)
-{
-       /*MokoAlsaVolumeButton *button = MOKO_ALSA_VOLUME_BUTTON (
-               snd_mixer_get_callback_private (mixer));
-       MokoAlsaVolumeButtonPrivate *priv = ALSA_VOLUME_BUTTON_PRIVATE 
(button);*/
-       
-       return 0;
-}
-
-static int
-mixer_elem_event_cb (snd_mixer_elem_t *elem, unsigned int mask)
-{
-       MokoAlsaVolumeButton *button = MOKO_ALSA_VOLUME_BUTTON (
-               snd_mixer_elem_get_callback_private (elem));
-
-       update_adjustment (button);
-
-       return 0;
-}
-
-static void
-open_mixer (MokoAlsaVolumeButton *self)
-{
-       MokoAlsaVolumeButtonPrivate *priv = ALSA_VOLUME_BUTTON_PRIVATE (self);
-       
-       if (snd_mixer_open (&priv->mixer_handle, 0) != 0) {
-               g_warning ("Failed to get mixer handle");
-               priv->mixer_handle = NULL;
-               return;
-       }
-       
-       snd_mixer_set_callback (priv->mixer_handle, mixer_event_cb);
-       snd_mixer_set_callback_private (priv->mixer_handle, self);
-       
-       g_debug ("Opened mixer");
-}
-
-static void
-start_polling (MokoAlsaVolumeButton *self)
-{
-       struct pollfd *fds;
-       gint i, nfds;
-
-       MokoAlsaVolumeButtonPrivate *priv = ALSA_VOLUME_BUTTON_PRIVATE (self);
-       
-       if ((nfds = snd_mixer_poll_descriptors_count (priv->mixer_handle)) <= 
0){
-               g_warning ("No poll descriptors on mixer?");
-               return;
-       }
-       
-       fds = g_new0 (struct pollfd, nfds);
-       if (snd_mixer_poll_descriptors (priv->mixer_handle, fds, nfds) < 0) {
-               g_warning ("Error getting polling descriptors for sound mixer");
-               g_free (fds);
-               return;
-       }
-       
-       for (i = 0; i < nfds; i++) {
-               GIOChannel *channel = g_io_channel_unix_new (fds[i].fd);
-               g_debug ("Adding IO watch (IN: %d, OUT: %d)",
-                       fds[i].events & POLLIN, fds[i].events & POLLOUT);
-               g_io_add_watch (channel,
-                       ((fds[i].events & POLLIN) ? G_IO_IN : 0) |
-                       ((fds[i].events & POLLOUT) ? G_IO_OUT : 0) |
-                       ((fds[i].events & POLLPRI) ? G_IO_PRI : 0) |
-                       ((fds[i].events & POLLERR) ? G_IO_ERR : 0) |
-                       ((fds[i].events & POLLHUP) ? G_IO_HUP : 0) |
-                       ((fds[i].events & POLLNVAL) ? G_IO_NVAL : 0),
-                       (GIOFunc)io_func, self);
-       }
-       g_free (fds);
-       
-       g_debug ("Polling for events...");
-}
-
-static void
-close_mixer (MokoAlsaVolumeButton *self)
-{
-       MokoAlsaVolumeButtonPrivate *priv = ALSA_VOLUME_BUTTON_PRIVATE (self);
-       
-       if (!priv->mixer_handle) return;
-       
-       snd_mixer_close (priv->mixer_handle);
-       priv->mixer_handle = NULL;
-       g_debug ("Closed mixer");
-}
-
-static void
-detach_mixer (MokoAlsaVolumeButton *self)
-{
-       MokoAlsaVolumeButtonPrivate *priv = ALSA_VOLUME_BUTTON_PRIVATE (self);
-       
-       if (priv->mixer_handle && priv->device &&
-           priv->element && priv->mixer_elem) {
-               snd_mixer_detach (priv->mixer_handle, priv->device);
-               priv->mixer_elem = NULL;
-               g_debug ("Detached from mixer");
-               close_mixer (self);
-       }
-}
-
-static void
-attach_mixer (MokoAlsaVolumeButton *self)
-{
-       MokoAlsaVolumeButtonPrivate *priv = ALSA_VOLUME_BUTTON_PRIVATE (self);
-       
-       g_debug ("Trying to attach... %p, %s, %p", priv->mixer_handle,
-               priv->device, priv->element);
-       
-       open_mixer (self);
-       
-       if (priv->mixer_handle && priv->device && priv->element &&
-           (snd_mixer_attach (priv->mixer_handle, priv->device) == 0) &&
-           (snd_mixer_selem_register (priv->mixer_handle, NULL, NULL) == 0) &&
-           (snd_mixer_load (priv->mixer_handle) == 0)) {
-               priv->mixer_elem = snd_mixer_find_selem (
-                       priv->mixer_handle, priv->element);
-               if (!priv->mixer_elem) {
-                       g_warning ("Unable to find mixer element");
-                       snd_mixer_detach (priv->mixer_handle, priv->device);
-                       close_mixer (self);
-               } else {
-                       g_debug ("Attached to mixer");
-                       
-                       if (snd_mixer_selem_has_playback_volume (
-                           priv->mixer_elem)) {
-                               priv->control_type = PLAYBACK;
-                               snd_mixer_selem_get_playback_volume_range (
-                                       priv->mixer_elem,
-                                       &priv->min, &priv->max);
-                       } else if (snd_mixer_selem_has_capture_volume (
-                                priv->mixer_elem)) {
-                               priv->control_type = CAPTURE;
-                               snd_mixer_selem_get_capture_volume_range (
-                                       priv->mixer_elem,
-                                       &priv->min, &priv->max);
-                       } else
-                               priv->control_type = CONTROL;
-                       
-                       snd_mixer_elem_set_callback (
-                               priv->mixer_elem, mixer_elem_event_cb);
-                       snd_mixer_elem_set_callback_private (
-                               priv->mixer_elem, self);
-                       
-                       start_polling (self);
-                       update_adjustment (self);
-               }
-       } else {
-               close_mixer (self);
-       }
-}
-
-static void
 moko_alsa_volume_button_get_property (GObject *object, guint property_id,
                                      GValue *value, GParamSpec *pspec)
 {
        MokoAlsaVolumeButtonPrivate *priv = ALSA_VOLUME_BUTTON_PRIVATE (object);
        
        switch (property_id) {
-           case PROP_DEVICE :
-               g_value_set_string (value, priv->device);
+           case PROP_CONTROL :
+               g_value_set_object (value, priv->control);
                break;
-           case PROP_ELEMENT :
-               g_value_set_pointer (value, priv->element);
-               break;
            default:
                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
        }
@@ -267,17 +38,11 @@
                               const GValue *value, GParamSpec *pspec)
 {
        switch (property_id) {
-           case PROP_DEVICE :
-               moko_alsa_volume_button_set_device (
+           case PROP_CONTROL :
+               moko_alsa_volume_button_set_control (
                        MOKO_ALSA_VOLUME_BUTTON (object),
-                       g_value_get_string (value));
+                       g_value_get_object (value));
                break;
-               
-           case PROP_ELEMENT :
-               moko_alsa_volume_button_set_element (
-                       MOKO_ALSA_VOLUME_BUTTON (object),
-                       (snd_mixer_selem_id_t *)g_value_get_pointer (value));
-               break;
            default:
                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
        }
@@ -289,13 +54,8 @@
        MokoAlsaVolumeButton *button = MOKO_ALSA_VOLUME_BUTTON (object);
        MokoAlsaVolumeButtonPrivate *priv = ALSA_VOLUME_BUTTON_PRIVATE (button);
        
-       detach_mixer (button);
+       if (priv->control) g_object_unref (priv->control);
        
-       g_free (priv->device);
-       if (priv->element) {
-               snd_mixer_selem_id_free (priv->element);
-       }
-       
        G_OBJECT_CLASS (moko_alsa_volume_button_parent_class)->
                finalize (object);
 }
@@ -303,33 +63,15 @@
 static void
 moko_alsa_volume_button_value_changed (GtkScaleButton *button, gdouble value)
 {
-       long volume;
-       
        MokoAlsaVolumeButtonPrivate *priv = ALSA_VOLUME_BUTTON_PRIVATE (button);
        
-       if (!priv->mixer_elem) return;
-       
        if (GTK_SCALE_BUTTON_CLASS (moko_alsa_volume_button_parent_class)->
            value_changed)
                GTK_SCALE_BUTTON_CLASS (moko_alsa_volume_button_parent_class)->
                        value_changed (button, value);
        
-       volume = (long)((gtk_scale_button_get_value (
-               GTK_SCALE_BUTTON (button)) / 100.0) *
-               (gdouble)(priv->max-priv->min)) + priv->min;
-
-       switch (priv->control_type) {
-           case PLAYBACK :
-               snd_mixer_selem_set_playback_volume_all (
-                       priv->mixer_elem, volume);
-               break;
-           case CAPTURE :
-               snd_mixer_selem_set_capture_volume_all (
-                       priv->mixer_elem, volume);
-               break;
-           default :
-               g_warning ("Unhandled control type");
-       }
+       moko_alsa_volume_control_set_volume (priv->control,
+               gtk_scale_button_get_value (button) / 100.0);
 }
 
 static void
@@ -348,30 +90,18 @@
 
        g_object_class_install_property (
                object_class,
-               PROP_DEVICE,
-               g_param_spec_string (
-                       "device",
-                       "gchar *",
-                       "The alsa device name.",
-                       "default",
+               PROP_CONTROL,
+               g_param_spec_object (
+                       "control",
+                       "MokoAlsaVolumeControl",
+                       "The volume control object to hook onto.",
+                       MOKO_TYPE_ALSA_VOLUME_CONTROL,
                        G_PARAM_READWRITE));
-
-       g_object_class_install_property (
-               object_class,
-               PROP_ELEMENT,
-               g_param_spec_pointer (
-                       "element",
-                       "snd_mixer_selem_id_t",
-                       "The alsa simple mixer element ID.",
-                       G_PARAM_READWRITE));
 }
 
 static void
 moko_alsa_volume_button_init (MokoAlsaVolumeButton *self)
 {
-       MokoAlsaVolumeButtonPrivate *priv = ALSA_VOLUME_BUTTON_PRIVATE (self);
-       
-       priv->device = g_strdup ("default");
 }
 
 GtkWidget *
@@ -380,144 +110,40 @@
        return GTK_WIDGET (g_object_new (MOKO_TYPE_ALSA_VOLUME_BUTTON, NULL));
 }
 
-void
-moko_alsa_volume_button_set_device (MokoAlsaVolumeButton *button,
-                                   const gchar *device)
+static void
+volume_changed_cb (MokoAlsaVolumeControl *control, gdouble volume,
+                  MokoAlsaVolumeButton *button)
 {
-       MokoAlsaVolumeButtonPrivate *priv = ALSA_VOLUME_BUTTON_PRIVATE (button);
-
-       detach_mixer (button);
-       g_free (priv->device);
-       priv->device = g_strdup (device);
-       g_debug ("Device set: %s", device);
-       attach_mixer (button);
+       gtk_scale_button_set_value (GTK_SCALE_BUTTON (button), volume * 100.0);
 }
 
 void
-moko_alsa_volume_button_set_element (MokoAlsaVolumeButton *button,
-                                    snd_mixer_selem_id_t *element)
+moko_alsa_volume_button_set_control (MokoAlsaVolumeButton *button,
+                                    MokoAlsaVolumeControl *control)
 {
        MokoAlsaVolumeButtonPrivate *priv = ALSA_VOLUME_BUTTON_PRIVATE (button);
-
-       detach_mixer (button);
-       if (priv->element) {
-               snd_mixer_selem_id_free (priv->element);
-               priv->element = NULL;
-       }
        
-       if (snd_mixer_selem_id_malloc (&priv->element) != 0) {
-               g_warning ("Unable to allocate mixer element id");
-       } else if (element) {
-               snd_mixer_selem_id_copy (priv->element, element);
-               g_debug ("Element set");
-               attach_mixer (button);
+       if (priv->control) {
+               g_signal_handlers_disconnect_by_func (priv->control,
+                       volume_changed_cb, button);
+               g_object_unref (priv->control);
+               priv->control = NULL;
        }
-}
-
-void
-moko_alsa_volume_button_set_device_from_card_number (
-       MokoAlsaVolumeButton *button, gint number)
-{
-       void **hints;
        
-       if (snd_device_name_hint (number, "pcm", &hints) == 0) {
-               gchar *device = strdup (snd_device_name_get_hint (
-                       hints[0], "NAME"));
-               snd_device_name_free_hint (hints);
-               strchr (device, ':')[0] = '\0';
-               
-               moko_alsa_volume_button_set_device (button, device);
-               g_free (device);
-       } else
-               g_warning ("Unable to find card number %d", number);
-}
-
-void
-moko_alsa_volume_button_set_device_from_name (MokoAlsaVolumeButton *button,
-                                             const gchar *name)
-{
-       gint i = -1;
-       
-       if (!name) {
-               moko_alsa_volume_button_set_device (button, NULL);
-               return;
+       if (control) {
+               priv->control = g_object_ref (control);
+               g_signal_connect (priv->control, "volume_changed",
+                       G_CALLBACK (volume_changed_cb), button);
+               gtk_scale_button_set_value (GTK_SCALE_BUTTON (button),
+                       moko_alsa_volume_control_get_volume (control) * 100.0);
        }
-
-       while (snd_card_next (&i) == 0) {
-               void **hints;
-       
-               if (snd_device_name_hint (i, "pcm", &hints) == 0) {
-                       gchar *device = strdup (snd_device_name_get_hint (
-                               hints[0], "NAME"));
-                       snd_device_name_free_hint (hints);
-                       strchr (device, ':')[0] = '\0';
-                       
-                       if (strcmp (device, name) == 0) {
-                               moko_alsa_volume_button_set_device (
-                                       button, device);
-                               g_free (device);
-                               return;
-                       }
-                       g_free (device);
-               }
-       }
-       
-       g_warning ("Card '%s' not found", name);
 }
 
-void
-moko_alsa_volume_button_set_element_from_name (MokoAlsaVolumeButton *button,
-                                              const gchar *name)
+MokoAlsaVolumeControl *
+moko_alsa_volume_button_get_control (MokoAlsaVolumeButton *button)
 {
        MokoAlsaVolumeButtonPrivate *priv = ALSA_VOLUME_BUTTON_PRIVATE (button);
-
-       if (!priv->device) return;
        
-       detach_mixer (button);
-       
-       if (!name) {
-               moko_alsa_volume_button_set_element (button, NULL);
-               return;
-       }
-       
-       open_mixer (button);
-       if ((snd_mixer_attach (priv->mixer_handle, priv->device) == 0) &&
-           (snd_mixer_selem_register (priv->mixer_handle, NULL, NULL) == 0) &&
-           (snd_mixer_load (priv->mixer_handle) == 0)) {
-               snd_mixer_elem_t *elem;
-               
-               elem = snd_mixer_first_elem (priv->mixer_handle);
-               while (elem) {
-                       const char *elem_name = snd_mixer_selem_get_name (elem);
-                       if (strcmp (elem_name, name) == 0)
-                               break;
-                       elem = snd_mixer_elem_next (elem);
-               }
-               
-               if (!elem) {
-                       snd_mixer_detach (priv->mixer_handle, priv->device);
-                       close_mixer (button);
-                       g_warning ("Mixer element '%s' not found", name);
-                       attach_mixer (button);
-               } else {
-                       snd_mixer_selem_id_t *id;
-                       if (snd_mixer_selem_id_malloc (&id) != 0) {
-                               g_warning ("Unable to allocate element id");
-                               snd_mixer_detach (
-                                       priv->mixer_handle, priv->device);
-                               close_mixer (button);
-                       } else {
-                               snd_mixer_selem_get_id (elem, id);
-                               snd_mixer_detach (
-                                       priv->mixer_handle, priv->device);
-                               close_mixer (button);
-                               g_debug ("Setting element ID");
-                               moko_alsa_volume_button_set_element (
-                                       button, id);
-                               snd_mixer_selem_id_free (id);
-                       }
-               }
-       } else
-               g_warning ("Unable to open mixer on card '%s'", priv->device);
+       return priv->control;
 }
 

Modified: 
trunk/src/target/OM-2007.2/applications/openmoko-dialer2/src/dialer/moko-alsa-volume-button.h
===================================================================
--- 
trunk/src/target/OM-2007.2/applications/openmoko-dialer2/src/dialer/moko-alsa-volume-button.h
       2008-01-11 13:50:29 UTC (rev 3814)
+++ 
trunk/src/target/OM-2007.2/applications/openmoko-dialer2/src/dialer/moko-alsa-volume-button.h
       2008-01-11 14:25:55 UTC (rev 3815)
@@ -3,7 +3,7 @@
 
 #include <glib-object.h>
 #include <gtk/gtk.h>
-#include <alsa/asoundlib.h>
+#include "moko-alsa-volume-control.h"
 
 G_BEGIN_DECLS
 
@@ -41,21 +41,12 @@
 
 GtkWidget *moko_alsa_volume_button_new (void);
 
-void moko_alsa_volume_button_set_device (MokoAlsaVolumeButton *button,
-                                        const gchar *device);
+void moko_alsa_volume_button_set_control (MokoAlsaVolumeButton *button,
+                                         MokoAlsaVolumeControl *control);
 
-void moko_alsa_volume_button_set_element (MokoAlsaVolumeButton *button,
-                                         snd_mixer_selem_id_t *element);
+MokoAlsaVolumeControl *moko_alsa_volume_button_get_control (
+                       MokoAlsaVolumeButton *button);
 
-void moko_alsa_volume_button_set_device_from_card_number (
-                       MokoAlsaVolumeButton *button, gint number);
-
-void moko_alsa_volume_button_set_device_from_name (MokoAlsaVolumeButton 
*button,
-                                                  const gchar *name);
-
-void moko_alsa_volume_button_set_element_from_name (
-                       MokoAlsaVolumeButton *button, const gchar *name);
-
 G_END_DECLS
 
 #endif /* _MOKO_ALSA_VOLUME_BUTTON */

Added: 
trunk/src/target/OM-2007.2/applications/openmoko-dialer2/src/dialer/moko-alsa-volume-control.c
===================================================================
--- 
trunk/src/target/OM-2007.2/applications/openmoko-dialer2/src/dialer/moko-alsa-volume-control.c
      2008-01-11 13:50:29 UTC (rev 3814)
+++ 
trunk/src/target/OM-2007.2/applications/openmoko-dialer2/src/dialer/moko-alsa-volume-control.c
      2008-01-11 14:25:55 UTC (rev 3815)
@@ -0,0 +1,541 @@
+
+#include "moko-alsa-volume-control.h"
+
+G_DEFINE_TYPE (MokoAlsaVolumeControl, moko_alsa_volume_control, \
+       G_TYPE_OBJECT)
+
+#define ALSA_VOLUME_CONTROL_PRIVATE(o) \
+       (G_TYPE_INSTANCE_GET_PRIVATE ((o), MOKO_TYPE_ALSA_VOLUME_CONTROL, \
+        MokoAlsaVolumeControlPrivate))
+
+typedef struct _MokoAlsaVolumeControlPrivate MokoAlsaVolumeControlPrivate;
+
+struct _MokoAlsaVolumeControlPrivate {
+       gchar *device;
+       snd_mixer_selem_id_t *element;
+       
+       snd_mixer_t *mixer_handle;
+       snd_mixer_elem_t *mixer_elem;
+       gint control_type;
+       
+       glong min;
+       glong max;
+       glong volume;
+};
+
+enum {
+       PROP_DEVICE = 1,
+       PROP_ELEMENT,
+};
+
+enum {
+       PLAYBACK,
+       CAPTURE,
+       CONTROL
+};
+
+enum {
+       VOLUME_CHANGED,
+       LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+static gboolean
+io_func (GIOChannel *source, GIOCondition condition, MokoAlsaVolumeControl 
*self)
+{
+       switch (condition) {
+           case G_IO_IN : {
+               MokoAlsaVolumeControlPrivate *priv =
+                       ALSA_VOLUME_CONTROL_PRIVATE (self);
+               snd_mixer_handle_events (priv->mixer_handle);
+               
+               break;
+           }
+           case G_IO_ERR :
+           case G_IO_NVAL :
+               g_warning ("Encountered an error, stopping IO watch");
+               return FALSE;
+           default :
+               g_warning ("Unhandled IO condition");
+               break;
+       }
+       
+       return TRUE;
+}
+
+static void
+update_volume (MokoAlsaVolumeControl *control)
+{
+       long volume;
+       MokoAlsaVolumeControlPrivate *priv = ALSA_VOLUME_CONTROL_PRIVATE 
(control);
+       
+       /* TODO: Average out volume across channels? */
+       
+       switch (priv->control_type) {
+           case PLAYBACK :
+               snd_mixer_selem_get_playback_volume (
+                       priv->mixer_elem, 0, &volume);
+               break;
+           case CAPTURE :
+               snd_mixer_selem_get_capture_volume (
+                       priv->mixer_elem, 0, &volume);
+               break;
+           case CONTROL :
+           default :
+               /* TODO: Handle switches? */
+               g_warning ("Unhandled control type");
+               return;
+       }
+       
+       if (priv->volume != volume) {
+               priv->volume = volume;
+               g_signal_emit (control, signals[VOLUME_CHANGED],
+                       0, (gdouble)(priv->volume - priv->min) /
+                               (gdouble)(priv->max - priv->min));
+       }
+}
+
+static int
+mixer_event_cb (snd_mixer_t *mixer, unsigned int mask, snd_mixer_elem_t *elem)
+{
+       /* Do we need to update here? */
+       
+       return 0;
+}
+
+static int
+mixer_elem_event_cb (snd_mixer_elem_t *elem, unsigned int mask)
+{
+       MokoAlsaVolumeControl *control = MOKO_ALSA_VOLUME_CONTROL (
+               snd_mixer_elem_get_callback_private (elem));
+
+       update_volume (control);
+
+       return 0;
+}
+
+static void
+open_mixer (MokoAlsaVolumeControl *self)
+{
+       MokoAlsaVolumeControlPrivate *priv = ALSA_VOLUME_CONTROL_PRIVATE (self);
+       
+       if (snd_mixer_open (&priv->mixer_handle, 0) != 0) {
+               g_warning ("Failed to get mixer handle");
+               priv->mixer_handle = NULL;
+               return;
+       }
+       
+       snd_mixer_set_callback (priv->mixer_handle, mixer_event_cb);
+       snd_mixer_set_callback_private (priv->mixer_handle, self);
+       
+       g_debug ("Opened mixer");
+}
+
+static void
+start_polling (MokoAlsaVolumeControl *self)
+{
+       struct pollfd *fds;
+       gint i, nfds;
+
+       MokoAlsaVolumeControlPrivate *priv = ALSA_VOLUME_CONTROL_PRIVATE (self);
+       
+       if ((nfds = snd_mixer_poll_descriptors_count (priv->mixer_handle))<=0) {
+               g_warning ("No poll descriptors on mixer?");
+               return;
+       }
+       
+       fds = g_new0 (struct pollfd, nfds);
+       if (snd_mixer_poll_descriptors (priv->mixer_handle, fds, nfds) < 0) {
+               g_warning ("Error getting polling descriptors for sound mixer");
+               g_free (fds);
+               return;
+       }
+       
+       for (i = 0; i < nfds; i++) {
+               GIOChannel *channel = g_io_channel_unix_new (fds[i].fd);
+               g_debug ("Adding IO watch (IN: %d, OUT: %d)",
+                       fds[i].events & POLLIN, fds[i].events & POLLOUT);
+               g_io_add_watch (channel,
+                       ((fds[i].events & POLLIN) ? G_IO_IN : 0) |
+                       ((fds[i].events & POLLOUT) ? G_IO_OUT : 0) |
+                       ((fds[i].events & POLLPRI) ? G_IO_PRI : 0) |
+                       ((fds[i].events & POLLERR) ? G_IO_ERR : 0) |
+                       ((fds[i].events & POLLHUP) ? G_IO_HUP : 0) |
+                       ((fds[i].events & POLLNVAL) ? G_IO_NVAL : 0),
+                       (GIOFunc)io_func, self);
+       }
+       g_free (fds);
+       
+       g_debug ("Polling for events...");
+}
+
+static void
+close_mixer (MokoAlsaVolumeControl *self)
+{
+       MokoAlsaVolumeControlPrivate *priv = ALSA_VOLUME_CONTROL_PRIVATE (self);
+       
+       if (!priv->mixer_handle) return;
+       
+       snd_mixer_close (priv->mixer_handle);
+       priv->mixer_handle = NULL;
+       g_debug ("Closed mixer");
+}
+
+static void
+detach_mixer (MokoAlsaVolumeControl *self)
+{
+       MokoAlsaVolumeControlPrivate *priv = ALSA_VOLUME_CONTROL_PRIVATE (self);
+       
+       if (priv->mixer_handle && priv->device &&
+           priv->element && priv->mixer_elem) {
+               snd_mixer_detach (priv->mixer_handle, priv->device);
+               priv->mixer_elem = NULL;
+               g_debug ("Detached from mixer");
+               close_mixer (self);
+       }
+}
+
+static void
+attach_mixer (MokoAlsaVolumeControl *self)
+{
+       MokoAlsaVolumeControlPrivate *priv = ALSA_VOLUME_CONTROL_PRIVATE (self);
+       
+       g_debug ("Trying to attach... %p, %s, %p", priv->mixer_handle,
+               priv->device, priv->element);
+       
+       open_mixer (self);
+       
+       if (priv->mixer_handle && priv->device && priv->element &&
+           (snd_mixer_attach (priv->mixer_handle, priv->device) == 0) &&
+           (snd_mixer_selem_register (priv->mixer_handle, NULL, NULL) == 0) &&
+           (snd_mixer_load (priv->mixer_handle) == 0)) {
+               priv->mixer_elem = snd_mixer_find_selem (
+                       priv->mixer_handle, priv->element);
+               if (!priv->mixer_elem) {
+                       g_warning ("Unable to find mixer element");
+                       snd_mixer_detach (priv->mixer_handle, priv->device);
+                       close_mixer (self);
+               } else {
+                       g_debug ("Attached to mixer");
+                       
+                       if (snd_mixer_selem_has_playback_volume (
+                           priv->mixer_elem)) {
+                               priv->control_type = PLAYBACK;
+                               snd_mixer_selem_get_playback_volume_range (
+                                       priv->mixer_elem,
+                                       &priv->min, &priv->max);
+                       } else if (snd_mixer_selem_has_capture_volume (
+                                priv->mixer_elem)) {
+                               priv->control_type = CAPTURE;
+                               snd_mixer_selem_get_capture_volume_range (
+                                       priv->mixer_elem,
+                                       &priv->min, &priv->max);
+                       } else
+                               priv->control_type = CONTROL;
+                       
+                       snd_mixer_elem_set_callback (
+                               priv->mixer_elem, mixer_elem_event_cb);
+                       snd_mixer_elem_set_callback_private (
+                               priv->mixer_elem, self);
+                       
+                       start_polling (self);
+                       update_volume (self);
+               }
+       } else {
+               close_mixer (self);
+       }
+}
+
+static void
+moko_alsa_volume_control_get_property (GObject *object, guint property_id,
+                                     GValue *value, GParamSpec *pspec)
+{
+       MokoAlsaVolumeControlPrivate *priv =
+               ALSA_VOLUME_CONTROL_PRIVATE (object);
+       
+       switch (property_id) {
+           case PROP_DEVICE :
+               g_value_set_string (value, priv->device);
+               break;
+           case PROP_ELEMENT :
+               g_value_set_pointer (value, priv->element);
+               break;
+           default:
+               G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+       }
+}
+
+static void
+moko_alsa_volume_control_set_property (GObject *object, guint property_id,
+                              const GValue *value, GParamSpec *pspec)
+{
+       switch (property_id) {
+           case PROP_DEVICE :
+               moko_alsa_volume_control_set_device (
+                       MOKO_ALSA_VOLUME_CONTROL (object),
+                       g_value_get_string (value));
+               break;
+               
+           case PROP_ELEMENT :
+               moko_alsa_volume_control_set_element (
+                       MOKO_ALSA_VOLUME_CONTROL (object),
+                       (snd_mixer_selem_id_t *)g_value_get_pointer (value));
+               break;
+           default:
+               G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+       }
+}
+
+static void
+moko_alsa_volume_control_finalize (GObject *object)
+{
+       MokoAlsaVolumeControl *control = MOKO_ALSA_VOLUME_CONTROL (object);
+       MokoAlsaVolumeControlPrivate *priv =
+               ALSA_VOLUME_CONTROL_PRIVATE (control);
+       
+       detach_mixer (control);
+       
+       g_free (priv->device);
+       if (priv->element) {
+               snd_mixer_selem_id_free (priv->element);
+       }
+       
+       G_OBJECT_CLASS (moko_alsa_volume_control_parent_class)->
+               finalize (object);
+}
+
+static void
+moko_alsa_volume_control_class_init (MokoAlsaVolumeControlClass *klass)
+{
+       GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+       g_type_class_add_private (klass, sizeof (MokoAlsaVolumeControlPrivate));
+
+       object_class->get_property = moko_alsa_volume_control_get_property;
+       object_class->set_property = moko_alsa_volume_control_set_property;
+       object_class->finalize = moko_alsa_volume_control_finalize;
+       
+       g_object_class_install_property (
+               object_class,
+               PROP_DEVICE,
+               g_param_spec_string (
+                       "device",
+                       "gchar *",
+                       "The alsa device name.",
+                       "default",
+                       G_PARAM_READWRITE));
+
+       g_object_class_install_property (
+               object_class,
+               PROP_ELEMENT,
+               g_param_spec_pointer (
+                       "element",
+                       "snd_mixer_selem_id_t",
+                       "The alsa simple mixer element ID.",
+                       G_PARAM_READWRITE));
+       
+       signals[VOLUME_CHANGED] =
+               g_signal_new ("volume_changed",
+                       G_OBJECT_CLASS_TYPE (object_class),
+                       G_SIGNAL_RUN_LAST,
+                       G_STRUCT_OFFSET (MokoAlsaVolumeControlClass,
+                               volume_changed),
+                       NULL, NULL,
+                       g_cclosure_marshal_VOID__DOUBLE,
+                       G_TYPE_NONE, 1, G_TYPE_DOUBLE);
+}
+
+static void
+moko_alsa_volume_control_init (MokoAlsaVolumeControl *self)
+{
+       MokoAlsaVolumeControlPrivate *priv = ALSA_VOLUME_CONTROL_PRIVATE (self);
+       
+       priv->device = g_strdup ("default");
+}
+
+MokoAlsaVolumeControl *
+moko_alsa_volume_control_new (void)
+{
+       return g_object_new (MOKO_TYPE_ALSA_VOLUME_CONTROL, NULL);
+}
+
+void
+moko_alsa_volume_control_set_device (MokoAlsaVolumeControl *control,
+                                   const gchar *device)
+{
+       MokoAlsaVolumeControlPrivate *priv =
+               ALSA_VOLUME_CONTROL_PRIVATE (control);
+
+       detach_mixer (control);
+       g_free (priv->device);
+       priv->device = g_strdup (device);
+       g_debug ("Device set: %s", device);
+       attach_mixer (control);
+}
+
+void
+moko_alsa_volume_control_set_element (MokoAlsaVolumeControl *control,
+                                    snd_mixer_selem_id_t *element)
+{
+       MokoAlsaVolumeControlPrivate *priv =
+               ALSA_VOLUME_CONTROL_PRIVATE (control);
+
+       detach_mixer (control);
+       if (priv->element) {
+               snd_mixer_selem_id_free (priv->element);
+               priv->element = NULL;
+       }
+       
+       if (snd_mixer_selem_id_malloc (&priv->element) != 0) {
+               g_warning ("Unable to allocate mixer element id");
+       } else if (element) {
+               snd_mixer_selem_id_copy (priv->element, element);
+               g_debug ("Element set");
+               attach_mixer (control);
+       }
+}
+
+void
+moko_alsa_volume_control_set_device_from_card_number (
+       MokoAlsaVolumeControl *control, gint number)
+{
+       void **hints;
+       
+       if (snd_device_name_hint (number, "pcm", &hints) == 0) {
+               gchar *device = strdup (snd_device_name_get_hint (
+                       hints[0], "NAME"));
+               snd_device_name_free_hint (hints);
+               strchr (device, ':')[0] = '\0';
+               
+               moko_alsa_volume_control_set_device (control, device);
+               g_free (device);
+       } else
+               g_warning ("Unable to find card number %d", number);
+}
+
+void
+moko_alsa_volume_control_set_device_from_name (MokoAlsaVolumeControl *control,
+                                             const gchar *name)
+{
+       gint i = -1;
+       
+       if (!name) {
+               moko_alsa_volume_control_set_device (control, NULL);
+               return;
+       }
+
+       while (snd_card_next (&i) == 0) {
+               void **hints;
+       
+               if (snd_device_name_hint (i, "pcm", &hints) == 0) {
+                       gchar *device = strdup (snd_device_name_get_hint (
+                               hints[0], "NAME"));
+                       snd_device_name_free_hint (hints);
+                       strchr (device, ':')[0] = '\0';
+                       
+                       if (strcmp (device, name) == 0) {
+                               moko_alsa_volume_control_set_device (
+                                       control, device);
+                               g_free (device);
+                               return;
+                       }
+                       g_free (device);
+               }
+       }
+       
+       g_warning ("Card '%s' not found", name);
+}
+
+void
+moko_alsa_volume_control_set_element_from_name (MokoAlsaVolumeControl *control,
+                                              const gchar *name)
+{
+       MokoAlsaVolumeControlPrivate *priv =
+               ALSA_VOLUME_CONTROL_PRIVATE (control);
+
+       if (!priv->device) return;
+       
+       detach_mixer (control);
+       
+       if (!name) {
+               moko_alsa_volume_control_set_element (control, NULL);
+               return;
+       }
+       
+       open_mixer (control);
+       if ((snd_mixer_attach (priv->mixer_handle, priv->device) == 0) &&
+           (snd_mixer_selem_register (priv->mixer_handle, NULL, NULL) == 0) &&
+           (snd_mixer_load (priv->mixer_handle) == 0)) {
+               snd_mixer_elem_t *elem;
+               
+               elem = snd_mixer_first_elem (priv->mixer_handle);
+               while (elem) {
+                       const char *elem_name = snd_mixer_selem_get_name (elem);
+                       if (strcmp (elem_name, name) == 0)
+                               break;
+                       elem = snd_mixer_elem_next (elem);
+               }
+               
+               if (!elem) {
+                       snd_mixer_detach (priv->mixer_handle, priv->device);
+                       close_mixer (control);
+                       g_warning ("Mixer element '%s' not found", name);
+                       attach_mixer (control);
+               } else {
+                       snd_mixer_selem_id_t *id;
+                       if (snd_mixer_selem_id_malloc (&id) != 0) {
+                               g_warning ("Unable to allocate element id");
+                               snd_mixer_detach (
+                                       priv->mixer_handle, priv->device);
+                               close_mixer (control);
+                       } else {
+                               snd_mixer_selem_get_id (elem, id);
+                               snd_mixer_detach (
+                                       priv->mixer_handle, priv->device);
+                               close_mixer (control);
+                               g_debug ("Setting element ID");
+                               moko_alsa_volume_control_set_element (
+                                       control, id);
+                               snd_mixer_selem_id_free (id);
+                       }
+               }
+       } else
+               g_warning ("Unable to open mixer on card '%s'", priv->device);
+}
+
+gdouble
+moko_alsa_volume_control_get_volume (MokoAlsaVolumeControl *control)
+{
+       MokoAlsaVolumeControlPrivate *priv =
+               ALSA_VOLUME_CONTROL_PRIVATE (control);
+
+       return (gdouble)(priv->volume - priv->min) /
+               (gdouble)(priv->max - priv->min);
+}
+
+void
+moko_alsa_volume_control_set_volume (MokoAlsaVolumeControl *control,
+                                    gdouble volume)
+{
+       MokoAlsaVolumeControlPrivate *priv =
+               ALSA_VOLUME_CONTROL_PRIVATE (control);
+       
+       if (!priv->mixer_elem) return;
+       
+       volume = (long)(volume * (gdouble)(priv->max-priv->min)) + priv->min;
+
+       switch (priv->control_type) {
+           case PLAYBACK :
+               snd_mixer_selem_set_playback_volume_all (
+                       priv->mixer_elem, volume);
+               break;
+           case CAPTURE :
+               snd_mixer_selem_set_capture_volume_all (
+                       priv->mixer_elem, volume);
+               break;
+           default :
+               g_warning ("Unhandled control type");
+       }
+}
+

Added: 
trunk/src/target/OM-2007.2/applications/openmoko-dialer2/src/dialer/moko-alsa-volume-control.h
===================================================================
--- 
trunk/src/target/OM-2007.2/applications/openmoko-dialer2/src/dialer/moko-alsa-volume-control.h
      2008-01-11 13:50:29 UTC (rev 3814)
+++ 
trunk/src/target/OM-2007.2/applications/openmoko-dialer2/src/dialer/moko-alsa-volume-control.h
      2008-01-11 14:25:55 UTC (rev 3815)
@@ -0,0 +1,74 @@
+#ifndef _MOKO_ALSA_VOLUME_CONTROL
+#define _MOKO_ALSA_VOLUME_CONTROL
+
+#include <glib.h>
+#include <glib-object.h>
+#include <alsa/asoundlib.h>
+
+G_BEGIN_DECLS
+
+#define MOKO_TYPE_ALSA_VOLUME_CONTROL moko_alsa_volume_control_get_type()
+
+#define MOKO_ALSA_VOLUME_CONTROL(obj) \
+       (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+       MOKO_TYPE_ALSA_VOLUME_CONTROL, MokoAlsaVolumeControl))
+
+#define MOKO_ALSA_VOLUME_CONTROL_CLASS(klass) \
+       (G_TYPE_CHECK_CLASS_CAST ((klass), \
+       MOKO_TYPE_ALSA_VOLUME_CONTROL, MokoAlsaVolumeControlClass))
+
+#define MOKO_IS_ALSA_VOLUME_CONTROL(obj) \
+       (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+       MOKO_TYPE_ALSA_VOLUME_CONTROL))
+
+#define MOKO_IS_ALSA_VOLUME_CONTROL_CLASS(klass) \
+       (G_TYPE_CHECK_CLASS_TYPE ((klass), \
+       MOKO_TYPE_ALSA_VOLUME_CONTROL))
+
+#define MOKO_ALSA_VOLUME_CONTROL_GET_CLASS(obj) \
+       (G_TYPE_INSTANCE_GET_CLASS ((obj), \
+       MOKO_TYPE_ALSA_VOLUME_CONTROL, MokoAlsaVolumeControlClass))
+
+typedef struct {
+       GObject parent;
+} MokoAlsaVolumeControl;
+
+typedef struct {
+       GObjectClass parent_class;
+       
+       /* Signals */
+       void    (*volume_changed)       (MokoAlsaVolumeControl *control,
+                                        gdouble volume);
+} MokoAlsaVolumeControlClass;
+
+GType moko_alsa_volume_control_get_type (void);
+
+MokoAlsaVolumeControl *moko_alsa_volume_control_new (void);
+
+void moko_alsa_volume_control_set_device (MokoAlsaVolumeControl *control,
+                                        const gchar *device);
+
+void moko_alsa_volume_control_set_element (MokoAlsaVolumeControl *control,
+                                         snd_mixer_selem_id_t *element);
+
+void moko_alsa_volume_control_set_device_from_card_number (
+                       MokoAlsaVolumeControl *control,
+                       gint number);
+
+void moko_alsa_volume_control_set_device_from_name (
+                       MokoAlsaVolumeControl *control,
+                       const gchar *name);
+
+void moko_alsa_volume_control_set_element_from_name (
+                       MokoAlsaVolumeControl *control,
+                       const gchar *name);
+
+gdouble moko_alsa_volume_control_get_volume (MokoAlsaVolumeControl *control);
+
+void moko_alsa_volume_control_set_volume (MokoAlsaVolumeControl *control,
+                                         gdouble volume);
+
+G_END_DECLS
+
+#endif /* _MOKO_ALSA_VOLUME_CONTROL */
+




--- End Message ---
_______________________________________________
commitlog mailing list
[email protected]
http://lists.openmoko.org/mailman/listinfo/commitlog

Reply via email to