snd_hctl_t* CALSAHControlMonitor::GetHandle(const std::string& ctlHandleName) { if (!m_ctlHandles.count(ctlHandleName)) { snd_hctl_t *hctl; if (snd_hctl_open(&hctl, ctlHandleName.c_str(), 0) != 0) { CLog::Log(LOGWARNING, "CALSAHControlMonitor::GetHandle - snd_hctl_open() failed for \"%s\"", ctlHandleName.c_str()); return NULL; } if (snd_hctl_load(hctl) != 0) { CLog::Log(LOGERROR, "CALSAHControlMonitor::GetHandle - snd_hctl_load() failed for \"%s\"", ctlHandleName.c_str()); snd_hctl_close(hctl); return NULL; } snd_hctl_nonblock(hctl, 1); m_ctlHandles[ctlHandleName] = CTLHandle(hctl); } m_ctlHandles[ctlHandleName].useCount++; return m_ctlHandles[ctlHandleName].handle; }
void CALSAHControlMonitor::PutHandle(const std::string& ctlHandleName) { if (--m_ctlHandles[ctlHandleName].useCount == 0) { snd_hctl_close(m_ctlHandles[ctlHandleName].handle); m_ctlHandles.erase(ctlHandleName); } }
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); }
void CALSAHControlMonitor::Clear() { Stop(); for (std::map<std::string, CTLHandle>::iterator it = m_ctlHandles.begin(); it != m_ctlHandles.end(); ++it) { snd_hctl_close(it->second.handle); } m_ctlHandles.clear(); }
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; }
/****************************************************************************** * 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); }
/************************************************************************** * wodClose [internal] */ static DWORD wodClose(WORD wDevID) { DWORD ret = MMSYSERR_NOERROR; WINE_WAVEDEV* wwo; TRACE("(%u);\n", wDevID); if (wDevID >= ALSA_WodNumDevs) { TRACE("Asked for device %d, but only %d known!\n", wDevID, ALSA_WodNumDevs); return MMSYSERR_BADDEVICEID; } if (WOutDev[wDevID].pcm == NULL) { WARN("Requested to close already closed device %d!\n", wDevID); return MMSYSERR_BADDEVICEID; } wwo = &WOutDev[wDevID]; if (wwo->lpQueuePtr) { WARN("buffers still playing !\n"); ret = WAVERR_STILLPLAYING; } else { if (wwo->hThread != INVALID_HANDLE_VALUE) { ALSA_AddRingMessage(&wwo->msgRing, WINE_WM_CLOSING, 0, TRUE); } ALSA_DestroyRingMessage(&wwo->msgRing); if (wwo->hw_params) snd_pcm_hw_params_free(wwo->hw_params); wwo->hw_params = NULL; if (wwo->pcm) snd_pcm_close(wwo->pcm); wwo->pcm = NULL; if (wwo->hctl) { snd_hctl_free(wwo->hctl); snd_hctl_close(wwo->hctl); } wwo->hctl = NULL; ret = wodNotifyClient(wwo, WOM_CLOSE, 0L, 0L); } return ret; }
int phoneui_utils_sound_deinit() { int i, j; sound_state = SOUND_STATE_IDLE; sound_state_type = SOUND_STATE_TYPE_DEFAULT; /*FIXME: add freeing the controls array properly */ for (i = 0 ; i < CONTROLS_LEN ; i++) { for (j = 0 ; j < CONTROL_END ; j++) { if (controls[i][j].name) { /* Just a way to check if init, should probably change */ free_sound_control(&controls[i][j]); } } } snd_hctl_close(hctl); g_source_destroy(source_alsa_poll); free(poll_fds); poll_fd_count = 0; hctl = NULL; return 0; }
void CAESinkALSA::EnumerateDevice(AEDeviceInfoList &list, const std::string &device, const std::string &description, snd_config_t *config) { snd_pcm_t *pcmhandle = NULL; if (!OpenPCMDevice(device, "", ALSA_MAX_CHANNELS, &pcmhandle, config)) return; snd_pcm_info_t *pcminfo; snd_pcm_info_alloca(&pcminfo); memset(pcminfo, 0, snd_pcm_info_sizeof()); int err = snd_pcm_info(pcmhandle, pcminfo); if (err < 0) { CLog::Log(LOGINFO, "CAESinkALSA - Unable to get pcm_info for \"%s\"", device.c_str()); snd_pcm_close(pcmhandle); } int cardNr = snd_pcm_info_get_card(pcminfo); CAEDeviceInfo info; info.m_deviceName = device; info.m_deviceType = AEDeviceTypeFromName(device); if (cardNr >= 0) { /* "HDA NVidia", "HDA Intel", "HDA ATI HDMI", "SB Live! 24-bit External", ... */ char *cardName; if (snd_card_get_name(cardNr, &cardName) == 0) info.m_displayName = cardName; if (info.m_deviceType == AE_DEVTYPE_HDMI && info.m_displayName.size() > 5 && info.m_displayName.substr(info.m_displayName.size()-5) == " HDMI") { /* We already know this is HDMI, strip it */ info.m_displayName.erase(info.m_displayName.size()-5); } /* "CONEXANT Analog", "USB Audio", "HDMI 0", "ALC889 Digital" ... */ std::string pcminfoName = snd_pcm_info_get_name(pcminfo); /* * Filter "USB Audio", in those cases snd_card_get_name() is more * meaningful already */ if (pcminfoName != "USB Audio") info.m_displayNameExtra = pcminfoName; if (info.m_deviceType == AE_DEVTYPE_HDMI) { /* replace, this was likely "HDMI 0" */ info.m_displayNameExtra = "HDMI"; int dev = snd_pcm_info_get_device(pcminfo); if (dev >= 0) { /* lets see if we can get ELD info */ snd_ctl_t *ctlhandle; std::stringstream sstr; sstr << "hw:" << cardNr; std::string strHwName = sstr.str(); if (snd_ctl_open_lconf(&ctlhandle, strHwName.c_str(), 0, config) == 0) { snd_hctl_t *hctl; if (snd_hctl_open_ctl(&hctl, ctlhandle) == 0) { snd_hctl_load(hctl); bool badHDMI = false; if (!GetELD(hctl, dev, info, badHDMI)) CLog::Log(LOGDEBUG, "CAESinkALSA - Unable to obtain ELD information for device \"%s\" (not supported by device, or kernel older than 3.2)", device.c_str()); /* snd_hctl_close also closes ctlhandle */ snd_hctl_close(hctl); if (badHDMI) { /* * Warn about disconnected devices, but keep them enabled * Detection can go wrong on Intel, Nvidia and on all * AMD (fglrx) hardware, so it is not safe to close those * handles */ CLog::Log(LOGDEBUG, "CAESinkALSA - HDMI device \"%s\" may be unconnected (no ELD data)", device.c_str()); } } else { snd_ctl_close(ctlhandle); } } } } else if (info.m_deviceType == AE_DEVTYPE_IEC958) { /* append instead of replace, pcminfoName is useful for S/PDIF */ if (!info.m_displayNameExtra.empty()) info.m_displayNameExtra += ' '; info.m_displayNameExtra += "S/PDIF"; } else if (info.m_displayNameExtra.empty()) { /* for USB audio, it gets a bit confusing as there is * - "SB Live! 24-bit External" * - "SB Live! 24-bit External, S/PDIF" * so add "Analog" qualifier to the first one */ info.m_displayNameExtra = "Analog"; } /* "default" is a device that will be used for all inputs, while * "@" will be mangled to front/default/surroundXX as necessary */ if (device == "@" || device == "default") { /* Make it "Default (whatever)" */ info.m_displayName = "Default (" + info.m_displayName + (info.m_displayNameExtra.empty() ? "" : " " + info.m_displayNameExtra + ")"); info.m_displayNameExtra = ""; } } else { /* virtual devices: "default", "pulse", ... */ /* description can be e.g. "PulseAudio Sound Server" - for hw devices it is * normally uninteresting, like "HDMI Audio Output" or "Default Audio Device", * so we only use it for virtual devices that have no better display name */ info.m_displayName = description; } snd_pcm_hw_params_t *hwparams; snd_pcm_hw_params_alloca(&hwparams); memset(hwparams, 0, snd_pcm_hw_params_sizeof()); /* ensure we can get a playback configuration for the device */ if (snd_pcm_hw_params_any(pcmhandle, hwparams) < 0) { CLog::Log(LOGINFO, "CAESinkALSA - No playback configurations available for device \"%s\"", device.c_str()); snd_pcm_close(pcmhandle); return; } /* detect the available sample rates */ for (unsigned int *rate = ALSASampleRateList; *rate != 0; ++rate) if (snd_pcm_hw_params_test_rate(pcmhandle, hwparams, *rate, 0) >= 0) info.m_sampleRates.push_back(*rate); /* detect the channels available */ int channels = 0; for (int i = ALSA_MAX_CHANNELS; i >= 1; --i) { /* Reopen the device if needed on the special "surroundXX" cases */ if (info.m_deviceType == AE_DEVTYPE_PCM && (i == 8 || i == 6 || i == 4)) OpenPCMDevice(device, "", i, &pcmhandle, config); if (snd_pcm_hw_params_test_channels(pcmhandle, hwparams, i) >= 0) { channels = i; break; } } if (device == "default" && channels == 2) { /* This looks like the ALSA standard default stereo dmix device, we * probably want to use "@" instead to get surroundXX. */ snd_pcm_close(pcmhandle); EnumerateDevice(list, "@", description, config); return; } CAEChannelInfo alsaChannels; for (int i = 0; i < channels; ++i) { if (!info.m_channels.HasChannel(ALSAChannelMap[i])) info.m_channels += ALSAChannelMap[i]; alsaChannels += ALSAChannelMap[i]; } /* remove the channels from m_channels that we cant use */ info.m_channels.ResolveChannels(alsaChannels); /* detect the PCM sample formats that are available */ for (enum AEDataFormat i = AE_FMT_MAX; i > AE_FMT_INVALID; i = (enum AEDataFormat)((int)i - 1)) { if (AE_IS_RAW(i) || i == AE_FMT_MAX) continue; snd_pcm_format_t fmt = AEFormatToALSAFormat(i); if (fmt == SND_PCM_FORMAT_UNKNOWN) continue; if (snd_pcm_hw_params_test_format(pcmhandle, hwparams, fmt) >= 0) info.m_dataFormats.push_back(i); } snd_pcm_close(pcmhandle); list.push_back(info); }
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 findSoundCards(char **cardname) { int idx, dev, err; snd_ctl_t *handle; snd_hctl_t *hctlhandle; snd_ctl_card_info_t *cardinfo; snd_pcm_info_t *pcminfo; char str[32]; snd_ctl_card_info_alloca(&cardinfo); snd_pcm_info_alloca(&pcminfo); snd_hctl_elem_t *elem; snd_ctl_elem_id_t *id; snd_ctl_elem_info_t *info; snd_ctl_elem_id_alloca(&id); snd_ctl_elem_info_alloca(&info); idx = -1; while (1) { if ((err = snd_card_next(&idx)) < 0) { LOGE("Card next error: %s\n", snd_strerror(err)); break; } if (idx < 0) break; sprintf(str, "hw:CARD=%i", idx); if ((err = snd_ctl_open(&handle, str, 0)) < 0) { LOGE("Open error: %s\n", snd_strerror(err)); continue; } if ((err = snd_ctl_card_info(handle, cardinfo)) < 0) { LOGE("HW info error: %s\n", snd_strerror(err)); continue; } LOGD("Soundcard #%i:\n", idx + 1); LOGD(" card - %i\n", snd_ctl_card_info_get_card(cardinfo)); LOGD(" id - '%s'\n", snd_ctl_card_info_get_id(cardinfo)); LOGD(" driver - '%s'\n", snd_ctl_card_info_get_driver(cardinfo)); LOGD(" name - '%s'\n", snd_ctl_card_info_get_name(cardinfo)); LOGD(" longname - '%s'\n", snd_ctl_card_info_get_longname(cardinfo)); LOGD(" mixername - '%s'\n", snd_ctl_card_info_get_mixername(cardinfo)); LOGD(" components - '%s'\n", snd_ctl_card_info_get_components(cardinfo)); strcpy(cardname[idx], snd_ctl_card_info_get_name(cardinfo)); LOGD("\n\n-----get cart name and id: %s : %d",cardname[idx],idx); snd_ctl_close(handle); if ((err = snd_hctl_open(&hctlhandle, str, 0)) < 0) { LOGE("Control %s open error: %s", str, snd_strerror(err)); return err; } if ((err = snd_hctl_load(hctlhandle)) < 0) { LOGE("Control %s local error: %s\n", str, snd_strerror(err)); return err; } for (elem = snd_hctl_first_elem(hctlhandle); elem; elem = snd_hctl_elem_next(elem)) { if ((err = snd_hctl_elem_info(elem, info)) < 0) { LOGE("Control %s snd_hctl_elem_info error: %s\n", str, snd_strerror(err)); return err; } snd_hctl_elem_get_id(elem, id); show_control_id(id); } snd_hctl_close(hctlhandle); } snd_config_update_free_global(); return 0; }
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; }
int phoneui_utils_sound_init_finish(GKeyFile *keyfile,char* suffix) { int err, f; char *device_name; char *alsa; static GSourceFuncs funcs = { _sourcefunc_prepare, _sourcefunc_check, _sourcefunc_dispatch, 0, 0, 0 }; alsa = malloc(strlen(suffix) + strlen("alsa") + 1); if (alsa) { strcpy(alsa, "alsa"); strcat(alsa, suffix); }else{ alsa = strdup("alsa"); g_warning("Malloc failure in %s at line %d",__func__,__LINE__); } sound_state = SOUND_STATE_IDLE; sound_state_type = SOUND_STATE_TYPE_DEFAULT; device_name = g_key_file_get_string(keyfile, alsa, "hardware_control_name", NULL); if (!device_name) { g_message("No hw control found, using default"); device_name = strdup("hw:0"); } if (hctl) { snd_hctl_close(hctl); } err = snd_hctl_open(&hctl, device_name, 0); if (err) { g_warning("Cannot open alsa:hardware_control_name '%s': %s", device_name, snd_strerror(err)); g_key_file_free(keyfile); return err; } err = snd_hctl_load(hctl); if (err) { g_warning("Cannot load alsa:hardware_control_name '%s': %s", device_name, snd_strerror(err)); } free(device_name); /*FIXME: add idle bt */ _phoneui_utils_sound_init_set_control(keyfile, "idle", suffix, SOUND_STATE_IDLE, SOUND_STATE_TYPE_HANDSET); _phoneui_utils_sound_init_set_control(keyfile, "bluetooth", suffix, SOUND_STATE_CALL, SOUND_STATE_TYPE_BLUETOOTH); _phoneui_utils_sound_init_set_control(keyfile, "handset", suffix, SOUND_STATE_CALL, SOUND_STATE_TYPE_HANDSET); _phoneui_utils_sound_init_set_control(keyfile, "headset", suffix, SOUND_STATE_CALL, SOUND_STATE_TYPE_HEADSET); _phoneui_utils_sound_init_set_control(keyfile, "speaker", suffix, SOUND_STATE_SPEAKER, SOUND_STATE_TYPE_HANDSET); snd_hctl_nonblock(hctl, 1); poll_fd_count = snd_hctl_poll_descriptors_count(hctl); poll_fds = malloc(sizeof(struct pollfd) * poll_fd_count); snd_hctl_poll_descriptors(hctl, poll_fds, poll_fd_count); source_alsa_poll = g_source_new(&funcs, sizeof(GSource)); for (f = 0; f < poll_fd_count; f++) { g_source_add_poll(source_alsa_poll, (GPollFD *)&poll_fds[f]); } g_source_attach(source_alsa_poll, NULL); /*Register for HEADPHONE insertion */ phoneui_info_register_input_events(_input_events_cb, NULL); fso_audio = (FreeSmartphoneDeviceAudio *)_fso (FREE_SMARTPHONE_DEVICE_TYPE_AUDIO_PROXY, FSO_FRAMEWORK_DEVICE_ServiceDBusName, FSO_FRAMEWORK_DEVICE_AudioServicePath, FSO_FRAMEWORK_DEVICE_AudioServiceFace); g_key_file_free(keyfile); return err; }
/** * 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; }
/************************************************************************** * wodOpen [internal] */ static DWORD wodOpen(WORD wDevID, LPWAVEOPENDESC lpDesc, DWORD dwFlags) { WINE_WAVEDEV* wwo; snd_pcm_t * pcm = NULL; snd_hctl_t * hctl = NULL; snd_pcm_hw_params_t * hw_params = NULL; snd_pcm_sw_params_t * sw_params; snd_pcm_access_t access; snd_pcm_format_t format = -1; unsigned int rate; unsigned int buffer_time = 120000; unsigned int period_time = 22000; snd_pcm_uframes_t buffer_size; snd_pcm_uframes_t period_size; int flags; int err=0; int dir=0; DWORD retcode = 0; TRACE("(%u, %p, %08X);\n", wDevID, lpDesc, dwFlags); if (lpDesc == NULL) { WARN("Invalid Parameter !\n"); return MMSYSERR_INVALPARAM; } if (wDevID >= ALSA_WodNumDevs) { TRACE("Asked for device %d, but only %d known!\n", wDevID, ALSA_WodNumDevs); return MMSYSERR_BADDEVICEID; } /* only PCM format is supported so far... */ if (!ALSA_supportedFormat(lpDesc->lpFormat)) { WARN("Bad format: tag=%04X nChannels=%d nSamplesPerSec=%d !\n", lpDesc->lpFormat->wFormatTag, lpDesc->lpFormat->nChannels, lpDesc->lpFormat->nSamplesPerSec); return WAVERR_BADFORMAT; } if (dwFlags & WAVE_FORMAT_QUERY) { TRACE("Query format: tag=%04X nChannels=%d nSamplesPerSec=%d !\n", lpDesc->lpFormat->wFormatTag, lpDesc->lpFormat->nChannels, lpDesc->lpFormat->nSamplesPerSec); return MMSYSERR_NOERROR; } wwo = &WOutDev[wDevID]; if (wwo->pcm != NULL) { WARN("%d already allocated\n", wDevID); return MMSYSERR_ALLOCATED; } if (dwFlags & WAVE_DIRECTSOUND) FIXME("Why are we called with DirectSound flag? It doesn't use MMSYSTEM any more\n"); /* not supported, ignore it */ dwFlags &= ~WAVE_DIRECTSOUND; flags = SND_PCM_NONBLOCK; if ( (err = snd_pcm_open(&pcm, wwo->pcmname, SND_PCM_STREAM_PLAYBACK, flags)) < 0) { ERR("Error open: %s\n", snd_strerror(err)); return MMSYSERR_NOTENABLED; } if (wwo->ctlname) { err = snd_hctl_open(&hctl, wwo->ctlname, 0); if (err >= 0) { snd_hctl_load(hctl); } else { WARN("Could not open hctl for [%s]: %s\n", wwo->ctlname, snd_strerror(err)); hctl = NULL; } } wwo->wFlags = HIWORD(dwFlags & CALLBACK_TYPEMASK); wwo->waveDesc = *lpDesc; ALSA_copyFormat(lpDesc->lpFormat, &wwo->format); TRACE("Requested this format: %dx%dx%d %s\n", wwo->format.Format.nSamplesPerSec, wwo->format.Format.wBitsPerSample, wwo->format.Format.nChannels, ALSA_getFormat(wwo->format.Format.wFormatTag)); if (wwo->format.Format.wBitsPerSample == 0) { WARN("Resetting zeroed wBitsPerSample\n"); wwo->format.Format.wBitsPerSample = 8 * (wwo->format.Format.nAvgBytesPerSec / wwo->format.Format.nSamplesPerSec) / wwo->format.Format.nChannels; } #define EXIT_ON_ERROR(f,e,txt) do \ { \ int err; \ if ( (err = (f) ) < 0) \ { \ WARN(txt ": %s\n", snd_strerror(err)); \ retcode=e; \ goto errexit; \ } \ } while(0) sw_params = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, snd_pcm_sw_params_sizeof() ); snd_pcm_hw_params_malloc(&hw_params); if (! hw_params) { retcode = MMSYSERR_NOMEM; goto errexit; } snd_pcm_hw_params_any(pcm, hw_params); access = SND_PCM_ACCESS_MMAP_INTERLEAVED; if ( ( err = snd_pcm_hw_params_set_access(pcm, hw_params, access ) ) < 0) { WARN("mmap not available. switching to standard write.\n"); access = SND_PCM_ACCESS_RW_INTERLEAVED; EXIT_ON_ERROR( snd_pcm_hw_params_set_access(pcm, hw_params, access ), MMSYSERR_INVALPARAM, "unable to set access for playback"); wwo->write = snd_pcm_writei; } else wwo->write = snd_pcm_mmap_writei; if ((err = snd_pcm_hw_params_set_channels(pcm, hw_params, wwo->format.Format.nChannels)) < 0) { WARN("unable to set required channels: %d\n", wwo->format.Format.nChannels); EXIT_ON_ERROR( snd_pcm_hw_params_set_channels(pcm, hw_params, wwo->format.Format.nChannels ), WAVERR_BADFORMAT, "unable to set required channels" ); } if ((wwo->format.Format.wFormatTag == WAVE_FORMAT_PCM) || ((wwo->format.Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE) && IsEqualGUID(&wwo->format.SubFormat, &KSDATAFORMAT_SUBTYPE_PCM))) { format = (wwo->format.Format.wBitsPerSample == 8) ? SND_PCM_FORMAT_U8 : (wwo->format.Format.wBitsPerSample == 16) ? SND_PCM_FORMAT_S16_LE : (wwo->format.Format.wBitsPerSample == 24) ? SND_PCM_FORMAT_S24_3LE : (wwo->format.Format.wBitsPerSample == 32) ? SND_PCM_FORMAT_S32_LE : -1; } else if ((wwo->format.Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE) && IsEqualGUID(&wwo->format.SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)){ format = (wwo->format.Format.wBitsPerSample == 32) ? SND_PCM_FORMAT_FLOAT_LE : -1; } else { ERR("invalid format: %0x04x\n", wwo->format.Format.wFormatTag); retcode = WAVERR_BADFORMAT; goto errexit; } if ((err = snd_pcm_hw_params_set_format(pcm, hw_params, format)) < 0) { WARN("unable to set required format: %s\n", snd_pcm_format_name(format)); EXIT_ON_ERROR( snd_pcm_hw_params_set_format(pcm, hw_params, format), WAVERR_BADFORMAT, "unable to set required format" ); } rate = wwo->format.Format.nSamplesPerSec; dir=0; err = snd_pcm_hw_params_set_rate_near(pcm, hw_params, &rate, &dir); if (err < 0) { WARN("Rate %d Hz not available for playback: %s\n", wwo->format.Format.nSamplesPerSec, snd_strerror(rate)); retcode = WAVERR_BADFORMAT; goto errexit; } if (!ALSA_NearMatch(rate, wwo->format.Format.nSamplesPerSec)) { WARN("Rate doesn't match (requested %d Hz, got %d Hz)\n", wwo->format.Format.nSamplesPerSec, rate); retcode = WAVERR_BADFORMAT; goto errexit; } TRACE("Got this format: %dx%dx%d %s\n", wwo->format.Format.nSamplesPerSec, wwo->format.Format.wBitsPerSample, wwo->format.Format.nChannels, ALSA_getFormat(wwo->format.Format.wFormatTag)); dir=0; EXIT_ON_ERROR( snd_pcm_hw_params_set_buffer_time_near(pcm, hw_params, &buffer_time, &dir), MMSYSERR_INVALPARAM, "unable to set buffer time"); dir=0; EXIT_ON_ERROR( snd_pcm_hw_params_set_period_time_near(pcm, hw_params, &period_time, &dir), MMSYSERR_INVALPARAM, "unable to set period time"); EXIT_ON_ERROR( snd_pcm_hw_params(pcm, hw_params), MMSYSERR_INVALPARAM, "unable to set hw params for playback"); err = snd_pcm_hw_params_get_period_size(hw_params, &period_size, &dir); err = snd_pcm_hw_params_get_buffer_size(hw_params, &buffer_size); snd_pcm_sw_params_current(pcm, sw_params); EXIT_ON_ERROR( snd_pcm_sw_params_set_start_threshold(pcm, sw_params, 1), MMSYSERR_ERROR, "unable to set start threshold"); EXIT_ON_ERROR( snd_pcm_sw_params_set_silence_size(pcm, sw_params, 0), MMSYSERR_ERROR, "unable to set silence size"); EXIT_ON_ERROR( snd_pcm_sw_params_set_avail_min(pcm, sw_params, period_size), MMSYSERR_ERROR, "unable to set avail min"); EXIT_ON_ERROR( snd_pcm_sw_params_set_silence_threshold(pcm, sw_params, 0), MMSYSERR_ERROR, "unable to set silence threshold"); EXIT_ON_ERROR( snd_pcm_sw_params(pcm, sw_params), MMSYSERR_ERROR, "unable to set sw params for playback"); #undef EXIT_ON_ERROR snd_pcm_prepare(pcm); if (TRACE_ON(wave)) ALSA_TraceParameters(hw_params, sw_params, FALSE); /* now, we can save all required data for later use... */ wwo->dwBufferSize = snd_pcm_frames_to_bytes(pcm, buffer_size); wwo->lpQueuePtr = wwo->lpPlayPtr = wwo->lpLoopPtr = NULL; wwo->dwPlayedTotal = wwo->dwWrittenTotal = 0; wwo->dwPartialOffset = 0; ALSA_InitRingMessage(&wwo->msgRing); wwo->hStartUpEvent = CreateEventW(NULL, FALSE, FALSE, NULL); wwo->hThread = CreateThread(NULL, 0, wodPlayer, (LPVOID)(DWORD_PTR)wDevID, 0, &(wwo->dwThreadID)); if (wwo->hThread) SetThreadPriority(wwo->hThread, THREAD_PRIORITY_TIME_CRITICAL); else { ERR("Thread creation for the wodPlayer failed!\n"); CloseHandle(wwo->hStartUpEvent); retcode = MMSYSERR_NOMEM; goto errexit; } WaitForSingleObject(wwo->hStartUpEvent, INFINITE); CloseHandle(wwo->hStartUpEvent); wwo->hStartUpEvent = INVALID_HANDLE_VALUE; TRACE("handle=%p\n", pcm); TRACE("wBitsPerSample=%u, nAvgBytesPerSec=%u, nSamplesPerSec=%u, nChannels=%u nBlockAlign=%u!\n", wwo->format.Format.wBitsPerSample, wwo->format.Format.nAvgBytesPerSec, wwo->format.Format.nSamplesPerSec, wwo->format.Format.nChannels, wwo->format.Format.nBlockAlign); HeapFree( GetProcessHeap(), 0, sw_params ); wwo->pcm = pcm; wwo->hctl = hctl; if ( wwo->hw_params ) snd_pcm_hw_params_free(wwo->hw_params); wwo->hw_params = hw_params; return wodNotifyClient(wwo, WOM_OPEN, 0L, 0L); errexit: if (pcm) snd_pcm_close(pcm); if (hctl) { snd_hctl_free(hctl); snd_hctl_close(hctl); } if ( hw_params ) snd_pcm_hw_params_free(hw_params); HeapFree( GetProcessHeap(), 0, sw_params ); if (wwo->msgRing.ring_buffer_size > 0) ALSA_DestroyRingMessage(&wwo->msgRing); return retcode; }
/*---------------------------------------------------------------------------- ** ALSA_ComputeCaps ** ** Given an ALSA PCM, figure out our HW CAPS structure info. ** ctl can be null, pcm is required, as is all output parms. ** */ static int ALSA_ComputeCaps(snd_ctl_t *ctl, snd_pcm_t *pcm, WORD *channels, DWORD *flags, DWORD *formats, DWORD *supports) { snd_pcm_hw_params_t *hw_params; snd_pcm_format_mask_t *fmask; snd_pcm_access_mask_t *acmask; unsigned int ratemin = 0; unsigned int ratemax = 0; unsigned int chmin = 0; unsigned int chmax = 0; int rc, dir = 0; hw_params = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, snd_pcm_hw_params_sizeof() ); fmask = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, snd_pcm_format_mask_sizeof() ); acmask = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, snd_pcm_access_mask_sizeof() ); if ((rc = snd_pcm_hw_params_any(pcm, hw_params)) < 0) goto done; snd_pcm_hw_params_get_format_mask(hw_params, fmask); if ((rc = snd_pcm_hw_params_get_access_mask(hw_params, acmask)) < 0) goto done; if ((rc = snd_pcm_hw_params_get_rate_min(hw_params, &ratemin, &dir)) < 0) goto done; if ((rc = snd_pcm_hw_params_get_rate_max(hw_params, &ratemax, &dir)) < 0) goto done; if ((rc = snd_pcm_hw_params_get_channels_min(hw_params, &chmin)) < 0) goto done; if ((rc = snd_pcm_hw_params_get_channels_max(hw_params, &chmax)) < 0) goto done; #define X(r,v) \ if ( (r) >= ratemin && ( (r) <= ratemax || ratemax == -1) ) \ { \ if (snd_pcm_format_mask_test( fmask, SND_PCM_FORMAT_U8)) \ { \ if (chmin <= 1 && 1 <= chmax) \ *formats |= WAVE_FORMAT_##v##M08; \ if (chmin <= 2 && 2 <= chmax) \ *formats |= WAVE_FORMAT_##v##S08; \ } \ if (snd_pcm_format_mask_test( fmask, SND_PCM_FORMAT_S16_LE)) \ { \ if (chmin <= 1 && 1 <= chmax) \ *formats |= WAVE_FORMAT_##v##M16; \ if (chmin <= 2 && 2 <= chmax) \ *formats |= WAVE_FORMAT_##v##S16; \ } \ } X(11025,1); X(22050,2); X(44100,4); X(48000,48); X(96000,96); #undef X if (chmin > 1) FIXME("Device has a minimum of %d channels\n", chmin); *channels = chmax; /* FIXME: is sample accurate always true ? ** Can we do WAVECAPS_PITCH, WAVECAPS_SYNC, or WAVECAPS_PLAYBACKRATE? */ *supports |= WAVECAPS_SAMPLEACCURATE; *supports |= WAVECAPS_DIRECTSOUND; /* check for volume control support */ if (ctl) { if (snd_ctl_name(ctl)) { snd_hctl_t *hctl; if (snd_hctl_open(&hctl, snd_ctl_name(ctl), 0) >= 0) { snd_hctl_load(hctl); if (!ALSA_CheckSetVolume( hctl, NULL, NULL, NULL, NULL, NULL, NULL, NULL )) { *supports |= WAVECAPS_VOLUME; if (chmin <= 2 && 2 <= chmax) *supports |= WAVECAPS_LRVOLUME; } snd_hctl_free(hctl); snd_hctl_close(hctl); } } } *flags = DSCAPS_CERTIFIED | DSCAPS_CONTINUOUSRATE; *flags |= DSCAPS_SECONDARYMONO | DSCAPS_SECONDARYSTEREO; *flags |= DSCAPS_SECONDARY8BIT | DSCAPS_SECONDARY16BIT; if (*formats & (WAVE_FORMAT_1M08 | WAVE_FORMAT_2M08 | WAVE_FORMAT_4M08 | WAVE_FORMAT_48M08 | WAVE_FORMAT_96M08 | WAVE_FORMAT_1M16 | WAVE_FORMAT_2M16 | WAVE_FORMAT_4M16 | WAVE_FORMAT_48M16 | WAVE_FORMAT_96M16) ) *flags |= DSCAPS_PRIMARYMONO; if (*formats & (WAVE_FORMAT_1S08 | WAVE_FORMAT_2S08 | WAVE_FORMAT_4S08 | WAVE_FORMAT_48S08 | WAVE_FORMAT_96S08 | WAVE_FORMAT_1S16 | WAVE_FORMAT_2S16 | WAVE_FORMAT_4S16 | WAVE_FORMAT_48S16 | WAVE_FORMAT_96S16) ) *flags |= DSCAPS_PRIMARYSTEREO; if (*formats & (WAVE_FORMAT_1M08 | WAVE_FORMAT_2M08 | WAVE_FORMAT_4M08 | WAVE_FORMAT_48M08 | WAVE_FORMAT_96M08 | WAVE_FORMAT_1S08 | WAVE_FORMAT_2S08 | WAVE_FORMAT_4S08 | WAVE_FORMAT_48S08 | WAVE_FORMAT_96S08) ) *flags |= DSCAPS_PRIMARY8BIT; if (*formats & (WAVE_FORMAT_1M16 | WAVE_FORMAT_2M16 | WAVE_FORMAT_4M16 | WAVE_FORMAT_48M16 | WAVE_FORMAT_96M16 | WAVE_FORMAT_1S16 | WAVE_FORMAT_2S16 | WAVE_FORMAT_4S16 | WAVE_FORMAT_48S16 | WAVE_FORMAT_96S16) ) *flags |= DSCAPS_PRIMARY16BIT; rc = 0; done: if (rc < 0) ERR("failed: %s(%d)\n", snd_strerror(rc), rc); HeapFree( GetProcessHeap(), 0, hw_params ); HeapFree( GetProcessHeap(), 0, fmask ); HeapFree( GetProcessHeap(), 0, acmask ); return rc; }
void CAESinkALSA::EnumerateDevicesEx(AEDeviceInfoList &list) { /* ensure that ALSA has been initialized */ if(!snd_config) snd_config_update(); snd_ctl_t *ctlhandle; snd_pcm_t *pcmhandle; snd_ctl_card_info_t *ctlinfo; snd_ctl_card_info_alloca(&ctlinfo); memset(ctlinfo, 0, snd_ctl_card_info_sizeof()); snd_pcm_hw_params_t *hwparams; snd_pcm_hw_params_alloca(&hwparams); memset(hwparams, 0, snd_pcm_hw_params_sizeof()); snd_pcm_info_t *pcminfo; snd_pcm_info_alloca(&pcminfo); memset(pcminfo, 0, snd_pcm_info_sizeof()); /* get the sound config */ snd_config_t *config; snd_config_copy(&config, snd_config); std::string strHwName; int n_cards = -1; while (snd_card_next(&n_cards) == 0 && n_cards != -1) { std::stringstream sstr; sstr << "hw:" << n_cards; std::string strHwName = sstr.str(); if (snd_ctl_open_lconf(&ctlhandle, strHwName.c_str(), 0, config) != 0) { CLog::Log(LOGDEBUG, "CAESinkALSA::EnumerateDevicesEx - Unable to open control for device %s", strHwName.c_str()); continue; } if (snd_ctl_card_info(ctlhandle, ctlinfo) != 0) { CLog::Log(LOGDEBUG, "CAESinkALSA::EnumerateDevicesEx - Unable to get card control info for device %s", strHwName.c_str()); snd_ctl_close(ctlhandle); continue; } snd_hctl_t *hctl; if (snd_hctl_open_ctl(&hctl, ctlhandle) != 0) hctl = NULL; snd_hctl_load(hctl); int pcm_index = 0; int iec958_index = 0; int hdmi_index = 0; int dev = -1; while (snd_ctl_pcm_next_device(ctlhandle, &dev) == 0 && dev != -1) { snd_pcm_info_set_device (pcminfo, dev); snd_pcm_info_set_subdevice(pcminfo, 0 ); snd_pcm_info_set_stream (pcminfo, SND_PCM_STREAM_PLAYBACK); if (snd_ctl_pcm_info(ctlhandle, pcminfo) < 0) { CLog::Log(LOGDEBUG, "CAESinkALSA::EnumerateDevicesEx - Skipping device %s,%d as it does not have PCM playback ability", strHwName.c_str(), dev); continue; } int dev_index; sstr.str(std::string()); CAEDeviceInfo info; std::string devname = snd_pcm_info_get_name(pcminfo); bool maybeHDMI = false; /* detect HDMI */ if (devname.find("HDMI") != std::string::npos) { info.m_deviceType = AE_DEVTYPE_HDMI; dev_index = hdmi_index++; sstr << "hdmi"; } else { /* detect IEC958 */ /* some HDMI devices (intel) report Digital for HDMI also */ if (devname.find("Digital") != std::string::npos) maybeHDMI = true; if (maybeHDMI || devname.find("IEC958" ) != std::string::npos) { info.m_deviceType = AE_DEVTYPE_IEC958; dev_index = iec958_index; /* dont increment, it might be HDMI */ sstr << "iec958"; } else { info.m_deviceType = AE_DEVTYPE_PCM; dev_index = pcm_index++; sstr << "hw"; } } /* build the driver string to pass to ALSA */ sstr << ":CARD=" << snd_ctl_card_info_get_id(ctlinfo) << ",DEV=" << dev_index; info.m_deviceName = sstr.str(); /* get the friendly display name*/ info.m_displayName = snd_ctl_card_info_get_name(ctlinfo); info.m_displayNameExtra = devname; /* open the device for testing */ int err = snd_pcm_open_lconf(&pcmhandle, info.m_deviceName.c_str(), SND_PCM_STREAM_PLAYBACK, 0, config); /* if open of possible IEC958 failed and it could be HDMI, try as HDMI */ if (err < 0 && maybeHDMI) { /* check for HDMI if it failed */ sstr.str(std::string()); dev_index = hdmi_index; sstr << "hdmi"; sstr << ":CARD=" << snd_ctl_card_info_get_id(ctlinfo) << ",DEV=" << dev_index; info.m_deviceName = sstr.str(); err = snd_pcm_open_lconf(&pcmhandle, info.m_deviceName.c_str(), SND_PCM_STREAM_PLAYBACK, 0, config); /* if it was valid, increment the index and set the type */ if (err >= 0) { ++hdmi_index; info.m_deviceType = AE_DEVTYPE_HDMI; } } /* if it's still IEC958, increment the index */ if (info.m_deviceType == AE_DEVTYPE_IEC958) ++iec958_index; /* final error check */ if (err < 0) { CLog::Log(LOGINFO, "CAESinkALSA::EnumerateDevicesEx - Unable to open %s for capability detection", strHwName.c_str()); continue; } /* see if we can get ELD for this device */ if (info.m_deviceType == AE_DEVTYPE_HDMI) { bool badHDMI = false; if (hctl && !GetELD(hctl, dev, info, badHDMI)) CLog::Log(LOGDEBUG, "CAESinkALSA::EnumerateDevicesEx - Unable to obtain ELD information for device %s, make sure you have ALSA >= 1.0.25", info.m_deviceName.c_str()); if (badHDMI) { CLog::Log(LOGDEBUG, "CAESinkALSA::EnumerateDevicesEx - Skipping HDMI device %s as it has no ELD data", info.m_deviceName.c_str()); continue; } } /* ensure we can get a playback configuration for the device */ if (snd_pcm_hw_params_any(pcmhandle, hwparams) < 0) { CLog::Log(LOGINFO, "CAESinkALSA::EnumerateDevicesEx - No playback configurations available for device %s", info.m_deviceName.c_str()); snd_pcm_close(pcmhandle); continue; } /* detect the available sample rates */ for (unsigned int *rate = ALSASampleRateList; *rate != 0; ++rate) if (snd_pcm_hw_params_test_rate(pcmhandle, hwparams, *rate, 0) >= 0) info.m_sampleRates.push_back(*rate); /* detect the channels available */ int channels = 0; for (int i = 1; i <= ALSA_MAX_CHANNELS; ++i) if (snd_pcm_hw_params_test_channels(pcmhandle, hwparams, i) >= 0) channels = i; CAEChannelInfo alsaChannels; for (int i = 0; i < channels; ++i) { if (!info.m_channels.HasChannel(ALSAChannelMap[i])) info.m_channels += ALSAChannelMap[i]; alsaChannels += ALSAChannelMap[i]; } /* remove the channels from m_channels that we cant use */ info.m_channels.ResolveChannels(alsaChannels); /* detect the PCM sample formats that are available */ for (enum AEDataFormat i = AE_FMT_MAX; i > AE_FMT_INVALID; i = (enum AEDataFormat)((int)i - 1)) { if (AE_IS_RAW(i) || i == AE_FMT_MAX) continue; snd_pcm_format_t fmt = AEFormatToALSAFormat(i); if (fmt == SND_PCM_FORMAT_UNKNOWN) continue; if (snd_pcm_hw_params_test_format(pcmhandle, hwparams, fmt) >= 0) info.m_dataFormats.push_back(i); } snd_pcm_close(pcmhandle); list.push_back(info); } /* snd_hctl_close also closes ctlhandle */ if (hctl) snd_hctl_close(hctl); else snd_ctl_close(ctlhandle); } }
int main() { int cardNumber = -1; int errNum; char *controlType; char deviceID[16]; // ------------------------------------------------------------------------ // ALSA control elements. // ------------------------------------------------------------------------ snd_ctl_t *ctl; // Simple control handle. snd_ctl_elem_id_t *id; // Simple control element id. snd_ctl_elem_value_t *control; // Simple control element value. snd_ctl_elem_type_t type; // Simple control element type. snd_ctl_elem_info_t *info; // Simple control element info container. snd_ctl_card_info_t *card; // Simple control card info container. snd_hctl_t *hctl; // High level control handle; snd_hctl_elem_t *elem; // High level control element handle. // ------------------------------------------------------------------------ // Initialise ALSA card and device types. // ------------------------------------------------------------------------ snd_ctl_card_info_alloca( &card ); snd_ctl_elem_value_alloca( &control ); snd_ctl_elem_id_alloca( &id ); snd_ctl_elem_info_alloca( &info ); // ------------------------------------------------------------------------ // Start card section. // ------------------------------------------------------------------------ // For each card. while (1) { // Find next card number. If < 0 then returns 1st card. errNum = snd_card_next( &cardNumber ); if (( errNum < 0 ) || ( cardNumber < 0 )) break; // Concatenate strings to get card's control interface. sprintf( deviceID, "hw:%i", cardNumber ); // Try to open card. if ( snd_ctl_open( &ctl, deviceID, 0 ) < 0 ) { printf( "Error opening card.\n" ); continue; } // Fill control card info element. if ( snd_ctl_card_info( ctl, card ) < 0 ) { printf( "Error getting card info.\n" ); continue; } // -------------------------------------------------------------------- // Print header block. // -------------------------------------------------------------------- printf( "\t+-----------------------------" ); printf( "-----------------------------+\n" ); printf( "\t| Card: %d - %-46s |", cardNumber, snd_ctl_card_info_get_name( card )); printf( "\n" ); printf( "\t+--------+------------" ); printf( "+------------------------------------+\n" ); printf( "\t| Device | Type " ); printf( "| Name |\n" ); printf( "\t+--------+------------" ); printf( "+------------------------------------+\n" ); // -------------------------------------------------------------------- // Start control section. // -------------------------------------------------------------------- // Open an empty high level control. if ( snd_hctl_open( &hctl, deviceID, 0 ) < 0 ) printf( "Error opening high level control.\n" ); // Load high level control element. if ( snd_hctl_load( hctl ) < 0 ) printf( "Error loading high level control.\n" ); // -------------------------------------------------------------------- // For each control element. // -------------------------------------------------------------------- for ( elem = snd_hctl_first_elem( hctl ); elem; elem = snd_hctl_elem_next( elem )) { // Get ID of high level control element. snd_hctl_elem_get_id( elem, id ); // ---------------------------------------------------------------- // Determine control type. // ---------------------------------------------------------------- if ( snd_hctl_elem_info( elem, info ) < 0 ) printf( "Can't get control information.\n" ); type = snd_ctl_elem_info_get_type( info ); switch ( type ) { case SND_CTL_ELEM_TYPE_NONE: controlType = "None"; break; case SND_CTL_ELEM_TYPE_BOOLEAN: controlType = "Boolean"; break; case SND_CTL_ELEM_TYPE_INTEGER: controlType = "Integer"; break; case SND_CTL_ELEM_TYPE_INTEGER64: controlType = "Integer64"; break; case SND_CTL_ELEM_TYPE_ENUMERATED: controlType = "Enumerated"; break; case SND_CTL_ELEM_TYPE_BYTES: controlType = "Bytes"; break; case SND_CTL_ELEM_TYPE_IEC958: controlType = "IEC958"; break; default: controlType = "Not Found"; break; } printf( "\t| %-6i | %-10s | %-34s |\n", snd_hctl_elem_get_numid( elem ), controlType, snd_hctl_elem_get_name( elem )); } printf( "\t+--------+------------" ); printf( "+------------------------------------+\n\n" ); // -------------------------------------------------------------------- // Tidy up. // -------------------------------------------------------------------- snd_hctl_close( hctl ); snd_ctl_close( ctl ); } return 0; }