size_t actlstr(char *buf, size_t n, char *ch, struct mixer *mx) { size_t ret; char *status; struct mixer_ctl *ctl; if (!(ctl = mixer_get_ctl_by_name(mx, ch))) { mixer_close(mx); die("couldn't find mixer ctl '%s'\n", ch); } switch (mixer_ctl_get_type(ctl)) { case MIXER_CTL_TYPE_INT: if ((ret = snprintf(buf, n, "%d%%", mixer_ctl_get_percent(ctl, 0))) > n) ret = n; break; case MIXER_CTL_TYPE_BOOL: status = mixer_ctl_get_value(ctl, 0) ? "On" : "Off"; ret = stpncpy(buf, status, n) - buf; break; default: mixer_close(mx); die("unsupported ctl type '%s'\n", mixer_ctl_get_type_string(ctl)); }; return ret; }
static int set_clocks_enabled(bool enable) { enum mixer_ctl_type type; struct mixer_ctl *ctl; struct mixer *mixer = mixer_open(0); if (mixer == NULL) { ALOGE("Error opening mixer 0"); return -1; } ctl = mixer_get_ctl_by_name(mixer, AMP_MIXER_CTL); if (ctl == NULL) { mixer_close(mixer); ALOGE("%s: Could not find %s\n", __func__, AMP_MIXER_CTL); return -ENODEV; } type = mixer_ctl_get_type(ctl); if (type != MIXER_CTL_TYPE_ENUM) { ALOGE("%s: %s is not supported\n", __func__, AMP_MIXER_CTL); mixer_close(mixer); return -ENOTTY; } mixer_ctl_set_value(ctl, 0, enable); mixer_close(mixer); return 0; }
bool audio_set_volume(audio_t *audio, unsigned volume) { struct mixer *mixer; bool res; mixer = mixer_open(audio->dev.card); if (! mixer) { fprintf(stderr, "Failed to open mixer\n"); return false; } if (audio->dev.playback) { res = do_set_volume(mixer, "PCM Playback Volume", volume) || mixer_set(mixer, "PCM Playback Route", 1); } else { res = do_set_volume(mixer, "Mic Capture Volume", volume) || mixer_set(mixer, "Mic Capture Switch", 1) || mixer_set(mixer, "Speaker Playback Switch", 0) || mixer_set(mixer, "Mic Playback Switch", 0); } mixer_close(mixer); return res; }
static int adev_set_master_volume(struct audio_hw_device *dev, float volume) { #if 0 //TARGET_AUDIO_PRIMARY struct mixer *mixer; struct mixer_ctl *ctl; struct audio_device * adev = (struct audio_device *)dev; if ((0 > volume) || (1 < volume) || (NULL == adev)) return -EINVAL; pthread_mutex_lock(&adev->lock); adev->master_volume = (int)(volume*100); if (!(mixer = mixer_open(0))) { pthread_mutex_unlock(&adev->lock); return -ENOSYS; } ctl = mixer_get_ctl_by_name(mixer, "HP Playback Volume"); mixer_ctl_set_value(ctl,0,adjust_volume(adev->master_volume)); mixer_ctl_set_value(ctl,1,adjust_volume(adev->master_volume)); mixer_close(mixer); pthread_mutex_unlock(&adev->lock); return 0; #else return -ENOSYS; #endif }
TinyAudioHardware::~TinyAudioHardware() { closeOutputStream((AudioStreamOut *)mOutput); closeInputStream((AudioStreamIn *)mInput); if (mMixer) mixer_close(mMixer); }
int offload_update_mixer_and_effects_ctl(int card, int device_id, struct mixer *mixer, struct mixer_ctl *ctl) { char mixer_string[128]; snprintf(mixer_string, sizeof(mixer_string), "%s %d", "Audio Effects Config", device_id); ALOGV("%s: mixer_string: %s", __func__, mixer_string); mixer = mixer_open(card); if (!mixer) { ALOGE("Failed to open mixer"); ctl = NULL; return -EINVAL; } else { ctl = mixer_get_ctl_by_name(mixer, mixer_string); if (!ctl) { ALOGE("mixer_get_ctl_by_name failed"); mixer_close(mixer); mixer = NULL; return -EINVAL; } } ALOGV("mixer: %p, ctl: %p", mixer, ctl); return 0; }
struct mixer *mixer_open(unsigned int card) { struct mixer *mixer = NULL; int fd; char fn[256]; snprintf(fn, sizeof(fn), "/dev/snd/controlC%u", card); fd = open(fn, O_RDWR); if (fd < 0) return 0; mixer = calloc(1, sizeof(*mixer)); if (!mixer) goto fail; if (ioctl(fd, SNDRV_CTL_IOCTL_CARD_INFO, &mixer->card_info) < 0) goto fail; mixer->fd = fd; if (add_controls(mixer) != 0) goto fail; return mixer; fail: if (mixer) mixer_close(mixer); else if (fd >= 0) close(fd); return NULL; }
TinyAlsaSubsystem::~TinyAlsaSubsystem() { MixerMap::const_iterator it; for (it = mMixers.begin(); it != mMixers.end(); ++it) { mixer_close(it->second); } }
void audio_route_free(struct audio_route *ar) { free_mixer_state(ar); mixer_close(ar->mixer); path_free(ar); free(ar); ar = NULL; }
TEST(pcmtest, CheckMixerDevices) { struct mixer *mixer; for (unsigned int i = 0; i < mixers; i++) { mixer = mixer_open(i); EXPECT_TRUE(mixer != NULL); if (mixer) mixer_close(mixer); } }
void audio_route_free(struct audio_route *ar) { if (!ar) { ALOGE("%s: invalid audio_route", __func__); return; } free_mixer_state(ar); mixer_close(ar->mixer); free(ar); }
/* * Parse the audio configuration file. * The file is named audio_conf.txt and must begin with the following header: * * card=<ALSA card number> * device=<ALSA device number> * period_size=<period size> * period_count=<period count> * * This header is followed by zero or more mixer settings, each with the format: * mixer "<name>" = <value list> * Since mixer names can contain spaces, the name must be enclosed in double quotes. * The values in the value list can be integers, booleans (represented by 0 or 1) * or strings for enum values. */ bool AudioPlayer::init(const char* config) { int tempInt; struct mixer* mixer = NULL; char name[MAX_LINE_LENGTH]; for (;;) { const char* endl = strstr(config, "\n"); if (!endl) break; String8 line(config, endl - config); if (line.length() >= MAX_LINE_LENGTH) { ALOGE("Line too long in audio_conf.txt"); return false; } const char* l = line.string(); if (sscanf(l, "card=%d", &tempInt) == 1) { ALOGD("card=%d", tempInt); mCard = tempInt; mixer = mixer_open(mCard); if (!mixer) { ALOGE("could not open mixer for card %d", mCard); return false; } } else if (sscanf(l, "device=%d", &tempInt) == 1) { ALOGD("device=%d", tempInt); mDevice = tempInt; } else if (sscanf(l, "period_size=%d", &tempInt) == 1) { ALOGD("period_size=%d", tempInt); mPeriodSize = tempInt; } else if (sscanf(l, "period_count=%d", &tempInt) == 1) { ALOGD("period_count=%d", tempInt); mPeriodCount = tempInt; } else if (sscanf(l, "mixer \"%[0-9a-zA-Z _]s\"", name) == 1) { const char* values = strchr(l, '='); if (values) { values++; // skip '=' ALOGD("name: \"%s\" = %s", name, values); setMixerValue(mixer, name, values); } else { ALOGE("values missing for name: \"%s\"", name); } } config = ++endl; } mixer_close(mixer); if (mCard >= 0 && mDevice >= 0) { return true; } return false; }
int SetAudio_pga_parameter_eng(AUDIO_TOTAL_T *aud_params_ptr, unsigned int params_size, uint32_t vol_level) { int ret = 0; int card_id; pga_gain_nv_t pga_gain_nv; struct mixer *mixer; struct audio_pga *pga; memset(&pga_gain_nv,0,sizeof(pga_gain_nv_t)); if (sizeof(AUDIO_TOTAL_T) != params_size) { ALOGE("%s, Error: params_size = %d, total size = %d", __func__,params_size, sizeof(AUDIO_TOTAL_T)); return -1; } ret = GetAudio_pga_nv(aud_params_ptr,&pga_gain_nv,vol_level); if(ret < 0){ return -1; } card_id = get_snd_card_number(CARD_SPRDPHONE); ALOGW("%s card_id = %d", __func__,card_id); if (card_id < 0) return -1; mixer = mixer_open(card_id); if (!mixer) { ALOGE("%s Failed to open mixer",__func__); return -1; } pga = audio_pga_init(mixer); if (!pga) { mixer_close(mixer); ALOGE("%s Warning: Unable to locate PGA from XML.",__func__); return -1; } ret = SetAudio_gain_4eng(pga,&pga_gain_nv,aud_params_ptr); if(ret < 0){ mixer_close(mixer); return -1; } mixer_close(mixer); return 0; }
static int SetAudio_gain_4eng(struct audio_pga *pga, pga_gain_nv_t *pga_gain_nv, AUDIO_TOTAL_T *aud_params_ptr) { int card_id = 0; int32_t lmode = 0; struct mixer *mixer = NULL; struct mixer_ctl *pa_config_ctl = NULL; ALOGD("vb_pga.c %s", __func__); if((NULL == aud_params_ptr) || (NULL == pga_gain_nv) || (NULL == pga)){ ALOGE("%s aud_params_ptr or pga_gain_nv or audio_pga is NULL",__func__); return -1; } card_id = get_snd_card_number(CARD_SPRDPHONE); if (card_id < 0){ ALOGE("%s get_snd_card_number error(%d)",__func__,card_id); return -1; } mixer = mixer_open(card_id); if (!mixer) { ALOGE("%s Unable to open the mixer, aborting.",__func__); return -1; } pa_config_ctl = mixer_get_ctl_by_name(mixer, MIXER_CTL_INNER_PA_CONFIG); lmode = GetAudio_mode_number_from_nv(aud_params_ptr); ALOGD("vb_pga.c %s, mode: %d", __func__, lmode); if(0 == lmode){ //Headset audio_pga_apply(pga,pga_gain_nv->fm_pga_gain_l,"linein-hp-l"); audio_pga_apply(pga,pga_gain_nv->fm_pga_gain_r,"linein-hp-r"); audio_pga_apply(pga,pga_gain_nv->dac_pga_gain_l,"headphone-l"); audio_pga_apply(pga,pga_gain_nv->dac_pga_gain_r,"headphone-r"); audio_pga_apply(pga,pga_gain_nv->adc_pga_gain_l,"capture-l"); audio_pga_apply(pga,pga_gain_nv->adc_pga_gain_r,"capture-r"); }else if(1 == lmode){ //Headfree audio_pga_apply(pga,pga_gain_nv->dac_pga_gain_l,"headphone-spk-l"); audio_pga_apply(pga,pga_gain_nv->dac_pga_gain_r,"headphone-spk-r"); mixer_ctl_set_value(pa_config_ctl, 0, pga_gain_nv->pa_config); }else if(2 == lmode){ //Handset audio_pga_apply(pga,pga_gain_nv->dac_pga_gain_l,"earpiece"); audio_pga_apply(pga,pga_gain_nv->adc_pga_gain_l,"capture-l"); audio_pga_apply(pga,pga_gain_nv->adc_pga_gain_r,"capture-r"); }else if(3 == lmode){ //Handsfree audio_pga_apply(pga,pga_gain_nv->fm_pga_gain_l,"linein-spk-l"); audio_pga_apply(pga,pga_gain_nv->fm_pga_gain_r,"linein-spk-r"); audio_pga_apply(pga,pga_gain_nv->dac_pga_gain_l,"speaker-l"); audio_pga_apply(pga,pga_gain_nv->dac_pga_gain_r,"speaker-r"); mixer_ctl_set_value(pa_config_ctl, 0, pga_gain_nv->pa_config); audio_pga_apply(pga,pga_gain_nv->adc_pga_gain_l,"capture-l"); audio_pga_apply(pga,pga_gain_nv->adc_pga_gain_r,"capture-r"); } mixer_close(mixer); ALOGW("%s, set cp mode(0x%x) ",__func__,lmode); return 0; }
int main(int argc, G_GNUC_UNUSED char **argv) { GError *error = NULL; struct mixer *mixer; bool success; int volume; if (argc != 2) { g_printerr("Usage: read_mixer PLUGIN\n"); return 1; } g_thread_init(NULL); mixer = mixer_new(&alsa_mixer_plugin, NULL, NULL, &error); if (mixer == NULL) { g_printerr("mixer_new() failed: %s\n", error->message); g_error_free(error); return 2; } success = mixer_open(mixer, &error); if (!success) { mixer_free(mixer); g_printerr("failed to open the mixer: %s\n", error->message); g_error_free(error); return 2; } volume = mixer_get_volume(mixer, &error); mixer_close(mixer); mixer_free(mixer); assert(volume >= -1 && volume <= 100); if (volume < 0) { if (error != NULL) { g_printerr("failed to read volume: %s\n", error->message); g_error_free(error); } else g_printerr("failed to read volume\n"); return 2; } g_print("%d\n", volume); return 0; }
size_t alsavol(char *dest, size_t n) { size_t ret; struct mixer *mx; if (!(mx = mixer_open(sndcrd))) die("couldn't open mixer for card %d\n", sndcrd); ret = actlstr(dest, n, (char*)swtchname, mx); if (strcmp(dest, "Off")) ret = actlstr(dest, n, (char*)volumname, mx); mixer_close(mx); return ret; }
int audio_route_control_set_enum(unsigned int card_slot, char *control_name, char *string) { struct mixer *control_mixer; struct mixer_ctl *ctl; const char *name; unsigned int num_ctls, num_values; unsigned int i, j; enum mixer_ctl_type type; int value; int ret, mixer_ret; control_mixer = mixer_open(card_slot); if (!control_mixer) { ALOGE("Unable to open the control mixer, aborting."); return -1; } ALOGV("Control mixer open successful."); num_ctls = mixer_get_num_ctls(control_mixer); ret = 0; for (i = 0; i < num_ctls; i++) { ctl = mixer_get_ctl(control_mixer, i); name = mixer_ctl_get_name(ctl); if (name && strcmp(name, control_name) == 0) { /* Found the control, update and exit */ type = mixer_ctl_get_type(ctl); if (type == MIXER_CTL_TYPE_ENUM) { if (mixer_ctl_set_enum_by_string(ctl, string)) { ALOGE("Error: invalid enum value"); ret = -1; } else { ALOGV("Setting %s to string %s", name, string); } } else { ALOGV("Error: only enum types can be set with strings"); ret = -1; } break; } } mixer_close(control_mixer); return ret; }
int audio_route_control_set_number(unsigned int card_slot, char *control_name, char *string) { struct mixer *control_mixer; struct mixer_ctl *ctl; const char *name; unsigned int num_ctls, num_values; unsigned int i, j; enum mixer_ctl_type type; int value; int ret, mixer_ret; control_mixer = mixer_open(card_slot); if (!control_mixer) { ALOGE("Unable to open the control mixer, aborting."); return -1; } ALOGV("Control mixer open successful."); num_ctls = mixer_get_num_ctls(control_mixer); ret = 0; for (i = 0; i < num_ctls; i++) { ctl = mixer_get_ctl(control_mixer, i); name = mixer_ctl_get_name(ctl); if (name && strcmp(name, control_name) == 0) { /* Found the control, update and exit */ value = atoi(string); num_values = mixer_ctl_get_num_values(ctl); for (j = 0; j < num_values; j++) { mixer_ret = mixer_ctl_set_value(ctl, j, value); if (mixer_ret) { ALOGE("Error: invalid value (%s to %d)", name, value); mixer_close(control_mixer); /* Add up the number of failed controller values */ ret += -1; } } if (ret == 0) ALOGV("Setting %s to int %d", name, value); break; } } return ret; }
void send_channel_map_driver(struct pcm *pcm) { int i, ret; struct mixer *mixer; const char* device = "/dev/snd/controlC0"; mixer = mixer_open(device); if (!mixer) { fprintf(stderr,"oops: %s: %d\n", strerror(errno), __LINE__); return; } ret = pcm_set_channel_map(pcm, mixer, 8, channel_map); if (ret < 0) fprintf(stderr, "could not set channel mask\n"); mixer_close(mixer); return; }
TEST_F(MixerTest, tryTinyAlsaTest) { int hwId = AudioHardware::detectAudioHw(); ASSERT_TRUE(hwId >= 0); struct mixer* mixerp = mixer_open(hwId); ASSERT_TRUE(mixerp != NULL); int num_ctls = mixer_get_num_ctls(mixerp); LOGI("Number of mixel control %d", num_ctls); for (int i = 0; i < num_ctls; i++) { struct mixer_ctl* control = mixer_get_ctl(mixerp, i); ASSERT_TRUE(control != NULL); LOGI("Mixer control %s type %s value %d", mixer_ctl_get_name(control), mixer_ctl_get_type_string(control), mixer_ctl_get_num_values(control)); free(control); } // no mixer control for MobilePre. If this assumption fails, // mixer control should be added. ASSERT_TRUE(num_ctls == 0); mixer_close(mixerp); }
static int loop_test(void) { struct mixer *mixer; int card = 0; mixer = mixer_open(card); if (!mixer) { fprintf(stderr, "Failed to open mixer\n"); return EXIT_FAILURE; } tinymix_set_value(mixer, 92, 1); tinymix_set_value(mixer, 93, 1); tinymix_set_value(mixer, 95, 1); tinymix_set_value(mixer, 100, 1); tinymix_set_value(mixer, 0, 60); tinymix_set_value(mixer, 34,7); tinymix_set_value(mixer, 18,7); mixer_close(mixer); return 0; }
static int exit_loop_mode() { struct mixer *mixer; int card = 0; mixer = mixer_open(card); if (!mixer) { fprintf(stderr, "Failed to open mixer\n"); return EXIT_FAILURE; } tinymix_set_value(mixer, 92, 0); tinymix_set_value(mixer, 93, 0); tinymix_set_value(mixer, 95, 0); tinymix_set_value(mixer, 100, 0); mixer_close(mixer); if(writeline("AT+ECHO1OFF")){ return -1; } return 0; }
static bool do_set_volume(struct mixer *mixer, const char *name, unsigned volume) { struct mixer_ctl *ctl; unsigned i; ctl = mixer_get_ctl_by_name(mixer, name); if (! ctl) { fprintf(stderr, "Failed to find control: %s\n", name); mixer_close(mixer); return false; } for (i = 0; i < mixer_ctl_get_num_values(ctl); i++) { mixer_ctl_set_percent(ctl, i, volume); } return true; }
static void do_mixer_settings(FILE *file) { struct mixer *mixer; char buf[256], *name, *value; mixer = mixer_open(0); if(!mixer) { log_info("cannot open mixer"); return; } log_info("processing mixer settings from %s", alsa_config_file); while(fgets(buf, sizeof(buf),file)) { if(parse_config_line(buf, &name, &value)) { log_info("%s -> %s", name, value); tinymix_set_value(mixer, name, value); } } mixer_close(mixer); log_info("mixer settings processed"); }
int main(int argc, char **argv) { struct mixer *mixer; int card = 0; if ((argc > 2) && (strcmp(argv[1], "-D") == 0)) { argv++; if (argv[1]) { card = atoi(argv[1]); argv++; argc -= 2; } else { argc -= 1; } } mixer = mixer_open(card); if (!mixer) { fprintf(stderr, "Failed to open mixer\n"); return EXIT_FAILURE; } if (argc == 1) { printf("Mixer name: '%s'\n", mixer_get_name(mixer)); tinymix_list_controls(mixer); } else if (argc == 2) { tinymix_detail_control(mixer, argv[1], 1); } else if (argc >= 3) { tinymix_set_value(mixer, argv[1], &argv[2], argc - 2); } else { printf("Usage: tinymix [-D card] [control id] [value to set]\n"); } mixer_close(mixer); return 0; }
int main(int argc, char **argv) { struct mixer *mixer; mixer = mixer_open(0); if (!mixer) { fprintf(stderr, "Failed to open mixer\n"); return EXIT_FAILURE; } if (argc == 1) tinymix_list_controls(mixer); else if (argc == 2) tinymix_detail_control(mixer, atoi(argv[1]), 1); else if (argc == 3) tinymix_set_value(mixer, atoi(argv[1]), argv[2]); else printf("Usage: tinymix [control id] [value to set]\n"); mixer_close(mixer); return 0; }
/** Opens a mixer for a given card. * @param card The card to open the mixer for. * @returns An initialized mixer handle. * @ingroup libtinyalsa-mixer */ struct mixer *mixer_open(unsigned int card) { struct snd_ctl_elem_list elist; struct snd_ctl_elem_id *eid = NULL; struct mixer *mixer = NULL; unsigned int n; int fd; char fn[256]; snprintf(fn, sizeof(fn), "/dev/snd/controlC%u", card); fd = open(fn, O_RDWR); if (fd < 0) return 0; memset(&elist, 0, sizeof(elist)); if (ioctl(fd, SNDRV_CTL_IOCTL_ELEM_LIST, &elist) < 0) goto fail; mixer = calloc(1, sizeof(*mixer)); if (!mixer) goto fail; mixer->ctl = calloc(elist.count, sizeof(struct mixer_ctl)); if (!mixer->ctl) goto fail; if (ioctl(fd, SNDRV_CTL_IOCTL_CARD_INFO, &mixer->card_info) < 0) goto fail; eid = calloc(elist.count, sizeof(struct snd_ctl_elem_id)); if (!eid) goto fail; mixer->count = elist.count; mixer->fd = fd; elist.space = mixer->count; elist.pids = eid; if (ioctl(fd, SNDRV_CTL_IOCTL_ELEM_LIST, &elist) < 0) goto fail; for (n = 0; n < mixer->count; n++) { struct snd_ctl_elem_info *ei = &mixer->ctl[n].info; ei->id.numid = eid[n].numid; if (ioctl(fd, SNDRV_CTL_IOCTL_ELEM_INFO, ei) < 0) goto fail; mixer->ctl[n].mixer = mixer; } free(eid); return mixer; fail: /* TODO: verify frees in failure case */ if (eid) free(eid); if (mixer) mixer_close(mixer); else if (fd >= 0) close(fd); return 0; }
struct audio_route *audio_route_init(void) { struct config_parse_state state; XML_Parser parser; FILE *file; int bytes_read; void *buf; int i; struct mixer_path *path; struct audio_route *ar; ar = calloc(1, sizeof(struct audio_route)); if (!ar) goto err_calloc; ar->mixer = mixer_open(MIXER_CARD); if (!ar->mixer) { ALOGE("Unable to open the mixer, aborting."); goto err_mixer_open; } ar->mixer_path = NULL; ar->mixer_path_size = 0; ar->num_mixer_paths = 0; /* allocate space for and read current mixer settings */ if (alloc_mixer_state(ar) < 0) goto err_mixer_state; file = fopen(MIXER_XML_PATH, "r"); if (!file) { ALOGE("Failed to open %s", MIXER_XML_PATH); goto err_fopen; } parser = XML_ParserCreate(NULL); if (!parser) { ALOGE("Failed to create XML parser"); goto err_parser_create; } memset(&state, 0, sizeof(state)); state.ar = ar; XML_SetUserData(parser, &state); XML_SetElementHandler(parser, start_tag, end_tag); for (;;) { buf = XML_GetBuffer(parser, BUF_SIZE); if (buf == NULL) goto err_parse; bytes_read = fread(buf, 1, BUF_SIZE, file); if (bytes_read < 0) goto err_parse; if (XML_ParseBuffer(parser, bytes_read, bytes_read == 0) == XML_STATUS_ERROR) { ALOGE("Error in mixer xml (%s)", MIXER_XML_PATH); goto err_parse; } if (bytes_read == 0) break; } audio_route_apply_path(ar, "init"); /* apply the initial mixer values, and save them so we can reset the mixer to the original values */ update_mixer_state(ar); save_mixer_state(ar); XML_ParserFree(parser); fclose(file); return ar; err_parse: XML_ParserFree(parser); err_parser_create: fclose(file); err_fopen: free_mixer_state(ar); err_mixer_state: mixer_close(ar->mixer); err_mixer_open: free(ar); ar = NULL; err_calloc: return NULL; }
struct mixer *mixer_open(const char *device) { struct snd_ctl_elem_list elist; struct snd_ctl_elem_info tmp; struct snd_ctl_elem_id *eid = NULL; struct mixer *mixer = NULL; unsigned n, m; int fd; fd = open(device, O_RDWR); if (fd < 0) { ALOGE("Control open failed\n"); return 0; } memset(&elist, 0, sizeof(elist)); if (ioctl(fd, SNDRV_CTL_IOCTL_ELEM_LIST, &elist) < 0) { ALOGE("SNDRV_CTL_IOCTL_ELEM_LIST failed\n"); goto fail; } mixer = calloc(1, sizeof(*mixer)); if (!mixer) goto fail; mixer->ctl = calloc(elist.count, sizeof(struct mixer_ctl)); mixer->info = calloc(elist.count, sizeof(struct snd_ctl_elem_info)); if (!mixer->ctl || !mixer->info) goto fail; eid = calloc(elist.count, sizeof(struct snd_ctl_elem_id)); if (!eid) goto fail; mixer->count = elist.count; mixer->fd = fd; elist.space = mixer->count; elist.pids = eid; if (ioctl(fd, SNDRV_CTL_IOCTL_ELEM_LIST, &elist) < 0) goto fail; for (n = 0; n < mixer->count; n++) { struct snd_ctl_elem_info *ei = mixer->info + n; ei->id.numid = eid[n].numid; if (ioctl(fd, SNDRV_CTL_IOCTL_ELEM_INFO, ei) < 0) goto fail; mixer->ctl[n].info = ei; mixer->ctl[n].mixer = mixer; if (ei->type == SNDRV_CTL_ELEM_TYPE_ENUMERATED) { char **enames = calloc(ei->value.enumerated.items, sizeof(char*)); if (!enames) goto fail; mixer->ctl[n].ename = enames; for (m = 0; m < ei->value.enumerated.items; m++) { memset(&tmp, 0, sizeof(tmp)); tmp.id.numid = ei->id.numid; tmp.value.enumerated.item = m; if (ioctl(fd, SNDRV_CTL_IOCTL_ELEM_INFO, &tmp) < 0) goto fail; enames[m] = strdup(tmp.value.enumerated.name); if (!enames[m]) goto fail; } } } free(eid); return mixer; fail: if (eid) free(eid); if (mixer) mixer_close(mixer); else if (fd >= 0) close(fd); return 0; }
struct mixer *mixer_open(unsigned int card) { struct snd_ctl_elem_list elist; struct snd_ctl_elem_info tmp; struct snd_ctl_elem_id *eid = NULL; struct mixer *mixer = NULL; unsigned int n, m; int fd; char fn[256]; snprintf(fn, sizeof(fn), "/dev/snd/controlC%u", card); fd = open(fn, O_RDWR); if (fd < 0) return 0; memset(&elist, 0, sizeof(elist)); if (ioctl(fd, SNDRV_CTL_IOCTL_ELEM_LIST, &elist) < 0) goto fail; mixer = calloc(1, sizeof(*mixer)); if (!mixer) goto fail; mixer->ctl = calloc(elist.count, sizeof(struct mixer_ctl)); mixer->elem_info = calloc(elist.count, sizeof(struct snd_ctl_elem_info)); if (!mixer->ctl || !mixer->elem_info) goto fail; if (ioctl(fd, SNDRV_CTL_IOCTL_CARD_INFO, &mixer->card_info) < 0) goto fail; eid = calloc(elist.count, sizeof(struct snd_ctl_elem_id)); if (!eid) goto fail; mixer->count = elist.count; mixer->fd = fd; elist.space = mixer->count; elist.pids = eid; if (ioctl(fd, SNDRV_CTL_IOCTL_ELEM_LIST, &elist) < 0) goto fail; for (n = 0; n < mixer->count; n++) { struct snd_ctl_elem_info *ei = mixer->elem_info + n; ei->id.numid = eid[n].numid; if (ioctl(fd, SNDRV_CTL_IOCTL_ELEM_INFO, ei) < 0) goto fail; mixer->ctl[n].info = ei; mixer->ctl[n].mixer = mixer; if (ei->type == SNDRV_CTL_ELEM_TYPE_ENUMERATED) { char **enames = calloc(ei->value.enumerated.items, sizeof(char*)); if (!enames) goto fail; mixer->ctl[n].ename = enames; for (m = 0; m < ei->value.enumerated.items; m++) { memset(&tmp, 0, sizeof(tmp)); tmp.id.numid = ei->id.numid; tmp.value.enumerated.item = m; if (ioctl(fd, SNDRV_CTL_IOCTL_ELEM_INFO, &tmp) < 0) goto fail; enames[m] = strdup(tmp.value.enumerated.name); if (!enames[m]) goto fail; } } } free(eid); return mixer; fail: /* TODO: verify frees in failure case */ if (eid) free(eid); if (mixer) mixer_close(mixer); else if (fd >= 0) close(fd); return 0; }