/** * \brief Convert card string to an integer value. * \param string String containing card identifier * \return zero if success, otherwise a negative error code * * The accepted format is an integer value in ASCII representation * or the card identifier (the id parameter for sound-card drivers). */ int snd_card_get_index(const char *string) { int card; snd_ctl_t *handle; snd_ctl_card_info_t info; if (!string || *string == '\0') return -EINVAL; if ((isdigit(*string) && *(string + 1) == 0) || (isdigit(*string) && isdigit(*(string + 1)) && *(string + 2) == 0)) { if (sscanf(string, "%i", &card) != 1) return -EINVAL; if (card < 0 || card > 31) return -EINVAL; if (snd_card_load(card)) return card; return -ENODEV; } for (card = 0; card < 32; card++) { if (! snd_card_load(card)) continue; if (snd_ctl_hw_open(&handle, NULL, card, 0) < 0) continue; if (snd_ctl_card_info(handle, &info) < 0) { snd_ctl_close(handle); continue; } snd_ctl_close(handle); if (!strcmp((const char *)info.id, string)) return card; } return -ENODEV; }
/** * \brief Obtain the card long name. * \param card Card number * \param name Result - card long name corresponding to card number * \result zero if success, otherwise a negative error code */ int snd_card_get_longname(int card, char **name) { snd_ctl_t *handle; snd_ctl_card_info_t info; int err; if (name == NULL) return -EINVAL; if ((err = snd_ctl_hw_open(&handle, NULL, card, 0)) < 0) return err; if ((err = snd_ctl_card_info(handle, &info)) < 0) { snd_ctl_close(handle); return err; } snd_ctl_close(handle); *name = strdup((const char *)info.longname); if (*name == NULL) return -ENOMEM; return 0; }
int snd_rawmidi_hw_open(snd_rawmidi_t **inputp, snd_rawmidi_t **outputp, const char *name, int card, int device, int subdevice, int mode) { int fd, ver, ret; int attempt = 0; char filename[sizeof(SNDRV_FILE_RAWMIDI) + 20]; snd_ctl_t *ctl; snd_rawmidi_t *rmidi; snd_rawmidi_hw_t *hw = NULL; snd_rawmidi_info_t info; int fmode; if (inputp) *inputp = NULL; if (outputp) *outputp = NULL; if ((ret = snd_ctl_hw_open(&ctl, NULL, card, 0)) < 0) return ret; sprintf(filename, SNDRV_FILE_RAWMIDI, card, device); __again: if (attempt++ > 3) { snd_ctl_close(ctl); return -EBUSY; } ret = snd_ctl_rawmidi_prefer_subdevice(ctl, subdevice); if (ret < 0) { snd_ctl_close(ctl); return ret; } if (!inputp) fmode = O_WRONLY; else if (!outputp) fmode = O_RDONLY; else fmode = O_RDWR; if (mode & SND_RAWMIDI_APPEND) { assert(outputp); fmode |= O_APPEND; } if (mode & SND_RAWMIDI_NONBLOCK) { fmode |= O_NONBLOCK; } if (mode & SND_RAWMIDI_SYNC) { fmode |= O_SYNC; } assert(!(mode & ~(SND_RAWMIDI_APPEND|SND_RAWMIDI_NONBLOCK|SND_RAWMIDI_SYNC))); fd = snd_open_device(filename, fmode); if (fd < 0) { snd_card_load(card); fd = snd_open_device(filename, fmode); if (fd < 0) { snd_ctl_close(ctl); SYSERR("open %s failed", filename); return -errno; } } #if 0 /* * this is bogus, an application have to care about open filedescriptors */ if (fcntl(fd, F_SETFD, FD_CLOEXEC) != 0) { SYSERR("fcntl FD_CLOEXEC failed"); ret = -errno; close(fd); return ret; } #endif if (ioctl(fd, SNDRV_RAWMIDI_IOCTL_PVERSION, &ver) < 0) { ret = -errno; SYSERR("SNDRV_RAWMIDI_IOCTL_PVERSION failed"); close(fd); snd_ctl_close(ctl); return ret; } if (SNDRV_PROTOCOL_INCOMPATIBLE(ver, SNDRV_RAWMIDI_VERSION_MAX)) { close(fd); snd_ctl_close(ctl); return -SND_ERROR_INCOMPATIBLE_VERSION; } if (subdevice >= 0) { memset(&info, 0, sizeof(info)); info.stream = outputp ? SNDRV_RAWMIDI_STREAM_OUTPUT : SNDRV_RAWMIDI_STREAM_INPUT; if (ioctl(fd, SNDRV_RAWMIDI_IOCTL_INFO, &info) < 0) { SYSERR("SNDRV_RAWMIDI_IOCTL_INFO failed"); ret = -errno; close(fd); snd_ctl_close(ctl); return ret; } if (info.subdevice != (unsigned int) subdevice) { close(fd); goto __again; } } snd_ctl_close(ctl); hw = calloc(1, sizeof(snd_rawmidi_hw_t)); if (hw == NULL) goto _nomem; hw->card = card; hw->device = device; hw->subdevice = subdevice; hw->fd = fd; if (inputp) { rmidi = calloc(1, sizeof(snd_rawmidi_t)); if (rmidi == NULL) goto _nomem; if (name) rmidi->name = strdup(name); rmidi->type = SND_RAWMIDI_TYPE_HW; rmidi->stream = SND_RAWMIDI_STREAM_INPUT; rmidi->mode = mode; rmidi->poll_fd = fd; rmidi->ops = &snd_rawmidi_hw_ops; rmidi->private_data = hw; hw->open++; *inputp = rmidi; } if (outputp) { rmidi = calloc(1, sizeof(snd_rawmidi_t)); if (rmidi == NULL) goto _nomem; if (name) rmidi->name = strdup(name); rmidi->type = SND_RAWMIDI_TYPE_HW; rmidi->stream = SND_RAWMIDI_STREAM_OUTPUT; rmidi->mode = mode; rmidi->poll_fd = fd; rmidi->ops = &snd_rawmidi_hw_ops; rmidi->private_data = hw; hw->open++; *outputp = rmidi; } return 0; _nomem: close(fd); free(hw); if (inputp) free(*inputp); if (outputp) free(*outputp); return -ENOMEM; }
bool LegacyAmixerControl::accessHW(bool receive, string &error) { CAutoLog autoLog(getConfigurableElement(), "ALSA", isDebugEnabled()); #ifdef SIMULATION if (receive) { memset(getBlackboardLocation(), 0, getSize()); } log_info("%s ALSA Element Instance: %s\t\t(Control Element: %s)", receive ? "Reading" : "Writing", getConfigurableElement()->getPath().c_str(), getControlName().c_str()); return true; #endif int ret; // Mixer handle snd_ctl_t *sndCtrl; uint32_t value; uint32_t index; uint32_t elementCount; snd_ctl_elem_id_t *id; snd_ctl_elem_info_t *info; snd_ctl_elem_value_t *control; logControlInfo(receive); // Check parameter type is ok (deferred error, no exceptions available :-() if (!isTypeSupported()) { error = "Parameter type not supported."; return false; } int cardNumber = getCardNumber(); if (cardNumber < 0) { error = "Card " + getCardName() + " not found. Error: " + strerror(cardNumber); return false; } #ifdef ANDROID if ((ret = snd_ctl_hw_open(&sndCtrl, NULL, cardNumber, 0)) < 0) { error = snd_strerror(ret); return false; } #else // Create device name ostringstream deviceName; deviceName << "hw:" << cardNumber; // Open sound control if ((ret = snd_ctl_open(&sndCtrl, deviceName.str().c_str(), 0)) < 0) { error = snd_strerror(ret); return false; } #endif // Allocate in stack snd_ctl_elem_id_alloca(&id); snd_ctl_elem_info_alloca(&info); snd_ctl_elem_value_alloca(&control); // Set interface snd_ctl_elem_id_set_interface(id, SND_CTL_ELEM_IFACE_MIXER); string controlName = getControlName(); // Set name or id if (isdigit(controlName[0])) { snd_ctl_elem_id_set_numid(id, asInteger(controlName)); } else { snd_ctl_elem_id_set_name(id, controlName.c_str()); } // Init info id snd_ctl_elem_info_set_id(info, id); // Get info if ((ret = snd_ctl_elem_info(sndCtrl, info)) < 0) { error = "ALSA: Unable to get element info " + controlName + ": " + snd_strerror(ret); // Close sound control snd_ctl_close(sndCtrl); return false; } // Get type snd_ctl_elem_type_t eType = snd_ctl_elem_info_get_type(info); // Get element count elementCount = snd_ctl_elem_info_get_count(info); uint32_t scalarSize = getScalarSize(); // If size defined in the PFW different from alsa mixer control size, return an error if (elementCount * scalarSize != getSize()) { error = "ALSA: Control element count (" + asString(elementCount) + ") and configurable scalar element count (" + asString(getSize() / scalarSize) + ") mismatch"; // Close sound control snd_ctl_close(sndCtrl); return false; } // Set value id snd_ctl_elem_value_set_id(control, id); if (receive) { // Read element if ((ret = snd_ctl_elem_read(sndCtrl, control)) < 0) { error = "ALSA: Unable to read element " + controlName + ": " + snd_strerror(ret); // Close sound control snd_ctl_close(sndCtrl); return false; } // Go through all indexes for (index = 0; index < elementCount; index++) { switch (eType) { case SND_CTL_ELEM_TYPE_BOOLEAN: value = snd_ctl_elem_value_get_boolean(control, index); break; case SND_CTL_ELEM_TYPE_INTEGER: value = snd_ctl_elem_value_get_integer(control, index); break; case SND_CTL_ELEM_TYPE_INTEGER64: value = snd_ctl_elem_value_get_integer64(control, index); break; case SND_CTL_ELEM_TYPE_ENUMERATED: value = snd_ctl_elem_value_get_enumerated(control, index); break; case SND_CTL_ELEM_TYPE_BYTES: value = snd_ctl_elem_value_get_byte(control, index); break; default: error = "ALSA: Unknown control element type while reading alsa element " + controlName; return false; } if (isDebugEnabled()) { log_info("Reading alsa element %s, index %u with value %u", controlName.c_str(), index, value); } // Write data to blackboard (beware this code is OK on Little Endian machines only) toBlackboard(value); } } else { // Go through all indexes for (index = 0; index < elementCount; index++) { // Read data from blackboard (beware this code is OK on Little Endian machines only) value = fromBlackboard(); if (isDebugEnabled()) { log_info("Writing alsa element %s, index %u with value %u", controlName.c_str(), index, value); } switch (eType) { case SND_CTL_ELEM_TYPE_BOOLEAN: snd_ctl_elem_value_set_boolean(control, index, value); break; case SND_CTL_ELEM_TYPE_INTEGER: snd_ctl_elem_value_set_integer(control, index, value); break; case SND_CTL_ELEM_TYPE_INTEGER64: snd_ctl_elem_value_set_integer64(control, index, value); break; case SND_CTL_ELEM_TYPE_ENUMERATED: snd_ctl_elem_value_set_enumerated(control, index, value); break; case SND_CTL_ELEM_TYPE_BYTES: snd_ctl_elem_value_set_byte(control, index, value); break; default: error = "ALSA: Unknown control element type while writing alsa element " + controlName; return false; } } // Write element if ((ret = snd_ctl_elem_write(sndCtrl, control)) < 0) { error = "ALSA: Unable to write element " + controlName + ": " + snd_strerror(ret); // Close sound control snd_ctl_close(sndCtrl); return false; } } // Close sound control snd_ctl_close(sndCtrl); return true; }