📄 rtaudio.cpp
字号:
error(RtError::MEMORY_ERROR); } // Get the array of AudioDeviceIDs. err = AudioHardwareGetProperty(kAudioHardwarePropertyDevices, &dataSize, (void *) deviceList); if (err != noErr) { free(deviceList); sprintf(message_, "RtApiCore: OS-X error getting device properties!"); error(RtError::SYSTEM_ERROR); } // Create list of device structures and write device identifiers. RtApiDevice device; AudioDeviceID *id; for (int i=0; i<nDevices_; i++) { devices_.push_back(device); id = (AudioDeviceID *) malloc( sizeof(AudioDeviceID) ); *id = deviceList[i]; devices_[i].apiDeviceId = (void *) id; } free(deviceList);}int RtApiCore :: getDefaultInputDevice(void){ AudioDeviceID id, *deviceId; UInt32 dataSize = sizeof( AudioDeviceID ); OSStatus result = AudioHardwareGetProperty( kAudioHardwarePropertyDefaultInputDevice, &dataSize, &id ); if (result != noErr) { sprintf( message_, "RtApiCore: OS-X error getting default input device." ); error(RtError::WARNING); return 0; } for ( int i=0; i<nDevices_; i++ ) { deviceId = (AudioDeviceID *) devices_[i].apiDeviceId; if ( id == *deviceId ) return i; } return 0;}int RtApiCore :: getDefaultOutputDevice(void){ AudioDeviceID id, *deviceId; UInt32 dataSize = sizeof( AudioDeviceID ); OSStatus result = AudioHardwareGetProperty( kAudioHardwarePropertyDefaultOutputDevice, &dataSize, &id ); if (result != noErr) { sprintf( message_, "RtApiCore: OS-X error getting default output device." ); error(RtError::WARNING); return 0; } for ( int i=0; i<nDevices_; i++ ) { deviceId = (AudioDeviceID *) devices_[i].apiDeviceId; if ( id == *deviceId ) return i; } return 0;}static bool deviceSupportsFormat( AudioDeviceID id, bool isInput, AudioStreamBasicDescription *desc, bool isDuplex ){ OSStatus result = noErr; UInt32 dataSize = sizeof( AudioStreamBasicDescription ); result = AudioDeviceGetProperty( id, 0, isInput, kAudioDevicePropertyStreamFormatSupported, &dataSize, desc ); if (result == kAudioHardwareNoError) { if ( isDuplex ) { result = AudioDeviceGetProperty( id, 0, true, kAudioDevicePropertyStreamFormatSupported, &dataSize, desc ); if (result != kAudioHardwareNoError) return false; } return true; } return false;}void RtApiCore :: probeDeviceInfo( RtApiDevice *info ){ OSStatus err = noErr; // Get the device manufacturer and name. char name[256]; char fullname[512]; UInt32 dataSize = 256; AudioDeviceID *id = (AudioDeviceID *) info->apiDeviceId; err = AudioDeviceGetProperty( *id, 0, false, kAudioDevicePropertyDeviceManufacturer, &dataSize, name ); if (err != noErr) { sprintf( message_, "RtApiCore: OS-X error getting device manufacturer." ); error(RtError::DEBUG_WARNING); return; } strncpy(fullname, name, 256); strcat(fullname, ": " ); dataSize = 256; err = AudioDeviceGetProperty( *id, 0, false, kAudioDevicePropertyDeviceName, &dataSize, name ); if (err != noErr) { sprintf( message_, "RtApiCore: OS-X error getting device name." ); error(RtError::DEBUG_WARNING); return; } strncat(fullname, name, 254); info->name.erase(); info->name.append( (const char *)fullname, strlen(fullname)+1); // Get output channel information. unsigned int i, minChannels = 0, maxChannels = 0, nStreams = 0; AudioBufferList *bufferList = nil; err = AudioDeviceGetPropertyInfo( *id, 0, false, kAudioDevicePropertyStreamConfiguration, &dataSize, NULL ); if (err == noErr && dataSize > 0) { bufferList = (AudioBufferList *) malloc( dataSize ); if (bufferList == NULL) { sprintf(message_, "RtApiCore: memory allocation error!"); error(RtError::DEBUG_WARNING); return; } err = AudioDeviceGetProperty( *id, 0, false, kAudioDevicePropertyStreamConfiguration, &dataSize, bufferList ); if (err == noErr) { maxChannels = 0; minChannels = 1000; nStreams = bufferList->mNumberBuffers; for ( i=0; i<nStreams; i++ ) { maxChannels += bufferList->mBuffers[i].mNumberChannels; if ( bufferList->mBuffers[i].mNumberChannels < minChannels ) minChannels = bufferList->mBuffers[i].mNumberChannels; } } } free (bufferList); if (err != noErr || dataSize <= 0) { sprintf( message_, "RtApiCore: OS-X error getting output channels for device (%s).", info->name.c_str() ); error(RtError::DEBUG_WARNING); return; } if ( nStreams ) { if ( maxChannels > 0 ) info->maxOutputChannels = maxChannels; if ( minChannels > 0 ) info->minOutputChannels = minChannels; } // Get input channel information. bufferList = nil; err = AudioDeviceGetPropertyInfo( *id, 0, true, kAudioDevicePropertyStreamConfiguration, &dataSize, NULL ); if (err == noErr && dataSize > 0) { bufferList = (AudioBufferList *) malloc( dataSize ); if (bufferList == NULL) { sprintf(message_, "RtApiCore: memory allocation error!"); error(RtError::DEBUG_WARNING); return; } err = AudioDeviceGetProperty( *id, 0, true, kAudioDevicePropertyStreamConfiguration, &dataSize, bufferList ); if (err == noErr) { maxChannels = 0; minChannels = 1000; nStreams = bufferList->mNumberBuffers; for ( i=0; i<nStreams; i++ ) { if ( bufferList->mBuffers[i].mNumberChannels < minChannels ) minChannels = bufferList->mBuffers[i].mNumberChannels; maxChannels += bufferList->mBuffers[i].mNumberChannels; } } } free (bufferList); if (err != noErr || dataSize <= 0) { sprintf( message_, "RtApiCore: OS-X error getting input channels for device (%s).", info->name.c_str() ); error(RtError::DEBUG_WARNING); return; } if ( nStreams ) { if ( maxChannels > 0 ) info->maxInputChannels = maxChannels; if ( minChannels > 0 ) info->minInputChannels = minChannels; } // If device opens for both playback and capture, we determine the channels. if (info->maxOutputChannels > 0 && info->maxInputChannels > 0) { info->hasDuplexSupport = true; info->maxDuplexChannels = (info->maxOutputChannels > info->maxInputChannels) ? info->maxInputChannels : info->maxOutputChannels; info->minDuplexChannels = (info->minOutputChannels > info->minInputChannels) ? info->minInputChannels : info->minOutputChannels; } // Probe the device sample rate and data format parameters. The // core audio query mechanism is performed on a "stream" // description, which can have a variable number of channels and // apply to input or output only. // Create a stream description structure. AudioStreamBasicDescription description; dataSize = sizeof( AudioStreamBasicDescription ); memset(&description, 0, sizeof(AudioStreamBasicDescription)); bool isInput = false; if ( info->maxOutputChannels == 0 ) isInput = true; bool isDuplex = false; if ( info->maxDuplexChannels > 0 ) isDuplex = true; // Determine the supported sample rates. info->sampleRates.clear(); for (unsigned int k=0; k<MAX_SAMPLE_RATES; k++) { description.mSampleRate = (double) SAMPLE_RATES[k]; if ( deviceSupportsFormat( *id, isInput, &description, isDuplex ) ) info->sampleRates.push_back( SAMPLE_RATES[k] ); } if (info->sampleRates.size() == 0) { sprintf( message_, "RtApiCore: No supported sample rates found for OS-X device (%s).", info->name.c_str() ); error(RtError::DEBUG_WARNING); return; } // Determine the supported data formats. info->nativeFormats = 0; description.mFormatID = kAudioFormatLinearPCM; description.mBitsPerChannel = 8; description.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsPacked | kLinearPCMFormatFlagIsBigEndian; if ( deviceSupportsFormat( *id, isInput, &description, isDuplex ) ) info->nativeFormats |= RTAUDIO_SINT8; else { description.mFormatFlags &= ~kLinearPCMFormatFlagIsBigEndian; if ( deviceSupportsFormat( *id, isInput, &description, isDuplex ) ) info->nativeFormats |= RTAUDIO_SINT8; } description.mBitsPerChannel = 16; description.mFormatFlags |= kLinearPCMFormatFlagIsBigEndian; if ( deviceSupportsFormat( *id, isInput, &description, isDuplex ) ) info->nativeFormats |= RTAUDIO_SINT16; else { description.mFormatFlags &= ~kLinearPCMFormatFlagIsBigEndian; if ( deviceSupportsFormat( *id, isInput, &description, isDuplex ) ) info->nativeFormats |= RTAUDIO_SINT16; } description.mBitsPerChannel = 32; description.mFormatFlags |= kLinearPCMFormatFlagIsBigEndian; if ( deviceSupportsFormat( *id, isInput, &description, isDuplex ) ) info->nativeFormats |= RTAUDIO_SINT32; else { description.mFormatFlags &= ~kLinearPCMFormatFlagIsBigEndian; if ( deviceSupportsFormat( *id, isInput, &description, isDuplex ) ) info->nativeFormats |= RTAUDIO_SINT32; } description.mBitsPerChannel = 24; description.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsAlignedHigh | kLinearPCMFormatFlagIsBigEndian; if ( deviceSupportsFormat( *id, isInput, &description, isDuplex ) ) info->nativeFormats |= RTAUDIO_SINT24; else { description.mFormatFlags &= ~kLinearPCMFormatFlagIsBigEndian; if ( deviceSupportsFormat( *id, isInput, &description, isDuplex ) ) info->nativeFormats |= RTAUDIO_SINT24; } description.mBitsPerChannel = 32; description.mFormatFlags = kLinearPCMFormatFlagIsFloat | kLinearPCMFormatFlagIsPacked | kLinearPCMFormatFlagIsBigEndian; if ( deviceSupportsFormat( *id, isInput, &description, isDuplex ) ) info->nativeFormats |= RTAUDIO_FLOAT32; else { description.mFormatFlags &= ~kLinearPCMFormatFlagIsBigEndian; if ( deviceSupportsFormat( *id, isInput, &description, isDuplex ) ) info->nativeFormats |= RTAUDIO_FLOAT32; } description.mBitsPerChannel = 64; description.mFormatFlags |= kLinearPCMFormatFlagIsBigEndian; if ( deviceSupportsFormat( *id, isInput, &description, isDuplex ) ) info->nativeFormats |= RTAUDIO_FLOAT64; else { description.mFormatFlags &= ~kLinearPCMFormatFlagIsBigEndian; if ( deviceSupportsFormat( *id, isInput, &description, isDuplex ) ) info->nativeFormats |= RTAUDIO_FLOAT64; } // Check that we have at least one supported format. if (info->nativeFormats == 0) { sprintf(message_, "RtApiCore: OS-X device (%s) data format not supported by RtAudio.", info->name.c_str()); error(RtError::DEBUG_WARNING); return; } info->probed = true;}OSStatus callbackHandler( AudioDeviceID inDevice, const AudioTimeStamp* inNow, const AudioBufferList* inInputData, const AudioTimeStamp* inInputTime, AudioBufferList* outOutputData, const AudioTimeStamp* inOutputTime, void* infoPointer ){ CallbackInfo *info = (CallbackInfo *) infoPointer; RtApiCore *object = (RtApiCore *) info->object; try { object->callbackEvent( inDevice, (void *)inInputData, (void *)outOutputData ); } catch (RtError &exception) { fprintf(stderr, "\nRtApiCore: callback handler error (%s)!\n\n", exception.getMessageString()); return kAudioHardwareUnspecifiedError; } return kAudioHardwareNoError;}OSStatus deviceListener( AudioDeviceID inDevice, UInt32 channel, Boolean isInput, AudioDevicePropertyID propertyID, void* handlePointer ){ CoreHandle *handle = (CoreHandle *) handlePointer; if ( propertyID == kAudioDeviceProcessorOverload ) { if ( isInput ) fprintf(stderr, "\nRtApiCore: OS-X audio input overrun detected!\n"); else fprintf(stderr, "\nRtApiCore: OS-X audio output underrun detected!\n"); handle->xrun = true; } return kAudioHardwareNoError;}bool RtApiCore :: probeDeviceOpen( int device, StreamMode mode, int channels, int sampleRate, RtAudioFormat format, int *bufferSize, int numberOfBuffers ){ // Setup for stream mode. bool isInput = false; AudioDeviceID id = *((AudioDeviceID *) devices_[device].apiDeviceId); if ( mode == INPUT ) isInput = true; // Search for a stream which contains the desired number of channels. OSStatus err = noErr; UInt32 dataSize; unsigned int deviceChannels, nStreams = 0; UInt32 iChannel = 0, iStream = 0; AudioBufferList *bufferList = nil; err = AudioDeviceGetPropertyInfo( id, 0, isInput, kAudioDevicePropertyStreamConfiguration, &dataSize, NULL ); if (err == noErr && dataSize > 0) { bufferList = (AudioBufferList *) malloc( dataSize ); if (bufferList == NULL) { sprintf(message_, "RtApiCore: memory allocation error in probeDeviceOpen()!"); error(RtError::DEBUG_WARNING); return FAILURE; } err = AudioDeviceGetProperty( id, 0, isInput, kAudioDevicePropertyStreamConfiguration, &dataSize, bufferList ); if (err == noErr) { stream_.deInterleave[mode] = false; nStreams = bufferList->mNumberBuffers; for ( iStream=0; iStream<nStreams; iStream++ ) { if ( bufferList->mBuffers[iStream].mNumberChannels >= (unsigned int) channels ) break; iChannel += bufferList->mBuffers[iStream].mNumberChannels; } // If we didn't find a single stream above, see if we can meet // the channel specification in mono mode (i.e. using separate // non-interleaved buffers). This can only work if there are N // consecutive one-channel streams, where N is the number of // desired channels. iChannel = 0; if ( iStream >= nStreams && nStreams >= (unsigned int) channels ) { int counter = 0; for ( iStream=0; iStream<nStreams; iS
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -