📄 rtaudio.cpp
字号:
stream_.convertInfo[mode].inOffset.push_back( k ); stream_.convertInfo[mode].outOffset.push_back( k ); } } } return SUCCESS; error: if (handle) { if (handle[0]) close(handle[0]); free(handle); stream_.apiHandle = 0; } if (stream_.userBuffer) { free(stream_.userBuffer); stream_.userBuffer = 0; } error(RtError::DEBUG_WARNING); return FAILURE;}void RtApiOss :: closeStream(){ // We don't want an exception to be thrown here because this // function is called by our class destructor. So, do our own // stream check. if ( stream_.mode == UNINITIALIZED ) { sprintf(message_, "RtApiOss::closeStream(): no open stream to close!"); error(RtError::WARNING); return; } int *handle = (int *) stream_.apiHandle; if (stream_.state == STREAM_RUNNING) { if (stream_.mode == OUTPUT || stream_.mode == DUPLEX) ioctl(handle[0], SNDCTL_DSP_RESET, 0); else ioctl(handle[1], SNDCTL_DSP_RESET, 0); stream_.state = STREAM_STOPPED; } if (stream_.callbackInfo.usingCallback) { stream_.callbackInfo.usingCallback = false; pthread_join(stream_.callbackInfo.thread, NULL); } if (handle) { if (handle[0]) close(handle[0]); if (handle[1]) close(handle[1]); free(handle); stream_.apiHandle = 0; } if (stream_.userBuffer) { free(stream_.userBuffer); stream_.userBuffer = 0; } if (stream_.deviceBuffer) { free(stream_.deviceBuffer); stream_.deviceBuffer = 0; } stream_.mode = UNINITIALIZED;}void RtApiOss :: startStream(){ verifyStream(); if (stream_.state == STREAM_RUNNING) return; MUTEX_LOCK(&stream_.mutex); stream_.state = STREAM_RUNNING; // No need to do anything else here ... OSS automatically starts // when fed samples. MUTEX_UNLOCK(&stream_.mutex);}void RtApiOss :: stopStream(){ verifyStream(); if (stream_.state == STREAM_STOPPED) return; // Change the state before the lock to improve shutdown response // when using a callback. stream_.state = STREAM_STOPPED; MUTEX_LOCK(&stream_.mutex); int err; int *handle = (int *) stream_.apiHandle; if (stream_.mode == OUTPUT || stream_.mode == DUPLEX) { err = ioctl(handle[0], SNDCTL_DSP_POST, 0); //err = ioctl(handle[0], SNDCTL_DSP_SYNC, 0); if (err < -1) { sprintf(message_, "RtApiOss: error stopping device (%s).", devices_[stream_.device[0]].name.c_str()); error(RtError::DRIVER_ERROR); } } else { err = ioctl(handle[1], SNDCTL_DSP_POST, 0); //err = ioctl(handle[1], SNDCTL_DSP_SYNC, 0); if (err < -1) { sprintf(message_, "RtApiOss: error stopping device (%s).", devices_[stream_.device[1]].name.c_str()); error(RtError::DRIVER_ERROR); } } MUTEX_UNLOCK(&stream_.mutex);}void RtApiOss :: abortStream(){ stopStream();}int RtApiOss :: streamWillBlock(){ verifyStream(); if (stream_.state == STREAM_STOPPED) return 0; MUTEX_LOCK(&stream_.mutex); int bytes = 0, channels = 0, frames = 0; audio_buf_info info; int *handle = (int *) stream_.apiHandle; if (stream_.mode == OUTPUT || stream_.mode == DUPLEX) { ioctl(handle[0], SNDCTL_DSP_GETOSPACE, &info); bytes = info.bytes; channels = stream_.nDeviceChannels[0]; } if (stream_.mode == INPUT || stream_.mode == DUPLEX) { ioctl(handle[1], SNDCTL_DSP_GETISPACE, &info); if (stream_.mode == DUPLEX ) { bytes = (bytes < info.bytes) ? bytes : info.bytes; channels = stream_.nDeviceChannels[0]; } else { bytes = info.bytes; channels = stream_.nDeviceChannels[1]; } } frames = (int) (bytes / (channels * formatBytes(stream_.deviceFormat[0]))); frames -= stream_.bufferSize; if (frames < 0) frames = 0; MUTEX_UNLOCK(&stream_.mutex); return frames;}void RtApiOss :: tickStream(){ verifyStream(); int stopStream = 0; if (stream_.state == STREAM_STOPPED) { if (stream_.callbackInfo.usingCallback) usleep(50000); // sleep 50 milliseconds return; } else if (stream_.callbackInfo.usingCallback) { RtAudioCallback callback = (RtAudioCallback) stream_.callbackInfo.callback; stopStream = callback(stream_.userBuffer, stream_.bufferSize, stream_.callbackInfo.userData); } MUTEX_LOCK(&stream_.mutex); // The state might change while waiting on a mutex. if (stream_.state == STREAM_STOPPED) goto unlock; int result, *handle; char *buffer; int samples; RtAudioFormat format; handle = (int *) stream_.apiHandle; if (stream_.mode == OUTPUT || stream_.mode == DUPLEX) { // Setup parameters and do buffer conversion if necessary. if (stream_.doConvertBuffer[0]) { buffer = stream_.deviceBuffer; convertBuffer( buffer, stream_.userBuffer, stream_.convertInfo[0] ); samples = stream_.bufferSize * stream_.nDeviceChannels[0]; format = stream_.deviceFormat[0]; } else { buffer = stream_.userBuffer; samples = stream_.bufferSize * stream_.nUserChannels[0]; format = stream_.userFormat; } // Do byte swapping if necessary. if (stream_.doByteSwap[0]) byteSwapBuffer(buffer, samples, format); // Write samples to device. result = write(handle[0], buffer, samples * formatBytes(format)); if (result == -1) { // This could be an underrun, but the basic OSS API doesn't provide a means for determining that. sprintf(message_, "RtApiOss: audio write error for device (%s).", devices_[stream_.device[0]].name.c_str()); error(RtError::DRIVER_ERROR); } } if (stream_.mode == INPUT || stream_.mode == DUPLEX) { // Setup parameters. if (stream_.doConvertBuffer[1]) { buffer = stream_.deviceBuffer; samples = stream_.bufferSize * stream_.nDeviceChannels[1]; format = stream_.deviceFormat[1]; } else { buffer = stream_.userBuffer; samples = stream_.bufferSize * stream_.nUserChannels[1]; format = stream_.userFormat; } // Read samples from device. result = read(handle[1], buffer, samples * formatBytes(format)); if (result == -1) { // This could be an overrun, but the basic OSS API doesn't provide a means for determining that. sprintf(message_, "RtApiOss: audio read error for device (%s).", devices_[stream_.device[1]].name.c_str()); error(RtError::DRIVER_ERROR); } // Do byte swapping if necessary. if (stream_.doByteSwap[1]) byteSwapBuffer(buffer, samples, format); // Do buffer conversion if necessary. if (stream_.doConvertBuffer[1]) convertBuffer( stream_.userBuffer, stream_.deviceBuffer, stream_.convertInfo[1] ); } unlock: MUTEX_UNLOCK(&stream_.mutex); if (stream_.callbackInfo.usingCallback && stopStream) this->stopStream();}void RtApiOss :: setStreamCallback(RtAudioCallback callback, void *userData){ verifyStream(); CallbackInfo *info = (CallbackInfo *) &stream_.callbackInfo; if ( info->usingCallback ) { sprintf(message_, "RtApiOss: A callback is already set for this stream!"); error(RtError::WARNING); return; } info->callback = (void *) callback; info->userData = userData; info->usingCallback = true; info->object = (void *) this; // Set the thread attributes for joinable and realtime scheduling // priority. The higher priority will only take affect if the // program is run as root or suid. pthread_attr_t attr; pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); pthread_attr_setschedpolicy(&attr, SCHED_RR); int err = pthread_create(&(info->thread), &attr, ossCallbackHandler, &stream_.callbackInfo); pthread_attr_destroy(&attr); if (err) { info->usingCallback = false; sprintf(message_, "RtApiOss: error starting callback thread!"); error(RtError::THREAD_ERROR); }}void RtApiOss :: cancelStreamCallback(){ verifyStream(); if (stream_.callbackInfo.usingCallback) { if (stream_.state == STREAM_RUNNING) stopStream(); MUTEX_LOCK(&stream_.mutex); stream_.callbackInfo.usingCallback = false; pthread_join(stream_.callbackInfo.thread, NULL); stream_.callbackInfo.thread = 0; stream_.callbackInfo.callback = NULL; stream_.callbackInfo.userData = NULL; MUTEX_UNLOCK(&stream_.mutex); }}extern "C" void *ossCallbackHandler(void *ptr){ CallbackInfo *info = (CallbackInfo *) ptr; RtApiOss *object = (RtApiOss *) info->object; bool *usingCallback = &info->usingCallback; while ( *usingCallback ) { pthread_testcancel(); try { object->tickStream(); } catch (RtError &exception) { fprintf(stderr, "\nRtApiOss: callback thread error (%s) ... closing thread.\n\n", exception.getMessageString()); break; } } return 0;}//******************** End of __LINUX_OSS__ *********************//#endif#if defined(__MACOSX_CORE__)// The OS X CoreAudio API is designed to use a separate callback// procedure for each of its audio devices. A single RtAudio duplex// stream using two different devices is supported here, though it// cannot be guaranteed to always behave correctly because we cannot// synchronize these two callbacks. This same functionality can be// achieved with better synchrony by opening two separate streams for// the devices and using RtAudio blocking calls (i.e. tickStream()).//// A property listener is installed for over/underrun information.// However, no functionality is currently provided to allow property// listeners to trigger user handlers because it is unclear what could// be done if a critical stream parameter (buffer size, sample rate,// device disconnect) notification arrived. The listeners entail// quite a bit of extra code and most likely, a user program wouldn't// be prepared for the result anyway.// A structure to hold various information related to the CoreAudio API// implementation.struct CoreHandle { UInt32 index[2]; bool stopStream; bool xrun; char *deviceBuffer; pthread_cond_t condition; CoreHandle() :stopStream(false), xrun(false), deviceBuffer(0) {}};RtApiCore :: RtApiCore(){ this->initialize(); if (nDevices_ <= 0) { sprintf(message_, "RtApiCore: no Macintosh OS-X Core Audio devices found!"); error(RtError::NO_DEVICES_FOUND); }}RtApiCore :: ~RtApiCore(){ // The subclass destructor gets called before the base class // destructor, so close an existing stream before deallocating // apiDeviceId memory. if ( stream_.mode != UNINITIALIZED ) closeStream(); // Free our allocated apiDeviceId memory. AudioDeviceID *id; for ( unsigned int i=0; i<devices_.size(); i++ ) { id = (AudioDeviceID *) devices_[i].apiDeviceId; if (id) free(id); }}void RtApiCore :: initialize(void){ OSStatus err = noErr; UInt32 dataSize; AudioDeviceID *deviceList = NULL; nDevices_ = 0; // Find out how many audio devices there are, if any. err = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDevices, &dataSize, NULL); if (err != noErr) { sprintf(message_, "RtApiCore: OS-X error getting device info!"); error(RtError::SYSTEM_ERROR); } nDevices_ = dataSize / sizeof(AudioDeviceID); if (nDevices_ == 0) return; // Make space for the devices we are about to get. deviceList = (AudioDeviceID *) malloc( dataSize ); if (deviceList == NULL) { sprintf(message_, "RtApiCore: memory allocation error during initialization!");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -