From: James Courtier-Dutton Date: Sat, 22 Jul 2006 13:56:48 +0000 (+0100) Subject: Implement support for dB gain display in alsamixer. X-Git-Tag: v1.0.12rc2~6 X-Git-Url: https://git.alsa-project.org/?a=commitdiff_plain;h=5e3fc878889f47295e079a84c2c5a3fbc57b91be;p=alsa-lib.git Implement support for dB gain display in alsamixer. --- diff --git a/include/control.h b/include/control.h index af0f91a6..b84028c7 100644 --- a/include/control.h +++ b/include/control.h @@ -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); diff --git a/src/control/hcontrol.c b/src/control/hcontrol.c index 9738d652..ee0b37dc 100644 --- a/src/control/hcontrol.c +++ b/src/control/hcontrol.c @@ -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 diff --git a/src/mixer/simple_none.c b/src/mixer/simple_none.c index 43563167..c07346b5 100644 --- a/src/mixer/simple_none.c +++ b/src/mixer/simple_none.c @@ -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,