bool CALSAHControlMonitor::Add(const std::string& ctlHandleName, snd_ctl_elem_iface_t interface, unsigned int device, const std::string& name) { snd_hctl_t *hctl = GetHandle(ctlHandleName); if (!hctl) { return false; } snd_ctl_elem_id_t *id; snd_ctl_elem_id_alloca(&id); snd_ctl_elem_id_set_interface(id, interface); snd_ctl_elem_id_set_name (id, name.c_str()); snd_ctl_elem_id_set_device (id, device); snd_hctl_elem_t *elem = snd_hctl_find_elem(hctl, id); if (!elem) { PutHandle(ctlHandleName); return false; } snd_hctl_elem_set_callback(elem, HCTLCallback); return true; }
static snd_hctl_elem_t * _phoneui_utils_sound_init_get_control_by_name(const char *ctl_name) { snd_ctl_elem_id_t *id; snd_ctl_elem_id_alloca(&id); snd_ctl_elem_id_set_interface(id, SND_CTL_ELEM_IFACE_MIXER); snd_ctl_elem_id_set_name(id, ctl_name); return snd_hctl_find_elem(hctl, id); }
bool CAESinkALSA::GetELD(snd_hctl_t *hctl, int device, CAEDeviceInfo& info, bool& badHDMI) { badHDMI = false; snd_ctl_elem_id_t *id; snd_ctl_elem_info_t *einfo; snd_ctl_elem_value_t *control; snd_hctl_elem_t *elem; snd_ctl_elem_id_alloca(&id); memset(id, 0, snd_ctl_elem_id_sizeof()); snd_ctl_elem_id_set_interface(id, SND_CTL_ELEM_IFACE_PCM); snd_ctl_elem_id_set_name (id, "ELD" ); snd_ctl_elem_id_set_device (id, device); elem = snd_hctl_find_elem(hctl, id); if (!elem) return false; snd_ctl_elem_info_alloca(&einfo); memset(einfo, 0, snd_ctl_elem_info_sizeof()); if (snd_hctl_elem_info(elem, einfo) < 0) return false; if (!snd_ctl_elem_info_is_readable(einfo)) return false; if (snd_ctl_elem_info_get_type(einfo) != SND_CTL_ELEM_TYPE_BYTES) return false; snd_ctl_elem_value_alloca(&control); memset(control, 0, snd_ctl_elem_value_sizeof()); if (snd_hctl_elem_read(elem, control) < 0) return false; int dataLength = snd_ctl_elem_info_get_count(einfo); /* if there is no ELD data, then its a bad HDMI device, either nothing attached OR an invalid nVidia HDMI device * OR the driver doesn't properly support ELD (notably ATI/AMD, 2012-05) */ if (!dataLength) badHDMI = true; else CAEELDParser::Parse( (const uint8_t*)snd_ctl_elem_value_get_bytes(control), dataLength, info ); info.m_deviceType = AE_DEVTYPE_HDMI; return true; }
int V4LRadioControl::volume() const { const QString ctlName("Line DAC Playback Volume"); const QString card("hw:0"); int volume = 0; int err; static snd_ctl_t *handle = NULL; snd_ctl_elem_info_t *info; snd_ctl_elem_id_t *id; snd_ctl_elem_value_t *control; snd_ctl_elem_info_alloca(&info); snd_ctl_elem_id_alloca(&id); snd_ctl_elem_value_alloca(&control); snd_ctl_elem_id_set_interface(id, SND_CTL_ELEM_IFACE_MIXER); /* MIXER */ snd_ctl_elem_id_set_name(id, ctlName.toAscii()); if ((err = snd_ctl_open(&handle, card.toAscii(), 0)) < 0) { return 0; } snd_ctl_elem_info_set_id(info, id); if ((err = snd_ctl_elem_info(handle, info)) < 0) { snd_ctl_close(handle); handle = NULL; return 0; } snd_ctl_elem_info_get_id(info, id); /* FIXME: Remove it when hctl find works ok !!! */ snd_ctl_elem_value_set_id(control, id); snd_ctl_close(handle); handle = NULL; snd_hctl_t *hctl; snd_hctl_elem_t *elem; if ((err = snd_hctl_open(&hctl, card.toAscii(), 0)) < 0) { return 0; } if ((err = snd_hctl_load(hctl)) < 0) { return 0; } elem = snd_hctl_find_elem(hctl, id); if (elem) volume = vol(elem); snd_hctl_close(hctl); return (volume/118.0) * 100; }
static int snd_hctl_handle_event(snd_hctl_t *hctl, snd_ctl_event_t *event) { snd_hctl_elem_t *elem; int res; assert(hctl); assert(hctl->ctl); switch (event->type) { case SND_CTL_EVENT_ELEM: break; default: return 0; } if (event->data.elem.mask == SNDRV_CTL_EVENT_MASK_REMOVE) { int dir; res = _snd_hctl_find_elem(hctl, &event->data.elem.id, &dir); assert(res >= 0 && dir == 0); if (res < 0 || dir != 0) return -ENOENT; snd_hctl_elem_remove(hctl, (unsigned int) res); return 0; } if (event->data.elem.mask & SNDRV_CTL_EVENT_MASK_ADD) { elem = calloc(1, sizeof(snd_hctl_elem_t)); if (elem == NULL) return -ENOMEM; elem->id = event->data.elem.id; elem->hctl = hctl; res = snd_hctl_elem_add(hctl, elem); if (res < 0) return res; } if (event->data.elem.mask & (SNDRV_CTL_EVENT_MASK_VALUE | SNDRV_CTL_EVENT_MASK_INFO)) { elem = snd_hctl_find_elem(hctl, &event->data.elem.id); assert(elem); if (!elem) return -ENOENT; res = snd_hctl_elem_throw_event(elem, event->data.elem.mask & (SNDRV_CTL_EVENT_MASK_VALUE | SNDRV_CTL_EVENT_MASK_INFO)); if (res < 0) return res; } return 0; }
static int setamixer(int devnum,char *param, int v1, int v2) { int type; char str[100]; snd_hctl_t *hctl; snd_ctl_elem_id_t *id; snd_ctl_elem_value_t *control; snd_hctl_elem_t *elem; snd_ctl_elem_info_t *info; sprintf(str,"hw:%d",devnum); if (snd_hctl_open(&hctl, str, 0)) return(-1); snd_hctl_load(hctl); snd_ctl_elem_id_alloca(&id); snd_ctl_elem_id_set_interface(id, SND_CTL_ELEM_IFACE_MIXER); snd_ctl_elem_id_set_name(id, param); elem = snd_hctl_find_elem(hctl, id); if (!elem) { snd_hctl_close(hctl); return(-1); } snd_ctl_elem_info_alloca(&info); snd_hctl_elem_info(elem,info); type = snd_ctl_elem_info_get_type(info); snd_ctl_elem_value_alloca(&control); snd_ctl_elem_value_set_id(control, id); switch(type) { case SND_CTL_ELEM_TYPE_INTEGER: snd_ctl_elem_value_set_integer(control, 0, v1); if (v2 > 0) snd_ctl_elem_value_set_integer(control, 1, v2); break; case SND_CTL_ELEM_TYPE_BOOLEAN: snd_ctl_elem_value_set_integer(control, 0, (v1 != 0)); break; } if (snd_hctl_elem_write(elem, control)) { snd_hctl_close(hctl); return(-1); } snd_hctl_close(hctl); return(0); }
/****************************************************************************** * setMixerInput *****************************************************************************/ static Int setMixerControl (const Char *name, Int value) { Int status; snd_hctl_t *hctl; snd_ctl_elem_id_t *id; snd_hctl_elem_t *elem; snd_ctl_elem_value_t *control; if ((status = snd_hctl_open(&hctl, AUDIO_MIXER, 0)) < 0) { Dmai_err2("setMixerControl %s open error: %s\n", AUDIO_MIXER, snd_strerror(status)); return Dmai_EFAIL;; } if ((status = snd_hctl_load(hctl)) < 0) { Dmai_err2("setMixerControl %s load error: %s\n", AUDIO_MIXER, snd_strerror(status)); return Dmai_EFAIL;; } snd_ctl_elem_id_alloca(&id); snd_ctl_elem_id_set_interface(id, SND_CTL_ELEM_IFACE_MIXER); snd_ctl_elem_id_set_name(id, name); elem = snd_hctl_find_elem(hctl, id); if (!elem) { Dmai_err1("setMixerControl %s find element error\n", AUDIO_MIXER); snd_hctl_close(hctl); return Dmai_EFAIL; } snd_ctl_elem_value_alloca(&control); snd_ctl_elem_value_set_id(control, id); snd_ctl_elem_value_set_integer(control, 0, value); snd_hctl_elem_write(elem, control); snd_hctl_close(hctl); return Dmai_EOK; }
static int amixer_max(int devnum,char *param) { int rv,type; char str[100]; snd_hctl_t *hctl; snd_ctl_elem_id_t *id; snd_hctl_elem_t *elem; snd_ctl_elem_info_t *info; sprintf(str,"hw:%d",devnum); if (snd_hctl_open(&hctl, str, 0)) return(-1); snd_hctl_load(hctl); snd_ctl_elem_id_alloca(&id); snd_ctl_elem_id_set_interface(id, SND_CTL_ELEM_IFACE_MIXER); snd_ctl_elem_id_set_name(id, param); elem = snd_hctl_find_elem(hctl, id); if (!elem) { snd_hctl_close(hctl); return(-1); } snd_ctl_elem_info_alloca(&info); snd_hctl_elem_info(elem,info); type = snd_ctl_elem_info_get_type(info); rv = 0; switch(type) { case SND_CTL_ELEM_TYPE_INTEGER: rv = snd_ctl_elem_info_get_max(info); break; case SND_CTL_ELEM_TYPE_BOOLEAN: rv = 1; break; } snd_hctl_close(hctl); return(rv); }
int main(int argc, char *argv[]) { char *format = FORMAT; char *device = DEVICE; char *volume_control = VOLUME_CONTROL; char *mute_control = MUTE_CONTROL; int interval = INTERVAL; bool snoop = false; int opt; while ((opt = getopt(argc, argv, "hsf:i:d:v:m:")) != -1) { switch (opt) { case 'h': printf("volume [-h|-s|-f FORMAT|-i INTERVAL|-d DEVICE|-v VOLUME_CONTROL|-m MUTE_CONTROL]\n"); exit(EXIT_SUCCESS); break; case 's': snoop = true; break; case 'f': format = optarg; break; case 'd': device = optarg; break; case 'i': interval = atoi(optarg); break; case 'v': volume_control = optarg; break; case 'm': mute_control = optarg; break; } } int exit_code; snd_hctl_t *hctl; snd_ctl_elem_id_t *volume_id; snd_ctl_elem_id_t *mute_id; snd_ctl_elem_value_t *volume_ctl; snd_ctl_elem_value_t *mute_ctl; snd_ctl_elem_info_t *volume_info; snd_hctl_elem_t *volume_elem; snd_hctl_elem_t *mute_elem; int vol_max, vol_min; if (snd_hctl_open(&hctl, device, 0) || snd_hctl_load(hctl)) { return EXIT_FAILURE; } snd_ctl_elem_id_malloc(&volume_id); snd_ctl_elem_id_malloc(&mute_id); snd_ctl_elem_value_malloc(&volume_ctl); snd_ctl_elem_value_malloc(&mute_ctl); snd_ctl_elem_info_malloc(&volume_info); snd_ctl_elem_id_set_interface(volume_id, SND_CTL_ELEM_IFACE_MIXER); snd_ctl_elem_id_set_interface(mute_id, SND_CTL_ELEM_IFACE_MIXER); snd_ctl_elem_id_set_name(volume_id, volume_control); snd_ctl_elem_id_set_name(mute_id, mute_control); snd_ctl_elem_value_set_id(volume_ctl, volume_id); snd_ctl_elem_value_set_id(mute_ctl, mute_id); volume_elem = snd_hctl_find_elem(hctl, volume_id); mute_elem = snd_hctl_find_elem(hctl, mute_id); snd_ctl_elem_info_set_id(volume_info, volume_id); snd_hctl_elem_info(volume_elem, volume_info); vol_min = (int)snd_ctl_elem_info_get_min(volume_info); vol_max = (int)snd_ctl_elem_info_get_max(volume_info); if (volume_elem == NULL || mute_elem == NULL) { snd_hctl_close(hctl); return EXIT_FAILURE; } struct sigaction action = {.sa_handler = &sig_handler}; sigaction(SIGUSR1, &action, NULL); if (snoop) for (;;) { if (update) { update = false; continue; } if ((exit_code = put_infos(vol_min, vol_max, volume_elem, mute_elem, volume_ctl, mute_ctl, format)) == EXIT_FAILURE) break; sleep(interval); } else exit_code = put_infos(vol_min, vol_max, volume_elem, mute_elem, volume_ctl, mute_ctl, format); snd_hctl_close(hctl); snd_ctl_elem_id_free(volume_id); snd_ctl_elem_id_free(mute_id); snd_ctl_elem_value_free(volume_ctl); snd_ctl_elem_value_free(mute_ctl); snd_ctl_elem_info_free(volume_info); return exit_code; }
static int amixer_control(t_amixer *x, int argc, t_atom *argv, int roflag) { int err; snd_ctl_t *handle; snd_ctl_elem_info_t *info; snd_ctl_elem_id_t *id; snd_ctl_elem_value_t *control; char *ptr; unsigned int idx, count; long tmp; snd_ctl_elem_type_t type; snd_ctl_elem_info_alloca(&info); snd_ctl_elem_id_alloca(&id); snd_ctl_elem_value_alloca(&control); if (argc < 1) { error("Specify a full control identifier: [[iface=<iface>,][name='name',][index=<index>,][device=<device>,][subdevice=<subdevice>]]|[numid=<numid>]\n"); return -EINVAL; } if(A_FLOAT==argv->a_type){ snd_ctl_elem_id_set_numid(id, atom_getint(argv)); if(0) { error("Wrong control identifier: %d\n", atom_getint(argv)); return -EINVAL; } } else { if (parse_control_id(atom_getsymbol(argv)->s_name, id)) { error("Wrong control identifier: %s\n", atom_getsymbol(argv)->s_name); return -EINVAL; } } if ((err = snd_ctl_open(&handle, x->card, 0)) < 0) { error("Control %s open error: %s\n", x->card, snd_strerror(err)); return err; } snd_ctl_elem_info_set_id(info, id); if ((err = snd_ctl_elem_info(handle, info)) < 0) { error("Control %s cinfo error: %s\n", x->card, snd_strerror(err)); return err; } snd_ctl_elem_info_get_id(info, id); /* FIXME: Remove it when hctl find works ok !!! */ type = snd_ctl_elem_info_get_type(info); count = snd_ctl_elem_info_get_count(info); snd_ctl_elem_value_set_id(control, id); if (!roflag) { t_float atom_float = atom_getfloat(argv+1); int atom_isfloat = (A_FLOAT==(argv+1)->a_type); post("now setting"); ptr = atom_getsymbol(argv+1)->s_name; for (idx = 0; idx < count && idx < 128 && ptr && *ptr; idx++) { switch (type) { case SND_CTL_ELEM_TYPE_BOOLEAN: tmp = 0; if(atom_isfloat){ tmp=(atom_float>0)?1:0; } else if (!strncasecmp(ptr, "on", 2) || !strncasecmp(ptr, "up", 2)) { tmp = 1; ptr += 2; } else if (!strncasecmp(ptr, "yes", 3)) { tmp = 1; ptr += 3; } else if (!strncasecmp(ptr, "toggle", 6)) { tmp = snd_ctl_elem_value_get_boolean(control, idx); tmp = tmp > 0 ? 0 : 1; ptr += 6; } else if (isdigit(*ptr)) { tmp = atoi(ptr) > 0 ? 1 : 0; while (isdigit(*ptr)) ptr++; } else { while (*ptr && *ptr != ',') ptr++; } snd_ctl_elem_value_set_boolean(control, idx, tmp); break; case SND_CTL_ELEM_TYPE_INTEGER: tmp = atom_isfloat?((int)atom_float):get_integer(&ptr, snd_ctl_elem_info_get_min(info), snd_ctl_elem_info_get_max(info)); snd_ctl_elem_value_set_integer(control, idx, tmp); break; case SND_CTL_ELEM_TYPE_INTEGER64: tmp = atom_isfloat?((int)atom_float):get_integer64(&ptr, snd_ctl_elem_info_get_min64(info), snd_ctl_elem_info_get_max64(info)); snd_ctl_elem_value_set_integer64(control, idx, tmp); break; case SND_CTL_ELEM_TYPE_ENUMERATED: tmp = atom_isfloat?((int)atom_float):get_integer(&ptr, 0, snd_ctl_elem_info_get_items(info) - 1); snd_ctl_elem_value_set_enumerated(control, idx, tmp); break; case SND_CTL_ELEM_TYPE_BYTES: tmp = atom_isfloat?((int)atom_float):get_integer(&ptr, 0, 255); snd_ctl_elem_value_set_byte(control, idx, tmp); break; default: break; } if (!strchr(atom_getsymbol(argv+1)->s_name, ',')) ptr = atom_getsymbol(argv+1)->s_name; else if (*ptr == ',') ptr++; } if ((err = snd_ctl_elem_write(handle, control)) < 0) { error("Control %s element write error: %s\n", x->card, snd_strerror(err)); return err; } } snd_ctl_close(handle); if (1) { snd_hctl_t *hctl; snd_hctl_elem_t *elem; if ((err = snd_hctl_open(&hctl, x->card, 0)) < 0) { error("Control %s open error: %s\n", x->card, snd_strerror(err)); return err; } if ((err = snd_hctl_load(hctl)) < 0) { error("Control %s load error: %s\n", x->card, snd_strerror(err)); return err; } elem = snd_hctl_find_elem(hctl, id); if (elem) show_control(x->card, " ", elem, LEVEL_BASIC | LEVEL_ID); else printf("Could not find the specified element\n"); snd_hctl_close(hctl); } }
static int cset(int argc, char *argv[], int roflag, int keep_handle) { int err; static snd_ctl_t *handle = NULL; snd_ctl_elem_info_t *info; snd_ctl_elem_id_t *id; snd_ctl_elem_value_t *control; char *ptr; unsigned int idx, count; long tmp; snd_ctl_elem_type_t type; snd_ctl_elem_info_alloca(&info); snd_ctl_elem_id_alloca(&id); snd_ctl_elem_value_alloca(&control); if (argc < 1) return -EINVAL; if (parse_control_id(argv[0], id)) return -EINVAL; if (handle == NULL && (err = snd_ctl_open(&handle, card, 0)) < 0) return err; snd_ctl_elem_info_set_id(info, id); if ((err = snd_ctl_elem_info(handle, info)) < 0) { if (!keep_handle) { snd_ctl_close(handle); handle = NULL; } return err; } snd_ctl_elem_info_get_id(info, id); type = snd_ctl_elem_info_get_type(info); count = snd_ctl_elem_info_get_count(info); snd_ctl_elem_value_set_id(control, id); if (!roflag) { ptr = argv[1]; for (idx = 0; idx < count && idx < 128 && ptr && *ptr; idx++) { switch (type) { case SND_CTL_ELEM_TYPE_BOOLEAN: tmp = 0; if (!strncasecmp(ptr, "on", 2) || !strncasecmp(ptr, "up", 2)) { tmp = 1; ptr += 2; } else if (!strncasecmp(ptr, "yes", 3)) { tmp = 1; ptr += 3; } else if (!strncasecmp(ptr, "toggle", 6)) { tmp = snd_ctl_elem_value_get_boolean(control, idx); tmp = tmp > 0 ? 0 : 1; ptr += 6; } else if (isdigit(*ptr)) { tmp = atoi(ptr) > 0 ? 1 : 0; while (isdigit(*ptr)) ptr++; } else { while (*ptr && *ptr != ',') ptr++; } snd_ctl_elem_value_set_boolean(control, idx, tmp); break; case SND_CTL_ELEM_TYPE_INTEGER: tmp = get_integer(&ptr, snd_ctl_elem_info_get_min(info), snd_ctl_elem_info_get_max(info)); snd_ctl_elem_value_set_integer(control, idx, tmp); break; case SND_CTL_ELEM_TYPE_INTEGER64: tmp = get_integer64(&ptr, snd_ctl_elem_info_get_min64(info), snd_ctl_elem_info_get_max64(info)); snd_ctl_elem_value_set_integer64(control, idx, tmp); break; case SND_CTL_ELEM_TYPE_ENUMERATED: tmp = get_ctl_enum_item_index(handle, info, &ptr); if (tmp < 0) tmp = get_integer(&ptr, 0, snd_ctl_elem_info_get_items(info) - 1); snd_ctl_elem_value_set_enumerated(control, idx, tmp); break; case SND_CTL_ELEM_TYPE_BYTES: tmp = get_integer(&ptr, 0, 255); snd_ctl_elem_value_set_byte(control, idx, tmp); break; default: break; } if (!strchr(argv[1], ',')) ptr = argv[1]; else if (*ptr == ',') ptr++; } if ((err = snd_ctl_elem_write(handle, control)) < 0) { if (!keep_handle) { snd_ctl_close(handle); handle = NULL; } return err; } } if (! keep_handle) { snd_ctl_close(handle); handle = NULL; } if (!quiet) { snd_hctl_t *hctl; snd_hctl_elem_t *elem; if ((err = snd_hctl_open(&hctl, card, 0)) < 0) return err; if ((err = snd_hctl_load(hctl)) < 0) return err; elem = snd_hctl_find_elem(hctl, id); if (elem) show_control(" ", elem, LEVEL_BASIC | LEVEL_ID); snd_hctl_close(hctl); } return 0; }
/** * alsa dumy codec controls interface */ int dummy_alsa_control_raw(char * id_string , long vol, int rw, long * value){ int err; snd_hctl_t *hctl; snd_ctl_elem_id_t *id; snd_hctl_elem_t *elem; snd_ctl_elem_value_t *control; snd_ctl_elem_info_t *info; snd_ctl_elem_type_t type; unsigned int idx = 0, count; long tmp, min, max; char dev[10] = {0}; int card = alsa_get_aml_card(); int port = alsa_get_spdif_port(); adec_print("card = %d, port = %d\n", card, port); sprintf(dev, "hw:%d,%d", (card >= 0) ? card : 0, (port >= 0) ? port : 0); if ((err = snd_hctl_open(&hctl, dev, 0)) < 0) { printf("Control %s open error: %s\n", dev, snd_strerror(err)); return err; } if (err = snd_hctl_load(hctl)< 0) { printf("Control %s open error: %s\n", dev, snd_strerror(err)); return err; } snd_ctl_elem_id_alloca(&id); snd_ctl_elem_id_set_interface(id, SND_CTL_ELEM_IFACE_MIXER); snd_ctl_elem_id_set_name(id, id_string); elem = snd_hctl_find_elem(hctl, id); snd_ctl_elem_value_alloca(&control); snd_ctl_elem_value_set_id(control, id); snd_ctl_elem_info_alloca(&info); if ((err = snd_hctl_elem_info(elem, info)) < 0) { printf("Control %s snd_hctl_elem_info error: %s\n", dev, snd_strerror(err)); return err; } count = snd_ctl_elem_info_get_count(info); type = snd_ctl_elem_info_get_type(info); for (idx = 0; idx < count; idx++) { switch (type) { case SND_CTL_ELEM_TYPE_BOOLEAN: if(rw){ tmp = 0; if (vol >= 1) { tmp = 1; } snd_ctl_elem_value_set_boolean(control, idx, tmp); err = snd_hctl_elem_write(elem, control); }else *value = snd_ctl_elem_value_get_boolean(control, idx); break; case SND_CTL_ELEM_TYPE_INTEGER: if(rw){ min = snd_ctl_elem_info_get_min(info); max = snd_ctl_elem_info_get_max(info); if ((vol >= min) && (vol <= max)) tmp = vol; else if (vol < min) tmp = min; else if (vol > max) tmp = max; snd_ctl_elem_value_set_integer(control, idx, tmp); err = snd_hctl_elem_write(elem, control); }else *value = snd_ctl_elem_value_get_integer(control, idx); break; default: printf("?"); break; } if (err < 0){ printf ("control%s access error=%s,close control device\n", dev, snd_strerror(err)); snd_hctl_close(hctl); return err; } } return 0; }
/************************************************************************** * ALSA_CheckSetVolume [internal] * * Helper function for Alsa volume queries. This tries to simplify * the process of managing the volume. All parameters are optional * (pass NULL to ignore or not use). * Return values are MMSYSERR_NOERROR on success, or !0 on failure; * error codes are normalized into the possible documented return * values from waveOutGetVolume. */ int ALSA_CheckSetVolume(snd_hctl_t *hctl, int *out_left, int *out_right, int *out_min, int *out_max, int *out_step, int *new_left, int *new_right) { int rc = MMSYSERR_NOERROR; int value_count = 0; snd_hctl_elem_t * elem = NULL; snd_ctl_elem_info_t * eleminfop = NULL; snd_ctl_elem_value_t * elemvaluep = NULL; snd_ctl_elem_id_t * elemidp = NULL; const char *names[] = {"PCM Playback Volume", "Line Playback Volume", NULL}; const char **name; #define EXIT_ON_ERROR(f,txt,exitcode) do \ { \ int err; \ if ( (err = (f) ) < 0) \ { \ ERR(txt " failed: %s\n", snd_strerror(err)); \ rc = exitcode; \ goto out; \ } \ } while(0) if (! hctl) return MMSYSERR_NOTSUPPORTED; /* Allocate areas to return information about the volume */ EXIT_ON_ERROR(snd_ctl_elem_id_malloc(&elemidp), "snd_ctl_elem_id_malloc", MMSYSERR_NOMEM); EXIT_ON_ERROR(snd_ctl_elem_value_malloc (&elemvaluep), "snd_ctl_elem_value_malloc", MMSYSERR_NOMEM); EXIT_ON_ERROR(snd_ctl_elem_info_malloc (&eleminfop), "snd_ctl_elem_info_malloc", MMSYSERR_NOMEM); snd_ctl_elem_id_clear(elemidp); snd_ctl_elem_value_clear(elemvaluep); snd_ctl_elem_info_clear(eleminfop); /* Setup and find an element id that exactly matches the characteristic we want ** FIXME: It is probably short sighted to hard code and fixate on PCM Playback Volume */ for( name = names; *name; name++ ) { snd_ctl_elem_id_set_name(elemidp, *name); snd_ctl_elem_id_set_interface(elemidp, SND_CTL_ELEM_IFACE_MIXER); elem = snd_hctl_find_elem(hctl, elemidp); if (elem) { /* Read and return volume information */ EXIT_ON_ERROR(snd_hctl_elem_info(elem, eleminfop), "snd_hctl_elem_info", MMSYSERR_NOTSUPPORTED); value_count = snd_ctl_elem_info_get_count(eleminfop); if (out_min || out_max || out_step) { if (!snd_ctl_elem_info_is_readable(eleminfop)) { ERR("snd_ctl_elem_info_is_readable returned false; cannot return info\n"); rc = MMSYSERR_NOTSUPPORTED; goto out; } if (out_min) *out_min = snd_ctl_elem_info_get_min(eleminfop); if (out_max) *out_max = snd_ctl_elem_info_get_max(eleminfop); if (out_step) *out_step = snd_ctl_elem_info_get_step(eleminfop); } if (out_left || out_right) { EXIT_ON_ERROR(snd_hctl_elem_read(elem, elemvaluep), "snd_hctl_elem_read", MMSYSERR_NOTSUPPORTED); if (out_left) *out_left = snd_ctl_elem_value_get_integer(elemvaluep, 0); if (out_right) { if (value_count == 1) *out_right = snd_ctl_elem_value_get_integer(elemvaluep, 0); else if (value_count == 2) *out_right = snd_ctl_elem_value_get_integer(elemvaluep, 1); else { ERR("Unexpected value count %d from snd_ctl_elem_info_get_count while getting volume info\n", value_count); rc = -1; goto out; } } } /* Set the volume */ if (new_left || new_right) { EXIT_ON_ERROR(snd_hctl_elem_read(elem, elemvaluep), "snd_hctl_elem_read", MMSYSERR_NOTSUPPORTED); if (new_left) snd_ctl_elem_value_set_integer(elemvaluep, 0, *new_left); if (new_right) { if (value_count == 1) snd_ctl_elem_value_set_integer(elemvaluep, 0, *new_right); else if (value_count == 2) snd_ctl_elem_value_set_integer(elemvaluep, 1, *new_right); else { ERR("Unexpected value count %d from snd_ctl_elem_info_get_count while setting volume info\n", value_count); rc = -1; goto out; } } EXIT_ON_ERROR(snd_hctl_elem_write(elem, elemvaluep), "snd_hctl_elem_write", MMSYSERR_NOTSUPPORTED); } break; } } if( !*name ) { ERR("Could not find '{PCM,Line} Playback Volume' element\n"); rc = MMSYSERR_NOTSUPPORTED; } #undef EXIT_ON_ERROR out: if (elemvaluep) snd_ctl_elem_value_free(elemvaluep); if (eleminfop) snd_ctl_elem_info_free(eleminfop); if (elemidp) snd_ctl_elem_id_free(elemidp); return rc; }