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