/** * \brief Load an HCTL with all elements and sort them * \param hctl HCTL handle * \return 0 on success otherwise a negative error code */ int snd_hctl_load(snd_hctl_t *hctl) { snd_ctl_elem_list_t list; int err = 0; unsigned int idx; assert(hctl); assert(hctl->ctl); assert(hctl->count == 0); assert(list_empty(&hctl->elems)); memset(&list, 0, sizeof(list)); if ((err = snd_ctl_elem_list(hctl->ctl, &list)) < 0) goto _end; while (list.count != list.used) { err = snd_ctl_elem_list_alloc_space(&list, list.count); if (err < 0) goto _end; if ((err = snd_ctl_elem_list(hctl->ctl, &list)) < 0) goto _end; } if (hctl->alloc < list.count) { hctl->alloc = list.count; free(hctl->pelems); hctl->pelems = malloc(hctl->alloc * sizeof(*hctl->pelems)); if (!hctl->pelems) { err = -ENOMEM; goto _end; } } for (idx = 0; idx < list.count; idx++) { snd_hctl_elem_t *elem; elem = calloc(1, sizeof(snd_hctl_elem_t)); if (elem == NULL) { snd_hctl_free(hctl); err = -ENOMEM; goto _end; } elem->id = list.pids[idx]; elem->hctl = hctl; elem->compare_weight = get_compare_weight(&elem->id); hctl->pelems[idx] = elem; list_add_tail(&elem->list, &hctl->elems); hctl->count++; } if (!hctl->compare) hctl->compare = snd_hctl_compare_default; snd_hctl_sort(hctl); for (idx = 0; idx < hctl->count; idx++) { int res = snd_hctl_throw_event(hctl, SNDRV_CTL_EVENT_MASK_ADD, hctl->pelems[idx]); if (res < 0) return res; } err = snd_ctl_subscribe_events(hctl->ctl, 1); _end: free(list.pids); return err; }
static int get_controls(int cardno, snd_config_t *top) { snd_ctl_t *handle; snd_ctl_card_info_t *info; snd_config_t *state, *card, *control; snd_ctl_elem_list_t *list; unsigned int idx; int err; char name[32]; unsigned int count; const char *id; snd_ctl_card_info_alloca(&info); snd_ctl_elem_list_alloca(&list); sprintf(name, "hw:%d", cardno); err = snd_ctl_open(&handle, name, SND_CTL_READONLY); if (err < 0) { error("snd_ctl_open error: %s", snd_strerror(err)); return err; } err = snd_ctl_card_info(handle, info); if (err < 0) { error("snd_ctl_card_info error: %s", snd_strerror(err)); goto _close; } id = snd_ctl_card_info_get_id(info); err = snd_config_search(top, "state", &state); if (err == 0 && snd_config_get_type(state) != SND_CONFIG_TYPE_COMPOUND) { error("config state node is not a compound"); err = -EINVAL; goto _close; } if (err < 0) { err = snd_config_compound_add(top, "state", 1, &state); if (err < 0) { error("snd_config_compound_add: %s", snd_strerror(err)); goto _close; } } err = snd_config_search(state, id, &card); if (err == 0 && snd_config_get_type(card) != SND_CONFIG_TYPE_COMPOUND) { error("config state.%s node is not a compound", id); err = -EINVAL; goto _close; } if (err < 0) { err = snd_config_compound_add(state, id, 0, &card); if (err < 0) { error("snd_config_compound_add: %s", snd_strerror(err)); goto _close; } } err = snd_config_search(card, "control", &control); if (err == 0) { err = snd_config_delete(control); if (err < 0) { error("snd_config_delete: %s", snd_strerror(err)); goto _close; } } err = snd_ctl_elem_list(handle, list); if (err < 0) { error("Cannot determine controls: %s", snd_strerror(err)); goto _close; } count = snd_ctl_elem_list_get_count(list); err = snd_config_compound_add(card, "control", count > 0, &control); if (err < 0) { error("snd_config_compound_add: %s", snd_strerror(err)); goto _close; } if (count == 0) { err = 0; goto _close; } snd_ctl_elem_list_set_offset(list, 0); if (snd_ctl_elem_list_alloc_space(list, count) < 0) { error("No enough memory..."); goto _close; } if ((err = snd_ctl_elem_list(handle, list)) < 0) { error("Cannot determine controls (2): %s", snd_strerror(err)); goto _free; } for (idx = 0; idx < count; ++idx) { snd_ctl_elem_id_t *id; snd_ctl_elem_id_alloca(&id); snd_ctl_elem_list_get_id(list, idx, id); err = get_control(handle, id, control); if (err < 0) goto _free; } err = 0; _free: snd_ctl_elem_list_free_space(list); _close: snd_ctl_close(handle); return err; }
static int check_audio_route() { int err, idx, i; snd_ctl_t *handle; const char *route_ctrl_name = "Speaker Function"; snd_ctl_elem_value_t * elem_value; snd_ctl_elem_info_t *info; snd_ctl_elem_list_t elist; snd_ctl_elem_id_t *eid; snd_ctl_elem_value_alloca(&elem_value); snd_ctl_elem_info_alloca(&info); //snd_ctl_elem_value_set_numid(elem_value, 54); if ((err = snd_ctl_open(&handle, "hw:0", 0)) < 0) { db_msg("Open control error: %s\n", snd_strerror(err)); goto check_audio_route_err; } db_msg("card=%d\n", handle->card); memset(&elist, 0, sizeof(elist)); if (snd_ctl_elem_list(handle, &elist) < 0) { db_msg("snd_ctl_elem_list 1 failed\n"); goto check_audio_route_err; } eid = calloc(elist.count, sizeof(snd_ctl_elem_id_t)); elist.space = elist.count; elist.pids = eid; if (snd_ctl_elem_list(handle, &elist) < 0) { db_msg("snd_ctl_elem_list 2 failed\n"); goto check_audio_route_err; } for (i = 0; i < elist.count; ++i) { info->id.numid = eid[i].numid; if ((err = snd_ctl_elem_info(handle, info)) < 0) { db_msg("Cannot find the given element from control\n"); goto check_audio_route_err; } //db_msg("name[%d]=%s\n", i, snd_ctl_elem_info_get_name(info)); if (!strcmp(snd_ctl_elem_info_get_name(info), route_ctrl_name)) { db_msg("route ctrl found!!!\n"); break; } } snd_ctl_elem_value_set_numid(elem_value, info->id.numid); if ((err = snd_ctl_elem_read(handle,elem_value)) < 0) { db_msg("snd_ctl_elem_read error: %s\n", snd_strerror(err)); goto check_audio_route_err; } db_msg("numid=%d\n", snd_ctl_elem_value_get_numid(elem_value)); db_msg("name=%s\n", snd_ctl_elem_value_get_name(elem_value)); //to set the new value snd_ctl_elem_value_set_enumerated(elem_value,0, 1); if ((err = snd_ctl_elem_write(handle,elem_value)) < 0) { db_msg("snd_ctl_elem_write error: %s\n", snd_strerror(err)); goto check_audio_route_err; } //read it out again to check if we did set the registers. if ((err = snd_ctl_elem_read(handle,elem_value)) < 0) { db_msg("snd_ctl_elem_read error: %s\n", snd_strerror(err)); goto check_audio_route_err; } db_msg("after: %d\n", snd_ctl_elem_value_get_enumerated(elem_value, 0)); snd_ctl_close(handle); return 0; check_audio_route_err: snd_ctl_close(handle); return -1; }
/* Try and find an IEC958 PCM device and mixer on card 0 and open it * This function is only used on older ALSA installs that don't have the * correct iec958 alias stuff set up, and relies on there being only * one IEC958 PCM device (relies IEC958 in the device name) and one IEC958 * mixer control for doing the settings. */ static int alsaspdifsink_find_pcm_device (AlsaSPDIFSink * sink) { int err = -1, dev, idx, count; const gchar *ctl_name = "hw:0"; const gchar *spdif_name = SND_CTL_NAME_IEC958 ("", PLAYBACK, NONE); int card = sink->card; gchar pcm_name[24]; snd_pcm_t *pcm = NULL; snd_ctl_t *ctl = NULL; snd_ctl_card_info_t *info = NULL; snd_ctl_elem_list_t *clist = NULL; snd_ctl_elem_id_t *cid = NULL; snd_pcm_info_t *pinfo = NULL; GST_WARNING ("Opening IEC958 named device failed. Trying to autodetect"); if ((err = snd_ctl_open (&ctl, ctl_name, card)) < 0) return err; snd_ctl_card_info_malloc (&info); snd_pcm_info_malloc (&pinfo); /* Find a mixer for IEC958 settings */ snd_ctl_elem_list_malloc (&clist); if ((err = snd_ctl_elem_list (ctl, clist)) < 0) goto beach; if ((err = snd_ctl_elem_list_alloc_space (clist, snd_ctl_elem_list_get_count (clist))) < 0) goto beach; if ((err = snd_ctl_elem_list (ctl, clist)) < 0) goto beach; count = snd_ctl_elem_list_get_used (clist); for (idx = 0; idx < count; idx++) { if (strstr (snd_ctl_elem_list_get_name (clist, idx), spdif_name) != NULL) break; } if (idx == count) { /* No SPDIF mixer availble */ err = 0; goto beach; } snd_ctl_elem_id_malloc (&cid); snd_ctl_elem_list_get_id (clist, idx, cid); /* Now find a PCM device for IEC 958 */ if ((err = snd_ctl_card_info (ctl, info)) < 0) goto beach; dev = -1; do { if (snd_ctl_pcm_next_device (ctl, &dev) < 0) goto beach; if (dev < 0) break; /* No more devices */ /* Filter for playback devices */ snd_pcm_info_set_device (pinfo, dev); snd_pcm_info_set_subdevice (pinfo, 0); snd_pcm_info_set_stream (pinfo, SND_PCM_STREAM_PLAYBACK); if ((err = snd_ctl_pcm_info (ctl, pinfo)) < 0) { if (err != -ENOENT) goto beach; /* Genuine error */ /* Device has no playback streams */ continue; } if (strstr (snd_pcm_info_get_name (pinfo), "IEC958") == NULL) continue; /* Not the device we are looking for */ count = snd_pcm_info_get_subdevices_count (pinfo); GST_LOG_OBJECT (sink, "Device %d has %d subdevices\n", dev, snd_pcm_info_get_subdevices_count (pinfo)); for (idx = 0; idx < count; idx++) { snd_pcm_info_set_subdevice (pinfo, idx); if ((err = snd_ctl_pcm_info (ctl, pinfo)) < 0) goto beach; g_assert (snd_pcm_info_get_stream (pinfo) == SND_PCM_STREAM_PLAYBACK); GST_LOG_OBJECT (sink, "Found playback stream on dev %d sub-d %d\n", dev, idx); /* Found a suitable PCM device, let's open it */ g_snprintf (pcm_name, 24, "hw:%d,%d", card, dev); if ((err = snd_pcm_open (&(pcm), pcm_name, SND_PCM_STREAM_PLAYBACK, 0)) < 0) goto beach; break; } } while (pcm == NULL); if (pcm != NULL) { snd_ctl_elem_value_t *cval; snd_aes_iec958_t iec958; /* Have a PCM device and a mixer, set things up */ snd_ctl_elem_value_malloc (&cval); snd_ctl_elem_value_set_id (cval, cid); snd_ctl_elem_value_get_iec958 (cval, &iec958); iec958.status[0] = IEC958_AES0_NONAUDIO; iec958.status[1] = IEC958_AES1_CON_ORIGINAL | IEC958_AES1_CON_PCM_CODER; iec958.status[2] = 0; iec958.status[3] = IEC958_AES3_CON_FS_48000; snd_ctl_elem_value_set_iec958 (cval, &iec958); snd_ctl_elem_value_free (cval); sink->pcm = pcm; pcm = NULL; err = 0; } beach: if (pcm) snd_pcm_close (pcm); if (clist) snd_ctl_elem_list_clear (clist); if (ctl) snd_ctl_close (ctl); if (clist) snd_ctl_elem_list_free (clist); if (cid) snd_ctl_elem_id_free (cid); if (info) snd_ctl_card_info_free (info); if (pinfo) snd_pcm_info_free (pinfo); return err; }