OSDN Git Service

Implement support for dB gain display in alsamixer.
authorJames Courtier-Dutton <James@superbug.demon.co.uk>
Sat, 22 Jul 2006 13:56:48 +0000 (14:56 +0100)
committerJames Courtier-Dutton <James@superbug.demon.co.uk>
Sat, 22 Jul 2006 13:56:48 +0000 (14:56 +0100)
include/control.h
src/control/hcontrol.c
src/mixer/simple_none.c

index af0f91a..b84028c 100644 (file)
@@ -504,6 +504,7 @@ int snd_hctl_elem_write(snd_hctl_elem_t *elem, snd_ctl_elem_value_t * value);
 int snd_hctl_elem_tlv_read(snd_hctl_elem_t *elem, unsigned int *tlv, unsigned int tlv_size);
 int snd_hctl_elem_tlv_write(snd_hctl_elem_t *elem, const unsigned int *tlv);
 int snd_hctl_elem_tlv_command(snd_hctl_elem_t *elem, const unsigned int *tlv);
+int snd_hctl_elem_get_db_gain(snd_hctl_elem_t *elem, long volume, long *db_gain);
 
 snd_hctl_t *snd_hctl_elem_get_hctl(snd_hctl_elem_t *elem);
 
index 9738d65..ee0b37d 100644 (file)
@@ -787,6 +787,114 @@ int snd_hctl_handle_events(snd_hctl_t *hctl)
        return count;
 }
 
+static int snd_hctl_elem_decode_tlv_db_gain(unsigned int *tlv, unsigned int tlv_size, long volume, long *db_gain)
+{
+       unsigned int type;
+       unsigned int size;
+       unsigned int idx = 0;
+       int err = 0;
+
+       type = tlv[idx++];
+       size = tlv[idx++];
+       tlv_size -= 2 * sizeof(unsigned int);
+       if (size > tlv_size) {
+               printf("TLV size error (%i, %i, %i)!\n", type, size, tlv_size);
+               err=-EINVAL;
+               goto __exit_decode_db_gain;
+       }
+       switch (type) {
+       case SND_CTL_TLVT_CONTAINER:
+               size += sizeof(unsigned int) -1;
+               size /= sizeof(unsigned int);
+               printf("TLV container!\n");
+               while (idx < size) {
+                       if (tlv[idx+1] > (size - idx) * sizeof(unsigned int)) {
+                               printf("TLV size error in compound!\n");
+                               err=-EINVAL;
+                               goto __exit_decode_db_gain;
+                       }
+                       err = snd_hctl_elem_decode_tlv_db_gain(tlv + idx, tlv[idx+1], volume, db_gain);
+                       if (!err) break; /* db_gain obtained */
+                       idx += 2 + (tlv[1] + sizeof(unsigned int) - 1) / sizeof(unsigned int);
+               }
+               break;
+       case SND_CTL_TLVT_DB_SCALE:
+               if (size != 2 * sizeof(unsigned int)) {
+                       while (size > 0) {
+                               printf("0x%x", tlv[idx++]);
+                               size -= sizeof(unsigned int);
+                       }
+                       printf("\n");
+               } else {
+                       int min,step,mute;
+                       min = tlv[2];
+                       step = (tlv[3] & 0xffff);
+                       mute = (tlv[3] >> 16) & 1;
+                       *db_gain = (volume * step) + min;
+                       if (mute && (volume == 0)) *db_gain = -9999999;
+               }
+               break;
+       default:
+               printf("unk-%i-", type);
+               while (size > 0) {
+                       printf("0x%x", tlv[idx++]);
+                       size -= sizeof(unsigned int);
+               }
+               printf("\n");
+               break;
+       }
+
+       __exit_decode_db_gain:
+       return err;
+}
+
+/**
+ * \brief Get db_gain information for an HCTL element
+ * \param elem HCTL element
+ * \param volume The current control volume
+ * \param db_gain The return value in db_gain scale
+ * \return 0 otherwise a negative error code on failure
+ */
+int snd_hctl_elem_get_db_gain(snd_hctl_elem_t *elem, long volume, long *db_gain)
+{
+       snd_ctl_elem_info_t *info;
+       unsigned int *tlv;
+       unsigned int tlv_size=4096;
+       unsigned int type;
+       unsigned int size;
+       unsigned int idx = 0;
+       int err=0;
+
+       snd_ctl_elem_info_alloca(&info);
+       snd_hctl_elem_info(elem, info);
+
+       if (tlv_size < 2 * sizeof(unsigned int)) {
+               printf("TLV size error!\n");
+               err=-EINVAL;
+               goto __exit_db_gain;
+       }
+       if (!snd_ctl_elem_info_is_tlv_readable(info)) {
+               err=-EINVAL;
+               goto __exit_db_gain;
+       }
+       tlv = malloc(4096);
+       if ((err = snd_hctl_elem_tlv_read(elem, tlv, tlv_size)) < 0) {
+               printf("Control element TLV read error: %s\n", snd_strerror(err));
+               goto __free_exit_db_gain;
+       }
+       err = snd_hctl_elem_decode_tlv_db_gain(tlv, tlv_size, volume, db_gain);
+
+       __free_exit_db_gain:
+       free(tlv);
+       __exit_db_gain:
+       return err;
+}
+       
+
+
+
+
+
 /**
  * \brief Get information for an HCTL element
  * \param elem HCTL element
index 4356316..c07346b 100644 (file)
@@ -971,12 +971,37 @@ static int get_volume_ops(snd_mixer_elem_t *elem, int dir,
        return 0;
 }
 
-static int get_dB_ops(snd_mixer_elem_t *elem ATTRIBUTE_UNUSED,
-                     int dir ATTRIBUTE_UNUSED,
-                     snd_mixer_selem_channel_id_t channel ATTRIBUTE_UNUSED,
-                     long *value ATTRIBUTE_UNUSED)
+static int get_dB_ops(snd_mixer_elem_t *elem,
+                      int dir,
+                      snd_mixer_selem_channel_id_t channel,
+                      long *value)
 {
-       return -ENXIO;
+       selem_none_t *s = snd_mixer_elem_get_private(elem);
+       selem_ctl_t *c;
+       int err = -EINVAL;
+       long volume, db_gain;
+       if (dir == SM_PLAY) {
+               c = &s->ctls[CTL_PLAYBACK_VOLUME];
+               if (c->type != 2) {
+                       goto _err;
+               }
+       } else if (dir == SM_CAPT) {
+               c = &s->ctls[CTL_CAPTURE_VOLUME];
+               if (c->type != 2) {
+                       goto _err;
+               }
+       } else goto _err;
+       if (err = get_volume_ops(elem, dir, channel, &volume))  {
+               goto _err;
+       }
+       if ((err = snd_hctl_elem_get_db_gain(c->elem, volume, &db_gain)) < 0) {
+               goto _err;
+       }
+       err = 0;
+       *value = db_gain;
+_err:
+       //if (err) printf("get_dB_ops:err=%d\n",err);
+       return err;
 }
 
 static int get_switch_ops(snd_mixer_elem_t *elem, int dir,