Hi Jacob,

Many thanks for your comments.  They've saved me at least a couple of
hours of digging (though prompted some more!)
If you wouldn't mind and have the time, I have a few questions...

On Mon, Aug 31, 2009 at 6:43 PM, Jacob Meuser<jake...@sdf.lonestar.org> wrote:
> couple issues here ...
>
>   /* find the "master" device */
>   v->master_idx = -1;
>   devinfo.index = 0;
>   while (ioctl(v->dev_fd, AUDIO_MIXER_DEVINFO, &devinfo) >= 0)
>   {  if (strncmp(devinfo.label.name, "master", 7) == 0)
>         v->master_idx = devinfo.index;
>
>      devinfo.index++;
>   }
>
>   if (v->master_idx == -1)
>      errx(1, "failed to find \"master\" mixer device for volume init");
>
> you should make sure you get outputs.master as opposed to possibly
> record.master, or some other "master".  technically speaking, a device
> is free to make up whatever class it wants.  you have to find the
> "outputs" class index, and make sure that "master"'s mixer_class equals
> the "outputs" class index.


D'oh!  Thanks for that.  This is why (i think) it was failing for Edd
and (possibly) Brynet.


>
>   /* Volume values are stored as 8-bit values, however not all values are
>    * supported (i.e. fewer than 256 different volume levels may be
>    * supported).  As such, to accurately determine the percentages shown
>    * in the display, we have to find the maximum settings for this
>    * device.
>
> you could use the delta: devinfo.un.v.delta.  that is the step size
> of the hardware.  that is, you have to move that many volume units to
> affect a change in the hardware.  you could use this to determine
> the largest value ...

Many thanks, this is much easier.

>
>  So, we...
>    *    1. read the current volume values
>    *    2. set the volume to the max possible (255)
>
> 255 -> AUDIO_MAX_GAIN
>
>    *    3. read the volume values and see what the max is for this device
>    *    4. reset the volume to what was read in step 1 so we don't muck
>    *       with the users' volume.
>    */
>


>   /* read current volume */
>   v->info.dev = v->master_idx;
>   v->info.type = AUDIO_MIXER_VALUE;
>   if (ioctl(v->dev_fd, AUDIO_MIXER_READ, &(v->info)) < 0)
>      err(1, "ioctl AUDIO_MIXER_READ");
>
> that fails because on many devices because num_channels is not set
> correctly.  in sys/dev/ic/ac97.c:
>
> ac97_mixer_get_port(struct ac86_codec_if *codec_if, mixer_ctrl_t *cp)
> {
>        struct ac97_softc *as = (struct ac97_softc *)codec_if;
>        struct ac97_source_info *si = &as->source_info[cp->dev];
> ...
>        case AUDIO_MIXER_VALUE:
>        {
>                const struct audio_mixer_value *value = si->info;
>                u_int16_t  l, r;
>
>                if ((cp->un.value.num_channels <= 0) ||
>                    (cp->un.value.num_channels > value->num_channels))
>                        return (EINVAL);
>
> here, value->num_channels == devinfo.un.v.num_channels ...

Hmm, I'm not sure I understand.  Let me see if this is what you're
saying (and what i'm getting from ac97.c).

Currently, I ioctl with AUDIO_MIXER_READ, and the mixer_ctrl_t filled
would (I assumed) always have num_channels set to 1 or "other" (which
I always assume other would be >= 2), and I tried to handle like
this...

if (v->info.un.value.num_channels == 1)
   v->left = v->right = v->info.un.value.level[AUDIO_MIXER_LEVEL_MONO];
else
{  v->left  = v->info.un.value.level[AUDIO_MIXER_LEVEL_LEFT];
   v->right = v->info.un.value.level[AUDIO_MIXER_LEVEL_RIGHT];
}

But you're saying (and from the source i can see), that it may return
either 0 channels or ... something greater than values->num_channels,
in which case the ioctl returns EINVAL.

In such a case, what would the appropriate method be for querying
volume level?  Or would this represent a situation where this cannot
be queried (lack of hardware or hardware support)?
Or am I lost in left-field here... admittedly I need to look more into this.


Many Thanks again,
-ryan

Reply via email to