/** * @file adin_mic_freebsd.c * * * @brief マイク入力 (FreeBSD) * * マイク入力のための低レベル関数です.FreeBSDでこのファイルが使用されます. * * サウンドカードが 16bit モノラル で録音できることが必須です. * * JuliusはFreeBSDでミキサーデバイスの設定を一切行いません.録音デバイスの * 選択(マイク/ライン)や録音ボリュームの調節は他のツールで * 行なって下さい. * * デフォルトのデバイス名は "/dev/dsp" です.環境変数 AUDIODEV に * デバイス名を指定することで,他のデバイス名を使用できます. * * 動作確認はFreeBSD 3.2-RELEASE で行なわれました.サウンドドライバは * snd を使用しています. * * * @brief Microphone input on FreeBSD * * Low level I/O functions for microphone input on FreeBSD. * * To use microphone input in FreeBSD, sound card and sound driver must * support 16bit monaural recording. * * Julius does not alter any mixer device setting at all. You should * configure the mixer for recording source (mic/line) and recording volume * correctly using other audio tool. * * The default device name is "/dev/dsp", which can be changed by setting * environment variable AUDIODEV. * * Tested on FreeBSD 3.2-RELEASE with snd driver. * * * @author Akinobu LEE * @date Sun Feb 13 16:18:26 2005 * * $Revision: 1.8 $ * */ /* * Copyright (c) 1991-2012 Kawahara Lab., Kyoto University * Copyright (c) 2000-2005 Shikano Lab., Nara Institute of Science and Technology * Copyright (c) 2005-2012 Julius project team, Nagoya Institute of Technology * All rights reserved */ /* Thanks to Kentaro Nagatomo for information */ /* All functions are the same as OSS version, except the header filename */ #include #include #include #include #include #include #include /* sound header */ #if defined(HAVE_SYS_SOUNDCARD_H) #include #elif defined(HAVE_MACHINE_SOUNDCARD_H) #include #endif /// Default device name, can be overridden by AUDIODEV environment variable #define DEFAULT_DEVICE "/dev/dsp" static int srate; ///< Required sampling rate static int audio_fd; ///< Audio descriptor static boolean need_swap; ///< Whether input samples need byte-swapping struct pollfd fds[1]; ///< Workarea for polling device #define FREQALLOWRANGE 200 ///< Acceptable width of sampling frequency #define POLLINTERVAL 200 ///< Polling interval in miliseconds static char *defaultdev = DEFAULT_DEVICE; ///< Default device name static char devname[MAXPATHLEN]; ///< Current device name /** * Device initialization: check machine capability * * @param sfreq [in] required sampling frequency. * @param arg [in] a dummy data * * @return TRUE on success, FALSE on failure. */ boolean adin_mic_standby(int sfreq, void *arg) { /* store required sampling rate for checking after opening device */ srate = sfreq; return TRUE; } /** * Open the specified device and check capability of the opening device. * * @param devstr [in] device string to open * * @return TRUE on success, FALSE on failure. */ static boolean adin_mic_open(char *devstr) { int fmt, fmt_can, fmt1, fmt2, rfmt; /* sampling format */ int samplerate; /* actual sampling rate */ int stereo; /* mono */ char *p; /* open device */ if ((audio_fd = open(devstr, O_RDONLY)) == -1) { jlog("Error: adin_freebsd: failed to open %s\n", devstr); return(FALSE); } /* check whether soundcard can record 16bit data */ /* and set fmt */ if (ioctl(audio_fd, SNDCTL_DSP_GETFMTS, &fmt_can) == -1) { jlog("Error: adin_freebsd: failed to get formats from audio device\n"); return(FALSE); } #ifdef WORDS_BIGENDIAN fmt1 = AFMT_S16_BE; fmt2 = AFMT_S16_LE; #else fmt1 = AFMT_S16_LE; /* 16bit signed (little endian) */ fmt2 = AFMT_S16_BE; /* (big endian) */ #endif /* WORDS_BIGENDIAN */ /* fmt2 needs byte swap */ if (fmt_can & fmt1) { fmt = fmt1; need_swap = FALSE; } else if (fmt_can & fmt2) { fmt = fmt2; need_swap = TRUE; } else { jlog("Error: adin_freebsd: 16bit recording not supported on this device\n"); return FALSE; } #ifdef DEBUG if (need_swap) { jlog("Stat: adin_freebsd: samples need swap\n"); } else { jlog("Stat: adin_freebsd: samples need not swap\n"); } #endif if (close(audio_fd) != 0) return FALSE; /* re-open for recording */ /* open device */ if ((audio_fd = open(devstr, O_RDONLY)) == -1) { jlog("Error: adin_freebsd: failed to open %s", devstr); return(FALSE); } /* set format, samplerate, channels */ rfmt = fmt; if (ioctl(audio_fd, SNDCTL_DSP_SETFMT, &rfmt) == -1) { jlog("Error: adin_freebsd: failed to get available formats from device\n"); return(FALSE); } if (rfmt != fmt) { jlog("Error: adin_freebsd: 16bit recording is not supported on this device\n"); return FALSE; } stereo = 0; /* mono */ if (ioctl(audio_fd, SNDCTL_DSP_STEREO, &stereo) == -1) { jlog("Error: adin_freebsd: failed to set monoral recording\n"); return(FALSE); } if (stereo != 0) { jlog("Error: adin_freebsd: monoral recording not supported on this device\n"); return FALSE; } samplerate = srate; if (ioctl(audio_fd, SNDCTL_DSP_SPEED, &samplerate) == -1) { jlog("Erorr: adin_freebsd: failed to set sample rate to %dHz\n", srate); return(FALSE); } if (samplerate < srate - FREQALLOWRANGE || samplerate > srate + FREQALLOWRANGE) { jlog("Error: adin_freebsd: failed to set sampling rate to near %dHz. (%d)\n", srate, samplerate); return FALSE; } if (samplerate != srate) { jlog("Warning: adin_freebsd: specified sampling rate was %dHz but set to %dHz, \n", srate, samplerate); } /* set polling status */ fds[0].fd = audio_fd; fds[0].events = POLLIN; return TRUE; } /** * Start recording. * * @param pathname [in] path name to open or NULL for default * * @return TRUE on success, FALSE on failure. */ boolean adin_mic_begin(char *pathname) { /* set device name */ if (pathname != NULL) { strncpy(devname, pathname, MAXPATHLEN); jlog("Stat: adin_freebsd: device name = %s (from argument)\n", devname); } else if ((p = getenv("AUDIODEV")) != NULL) { strncpy(devname, p, MAXPATHLEN); jlog("Stat: adin_freebsd: device name = %s (from AUDIODEV)\n", devname); } else { strncpy(devname, defaultdev, MAXPATHLEN); jlog("Stat: adin_freebsd: device name = %s (application default)\n", devname); } /* open the device */ return(adin_mic_open(devname)); } /** * Stop recording. * * @return TRUE on success, FALSE on failure. */ boolean adin_mic_end() { if (close(audio_fd) != 0) return FALSE; return TRUE; } /** * @brief Read samples from device * * Try to read @a sampnum samples and returns actual number of recorded * samples currently available. This function will block until at least one * sample can be obtained. * * @param buf [out] samples obtained in this function * @param sampnum [in] wanted number of samples to be read * * @return actural number of read samples, -2 if error. */ int adin_mic_read(SP16 *buf, int sampnum) { int size,cnt; audio_buf_info info; /* wait till at least one sample can be read */ poll(fds, 1, POLLINTERVAL); /* get actual sample num in the device buffer */ if (ioctl(audio_fd, SNDCTL_DSP_GETISPACE, &info) == -1) { jlog("Error: adin_freebsd: adin_mic_read: sndctl_dsp_getispace"); return(-2); } /* get them as much as possible */ size = sampnum * sizeof(SP16); if (size > info.bytes) size = info.bytes; cnt = read(audio_fd, buf, size); if ( cnt < 0 ) { jlog("Error: adin_freebsd: adin_mic_read: read error\n"); return ( -2 ); } cnt /= sizeof(short); if (need_swap) swap_sample_bytes(buf, cnt); return(cnt); } /** * * Function to return current input source device name * * @return string of current input device name. * */ char * adin_mic_input_name() { return(devname); }