📄 adin_mic_linux_alsa.c
字号:
/** * @file adin_mic_linux_alsa.c * * <JA> * @brief マイク掐蜗 (Linux/ALSA) * * ALSA API を蝗脱する·マイク掐蜗のための你レベル簇眶ですˉ * 蝗脱には ALSA サウンドドライバ〖がインスト〖ルされていることが涩妥ですˉ * * サウンドカ〖ドが 16bit モノラル で峡不できることが涩寇ですˉ * * JuliusはLinuxではミキサ〖デバイスの肋年を办磊乖いませんˉ峡不デバイスの * 联买∈マイク/ライン∷や峡不ボリュ〖ムの拇泪は alsamixer など戮のツ〖ルで * 乖なって布さいˉ * * 剩眶サウンドカ〖ドはサポ〖トされていませんˉ剩眶のサウンドカ〖ドが * インスト〖ルされている眷圭·呵介の1つが脱いられますˉ * * バ〖ジョン 1.x に滦炳していますˉ1.0.13 で瓢侯を澄千しましたˉ * * デバイス叹は "default" が蝗脱されますˉ茨董恃眶 ALSADEV で恃构できますˉ * </JA> * <EN> * @brief Microphone input on Linux/ALSA * * Low level I/O functions for microphone input on Linux using * Advanced Linux Sound Architechture (ALSA) API, developed on version 0.9.x. * * Julius does not alter any mixer device setting at all on Linux. You should * configure the mixer for recording source (mic/line) and recording volume * correctly using other audio tool such as alsamixer. * * Note that sound card should support 16bit monaural recording, and multiple * cards are not supported (in that case the first one will be used). * * This file supports alsa version 1.x, and tested on 1.0.13. * * The default PCM device name is "default", and can be overwritten by * environment variable "ALSADEV". * </EN> * * @sa http://www.alsa-project.org/ * * @author Akinobu LEE * @date Sun Feb 13 16:18:26 2005 * * $Revision: 1.9 $ * *//* * Copyright (c) 1991-2007 Kawahara Lab., Kyoto University * Copyright (c) 2000-2005 Shikano Lab., Nara Institute of Science and Technology * Copyright (c) 2005-2007 Julius project team, Nagoya Institute of Technology * All rights reserved */#include <sent/stddefs.h>#include <sent/adin.h>#include <sys/ioctl.h>#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#ifdef HAS_ALSA#if defined(HAVE_ALSA_ASOUNDLIB_H)#include <alsa/asoundlib.h>#elif defined(HAVE_SYS_ASOUNDLIB_H)#include <sys/asoundlib.h>#endifstatic snd_pcm_t *handle; ///< Audio handlerstatic char *pcm_name = "default"; ///< Name of the PCM device, can be overridden by env ALSADEVstatic int latency = 32; ///< Lantency time in msec. You can override this value by specifying environment valuable "LATENCY_MSEC".static boolean need_swap; ///< Whether samples need byte swap#if (SND_LIB_MAJOR == 0)static struct pollfd *ufds; ///< Poll descriptorstatic int count; ///< Poll descriptor count#endif#define MAXPOLLINTERVAL 300 ///< Read timeout in msec.#endif /* HAS_ALSA */#ifdef HAS_ALSA/** * Output detailed device information. * * @param pcm_name [in] device name string * @param handle [in] pcm audio handler * */static voidoutput_card_info(char *pcm_name, snd_pcm_t *handle){ int err; snd_ctl_t *ctl; snd_ctl_card_info_t *info; snd_pcm_info_t *pcminfo; snd_ctl_card_info_alloca(&info); snd_pcm_info_alloca(&pcminfo); char ctlname[30]; int card; /* get PCM information to set current device and subdevice name */ if ((err = snd_pcm_info(handle, pcminfo)) < 0) { jlog("Warning: adin_alsa: failed to obtain pcm info\n"); jlog("Warning: adin_alsa: skip output of detailed audio device info\n"); return; } /* open control associated with the pcm device name */ card = snd_pcm_info_get_card(pcminfo); if (card < 0) { strcpy(ctlname, "default"); } else { snprintf(ctlname, 30, "hw:%d", card); } if ((err = snd_ctl_open(&ctl, ctlname, 0)) < 0) { jlog("Warning: adin_alsa: failed to open control device \"%s\", \n", ctlname); jlog("Warning: adin_alsa: skip output of detailed audio device info\n"); return; } /* get its card info */ if ((err = snd_ctl_card_info(ctl, info)) < 0) { jlog("Warning: adin_alsa: unable to get card info for %s\n", ctlname); jlog("Warning: adin_alsa: skip output of detailed audio device info\n"); snd_ctl_close(ctl); return; } /* get detailed PCM information of current device from control */ if ((err = snd_ctl_pcm_info(ctl, pcminfo)) < 0) { jlog("Error: adin_alsa: unable to get pcm info from card control\n"); jlog("Warning: adin_alsa: skip output of detailed audio device info\n"); snd_ctl_close(ctl); return; } /* output */ jlog("Stat: \"%s\": %s [%s] device %s [%s] %s\n", pcm_name, snd_ctl_card_info_get_id(info), snd_ctl_card_info_get_name(info), snd_pcm_info_get_id(pcminfo), snd_pcm_info_get_name(pcminfo), snd_pcm_info_get_subdevice_name(pcminfo)); /* close controller */ snd_ctl_close(ctl);}#endif /* HAS_ALSA *//** * Device initialization: check device capability and open for recording. * * @param sfreq [in] required sampling frequency. * @param dummy [in] a dummy data * * @return TRUE on success, FALSE on failure. */booleanadin_alsa_standby(int sfreq, void *dummy){#ifndef HAS_ALSA jlog("Error: ALSA not compiled in\n"); return FALSE;#else int err; snd_pcm_hw_params_t *hwparams; ///< Pointer to device hardware parameters#if (SND_LIB_MAJOR == 0) int actual_rate; /* sample rate returned by hardware */#else unsigned int actual_rate; /* sample rate returned by hardware */#endif int dir = 0; /* comparison result of exact rate and given rate */ char *p; /* check $ALSADEV for device name */ if ((p = getenv("ALSADEV")) != NULL) { pcm_name = p; jlog("Stat: adin_alsa: device name from ALSADEV: \"%s\"\n", pcm_name); } /* open device in non-block mode) */ if ((err = snd_pcm_open(&handle, pcm_name, SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK)) < 0) { jlog("Error: adin_alsa: cannot open PCM device \"%s\" (%s)\n", pcm_name, snd_strerror(err)); return(FALSE); } /* set device to non-block mode */ if ((err = snd_pcm_nonblock(handle, 1)) < 0) { jlog("Error: adin_alsa: cannot set PCM device to non-blocking mode\n"); return(FALSE); } /* allocate hwparam structure */ snd_pcm_hw_params_alloca(&hwparams); /* initialize hwparam structure */ if ((err = snd_pcm_hw_params_any(handle, hwparams)) < 0) { jlog("Error: adin_alsa: cannot initialize PCM device parameter structure (%s)\n", snd_strerror(err)); return(FALSE); } /* set interleaved read/write format */ if ((err = snd_pcm_hw_params_set_access(handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) { jlog("Error: adin_alsa: cannot set PCM device access mode (%s)\n", snd_strerror(err)); return(FALSE); } /* set sample format */#ifdef WORDS_BIGENDIAN /* try big endian, then little endian with byte swap */ if ((err = snd_pcm_hw_params_set_format(handle, hwparams, SND_PCM_FORMAT_S16_BE)) >= 0) { need_swap = FALSE; } else if ((err = snd_pcm_hw_params_set_format(handle, hwparams, SND_PCM_FORMAT_S16_LE)) >= 0) { need_swap = TRUE; } else { jlog("Error: adin_alsa: cannot set PCM device format to signed 16bit (%s)\n", snd_strerror(err)); return(FALSE); }#else /* LITTLE ENDIAN */ /* try little endian, then big endian with byte swap */ if ((err = snd_pcm_hw_params_set_format(handle, hwparams, SND_PCM_FORMAT_S16_LE)) >= 0) { need_swap = FALSE; } else if ((err = snd_pcm_hw_params_set_format(handle, hwparams, SND_PCM_FORMAT_S16_BE)) >= 0) { need_swap = TRUE; } else { jlog("Error: adin_alsa: cannot set PCM device format to signed 16bit (%s)\n", snd_strerror(err)); return(FALSE); }#endif /* set number of channels */ if ((err = snd_pcm_hw_params_set_channels(handle, hwparams, 1)) < 0) { jlog("Error: adin_alsa: cannot set PCM channel to %d (%s)\n", 1, snd_strerror(err)); return(FALSE); } /* set sample rate (if the exact rate is not supported by the hardware, use nearest possible rate */#if (SND_LIB_MAJOR == 0) actual_rate = snd_pcm_hw_params_set_rate_near(handle, hwparams, sfreq, &dir); if (actual_rate < 0) { jlog("Error: adin_alsa: cannot set PCM device sample rate to %d (%s)\n", sfreq, snd_strerror(actual_rate)); return(FALSE); }#else actual_rate = sfreq; err = snd_pcm_hw_params_set_rate_near(handle, hwparams, &actual_rate, &dir); if (err < 0) { jlog("Error: adin_alsa: cannot set PCM device sample rate to %d (%s)\n", sfreq, snd_strerror(err)); return(FALSE); }#endif if (actual_rate != sfreq) { jlog("Warning: adin_alsa: the exact rate %d Hz is not available by your PCM hardware.\n", sfreq); jlog("Warning: adin_alsa: using %d Hz instead.\n", actual_rate); } jlog("Stat: capture audio at %dHz\n", actual_rate); /* set period size */ {#if (SND_LIB_MAJOR == 0) int periodsize; /* period size (bytes) */ int actual_size; int maxsize, minsize;#else unsigned int period_time, period_time_current; snd_pcm_uframes_t chunk_size; boolean has_current_period;#endif boolean force = FALSE; /* set apropriate period size */ if ((p = getenv("LATENCY_MSEC")) != NULL) { latency = atoi(p); jlog("Stat: adin_alsa: trying to set latency to %d msec from LATENCY_MSEC)\n", latency); force = TRUE; } /* get hardware max/min size */#if (SND_LIB_MAJOR == 0) if ((maxsize = snd_pcm_hw_params_get_period_size_max(hwparams, &dir)) < 0) { jlog("Error: adin_alsa: cannot get maximum period size\n");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -