📄 rtaudio.cpp
字号:
{ return stream_.state;}RtAudioDeviceInfo RtApi :: getDeviceInfo( int device ){ if (device > (int) devices_.size() || device < 1) { sprintf(message_, "RtApi: invalid device specifier (%d)!", device); error(RtError::INVALID_DEVICE); } RtAudioDeviceInfo info; int deviceIndex = device - 1; // If the device wasn't successfully probed before, try it now (or again). if (devices_[deviceIndex].probed == false) { clearDeviceInfo(&devices_[deviceIndex]); probeDeviceInfo(&devices_[deviceIndex]); } info.name.append( devices_[deviceIndex].name ); info.probed = devices_[deviceIndex].probed; if ( info.probed == true ) { info.outputChannels = devices_[deviceIndex].maxOutputChannels; info.inputChannels = devices_[deviceIndex].maxInputChannels; info.duplexChannels = devices_[deviceIndex].maxDuplexChannels; for (unsigned int i=0; i<devices_[deviceIndex].sampleRates.size(); i++) info.sampleRates.push_back( devices_[deviceIndex].sampleRates[i] ); info.nativeFormats = devices_[deviceIndex].nativeFormats; if ( (deviceIndex == getDefaultOutputDevice()) || (deviceIndex == getDefaultInputDevice()) ) info.isDefault = true; } return info;}char * const RtApi :: getStreamBuffer(void){ verifyStream(); return stream_.userBuffer;}int RtApi :: getDefaultInputDevice(void){ // Should be implemented in subclasses if appropriate. return 0;}int RtApi :: getDefaultOutputDevice(void){ // Should be implemented in subclasses if appropriate. return 0;}void RtApi :: closeStream(void){ // MUST be implemented in subclasses!}void RtApi :: probeDeviceInfo( RtApiDevice *info ){ // MUST be implemented in subclasses!}bool RtApi :: probeDeviceOpen( int device, StreamMode mode, int channels, int sampleRate, RtAudioFormat format, int *bufferSize, int numberOfBuffers ){ // MUST be implemented in subclasses! return FAILURE;}// *************************************************** ////// OS/API-specific methods.//// *************************************************** //#if defined(__LINUX_OSS__)#include <unistd.h>#include <sys/stat.h>#include <sys/types.h>#include <sys/ioctl.h>#include <unistd.h>#include <fcntl.h>#include <sys/soundcard.h>#include <errno.h>#include <math.h>#define DAC_NAME "/dev/dsp"#define MAX_DEVICES 16#define MAX_CHANNELS 16extern "C" void *ossCallbackHandler(void * ptr);RtApiOss :: RtApiOss(){ this->initialize(); if (nDevices_ <= 0) { sprintf(message_, "RtApiOss: no Linux OSS audio devices found!"); error(RtError::NO_DEVICES_FOUND); }}RtApiOss :: ~RtApiOss(){ if ( stream_.mode != UNINITIALIZED ) closeStream();}void RtApiOss :: initialize(void){ // Count cards and devices nDevices_ = 0; // We check /dev/dsp before probing devices. /dev/dsp is supposed to // be a link to the "default" audio device, of the form /dev/dsp0, // /dev/dsp1, etc... However, I've seen many cases where /dev/dsp was a // real device, so we need to check for that. Also, sometimes the // link is to /dev/dspx and other times just dspx. I'm not sure how // the latter works, but it does. char device_name[16]; struct stat dspstat; int dsplink = -1; int i = 0; if (lstat(DAC_NAME, &dspstat) == 0) { if (S_ISLNK(dspstat.st_mode)) { i = readlink(DAC_NAME, device_name, sizeof(device_name)); if (i > 0) { device_name[i] = '\0'; if (i > 8) { // check for "/dev/dspx" if (!strncmp(DAC_NAME, device_name, 8)) dsplink = atoi(&device_name[8]); } else if (i > 3) { // check for "dspx" if (!strncmp("dsp", device_name, 3)) dsplink = atoi(&device_name[3]); } } else { sprintf(message_, "RtApiOss: cannot read value of symbolic link %s.", DAC_NAME); error(RtError::SYSTEM_ERROR); } } } else { sprintf(message_, "RtApiOss: cannot stat %s.", DAC_NAME); error(RtError::SYSTEM_ERROR); } // The OSS API doesn't provide a routine for determining the number // of devices. Thus, we'll just pursue a brute force method. The // idea is to start with /dev/dsp(0) and continue with higher device // numbers until we reach MAX_DSP_DEVICES. This should tell us how // many devices we have ... it is not a fullproof scheme, but hopefully // it will work most of the time. int fd = 0; RtApiDevice device; for (i=-1; i<MAX_DEVICES; i++) { // Probe /dev/dsp first, since it is supposed to be the default device. if (i == -1) sprintf(device_name, "%s", DAC_NAME); else if (i == dsplink) continue; // We've aready probed this device via /dev/dsp link ... try next device. else sprintf(device_name, "%s%d", DAC_NAME, i); // First try to open the device for playback, then record mode. fd = open(device_name, O_WRONLY | O_NONBLOCK); if (fd == -1) { // Open device for playback failed ... either busy or doesn't exist. if (errno != EBUSY && errno != EAGAIN) { // Try to open for capture fd = open(device_name, O_RDONLY | O_NONBLOCK); if (fd == -1) { // Open device for record failed. if (errno != EBUSY && errno != EAGAIN) continue; else { sprintf(message_, "RtApiOss: OSS record device (%s) is busy.", device_name); error(RtError::WARNING); // still count it for now } } } else { sprintf(message_, "RtApiOss: OSS playback device (%s) is busy.", device_name); error(RtError::WARNING); // still count it for now } } if (fd >= 0) close(fd); device.name.erase(); device.name.append( (const char *)device_name, strlen(device_name)+1); devices_.push_back(device); nDevices_++; }}void RtApiOss :: probeDeviceInfo(RtApiDevice *info){ int i, fd, channels, mask; // The OSS API doesn't provide a means for probing the capabilities // of devices. Thus, we'll just pursue a brute force method. // First try for playback fd = open(info->name.c_str(), O_WRONLY | O_NONBLOCK); if (fd == -1) { // Open device failed ... either busy or doesn't exist if (errno == EBUSY || errno == EAGAIN) sprintf(message_, "RtApiOss: OSS playback device (%s) is busy and cannot be probed.", info->name.c_str()); else sprintf(message_, "RtApiOss: OSS playback device (%s) open error.", info->name.c_str()); error(RtError::DEBUG_WARNING); goto capture_probe; } // We have an open device ... see how many channels it can handle for (i=MAX_CHANNELS; i>0; i--) { channels = i; if (ioctl(fd, SNDCTL_DSP_CHANNELS, &channels) == -1) { // This would normally indicate some sort of hardware error, but under ALSA's // OSS emulation, it sometimes indicates an invalid channel value. Further, // the returned channel value is not changed. So, we'll ignore the possible // hardware error. continue; // try next channel number } // Check to see whether the device supports the requested number of channels if (channels != i ) continue; // try next channel number // If here, we found the largest working channel value break; } info->maxOutputChannels = i; // Now find the minimum number of channels it can handle for (i=1; i<=info->maxOutputChannels; i++) { channels = i; if (ioctl(fd, SNDCTL_DSP_CHANNELS, &channels) == -1 || channels != i) continue; // try next channel number // If here, we found the smallest working channel value break; } info->minOutputChannels = i; close(fd); capture_probe: // Now try for capture fd = open(info->name.c_str(), O_RDONLY | O_NONBLOCK); if (fd == -1) { // Open device for capture failed ... either busy or doesn't exist if (errno == EBUSY || errno == EAGAIN) sprintf(message_, "RtApiOss: OSS capture device (%s) is busy and cannot be probed.", info->name.c_str()); else sprintf(message_, "RtApiOss: OSS capture device (%s) open error.", info->name.c_str()); error(RtError::DEBUG_WARNING); if (info->maxOutputChannels == 0) // didn't open for playback either ... device invalid return; goto probe_parameters; } // We have the device open for capture ... see how many channels it can handle for (i=MAX_CHANNELS; i>0; i--) { channels = i; if (ioctl(fd, SNDCTL_DSP_CHANNELS, &channels) == -1 || channels != i) { continue; // as above } // If here, we found a working channel value break; } info->maxInputChannels = i; // Now find the minimum number of channels it can handle for (i=1; i<=info->maxInputChannels; i++) { channels = i; if (ioctl(fd, SNDCTL_DSP_CHANNELS, &channels) == -1 || channels != i) continue; // try next channel number // If here, we found the smallest working channel value break; } info->minInputChannels = i; close(fd); if (info->maxOutputChannels == 0 && info->maxInputChannels == 0) { sprintf(message_, "RtApiOss: device (%s) reports zero channels for input and output.", info->name.c_str()); error(RtError::DEBUG_WARNING); return; } // If device opens for both playback and capture, we determine the channels. if (info->maxOutputChannels == 0 || info->maxInputChannels == 0) goto probe_parameters; fd = open(info->name.c_str(), O_RDWR | O_NONBLOCK); if (fd == -1) goto probe_parameters; ioctl(fd, SNDCTL_DSP_SETDUPLEX, 0); ioctl(fd, SNDCTL_DSP_GETCAPS, &mask); if (mask & DSP_CAP_DUPLEX) { info->hasDuplexSupport = true; // We have the device open for duplex ... see how many channels it can handle for (i=MAX_CHANNELS; i>0; i--) { channels = i; if (ioctl(fd, SNDCTL_DSP_CHANNELS, &channels) == -1 || channels != i) continue; // as above // If here, we found a working channel value break; } info->maxDuplexChannels = i; // Now find the minimum number of channels it can handle for (i=1; i<=info->maxDuplexChannels; i++) { channels = i; if (ioctl(fd, SNDCTL_DSP_CHANNELS, &channels) == -1 || channels != i) continue; // try next channel number // If here, we found the smallest working channel value break; } info->minDuplexChannels = i; } close(fd); probe_parameters: // At this point, we need to figure out the supported data formats // and sample rates. We'll proceed by openning the device in the // direction with the maximum number of channels, or playback if // they are equal. This might limit our sample rate options, but so // be it. if (info->maxOutputChannels >= info->maxInputChannels) { fd = open(info->name.c_str(), O_WRONLY | O_NONBLOCK); channels = info->maxOutputChannels; } else { fd = open(info->name.c_str(), O_RDONLY | O_NONBLOCK); channels = info->maxInputChannels; } if (fd == -1) { // We've got some sort of conflict ... abort sprintf(message_, "RtApiOss: device (%s) won't reopen during probe.", info->name.c_str()); error(RtError::DEBUG_WARNING); return; } // We have an open device ... set to maximum channels. i = channels; if (ioctl(fd, SNDCTL_DSP_CHANNELS, &channels) == -1 || channels != i) { // We've got some sort of conflict ... abort close(fd); sprintf(message_, "RtApiOss: device (%s) won't revert to previous channel setting.", info->name.c_str()); error(RtError::DEBUG_WARNING); return; } if (ioctl(fd, SNDCTL_DSP_GETFMTS, &mask) == -1) { close(fd); sprintf(message_, "RtApiOss: device (%s) can't get supported audio formats.", info->name.c_str()); error(RtError::DEBUG_WARNING); return; } // Probe the supported data formats ... we don't care about endian-ness just yet. int format; info->nativeFormats = 0;#if defined (AFMT_S32_BE) // This format does not seem to be in the 2.4 kernel version of OSS soundcard.h if (mask & AFMT_S32_BE) { format = AFMT_S32_BE; info->nativeFormats |= RTAUDIO_SINT32; }#endif#if defined (AFMT_S32_LE) /* This format is not in the 2.4.4 kernel version of OSS soundcard.h */ if (mask & AFMT_S32_LE) { format = AFMT_S32_LE; info->nativeFormats |= RTAUDIO_SINT32; }#endif if (mask & AFMT_S8) { format = AFMT_S8; info->nativeFormats |= RTAUDIO_SINT8; } if (mask & AFMT_S16_BE) { format = AFMT_S16_BE; info->nativeFormats |= RTAUDIO_SINT16; } if (mask & AFMT_S16_LE) { format = AFMT_S16_LE; info->nativeFormats |= RTAUDIO_SINT16; } // Check that we have at least one supported format if (info->nativeFormats == 0) { close(fd); sprintf(message_, "RtApiOss: device (%s) data format not supported by RtAudio.", info->name.c_str());
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -