/**
* @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);
}