CLAM-Development
1.1
|
00001 /* 00002 * Copyright (c) 2004 MUSIC TECHNOLOGY GROUP (MTG) 00003 * UNIVERSITAT POMPEU FABRA 00004 * 00005 * 00006 * This program is free software; you can redistribute it and/or modify 00007 * it under the terms of the GNU General Public License as published by 00008 * the Free Software Foundation; either version 2 of the License, or 00009 * (at your option) any later version. 00010 * 00011 * This program is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00014 * GNU General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU General Public License 00017 * along with this program; if not, write to the Free Software 00018 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 00019 * 00020 */ 00021 00022 /************************************************************************/ 00059 /************************************************************************/ 00060 00061 // RtAudio: Version 2.1.1, 24 October 2002 00062 00063 #include "RtAudio.hxx" 00064 #include <vector> 00065 #include <cstdio> 00066 #include <iostream> 00067 00068 // Static variable definitions. 00069 const unsigned int RtAudio :: SAMPLE_RATES[] = { 00070 4000, 5512, 8000, 9600, 11025, 16000, 22050, 00071 32000, 44100, 48000, 88200, 96000, 176400, 192000 00072 }; 00073 const RtAudio::RTAUDIO_FORMAT RtAudio :: RTAUDIO_SINT8 = 1; 00074 const RtAudio::RTAUDIO_FORMAT RtAudio :: RTAUDIO_SINT16 = 2; 00075 const RtAudio::RTAUDIO_FORMAT RtAudio :: RTAUDIO_SINT24 = 4; 00076 const RtAudio::RTAUDIO_FORMAT RtAudio :: RTAUDIO_SINT32 = 8; 00077 const RtAudio::RTAUDIO_FORMAT RtAudio :: RTAUDIO_FLOAT32 = 16; 00078 const RtAudio::RTAUDIO_FORMAT RtAudio :: RTAUDIO_FLOAT64 = 32; 00079 00080 #if defined(__WINDOWS_DS__) || defined(__WINDOWS_ASIO__) 00081 #define MUTEX_INITIALIZE(A) InitializeCriticalSection(A) 00082 #define MUTEX_LOCK(A) EnterCriticalSection(A) 00083 #define MUTEX_UNLOCK(A) LeaveCriticalSection(A) 00084 #else // pthread API 00085 #define MUTEX_INITIALIZE(A) pthread_mutex_init(A, NULL) 00086 #define MUTEX_LOCK(A) pthread_mutex_lock(A) 00087 #define MUTEX_UNLOCK(A) pthread_mutex_unlock(A) 00088 #endif 00089 00090 // *************************************************** // 00091 // 00092 // Public common (OS-independent) methods. 00093 // 00094 // *************************************************** // 00095 00096 RtAudio :: RtAudio() 00097 { 00098 initialize(); 00099 00100 if (nDevices <= 0) { 00101 sprintf(message, "RtAudio: no audio devices found!"); 00102 error(RtError::NO_DEVICES_FOUND); 00103 } 00104 } 00105 00106 RtAudio :: RtAudio(int *streamId, 00107 int outputDevice, int outputChannels, 00108 int inputDevice, int inputChannels, 00109 RTAUDIO_FORMAT format, int sampleRate, 00110 int *bufferSize, int numberOfBuffers) 00111 { 00112 initialize(); 00113 00114 if (nDevices <= 0) { 00115 sprintf(message, "RtAudio: no audio devices found!"); 00116 error(RtError::NO_DEVICES_FOUND); 00117 } 00118 00119 try { 00120 *streamId = openStream(outputDevice, outputChannels, inputDevice, inputChannels, 00121 format, sampleRate, bufferSize, numberOfBuffers); 00122 } 00123 catch (RtError &exception) { 00124 // deallocate the RTAUDIO_DEVICE structures 00125 if (devices) free(devices); 00126 throw exception; 00127 } 00128 } 00129 00130 RtAudio :: ~RtAudio() 00131 { 00132 // close any existing streams 00133 while ( streams.size() ) 00134 closeStream( streams.begin()->first ); 00135 00136 // deallocate the RTAUDIO_DEVICE structures 00137 if (devices) free(devices); 00138 } 00139 00140 int RtAudio :: openStream(int outputDevice, int outputChannels, 00141 int inputDevice, int inputChannels, 00142 RTAUDIO_FORMAT format, int sampleRate, 00143 int *bufferSize, int numberOfBuffers) 00144 { 00145 static int streamKey = 0; // Unique stream identifier ... OK for multiple instances. 00146 00147 if (outputChannels < 1 && inputChannels < 1) { 00148 sprintf(message,"RtAudio: one or both 'channel' parameters must be greater than zero."); 00149 error(RtError::INVALID_PARAMETER); 00150 } 00151 00152 if ( formatBytes(format) == 0 ) { 00153 sprintf(message,"RtAudio: 'format' parameter value is undefined."); 00154 error(RtError::INVALID_PARAMETER); 00155 } 00156 00157 if ( outputChannels > 0 ) { 00158 if (outputDevice > nDevices || outputDevice < 0) { 00159 sprintf(message,"RtAudio: 'outputDevice' parameter value (%d) is invalid.", outputDevice); 00160 error(RtError::INVALID_PARAMETER); 00161 } 00162 } 00163 00164 if ( inputChannels > 0 ) { 00165 if (inputDevice > nDevices || inputDevice < 0) { 00166 sprintf(message,"RtAudio: 'inputDevice' parameter value (%d) is invalid.", inputDevice); 00167 error(RtError::INVALID_PARAMETER); 00168 } 00169 } 00170 00171 // Allocate a new stream structure. 00172 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) calloc(1, sizeof(RTAUDIO_STREAM)); 00173 if (stream == NULL) { 00174 sprintf(message, "RtAudio: memory allocation error!"); 00175 error(RtError::MEMORY_ERROR); 00176 } 00177 stream->mode = UNINITIALIZED; 00178 MUTEX_INITIALIZE(&stream->mutex); 00179 00180 bool result = FAILURE; 00181 int device, defaultDevice = 0; 00182 STREAM_MODE mode; 00183 int channels; 00184 if ( outputChannels > 0 ) { 00185 00186 mode = OUTPUT; 00187 channels = outputChannels; 00188 00189 if ( outputDevice == 0 ) { // Try default device first. 00190 defaultDevice = getDefaultOutputDevice(); 00191 device = defaultDevice; 00192 } 00193 else 00194 device = outputDevice - 1; 00195 00196 for (int i=-1; i<nDevices; i++) { 00197 if (i >= 0 ) { 00198 if ( i == defaultDevice ) continue; 00199 device = i; 00200 } 00201 if (devices[device].probed == false) { 00202 // If the device wasn't successfully probed before, try it 00203 // again now. 00204 clearDeviceInfo(&devices[device]); 00205 probeDeviceInfo(&devices[device]); 00206 } 00207 if ( devices[device].probed ) 00208 result = probeDeviceOpen(device, stream, mode, channels, sampleRate, 00209 format, bufferSize, numberOfBuffers); 00210 if (result == SUCCESS) break; 00211 if ( outputDevice > 0 ) break; 00212 } 00213 } 00214 00215 if ( inputChannels > 0 && ( result == SUCCESS || outputChannels <= 0 ) ) { 00216 00217 mode = INPUT; 00218 channels = inputChannels; 00219 00220 if ( inputDevice == 0 ) { // Try default device first. 00221 defaultDevice = getDefaultInputDevice(); 00222 device = defaultDevice; 00223 } 00224 else 00225 device = inputDevice - 1; 00226 00227 for (int i=-1; i<nDevices; i++) { 00228 if (i >= 0 ) { 00229 if ( i == defaultDevice ) continue; 00230 device = i; 00231 } 00232 if (devices[device].probed == false) { 00233 // If the device wasn't successfully probed before, try it 00234 // again now. 00235 clearDeviceInfo(&devices[device]); 00236 probeDeviceInfo(&devices[device]); 00237 } 00238 if ( devices[device].probed ) 00239 result = probeDeviceOpen(device, stream, mode, channels, sampleRate, 00240 format, bufferSize, numberOfBuffers); 00241 if (result == SUCCESS) break; 00242 if ( outputDevice > 0 ) break; 00243 } 00244 } 00245 00246 streams[++streamKey] = (void *) stream; 00247 if ( result == SUCCESS ) 00248 return streamKey; 00249 00250 // If we get here, all attempted probes failed. Close any opened 00251 // devices and delete the allocated stream. 00252 closeStream(streamKey); 00253 if ( ( outputDevice == 0 && outputChannels > 0 ) 00254 || ( inputDevice == 0 && inputChannels > 0 ) ) 00255 sprintf(message,"RtAudio: no devices found for given parameters."); 00256 else 00257 sprintf(message,"RtAudio: unable to open specified device(s) with given stream parameters."); 00258 error(RtError::INVALID_PARAMETER); 00259 00260 return -1; 00261 } 00262 00263 int RtAudio :: getDeviceCount(void) 00264 { 00265 return nDevices; 00266 } 00267 00268 void RtAudio :: getDeviceInfo(int device, RTAUDIO_DEVICE *info) 00269 { 00270 if (device > nDevices || device < 1) { 00271 sprintf(message, "RtAudio: invalid device specifier (%d)!", device); 00272 error(RtError::INVALID_DEVICE); 00273 } 00274 00275 int deviceIndex = device - 1; 00276 00277 // If the device wasn't successfully probed before, try it now (or again). 00278 if (devices[deviceIndex].probed == false) { 00279 clearDeviceInfo(&devices[deviceIndex]); 00280 probeDeviceInfo(&devices[deviceIndex]); 00281 } 00282 00283 // Clear the info structure. 00284 memset(info, 0, sizeof(RTAUDIO_DEVICE)); 00285 00286 strncpy(info->name, devices[deviceIndex].name, 128); 00287 info->probed = devices[deviceIndex].probed; 00288 if ( info->probed == true ) { 00289 info->maxOutputChannels = devices[deviceIndex].maxOutputChannels; 00290 info->maxInputChannels = devices[deviceIndex].maxInputChannels; 00291 info->maxDuplexChannels = devices[deviceIndex].maxDuplexChannels; 00292 info->minOutputChannels = devices[deviceIndex].minOutputChannels; 00293 info->minInputChannels = devices[deviceIndex].minInputChannels; 00294 info->minDuplexChannels = devices[deviceIndex].minDuplexChannels; 00295 info->hasDuplexSupport = devices[deviceIndex].hasDuplexSupport; 00296 info->nSampleRates = devices[deviceIndex].nSampleRates; 00297 if (info->nSampleRates == -1) { 00298 info->sampleRates[0] = devices[deviceIndex].sampleRates[0]; 00299 info->sampleRates[1] = devices[deviceIndex].sampleRates[1]; 00300 } 00301 else { 00302 for (int i=0; i<info->nSampleRates; i++) 00303 info->sampleRates[i] = devices[deviceIndex].sampleRates[i]; 00304 } 00305 info->nativeFormats = devices[deviceIndex].nativeFormats; 00306 if ( deviceIndex == getDefaultOutputDevice() || 00307 deviceIndex == getDefaultInputDevice() ) 00308 info->isDefault = true; 00309 } 00310 00311 return; 00312 } 00313 00314 char * const RtAudio :: getStreamBuffer(int streamId) 00315 { 00316 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId); 00317 00318 return stream->userBuffer; 00319 } 00320 00321 #if defined(__LINUX_ALSA__) || defined(__LINUX_OSS__) || defined(__IRIX_AL__) 00322 00323 extern "C" void *callbackHandler(void * ptr); 00324 00325 void RtAudio :: setStreamCallback(int streamId, RTAUDIO_CALLBACK callback, void *userData) 00326 { 00327 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId); 00328 00329 CALLBACK_INFO *info = (CALLBACK_INFO *) &stream->callbackInfo; 00330 if ( info->usingCallback ) { 00331 sprintf(message, "RtAudio: A callback is already set for this stream!"); 00332 error(RtError::WARNING); 00333 return; 00334 } 00335 00336 info->callback = (void *) callback; 00337 info->userData = userData; 00338 info->usingCallback = true; 00339 info->object = (void *) this; 00340 info->streamId = streamId; 00341 00342 int err = pthread_create(&info->thread, NULL, callbackHandler, &stream->callbackInfo); 00343 00344 if (err) { 00345 info->usingCallback = false; 00346 sprintf(message, "RtAudio: error starting callback thread!"); 00347 error(RtError::THREAD_ERROR); 00348 } 00349 } 00350 00351 void RtAudio :: cancelStreamCallback(int streamId) 00352 { 00353 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId); 00354 00355 if (stream->callbackInfo.usingCallback) { 00356 00357 if (stream->state == STREAM_RUNNING) 00358 stopStream( streamId ); 00359 00360 MUTEX_LOCK(&stream->mutex); 00361 00362 stream->callbackInfo.usingCallback = false; 00363 pthread_cancel(stream->callbackInfo.thread); 00364 pthread_join(stream->callbackInfo.thread, NULL); 00365 stream->callbackInfo.thread = 0; 00366 stream->callbackInfo.callback = NULL; 00367 stream->callbackInfo.userData = NULL; 00368 00369 MUTEX_UNLOCK(&stream->mutex); 00370 } 00371 } 00372 00373 #endif 00374 00375 // *************************************************** // 00376 // 00377 // OS/API-specific methods. 00378 // 00379 // *************************************************** // 00380 00381 #if defined(__MACOSX_CORE__) 00382 00383 // The OS X CoreAudio API is designed to use a separate callback 00384 // procedure for each of its audio devices. A single RtAudio duplex 00385 // stream using two different devices is supported here, though it 00386 // cannot be guaranteed to always behave correctly because we cannot 00387 // synchronize these two callbacks. This same functionality can be 00388 // achieved with better synchrony by opening two separate streams for 00389 // the devices and using RtAudio blocking calls (i.e. tickStream()). 00390 // 00391 // The possibility of having multiple RtAudio streams accessing the 00392 // same CoreAudio device is not currently supported. The problem 00393 // involves the inability to install our callbackHandler function for 00394 // the same device more than once. I experimented with a workaround 00395 // for this, but it requires an additional buffer for mixing output 00396 // data before filling the CoreAudio device buffer. In the end, I 00397 // decided it wasn't worth supporting. 00398 // 00399 // Property listeners are currently not used. The issue is what could 00400 // be done if a critical stream parameter (buffer size, sample rate, 00401 // device disconnect) notification arrived. The listeners entail 00402 // quite a bit of extra code and most likely, a user program wouldn't 00403 // be prepared for the result anyway. Some initial listener code is 00404 // commented out. 00405 00406 void RtAudio :: initialize(void) 00407 { 00408 OSStatus err = noErr; 00409 UInt32 dataSize; 00410 AudioDeviceID *deviceList = NULL; 00411 nDevices = 0; 00412 00413 // Find out how many audio devices there are, if any. 00414 err = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDevices, &dataSize, NULL); 00415 if (err != noErr) { 00416 sprintf(message, "RtAudio: OSX error getting device info!"); 00417 error(RtError::SYSTEM_ERROR); 00418 } 00419 00420 nDevices = dataSize / sizeof(AudioDeviceID); 00421 if (nDevices == 0) return; 00422 00423 // Allocate the RTAUDIO_DEVICE structures. 00424 devices = (RTAUDIO_DEVICE *) calloc(nDevices, sizeof(RTAUDIO_DEVICE)); 00425 if (devices == NULL) { 00426 sprintf(message, "RtAudio: memory allocation error!"); 00427 error(RtError::MEMORY_ERROR); 00428 } 00429 00430 // Make space for the devices we are about to get. 00431 deviceList = (AudioDeviceID *) malloc( dataSize ); 00432 if (deviceList == NULL) { 00433 sprintf(message, "RtAudio: memory allocation error!"); 00434 error(RtError::MEMORY_ERROR); 00435 } 00436 00437 // Get the array of AudioDeviceIDs. 00438 err = AudioHardwareGetProperty(kAudioHardwarePropertyDevices, &dataSize, (void *) deviceList); 00439 if (err != noErr) { 00440 free(deviceList); 00441 sprintf(message, "RtAudio: OSX error getting device properties!"); 00442 error(RtError::SYSTEM_ERROR); 00443 } 00444 00445 // Write device identifiers to device structures and then 00446 // probe the device capabilities. 00447 for (int i=0; i<nDevices; i++) { 00448 devices[i].id[0] = deviceList[i]; 00449 //probeDeviceInfo(&devices[i]); 00450 } 00451 00452 free(deviceList); 00453 } 00454 00455 int RtAudio :: getDefaultInputDevice(void) 00456 { 00457 AudioDeviceID id; 00458 UInt32 dataSize = sizeof( AudioDeviceID ); 00459 00460 OSStatus result = AudioHardwareGetProperty( kAudioHardwarePropertyDefaultInputDevice, 00461 &dataSize, &id ); 00462 00463 if (result != noErr) { 00464 sprintf( message, "RtAudio: OSX error getting default input device." ); 00465 error(RtError::WARNING); 00466 return 0; 00467 } 00468 00469 for ( int i=0; i<nDevices; i++ ) { 00470 if ( id == devices[i].id[0] ) return i; 00471 } 00472 00473 return 0; 00474 } 00475 00476 int RtAudio :: getDefaultOutputDevice(void) 00477 { 00478 AudioDeviceID id; 00479 UInt32 dataSize = sizeof( AudioDeviceID ); 00480 00481 OSStatus result = AudioHardwareGetProperty( kAudioHardwarePropertyDefaultOutputDevice, 00482 &dataSize, &id ); 00483 00484 if (result != noErr) { 00485 sprintf( message, "RtAudio: OSX error getting default output device." ); 00486 error(RtError::WARNING); 00487 return 0; 00488 } 00489 00490 for ( int i=0; i<nDevices; i++ ) { 00491 if ( id == devices[i].id[0] ) return i; 00492 } 00493 00494 return 0; 00495 } 00496 00497 static bool deviceSupportsFormat( AudioDeviceID id, bool isInput, 00498 AudioStreamBasicDescription *desc, bool isDuplex ) 00499 { 00500 OSStatus result = noErr; 00501 UInt32 dataSize = sizeof( AudioStreamBasicDescription ); 00502 00503 result = AudioDeviceGetProperty( id, 0, isInput, 00504 kAudioDevicePropertyStreamFormatSupported, 00505 &dataSize, desc ); 00506 00507 if (result == kAudioHardwareNoError) { 00508 if ( isDuplex ) { 00509 result = AudioDeviceGetProperty( id, 0, true, 00510 kAudioDevicePropertyStreamFormatSupported, 00511 &dataSize, desc ); 00512 00513 00514 if (result != kAudioHardwareNoError) 00515 return false; 00516 } 00517 return true; 00518 } 00519 00520 return false; 00521 } 00522 00523 void RtAudio :: probeDeviceInfo(RTAUDIO_DEVICE *info) 00524 { 00525 OSStatus err = noErr; 00526 00527 // Get the device manufacturer and name. 00528 char name[256]; 00529 char fullname[512]; 00530 UInt32 dataSize = 256; 00531 err = AudioDeviceGetProperty( info->id[0], 0, false, 00532 kAudioDevicePropertyDeviceManufacturer, 00533 &dataSize, name ); 00534 if (err != noErr) { 00535 sprintf( message, "RtAudio: OSX error getting device manufacturer." ); 00536 error(RtError::DEBUG_WARNING); 00537 return; 00538 } 00539 strncpy(fullname, name, 256); 00540 strcat(fullname, ": " ); 00541 00542 dataSize = 256; 00543 err = AudioDeviceGetProperty( info->id[0], 0, false, 00544 kAudioDevicePropertyDeviceName, 00545 &dataSize, name ); 00546 if (err != noErr) { 00547 sprintf( message, "RtAudio: OSX error getting device name." ); 00548 error(RtError::DEBUG_WARNING); 00549 return; 00550 } 00551 strncat(fullname, name, 254); 00552 strncat(info->name, fullname, 128); 00553 00554 // Get output channel information. 00555 unsigned int i, minChannels, maxChannels, nStreams = 0; 00556 AudioBufferList *bufferList = nil; 00557 err = AudioDeviceGetPropertyInfo( info->id[0], 0, false, 00558 kAudioDevicePropertyStreamConfiguration, 00559 &dataSize, NULL ); 00560 if (err == noErr && dataSize > 0) { 00561 bufferList = (AudioBufferList *) malloc( dataSize ); 00562 if (bufferList == NULL) { 00563 sprintf(message, "RtAudio: memory allocation error!"); 00564 error(RtError::DEBUG_WARNING); 00565 return; 00566 } 00567 00568 err = AudioDeviceGetProperty( info->id[0], 0, false, 00569 kAudioDevicePropertyStreamConfiguration, 00570 &dataSize, bufferList ); 00571 if (err == noErr) { 00572 maxChannels = 0; 00573 minChannels = 1000; 00574 nStreams = bufferList->mNumberBuffers; 00575 for ( i=0; i<nStreams; i++ ) { 00576 maxChannels += bufferList->mBuffers[i].mNumberChannels; 00577 if ( bufferList->mBuffers[i].mNumberChannels < minChannels ) 00578 minChannels = bufferList->mBuffers[i].mNumberChannels; 00579 } 00580 } 00581 } 00582 if (err != noErr || dataSize <= 0) { 00583 sprintf( message, "RtAudio: OSX error getting output channels for device (%s).", info->name ); 00584 error(RtError::DEBUG_WARNING); 00585 return; 00586 } 00587 00588 free (bufferList); 00589 if ( nStreams ) { 00590 if ( maxChannels > 0 ) 00591 info->maxOutputChannels = maxChannels; 00592 if ( minChannels > 0 ) 00593 info->minOutputChannels = minChannels; 00594 } 00595 00596 // Get input channel information. 00597 bufferList = nil; 00598 err = AudioDeviceGetPropertyInfo( info->id[0], 0, true, 00599 kAudioDevicePropertyStreamConfiguration, 00600 &dataSize, NULL ); 00601 if (err == noErr && dataSize > 0) { 00602 bufferList = (AudioBufferList *) malloc( dataSize ); 00603 if (bufferList == NULL) { 00604 sprintf(message, "RtAudio: memory allocation error!"); 00605 error(RtError::DEBUG_WARNING); 00606 return; 00607 } 00608 err = AudioDeviceGetProperty( info->id[0], 0, true, 00609 kAudioDevicePropertyStreamConfiguration, 00610 &dataSize, bufferList ); 00611 if (err == noErr) { 00612 maxChannels = 0; 00613 minChannels = 1000; 00614 nStreams = bufferList->mNumberBuffers; 00615 for ( i=0; i<nStreams; i++ ) { 00616 if ( bufferList->mBuffers[i].mNumberChannels < minChannels ) 00617 minChannels = bufferList->mBuffers[i].mNumberChannels; 00618 maxChannels += bufferList->mBuffers[i].mNumberChannels; 00619 } 00620 } 00621 } 00622 if (err != noErr || dataSize <= 0) { 00623 sprintf( message, "RtAudio: OSX error getting input channels for device (%s).", info->name ); 00624 error(RtError::DEBUG_WARNING); 00625 return; 00626 } 00627 00628 free (bufferList); 00629 if ( nStreams ) { 00630 if ( maxChannels > 0 ) 00631 info->maxInputChannels = maxChannels; 00632 if ( minChannels > 0 ) 00633 info->minInputChannels = minChannels; 00634 } 00635 00636 // If device opens for both playback and capture, we determine the channels. 00637 if (info->maxOutputChannels > 0 && info->maxInputChannels > 0) { 00638 info->hasDuplexSupport = true; 00639 info->maxDuplexChannels = (info->maxOutputChannels > info->maxInputChannels) ? 00640 info->maxInputChannels : info->maxOutputChannels; 00641 info->minDuplexChannels = (info->minOutputChannels > info->minInputChannels) ? 00642 info->minInputChannels : info->minOutputChannels; 00643 } 00644 00645 // Probe the device sample rate and data format parameters. The 00646 // core audio query mechanism is performed on a "stream" 00647 // description, which can have a variable number of channels and 00648 // apply to input or output only. 00649 00650 // Create a stream description structure. 00651 AudioStreamBasicDescription description; 00652 dataSize = sizeof( AudioStreamBasicDescription ); 00653 memset(&description, 0, sizeof(AudioStreamBasicDescription)); 00654 bool isInput = false; 00655 if ( info->maxOutputChannels == 0 ) isInput = true; 00656 bool isDuplex = false; 00657 if ( info->maxDuplexChannels > 0 ) isDuplex = true; 00658 00659 // Determine the supported sample rates. 00660 info->nSampleRates = 0; 00661 for (i=0; i<MAX_SAMPLE_RATES; i++) { 00662 description.mSampleRate = (double) SAMPLE_RATES[i]; 00663 if ( deviceSupportsFormat( info->id[0], isInput, &description, isDuplex ) ) 00664 info->sampleRates[info->nSampleRates++] = SAMPLE_RATES[i]; 00665 } 00666 00667 if (info->nSampleRates == 0) { 00668 sprintf( message, "RtAudio: No supported sample rates found for OSX device (%s).", info->name ); 00669 error(RtError::DEBUG_WARNING); 00670 return; 00671 } 00672 00673 // Check for continuous sample rate support. 00674 description.mSampleRate = kAudioStreamAnyRate; 00675 if ( deviceSupportsFormat( info->id[0], isInput, &description, isDuplex ) ) { 00676 info->sampleRates[1] = info->sampleRates[info->nSampleRates-1]; 00677 info->nSampleRates = -1; 00678 } 00679 00680 // Determine the supported data formats. 00681 info->nativeFormats = 0; 00682 description.mFormatID = kAudioFormatLinearPCM; 00683 description.mBitsPerChannel = 8; 00684 description.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsPacked | kLinearPCMFormatFlagIsBigEndian; 00685 if ( deviceSupportsFormat( info->id[0], isInput, &description, isDuplex ) ) 00686 info->nativeFormats |= RTAUDIO_SINT8; 00687 else { 00688 description.mFormatFlags &= ~kLinearPCMFormatFlagIsBigEndian; 00689 if ( deviceSupportsFormat( info->id[0], isInput, &description, isDuplex ) ) 00690 info->nativeFormats |= RTAUDIO_SINT8; 00691 } 00692 00693 description.mBitsPerChannel = 16; 00694 description.mFormatFlags |= kLinearPCMFormatFlagIsBigEndian; 00695 if ( deviceSupportsFormat( info->id[0], isInput, &description, isDuplex ) ) 00696 info->nativeFormats |= RTAUDIO_SINT16; 00697 else { 00698 description.mFormatFlags &= ~kLinearPCMFormatFlagIsBigEndian; 00699 if ( deviceSupportsFormat( info->id[0], isInput, &description, isDuplex ) ) 00700 info->nativeFormats |= RTAUDIO_SINT16; 00701 } 00702 00703 description.mBitsPerChannel = 32; 00704 description.mFormatFlags |= kLinearPCMFormatFlagIsBigEndian; 00705 if ( deviceSupportsFormat( info->id[0], isInput, &description, isDuplex ) ) 00706 info->nativeFormats |= RTAUDIO_SINT32; 00707 else { 00708 description.mFormatFlags &= ~kLinearPCMFormatFlagIsBigEndian; 00709 if ( deviceSupportsFormat( info->id[0], isInput, &description, isDuplex ) ) 00710 info->nativeFormats |= RTAUDIO_SINT32; 00711 } 00712 00713 description.mBitsPerChannel = 24; 00714 description.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsAlignedHigh | kLinearPCMFormatFlagIsBigEndian; 00715 if ( deviceSupportsFormat( info->id[0], isInput, &description, isDuplex ) ) 00716 info->nativeFormats |= RTAUDIO_SINT24; 00717 else { 00718 description.mFormatFlags &= ~kLinearPCMFormatFlagIsBigEndian; 00719 if ( deviceSupportsFormat( info->id[0], isInput, &description, isDuplex ) ) 00720 info->nativeFormats |= RTAUDIO_SINT24; 00721 } 00722 00723 description.mBitsPerChannel = 32; 00724 description.mFormatFlags = kLinearPCMFormatFlagIsFloat | kLinearPCMFormatFlagIsPacked | kLinearPCMFormatFlagIsBigEndian; 00725 if ( deviceSupportsFormat( info->id[0], isInput, &description, isDuplex ) ) 00726 info->nativeFormats |= RTAUDIO_FLOAT32; 00727 else { 00728 description.mFormatFlags &= ~kLinearPCMFormatFlagIsBigEndian; 00729 if ( deviceSupportsFormat( info->id[0], isInput, &description, isDuplex ) ) 00730 info->nativeFormats |= RTAUDIO_FLOAT32; 00731 } 00732 00733 description.mBitsPerChannel = 64; 00734 description.mFormatFlags |= kLinearPCMFormatFlagIsBigEndian; 00735 if ( deviceSupportsFormat( info->id[0], isInput, &description, isDuplex ) ) 00736 info->nativeFormats |= RTAUDIO_FLOAT64; 00737 else { 00738 description.mFormatFlags &= ~kLinearPCMFormatFlagIsBigEndian; 00739 if ( deviceSupportsFormat( info->id[0], isInput, &description, isDuplex ) ) 00740 info->nativeFormats |= RTAUDIO_FLOAT64; 00741 } 00742 00743 // Check that we have at least one supported format. 00744 if (info->nativeFormats == 0) { 00745 sprintf(message, "RtAudio: OSX PCM device (%s) data format not supported by RtAudio.", 00746 info->name); 00747 error(RtError::DEBUG_WARNING); 00748 return; 00749 } 00750 00751 info->probed = true; 00752 } 00753 00754 OSStatus callbackHandler(AudioDeviceID inDevice, 00755 const AudioTimeStamp* inNow, 00756 const AudioBufferList* inInputData, 00757 const AudioTimeStamp* inInputTime, 00758 AudioBufferList* outOutputData, 00759 const AudioTimeStamp* inOutputTime, 00760 void* infoPointer) 00761 { 00762 CALLBACK_INFO *info = (CALLBACK_INFO *) infoPointer; 00763 00764 RtAudio *object = (RtAudio *) info->object; 00765 try { 00766 object->callbackEvent( info->streamId, inDevice, (void *)inInputData, (void *)outOutputData ); 00767 } 00768 catch (RtError &exception) { 00769 fprintf(stderr, "\nCallback handler error (%s)!\n\n", exception.getMessage()); 00770 return kAudioHardwareUnspecifiedError; 00771 } 00772 00773 return kAudioHardwareNoError; 00774 } 00775 00776 /* 00777 OSStatus deviceListener(AudioDeviceID inDevice, 00778 UInt32 channel, 00779 Boolean isInput, 00780 AudioDevicePropertyID propertyID, 00781 void* infoPointer) 00782 { 00783 CALLBACK_INFO *info = (CALLBACK_INFO *) infoPointer; 00784 00785 RtAudio *object = (RtAudio *) info->object; 00786 try { 00787 object->settingChange( info->streamId ); 00788 } 00789 catch (RtError &exception) { 00790 fprintf(stderr, "\nDevice listener error (%s)!\n\n", exception.getMessage()); 00791 return kAudioHardwareUnspecifiedError; 00792 } 00793 00794 return kAudioHardwareNoError; 00795 } 00796 */ 00797 00798 bool RtAudio :: probeDeviceOpen(int device, RTAUDIO_STREAM *stream, 00799 STREAM_MODE mode, int channels, 00800 int sampleRate, RTAUDIO_FORMAT format, 00801 int *bufferSize, int numberOfBuffers) 00802 { 00803 // Check to make sure we don't already have a stream accessing this device. 00804 RTAUDIO_STREAM *streamPtr; 00805 std::map<int, void *>::const_iterator i; 00806 for ( i=streams.begin(); i!=streams.end(); ++i ) { 00807 streamPtr = (RTAUDIO_STREAM *) i->second; 00808 if ( streamPtr->device[0] == device || streamPtr->device[1] == device ) { 00809 sprintf(message, "RtAudio: no current OS X support for multiple streams accessing the same device!"); 00810 error(RtError::WARNING); 00811 return FAILURE; 00812 } 00813 } 00814 00815 // Setup for stream mode. 00816 bool isInput = false; 00817 AudioDeviceID id = devices[device].id[0]; 00818 if ( mode == INPUT ) isInput = true; 00819 00820 // Search for a stream which contains the desired number of channels. 00821 OSStatus err = noErr; 00822 UInt32 dataSize; 00823 unsigned int deviceChannels, nStreams; 00824 UInt32 iChannel = 0, iStream = 0; 00825 AudioBufferList *bufferList = nil; 00826 err = AudioDeviceGetPropertyInfo( id, 0, isInput, 00827 kAudioDevicePropertyStreamConfiguration, 00828 &dataSize, NULL ); 00829 00830 if (err == noErr && dataSize > 0) { 00831 bufferList = (AudioBufferList *) malloc( dataSize ); 00832 if (bufferList == NULL) { 00833 sprintf(message, "RtAudio: memory allocation error!"); 00834 error(RtError::DEBUG_WARNING); 00835 return FAILURE; 00836 } 00837 err = AudioDeviceGetProperty( id, 0, isInput, 00838 kAudioDevicePropertyStreamConfiguration, 00839 &dataSize, bufferList ); 00840 00841 if (err == noErr) { 00842 stream->deInterleave[mode] = false; 00843 nStreams = bufferList->mNumberBuffers; 00844 for ( iStream=0; iStream<nStreams; iStream++ ) { 00845 if ( bufferList->mBuffers[iStream].mNumberChannels >= (unsigned int) channels ) break; 00846 iChannel += bufferList->mBuffers[iStream].mNumberChannels; 00847 } 00848 // If we didn't find a single stream above, see if we can meet 00849 // the channel specification in mono mode (i.e. using separate 00850 // non-interleaved buffers). This can only work if there are N 00851 // consecutive one-channel streams, where N is the number of 00852 // desired channels. 00853 iChannel = 0; 00854 if ( iStream >= nStreams && nStreams >= (unsigned int) channels ) { 00855 int counter = 0; 00856 for ( iStream=0; iStream<nStreams; iStream++ ) { 00857 if ( bufferList->mBuffers[iStream].mNumberChannels == 1 ) 00858 counter++; 00859 else 00860 counter = 0; 00861 if ( counter == channels ) { 00862 iStream -= channels - 1; 00863 iChannel -= channels - 1; 00864 stream->deInterleave[mode] = true; 00865 break; 00866 } 00867 iChannel += bufferList->mBuffers[iStream].mNumberChannels; 00868 } 00869 } 00870 } 00871 } 00872 if (err != noErr || dataSize <= 0) { 00873 if ( bufferList ) free( bufferList ); 00874 sprintf( message, "RtAudio: OSX error getting channels for device (%s).", devices[device].name ); 00875 error(RtError::DEBUG_WARNING); 00876 return FAILURE; 00877 } 00878 00879 if (iStream >= nStreams) { 00880 free (bufferList); 00881 sprintf( message, "RtAudio: unable to find OSX audio stream on device (%s) for requested channels (%d).", 00882 devices[device].name, channels ); 00883 error(RtError::DEBUG_WARNING); 00884 return FAILURE; 00885 } 00886 00887 // This is ok even for mono mode ... it gets updated later. 00888 deviceChannels = bufferList->mBuffers[iStream].mNumberChannels; 00889 free (bufferList); 00890 00891 // Determine the buffer size. 00892 AudioValueRange bufferRange; 00893 dataSize = sizeof(AudioValueRange); 00894 err = AudioDeviceGetProperty( id, 0, isInput, 00895 kAudioDevicePropertyBufferSizeRange, 00896 &dataSize, &bufferRange); 00897 if (err != noErr) { 00898 sprintf( message, "RtAudio: OSX error getting buffer size range for device (%s).", 00899 devices[device].name ); 00900 error(RtError::DEBUG_WARNING); 00901 return FAILURE; 00902 } 00903 00904 long bufferBytes = *bufferSize * deviceChannels * formatBytes(RTAUDIO_FLOAT32); 00905 if (bufferRange.mMinimum > bufferBytes) bufferBytes = (int) bufferRange.mMinimum; 00906 else if (bufferRange.mMaximum < bufferBytes) bufferBytes = (int) bufferRange.mMaximum; 00907 00908 // Set the buffer size. For mono mode, I'm assuming we only need to 00909 // make this setting for the first channel. 00910 UInt32 theSize = (UInt32) bufferBytes; 00911 dataSize = sizeof( UInt32); 00912 err = AudioDeviceSetProperty(id, NULL, 0, isInput, 00913 kAudioDevicePropertyBufferSize, 00914 dataSize, &theSize); 00915 if (err != noErr) { 00916 sprintf( message, "RtAudio: OSX error setting the buffer size for device (%s).", 00917 devices[device].name ); 00918 error(RtError::DEBUG_WARNING); 00919 return FAILURE; 00920 } 00921 00922 // If attempting to setup a duplex stream, the bufferSize parameter 00923 // MUST be the same in both directions! 00924 *bufferSize = bufferBytes / ( deviceChannels * formatBytes(RTAUDIO_FLOAT32) ); 00925 if ( stream->mode == OUTPUT && mode == INPUT && *bufferSize != stream->bufferSize ) { 00926 sprintf( message, "RtAudio: OSX error setting buffer size for duplex stream on device (%s).", 00927 devices[device].name ); 00928 error(RtError::DEBUG_WARNING); 00929 return FAILURE; 00930 } 00931 00932 stream->bufferSize = *bufferSize; 00933 stream->nBuffers = 1; 00934 00935 // Set the stream format description. Do for each channel in mono mode. 00936 AudioStreamBasicDescription description; 00937 dataSize = sizeof( AudioStreamBasicDescription ); 00938 if ( stream->deInterleave[mode] ) nStreams = channels; 00939 else nStreams = 1; 00940 for ( unsigned int i=0; i<nStreams; i++, iChannel++ ) { 00941 00942 err = AudioDeviceGetProperty( id, iChannel, isInput, 00943 kAudioDevicePropertyStreamFormat, 00944 &dataSize, &description ); 00945 if (err != noErr) { 00946 sprintf( message, "RtAudio: OSX error getting stream format for device (%s).", devices[device].name ); 00947 error(RtError::DEBUG_WARNING); 00948 return FAILURE; 00949 } 00950 00951 // Set the sample rate and data format id. 00952 description.mSampleRate = (double) sampleRate; 00953 description.mFormatID = kAudioFormatLinearPCM; 00954 err = AudioDeviceSetProperty( id, NULL, iChannel, isInput, 00955 kAudioDevicePropertyStreamFormat, 00956 dataSize, &description ); 00957 if (err != noErr) { 00958 sprintf( message, "RtAudio: OSX error setting sample rate or data format for device (%s).", devices[device].name ); 00959 error(RtError::DEBUG_WARNING); 00960 return FAILURE; 00961 } 00962 } 00963 00964 // Check whether we need byte-swapping (assuming OS X host is big-endian). 00965 iChannel -= nStreams; 00966 err = AudioDeviceGetProperty( id, iChannel, isInput, 00967 kAudioDevicePropertyStreamFormat, 00968 &dataSize, &description ); 00969 if (err != noErr) { 00970 sprintf( message, "RtAudio: OSX error getting stream format for device (%s).", devices[device].name ); 00971 error(RtError::DEBUG_WARNING); 00972 return FAILURE; 00973 } 00974 00975 stream->doByteSwap[mode] = false; 00976 if ( !description.mFormatFlags & kLinearPCMFormatFlagIsBigEndian ) 00977 stream->doByteSwap[mode] = true; 00978 00979 // From the CoreAudio documentation, PCM data must be supplied as 00980 // 32-bit floats. 00981 stream->userFormat = format; 00982 stream->deviceFormat[mode] = RTAUDIO_FLOAT32; 00983 00984 if ( stream->deInterleave[mode] ) 00985 stream->nDeviceChannels[mode] = channels; 00986 else 00987 stream->nDeviceChannels[mode] = description.mChannelsPerFrame; 00988 stream->nUserChannels[mode] = channels; 00989 00990 // Set handle and flags for buffer conversion. 00991 stream->handle[mode] = iStream; 00992 stream->doConvertBuffer[mode] = false; 00993 if (stream->userFormat != stream->deviceFormat[mode]) 00994 stream->doConvertBuffer[mode] = true; 00995 if (stream->nUserChannels[mode] < stream->nDeviceChannels[mode]) 00996 stream->doConvertBuffer[mode] = true; 00997 if (stream->nUserChannels[mode] > 1 && stream->deInterleave[mode]) 00998 stream->doConvertBuffer[mode] = true; 00999 01000 // Allocate necessary internal buffers. 01001 if ( stream->nUserChannels[0] != stream->nUserChannels[1] ) { 01002 01003 long buffer_bytes; 01004 if (stream->nUserChannels[0] >= stream->nUserChannels[1]) 01005 buffer_bytes = stream->nUserChannels[0]; 01006 else 01007 buffer_bytes = stream->nUserChannels[1]; 01008 01009 buffer_bytes *= *bufferSize * formatBytes(stream->userFormat); 01010 if (stream->userBuffer) free(stream->userBuffer); 01011 stream->userBuffer = (char *) calloc(buffer_bytes, 1); 01012 if (stream->userBuffer == NULL) 01013 goto memory_error; 01014 } 01015 01016 if ( stream->deInterleave[mode] ) { 01017 01018 long buffer_bytes; 01019 bool makeBuffer = true; 01020 if ( mode == OUTPUT ) 01021 buffer_bytes = stream->nDeviceChannels[0] * formatBytes(stream->deviceFormat[0]); 01022 else { // mode == INPUT 01023 buffer_bytes = stream->nDeviceChannels[1] * formatBytes(stream->deviceFormat[1]); 01024 if ( stream->mode == OUTPUT && stream->deviceBuffer ) { 01025 long bytes_out = stream->nDeviceChannels[0] * formatBytes(stream->deviceFormat[0]); 01026 if ( buffer_bytes < bytes_out ) makeBuffer = false; 01027 } 01028 } 01029 01030 if ( makeBuffer ) { 01031 buffer_bytes *= *bufferSize; 01032 if (stream->deviceBuffer) free(stream->deviceBuffer); 01033 stream->deviceBuffer = (char *) calloc(buffer_bytes, 1); 01034 if (stream->deviceBuffer == NULL) 01035 goto memory_error; 01036 01037 // If not de-interleaving, we point stream->deviceBuffer to the 01038 // OS X supplied device buffer before doing any necessary data 01039 // conversions. This presents a problem if we have a duplex 01040 // stream using one device which needs de-interleaving and 01041 // another device which doesn't. So, save a pointer to our own 01042 // device buffer in the CALLBACK_INFO structure. 01043 stream->callbackInfo.buffers = stream->deviceBuffer; 01044 } 01045 } 01046 01047 stream->sampleRate = sampleRate; 01048 stream->device[mode] = device; 01049 stream->state = STREAM_STOPPED; 01050 stream->callbackInfo.object = (void *) this; 01051 stream->callbackInfo.waitTime = (unsigned long) (200000.0 * stream->bufferSize / stream->sampleRate); 01052 stream->callbackInfo.device[mode] = id; 01053 if ( stream->mode == OUTPUT && mode == INPUT && stream->device[0] == device ) 01054 // Only one callback procedure per device. 01055 stream->mode = DUPLEX; 01056 else { 01057 err = AudioDeviceAddIOProc( id, callbackHandler, (void *) &stream->callbackInfo ); 01058 if (err != noErr) { 01059 sprintf( message, "RtAudio: OSX error setting callback for device (%s).", devices[device].name ); 01060 error(RtError::DEBUG_WARNING); 01061 return FAILURE; 01062 } 01063 if ( stream->mode == OUTPUT && mode == INPUT ) 01064 stream->mode = DUPLEX; 01065 else 01066 stream->mode = mode; 01067 } 01068 01069 // If we wanted to use property listeners, they would be setup here. 01070 01071 return SUCCESS; 01072 01073 memory_error: 01074 if (stream->userBuffer) { 01075 free(stream->userBuffer); 01076 stream->userBuffer = 0; 01077 } 01078 sprintf(message, "RtAudio: OSX error allocating buffer memory (%s).", devices[device].name); 01079 error(RtError::WARNING); 01080 return FAILURE; 01081 } 01082 01083 void RtAudio :: cancelStreamCallback(int streamId) 01084 { 01085 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId); 01086 01087 if (stream->callbackInfo.usingCallback) { 01088 01089 if (stream->state == STREAM_RUNNING) 01090 stopStream( streamId ); 01091 01092 MUTEX_LOCK(&stream->mutex); 01093 01094 stream->callbackInfo.usingCallback = false; 01095 stream->callbackInfo.userData = NULL; 01096 stream->state = STREAM_STOPPED; 01097 stream->callbackInfo.callback = NULL; 01098 01099 MUTEX_UNLOCK(&stream->mutex); 01100 } 01101 } 01102 01103 void RtAudio :: closeStream(int streamId) 01104 { 01105 // We don't want an exception to be thrown here because this 01106 // function is called by our class destructor. So, do our own 01107 // streamId check. 01108 if ( streams.find( streamId ) == streams.end() ) { 01109 sprintf(message, "RtAudio: invalid stream identifier!"); 01110 error(RtError::WARNING); 01111 return; 01112 } 01113 01114 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) streams[streamId]; 01115 01116 AudioDeviceID id; 01117 if (stream->mode == OUTPUT || stream->mode == DUPLEX) { 01118 id = devices[stream->device[0]].id[0]; 01119 if (stream->state == STREAM_RUNNING) 01120 AudioDeviceStop( id, callbackHandler ); 01121 AudioDeviceRemoveIOProc( id, callbackHandler ); 01122 } 01123 01124 if (stream->mode == INPUT || ( stream->mode == DUPLEX && stream->device[0] != stream->device[1]) ) { 01125 id = devices[stream->device[1]].id[0]; 01126 if (stream->state == STREAM_RUNNING) 01127 AudioDeviceStop( id, callbackHandler ); 01128 AudioDeviceRemoveIOProc( id, callbackHandler ); 01129 } 01130 01131 pthread_mutex_destroy(&stream->mutex); 01132 01133 if (stream->userBuffer) 01134 free(stream->userBuffer); 01135 01136 if ( stream->deInterleave[0] || stream->deInterleave[1] ) 01137 free(stream->callbackInfo.buffers); 01138 01139 free(stream); 01140 streams.erase(streamId); 01141 } 01142 01143 void RtAudio :: startStream(int streamId) 01144 { 01145 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId); 01146 01147 MUTEX_LOCK(&stream->mutex); 01148 01149 if (stream->state == STREAM_RUNNING) 01150 goto unlock; 01151 01152 OSStatus err; 01153 if (stream->mode == OUTPUT || stream->mode == DUPLEX) { 01154 01155 err = AudioDeviceStart(devices[stream->device[0]].id[0], callbackHandler); 01156 if (err != noErr) { 01157 sprintf(message, "RtAudio: OSX error starting callback procedure on device (%s).", 01158 devices[stream->device[0]].name); 01159 MUTEX_UNLOCK(&stream->mutex); 01160 error(RtError::DRIVER_ERROR); 01161 } 01162 } 01163 01164 if (stream->mode == INPUT || ( stream->mode == DUPLEX && stream->device[0] != stream->device[1]) ) { 01165 01166 err = AudioDeviceStart(devices[stream->device[1]].id[0], callbackHandler); 01167 if (err != noErr) { 01168 sprintf(message, "RtAudio: OSX error starting input callback procedure on device (%s).", 01169 devices[stream->device[0]].name); 01170 MUTEX_UNLOCK(&stream->mutex); 01171 error(RtError::DRIVER_ERROR); 01172 } 01173 } 01174 01175 stream->callbackInfo.streamId = streamId; 01176 stream->state = STREAM_RUNNING; 01177 stream->callbackInfo.blockTick = true; 01178 stream->callbackInfo.stopStream = false; 01179 01180 unlock: 01181 MUTEX_UNLOCK(&stream->mutex); 01182 } 01183 01184 void RtAudio :: stopStream(int streamId) 01185 { 01186 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId); 01187 01188 MUTEX_LOCK(&stream->mutex); 01189 01190 if (stream->state == STREAM_STOPPED) 01191 goto unlock; 01192 01193 OSStatus err; 01194 if (stream->mode == OUTPUT || stream->mode == DUPLEX) { 01195 01196 err = AudioDeviceStop(devices[stream->device[0]].id[0], callbackHandler); 01197 if (err != noErr) { 01198 sprintf(message, "RtAudio: OSX error stopping callback procedure on device (%s).", 01199 devices[stream->device[0]].name); 01200 MUTEX_UNLOCK(&stream->mutex); 01201 error(RtError::DRIVER_ERROR); 01202 } 01203 } 01204 01205 if (stream->mode == INPUT || ( stream->mode == DUPLEX && stream->device[0] != stream->device[1]) ) { 01206 01207 err = AudioDeviceStop(devices[stream->device[1]].id[0], callbackHandler); 01208 if (err != noErr) { 01209 sprintf(message, "RtAudio: OSX error stopping input callback procedure on device (%s).", 01210 devices[stream->device[0]].name); 01211 MUTEX_UNLOCK(&stream->mutex); 01212 error(RtError::DRIVER_ERROR); 01213 } 01214 } 01215 01216 stream->state = STREAM_STOPPED; 01217 01218 unlock: 01219 MUTEX_UNLOCK(&stream->mutex); 01220 } 01221 01222 void RtAudio :: abortStream(int streamId) 01223 { 01224 stopStream( streamId ); 01225 } 01226 01227 // I don't know how this function can be implemented. 01228 int RtAudio :: streamWillBlock(int streamId) 01229 { 01230 sprintf(message, "RtAudio: streamWillBlock() cannot be implemented for OS X."); 01231 error(RtError::WARNING); 01232 return 0; 01233 } 01234 01235 void RtAudio :: tickStream(int streamId) 01236 { 01237 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId); 01238 01239 if (stream->state == STREAM_STOPPED) 01240 return; 01241 01242 if (stream->callbackInfo.usingCallback) { 01243 sprintf(message, "RtAudio: tickStream() should not be used when a callback function is set!"); 01244 error(RtError::WARNING); 01245 return; 01246 } 01247 01248 // Block waiting here until the user data is processed in callbackEvent(). 01249 while ( stream->callbackInfo.blockTick ) 01250 usleep(stream->callbackInfo.waitTime); 01251 01252 MUTEX_LOCK(&stream->mutex); 01253 01254 stream->callbackInfo.blockTick = true; 01255 01256 MUTEX_UNLOCK(&stream->mutex); 01257 } 01258 01259 void RtAudio :: callbackEvent( int streamId, DEVICE_ID deviceId, void *inData, void *outData ) 01260 { 01261 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId); 01262 01263 CALLBACK_INFO *info; 01264 AudioBufferList *inBufferList = (AudioBufferList *) inData; 01265 AudioBufferList *outBufferList = (AudioBufferList *) outData; 01266 01267 if (stream->state == STREAM_STOPPED) return; 01268 01269 info = (CALLBACK_INFO *) &stream->callbackInfo; 01270 if ( !info->usingCallback ) { 01271 // Block waiting here until we get new user data in tickStream(). 01272 while ( !info->blockTick ) 01273 usleep(info->waitTime); 01274 } 01275 else if ( info->stopStream ) { 01276 // Check if the stream should be stopped (via the previous user 01277 // callback return value). We stop the stream here, rather than 01278 // after the function call, so that output data can first be 01279 // processed. 01280 this->stopStream(info->streamId); 01281 return; 01282 } 01283 01284 MUTEX_LOCK(&stream->mutex); 01285 01286 // Invoke user callback first, to get fresh output data. Don't 01287 // invoke the user callback if duplex mode, the input/output devices 01288 // are different, and this function is called for the input device. 01289 if ( info->usingCallback && (stream->mode != DUPLEX || deviceId == info->device[0] ) ) { 01290 RTAUDIO_CALLBACK callback = (RTAUDIO_CALLBACK) info->callback; 01291 info->stopStream = callback(stream->userBuffer, stream->bufferSize, info->userData); 01292 } 01293 01294 if ( stream->mode == OUTPUT || ( stream->mode == DUPLEX && deviceId == info->device[0] ) ) { 01295 01296 if (stream->doConvertBuffer[0]) { 01297 01298 if ( !stream->deInterleave[0] ) 01299 stream->deviceBuffer = (char *) outBufferList->mBuffers[stream->handle[0]].mData; 01300 else 01301 stream->deviceBuffer = (char *) stream->callbackInfo.buffers; 01302 01303 convertStreamBuffer(stream, OUTPUT); 01304 if ( stream->doByteSwap[0] ) 01305 byteSwapBuffer(stream->deviceBuffer, 01306 stream->bufferSize * stream->nDeviceChannels[0], 01307 stream->deviceFormat[0]); 01308 01309 if ( stream->deInterleave[0] ) { 01310 int bufferBytes = outBufferList->mBuffers[stream->handle[0]].mDataByteSize; 01311 for ( int i=0; i<stream->nDeviceChannels[0]; i++ ) { 01312 memcpy(outBufferList->mBuffers[stream->handle[0]+i].mData, 01313 &stream->deviceBuffer[i*bufferBytes], bufferBytes ); 01314 } 01315 } 01316 01317 } 01318 else { 01319 if (stream->doByteSwap[0]) 01320 byteSwapBuffer(stream->userBuffer, 01321 stream->bufferSize * stream->nUserChannels[0], 01322 stream->userFormat); 01323 01324 memcpy(outBufferList->mBuffers[stream->handle[0]].mData, 01325 stream->userBuffer, 01326 outBufferList->mBuffers[stream->handle[0]].mDataByteSize ); 01327 } 01328 } 01329 01330 if ( stream->mode == INPUT || ( stream->mode == DUPLEX && deviceId == info->device[1] ) ) { 01331 01332 if (stream->doConvertBuffer[1]) { 01333 01334 if ( stream->deInterleave[1] ) { 01335 stream->deviceBuffer = (char *) stream->callbackInfo.buffers; 01336 int bufferBytes = inBufferList->mBuffers[stream->handle[1]].mDataByteSize; 01337 for ( int i=0; i<stream->nDeviceChannels[1]; i++ ) { 01338 memcpy(&stream->deviceBuffer[i*bufferBytes], 01339 inBufferList->mBuffers[stream->handle[1]+i].mData, bufferBytes ); 01340 } 01341 } 01342 else 01343 stream->deviceBuffer = (char *) inBufferList->mBuffers[stream->handle[1]].mData; 01344 01345 if ( stream->doByteSwap[1] ) 01346 byteSwapBuffer(stream->deviceBuffer, 01347 stream->bufferSize * stream->nDeviceChannels[1], 01348 stream->deviceFormat[1]); 01349 convertStreamBuffer(stream, INPUT); 01350 01351 } 01352 else { 01353 memcpy(stream->userBuffer, 01354 inBufferList->mBuffers[stream->handle[1]].mData, 01355 inBufferList->mBuffers[stream->handle[1]].mDataByteSize ); 01356 01357 if (stream->doByteSwap[1]) 01358 byteSwapBuffer(stream->userBuffer, 01359 stream->bufferSize * stream->nUserChannels[1], 01360 stream->userFormat); 01361 } 01362 } 01363 01364 if ( !info->usingCallback && (stream->mode != DUPLEX || deviceId == info->device[1] ) ) 01365 info->blockTick = false; 01366 01367 MUTEX_UNLOCK(&stream->mutex); 01368 01369 } 01370 01371 void RtAudio :: setStreamCallback(int streamId, RTAUDIO_CALLBACK callback, void *userData) 01372 { 01373 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId); 01374 01375 stream->callbackInfo.callback = (void *) callback; 01376 stream->callbackInfo.userData = userData; 01377 stream->callbackInfo.usingCallback = true; 01378 } 01379 01380 //******************** End of __MACOSX_CORE__ *********************// 01381 01382 #elif defined(__LINUX_ALSA__) 01383 01384 #define MAX_DEVICES 16 01385 01386 void RtAudio :: initialize(void) 01387 { 01388 int card, result, device; 01389 char name[32]; 01390 const char *cardId; 01391 char deviceNames[MAX_DEVICES][32]; 01392 snd_ctl_t *handle; 01393 snd_ctl_card_info_t *info; 01394 snd_ctl_card_info_alloca(&info); 01395 01396 // Count cards and devices 01397 nDevices = 0; 01398 card = -1; 01399 snd_card_next(&card); 01400 while ( card >= 0 ) { 01401 sprintf(name, "hw:%d", card); 01402 result = snd_ctl_open(&handle, name, 0); 01403 if (result < 0) { 01404 sprintf(message, "RtAudio: ALSA control open (%i): %s.", card, snd_strerror(result)); 01405 error(RtError::DEBUG_WARNING); 01406 goto next_card; 01407 } 01408 result = snd_ctl_card_info(handle, info); 01409 if (result < 0) { 01410 sprintf(message, "RtAudio: ALSA control hardware info (%i): %s.", card, snd_strerror(result)); 01411 error(RtError::DEBUG_WARNING); 01412 goto next_card; 01413 } 01414 cardId = snd_ctl_card_info_get_id(info); 01415 device = -1; 01416 while (1) { 01417 result = snd_ctl_pcm_next_device(handle, &device); 01418 if (result < 0) { 01419 sprintf(message, "RtAudio: ALSA control next device (%i): %s.", card, snd_strerror(result)); 01420 error(RtError::DEBUG_WARNING); 01421 break; 01422 } 01423 if (device < 0) 01424 break; 01425 if ( strlen(cardId) ) 01426 sprintf( deviceNames[nDevices++], "hw:%s,%d", cardId, device ); 01427 else 01428 sprintf( deviceNames[nDevices++], "hw:%d,%d", card, device ); 01429 if ( nDevices > MAX_DEVICES ) break; 01430 } 01431 if ( nDevices > MAX_DEVICES ) break; 01432 next_card: 01433 snd_ctl_close(handle); 01434 snd_card_next(&card); 01435 } 01436 01437 if (nDevices == 0) return; 01438 01439 // Allocate the RTAUDIO_DEVICE structures. 01440 devices = (RTAUDIO_DEVICE *) calloc(nDevices, sizeof(RTAUDIO_DEVICE)); 01441 if (devices == NULL) { 01442 sprintf(message, "RtAudio: memory allocation error!"); 01443 error(RtError::MEMORY_ERROR); 01444 } 01445 01446 // Write device ascii identifiers to device structures and then 01447 // probe the device capabilities. 01448 for (int i=0; i<nDevices; i++) { 01449 strncpy(devices[i].name, deviceNames[i], 32); 01450 //probeDeviceInfo(&devices[i]); 01451 } 01452 } 01453 01454 int RtAudio :: getDefaultInputDevice(void) 01455 { 01456 // No ALSA API functions for default devices. 01457 return 0; 01458 } 01459 01460 int RtAudio :: getDefaultOutputDevice(void) 01461 { 01462 // No ALSA API functions for default devices. 01463 return 0; 01464 } 01465 01466 void RtAudio :: probeDeviceInfo(RTAUDIO_DEVICE *info) 01467 { 01468 int err; 01469 int open_mode = SND_PCM_ASYNC; 01470 snd_pcm_t *handle; 01471 snd_ctl_t *chandle; 01472 snd_pcm_stream_t stream; 01473 snd_pcm_info_t *pcminfo; 01474 snd_pcm_info_alloca(&pcminfo); 01475 snd_pcm_hw_params_t *params; 01476 snd_pcm_hw_params_alloca(¶ms); 01477 char name[32]; 01478 char *card; 01479 01480 // Open the control interface for this card. 01481 strncpy( name, info->name, 32 ); 01482 card = strtok(name, ","); 01483 err = snd_ctl_open(&chandle, card, 0); 01484 if (err < 0) { 01485 sprintf(message, "RtAudio: ALSA control open (%s): %s.", card, snd_strerror(err)); 01486 error(RtError::DEBUG_WARNING); 01487 return; 01488 } 01489 unsigned int dev = (unsigned int) atoi( strtok(NULL, ",") ); 01490 01491 // First try for playback 01492 stream = SND_PCM_STREAM_PLAYBACK; 01493 snd_pcm_info_set_device(pcminfo, dev); 01494 snd_pcm_info_set_subdevice(pcminfo, 0); 01495 snd_pcm_info_set_stream(pcminfo, stream); 01496 01497 if ((err = snd_ctl_pcm_info(chandle, pcminfo)) < 0) { 01498 if (err == -ENOENT) { 01499 sprintf(message, "RtAudio: ALSA pcm device (%s) doesn't handle output!", info->name); 01500 error(RtError::DEBUG_WARNING); 01501 } 01502 else { 01503 sprintf(message, "RtAudio: ALSA snd_ctl_pcm_info error for device (%s) output: %s", 01504 info->name, snd_strerror(err)); 01505 error(RtError::DEBUG_WARNING); 01506 } 01507 goto capture_probe; 01508 } 01509 01510 err = snd_pcm_open(&handle, info->name, stream, open_mode | SND_PCM_NONBLOCK ); 01511 if (err < 0) { 01512 if ( err == EBUSY ) 01513 sprintf(message, "RtAudio: ALSA pcm playback device (%s) is busy: %s.", 01514 info->name, snd_strerror(err)); 01515 else 01516 sprintf(message, "RtAudio: ALSA pcm playback open (%s) error: %s.", 01517 info->name, snd_strerror(err)); 01518 error(RtError::DEBUG_WARNING); 01519 goto capture_probe; 01520 } 01521 01522 // We have an open device ... allocate the parameter structure. 01523 err = snd_pcm_hw_params_any(handle, params); 01524 if (err < 0) { 01525 snd_pcm_close(handle); 01526 sprintf(message, "RtAudio: ALSA hardware probe error (%s): %s.", 01527 info->name, snd_strerror(err)); 01528 error(RtError::WARNING); 01529 goto capture_probe; 01530 } 01531 01532 // Get output channel information. 01533 info->minOutputChannels = snd_pcm_hw_params_get_channels_min(params); 01534 info->maxOutputChannels = snd_pcm_hw_params_get_channels_max(params); 01535 01536 snd_pcm_close(handle); 01537 01538 capture_probe: 01539 // Now try for capture 01540 stream = SND_PCM_STREAM_CAPTURE; 01541 snd_pcm_info_set_stream(pcminfo, stream); 01542 01543 err = snd_ctl_pcm_info(chandle, pcminfo); 01544 snd_ctl_close(chandle); 01545 if ( err < 0 ) { 01546 if (err == -ENOENT) { 01547 sprintf(message, "RtAudio: ALSA pcm device (%s) doesn't handle input!", info->name); 01548 error(RtError::DEBUG_WARNING); 01549 } 01550 else { 01551 sprintf(message, "RtAudio: ALSA snd_ctl_pcm_info error for device (%s) input: %s", 01552 info->name, snd_strerror(err)); 01553 error(RtError::DEBUG_WARNING); 01554 } 01555 if (info->maxOutputChannels == 0) 01556 // didn't open for playback either ... device invalid 01557 return; 01558 goto probe_parameters; 01559 } 01560 01561 err = snd_pcm_open(&handle, info->name, stream, open_mode | SND_PCM_NONBLOCK); 01562 if (err < 0) { 01563 if ( err == EBUSY ) 01564 sprintf(message, "RtAudio: ALSA pcm capture device (%s) is busy: %s.", 01565 info->name, snd_strerror(err)); 01566 else 01567 sprintf(message, "RtAudio: ALSA pcm capture open (%s) error: %s.", 01568 info->name, snd_strerror(err)); 01569 error(RtError::DEBUG_WARNING); 01570 if (info->maxOutputChannels == 0) 01571 // didn't open for playback either ... device invalid 01572 return; 01573 goto probe_parameters; 01574 } 01575 01576 // We have an open capture device ... allocate the parameter structure. 01577 err = snd_pcm_hw_params_any(handle, params); 01578 if (err < 0) { 01579 snd_pcm_close(handle); 01580 sprintf(message, "RtAudio: ALSA hardware probe error (%s): %s.", 01581 info->name, snd_strerror(err)); 01582 error(RtError::WARNING); 01583 if (info->maxOutputChannels > 0) 01584 goto probe_parameters; 01585 else 01586 return; 01587 } 01588 01589 // Get input channel information. 01590 info->minInputChannels = snd_pcm_hw_params_get_channels_min(params); 01591 info->maxInputChannels = snd_pcm_hw_params_get_channels_max(params); 01592 01593 snd_pcm_close(handle); 01594 01595 // If device opens for both playback and capture, we determine the channels. 01596 if (info->maxOutputChannels == 0 || info->maxInputChannels == 0) 01597 goto probe_parameters; 01598 01599 info->hasDuplexSupport = true; 01600 info->maxDuplexChannels = (info->maxOutputChannels > info->maxInputChannels) ? 01601 info->maxInputChannels : info->maxOutputChannels; 01602 info->minDuplexChannels = (info->minOutputChannels > info->minInputChannels) ? 01603 info->minInputChannels : info->minOutputChannels; 01604 01605 probe_parameters: 01606 // At this point, we just need to figure out the supported data 01607 // formats and sample rates. We'll proceed by opening the device in 01608 // the direction with the maximum number of channels, or playback if 01609 // they are equal. This might limit our sample rate options, but so 01610 // be it. 01611 01612 if (info->maxOutputChannels >= info->maxInputChannels) 01613 stream = SND_PCM_STREAM_PLAYBACK; 01614 else 01615 stream = SND_PCM_STREAM_CAPTURE; 01616 01617 err = snd_pcm_open(&handle, info->name, stream, open_mode); 01618 if (err < 0) { 01619 sprintf(message, "RtAudio: ALSA pcm (%s) won't reopen during probe: %s.", 01620 info->name, snd_strerror(err)); 01621 error(RtError::WARNING); 01622 return; 01623 } 01624 01625 // We have an open device ... allocate the parameter structure. 01626 err = snd_pcm_hw_params_any(handle, params); 01627 if (err < 0) { 01628 snd_pcm_close(handle); 01629 sprintf(message, "RtAudio: ALSA hardware reopen probe error (%s): %s.", 01630 info->name, snd_strerror(err)); 01631 error(RtError::WARNING); 01632 return; 01633 } 01634 01635 // Test a non-standard sample rate to see if continuous rate is supported. 01636 int dir = 0; 01637 if (snd_pcm_hw_params_test_rate(handle, params, 35500, dir) == 0) { 01638 // It appears that continuous sample rate support is available. 01639 info->nSampleRates = -1; 01640 info->sampleRates[0] = snd_pcm_hw_params_get_rate_min(params, &dir); 01641 info->sampleRates[1] = snd_pcm_hw_params_get_rate_max(params, &dir); 01642 } 01643 else { 01644 // No continuous rate support ... test our discrete set of sample rate values. 01645 info->nSampleRates = 0; 01646 for (int i=0; i<MAX_SAMPLE_RATES; i++) { 01647 if (snd_pcm_hw_params_test_rate(handle, params, SAMPLE_RATES[i], dir) == 0) { 01648 info->sampleRates[info->nSampleRates] = SAMPLE_RATES[i]; 01649 info->nSampleRates++; 01650 } 01651 } 01652 if (info->nSampleRates == 0) { 01653 snd_pcm_close(handle); 01654 return; 01655 } 01656 } 01657 01658 // Probe the supported data formats ... we don't care about endian-ness just yet 01659 snd_pcm_format_t format; 01660 info->nativeFormats = 0; 01661 format = SND_PCM_FORMAT_S8; 01662 if (snd_pcm_hw_params_test_format(handle, params, format) == 0) 01663 info->nativeFormats |= RTAUDIO_SINT8; 01664 format = SND_PCM_FORMAT_S16; 01665 if (snd_pcm_hw_params_test_format(handle, params, format) == 0) 01666 info->nativeFormats |= RTAUDIO_SINT16; 01667 format = SND_PCM_FORMAT_S24; 01668 if (snd_pcm_hw_params_test_format(handle, params, format) == 0) 01669 info->nativeFormats |= RTAUDIO_SINT24; 01670 format = SND_PCM_FORMAT_S32; 01671 if (snd_pcm_hw_params_test_format(handle, params, format) == 0) 01672 info->nativeFormats |= RTAUDIO_SINT32; 01673 format = SND_PCM_FORMAT_FLOAT; 01674 if (snd_pcm_hw_params_test_format(handle, params, format) == 0) 01675 info->nativeFormats |= RTAUDIO_FLOAT32; 01676 format = SND_PCM_FORMAT_FLOAT64; 01677 if (snd_pcm_hw_params_test_format(handle, params, format) == 0) 01678 info->nativeFormats |= RTAUDIO_FLOAT64; 01679 01680 // Check that we have at least one supported format 01681 if (info->nativeFormats == 0) { 01682 snd_pcm_close(handle); 01683 sprintf(message, "RtAudio: ALSA PCM device (%s) data format not supported by RtAudio.", 01684 info->name); 01685 error(RtError::WARNING); 01686 return; 01687 } 01688 01689 // That's all ... close the device and return 01690 snd_pcm_close(handle); 01691 info->probed = true; 01692 return; 01693 } 01694 01695 bool RtAudio :: probeDeviceOpen(int device, RTAUDIO_STREAM *stream, 01696 STREAM_MODE mode, int channels, 01697 int sampleRate, RTAUDIO_FORMAT format, 01698 int *bufferSize, int numberOfBuffers) 01699 { 01700 #if defined(__RTAUDIO_DEBUG__) 01701 snd_output_t *out; 01702 snd_output_stdio_attach(&out, stderr, 0); 01703 #endif 01704 01705 // I'm not using the "plug" interface ... too much inconsistent behavior. 01706 const char *name = devices[device].name; 01707 01708 snd_pcm_stream_t alsa_stream; 01709 if (mode == OUTPUT) 01710 alsa_stream = SND_PCM_STREAM_PLAYBACK; 01711 else 01712 alsa_stream = SND_PCM_STREAM_CAPTURE; 01713 01714 int err; 01715 snd_pcm_t *handle; 01716 int alsa_open_mode = SND_PCM_ASYNC; 01717 err = snd_pcm_open(&handle, name, alsa_stream, alsa_open_mode); 01718 if (err < 0) { 01719 sprintf(message,"RtAudio: ALSA pcm device (%s) won't open: %s.", 01720 name, snd_strerror(err)); 01721 error(RtError::WARNING); 01722 return FAILURE; 01723 } 01724 01725 // Fill the parameter structure. 01726 snd_pcm_hw_params_t *hw_params; 01727 snd_pcm_hw_params_alloca(&hw_params); 01728 err = snd_pcm_hw_params_any(handle, hw_params); 01729 if (err < 0) { 01730 snd_pcm_close(handle); 01731 sprintf(message, "RtAudio: ALSA error getting parameter handle (%s): %s.", 01732 name, snd_strerror(err)); 01733 error(RtError::WARNING); 01734 return FAILURE; 01735 } 01736 01737 #if defined(__RTAUDIO_DEBUG__) 01738 fprintf(stderr, "\nRtAudio: ALSA dump hardware params just after device open:\n\n"); 01739 snd_pcm_hw_params_dump(hw_params, out); 01740 #endif 01741 01742 01743 // Set access ... try interleaved access first, then non-interleaved 01744 if ( !snd_pcm_hw_params_test_access( handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED) ) { 01745 err = snd_pcm_hw_params_set_access(handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED); 01746 } 01747 else if ( !snd_pcm_hw_params_test_access( handle, hw_params, SND_PCM_ACCESS_RW_NONINTERLEAVED) ) { 01748 err = snd_pcm_hw_params_set_access(handle, hw_params, SND_PCM_ACCESS_RW_NONINTERLEAVED); 01749 stream->deInterleave[mode] = true; 01750 } 01751 else { 01752 snd_pcm_close(handle); 01753 sprintf(message, "RtAudio: ALSA device (%s) access not supported by RtAudio.", name); 01754 error(RtError::WARNING); 01755 return FAILURE; 01756 } 01757 01758 if (err < 0) { 01759 snd_pcm_close(handle); 01760 sprintf(message, "RtAudio: ALSA error setting access ( (%s): %s.", name, snd_strerror(err)); 01761 error(RtError::WARNING); 01762 return FAILURE; 01763 } 01764 01765 // Determine how to set the device format. 01766 stream->userFormat = format; 01767 snd_pcm_format_t device_format; 01768 01769 if (format == RTAUDIO_SINT8) 01770 device_format = SND_PCM_FORMAT_S8; 01771 else if (format == RTAUDIO_SINT16) 01772 device_format = SND_PCM_FORMAT_S16; 01773 else if (format == RTAUDIO_SINT24) 01774 device_format = SND_PCM_FORMAT_S24; 01775 else if (format == RTAUDIO_SINT32) 01776 device_format = SND_PCM_FORMAT_S32; 01777 else if (format == RTAUDIO_FLOAT32) 01778 device_format = SND_PCM_FORMAT_FLOAT; 01779 else if (format == RTAUDIO_FLOAT64) 01780 device_format = SND_PCM_FORMAT_FLOAT64; 01781 01782 if (snd_pcm_hw_params_test_format(handle, hw_params, device_format) == 0) { 01783 stream->deviceFormat[mode] = format; 01784 goto set_format; 01785 } 01786 01787 // The user requested format is not natively supported by the device. 01788 device_format = SND_PCM_FORMAT_FLOAT64; 01789 if (snd_pcm_hw_params_test_format(handle, hw_params, device_format) == 0) { 01790 stream->deviceFormat[mode] = RTAUDIO_FLOAT64; 01791 goto set_format; 01792 } 01793 01794 device_format = SND_PCM_FORMAT_FLOAT; 01795 if (snd_pcm_hw_params_test_format(handle, hw_params, device_format) == 0) { 01796 stream->deviceFormat[mode] = RTAUDIO_FLOAT32; 01797 goto set_format; 01798 } 01799 01800 device_format = SND_PCM_FORMAT_S32; 01801 if (snd_pcm_hw_params_test_format(handle, hw_params, device_format) == 0) { 01802 stream->deviceFormat[mode] = RTAUDIO_SINT32; 01803 goto set_format; 01804 } 01805 01806 device_format = SND_PCM_FORMAT_S24; 01807 if (snd_pcm_hw_params_test_format(handle, hw_params, device_format) == 0) { 01808 stream->deviceFormat[mode] = RTAUDIO_SINT24; 01809 goto set_format; 01810 } 01811 01812 device_format = SND_PCM_FORMAT_S16; 01813 if (snd_pcm_hw_params_test_format(handle, hw_params, device_format) == 0) { 01814 stream->deviceFormat[mode] = RTAUDIO_SINT16; 01815 goto set_format; 01816 } 01817 01818 device_format = SND_PCM_FORMAT_S8; 01819 if (snd_pcm_hw_params_test_format(handle, hw_params, device_format) == 0) { 01820 stream->deviceFormat[mode] = RTAUDIO_SINT8; 01821 goto set_format; 01822 } 01823 01824 // If we get here, no supported format was found. 01825 sprintf(message,"RtAudio: ALSA pcm device (%s) data format not supported by RtAudio.", name); 01826 snd_pcm_close(handle); 01827 error(RtError::WARNING); 01828 return FAILURE; 01829 01830 set_format: 01831 err = snd_pcm_hw_params_set_format(handle, hw_params, device_format); 01832 if (err < 0) { 01833 snd_pcm_close(handle); 01834 sprintf(message, "RtAudio: ALSA error setting format (%s): %s.", 01835 name, snd_strerror(err)); 01836 error(RtError::WARNING); 01837 return FAILURE; 01838 } 01839 01840 // Determine whether byte-swaping is necessary. 01841 stream->doByteSwap[mode] = false; 01842 if (device_format != SND_PCM_FORMAT_S8) { 01843 err = snd_pcm_format_cpu_endian(device_format); 01844 if (err == 0) 01845 stream->doByteSwap[mode] = true; 01846 else if (err < 0) { 01847 snd_pcm_close(handle); 01848 sprintf(message, "RtAudio: ALSA error getting format endian-ness (%s): %s.", 01849 name, snd_strerror(err)); 01850 error(RtError::WARNING); 01851 return FAILURE; 01852 } 01853 } 01854 01855 // Set the sample rate. 01856 err = snd_pcm_hw_params_set_rate(handle, hw_params, (unsigned int)sampleRate, 0); 01857 if (err < 0) { 01858 snd_pcm_close(handle); 01859 sprintf(message, "RtAudio: ALSA error setting sample rate (%d) on device (%s): %s.", 01860 sampleRate, name, snd_strerror(err)); 01861 error(RtError::WARNING); 01862 return FAILURE; 01863 } 01864 01865 // Determine the number of channels for this device. We support a possible 01866 // minimum device channel number > than the value requested by the user. 01867 stream->nUserChannels[mode] = channels; 01868 int device_channels = snd_pcm_hw_params_get_channels_max(hw_params); 01869 if (device_channels < channels) { 01870 snd_pcm_close(handle); 01871 sprintf(message, "RtAudio: channels (%d) not supported by device (%s).", 01872 channels, name); 01873 error(RtError::WARNING); 01874 return FAILURE; 01875 } 01876 01877 device_channels = snd_pcm_hw_params_get_channels_min(hw_params); 01878 if (device_channels < channels) device_channels = channels; 01879 stream->nDeviceChannels[mode] = device_channels; 01880 01881 // Set the device channels. 01882 err = snd_pcm_hw_params_set_channels(handle, hw_params, device_channels); 01883 if (err < 0) { 01884 snd_pcm_close(handle); 01885 sprintf(message, "RtAudio: ALSA error setting channels (%d) on device (%s): %s.", 01886 device_channels, name, snd_strerror(err)); 01887 error(RtError::WARNING); 01888 return FAILURE; 01889 } 01890 01891 // Set the buffer number, which in ALSA is referred to as the "period". 01892 int dir; 01893 int periods = numberOfBuffers; 01894 // Even though the hardware might allow 1 buffer, it won't work reliably. 01895 if (periods < 2) periods = 2; 01896 err = snd_pcm_hw_params_get_periods_min(hw_params, &dir); 01897 if (err > periods) periods = err; 01898 err = snd_pcm_hw_params_get_periods_max(hw_params, &dir); 01899 if (err < periods) periods = err; 01900 01901 err = snd_pcm_hw_params_set_periods(handle, hw_params, periods, 0); 01902 if (err < 0) { 01903 snd_pcm_close(handle); 01904 sprintf(message, "RtAudio: ALSA error setting periods (%s): %s.", 01905 name, snd_strerror(err)); 01906 error(RtError::WARNING); 01907 return FAILURE; 01908 } 01909 01910 // Set the buffer (or period) size. 01911 err = snd_pcm_hw_params_get_period_size_min(hw_params, &dir); 01912 if (err > *bufferSize) *bufferSize = err; 01913 01914 err = snd_pcm_hw_params_set_period_size(handle, hw_params, *bufferSize, 0); 01915 if (err < 0) { 01916 snd_pcm_close(handle); 01917 sprintf(message, "RtAudio: ALSA error setting period size (%s): %s.", 01918 name, snd_strerror(err)); 01919 error(RtError::WARNING); 01920 return FAILURE; 01921 } 01922 01923 // If attempting to setup a duplex stream, the bufferSize parameter 01924 // MUST be the same in both directions! 01925 if ( stream->mode == OUTPUT && mode == INPUT && *bufferSize != stream->bufferSize ) { 01926 sprintf( message, "RtAudio: ALSA error setting buffer size for duplex stream on device (%s).", 01927 name ); 01928 error(RtError::DEBUG_WARNING); 01929 return FAILURE; 01930 } 01931 01932 stream->bufferSize = *bufferSize; 01933 01934 // Install the hardware configuration 01935 err = snd_pcm_hw_params(handle, hw_params); 01936 if (err < 0) { 01937 snd_pcm_close(handle); 01938 sprintf(message, "RtAudio: ALSA error installing hardware configuration (%s): %s.", 01939 name, snd_strerror(err)); 01940 error(RtError::WARNING); 01941 return FAILURE; 01942 } 01943 01944 #if defined(__RTAUDIO_DEBUG__) 01945 fprintf(stderr, "\nRtAudio: ALSA dump hardware params after installation:\n\n"); 01946 snd_pcm_hw_params_dump(hw_params, out); 01947 #endif 01948 01949 /* 01950 // Install the software configuration 01951 snd_pcm_sw_params_t *sw_params = NULL; 01952 snd_pcm_sw_params_alloca(&sw_params); 01953 snd_pcm_sw_params_current(handle, sw_params); 01954 err = snd_pcm_sw_params(handle, sw_params); 01955 if (err < 0) { 01956 snd_pcm_close(handle); 01957 sprintf(message, "RtAudio: ALSA error installing software configuration (%s): %s.", 01958 name, snd_strerror(err)); 01959 error(RtError::WARNING); 01960 return FAILURE; 01961 } 01962 */ 01963 01964 // Set handle and flags for buffer conversion 01965 stream->handle[mode] = handle; 01966 stream->doConvertBuffer[mode] = false; 01967 if (stream->userFormat != stream->deviceFormat[mode]) 01968 stream->doConvertBuffer[mode] = true; 01969 if (stream->nUserChannels[mode] < stream->nDeviceChannels[mode]) 01970 stream->doConvertBuffer[mode] = true; 01971 if (stream->nUserChannels[mode] > 1 && stream->deInterleave[mode]) 01972 stream->doConvertBuffer[mode] = true; 01973 01974 // Allocate necessary internal buffers 01975 if ( stream->nUserChannels[0] != stream->nUserChannels[1] ) { 01976 01977 long buffer_bytes; 01978 if (stream->nUserChannels[0] >= stream->nUserChannels[1]) 01979 buffer_bytes = stream->nUserChannels[0]; 01980 else 01981 buffer_bytes = stream->nUserChannels[1]; 01982 01983 buffer_bytes *= *bufferSize * formatBytes(stream->userFormat); 01984 if (stream->userBuffer) free(stream->userBuffer); 01985 stream->userBuffer = (char *) calloc(buffer_bytes, 1); 01986 if (stream->userBuffer == NULL) 01987 goto memory_error; 01988 } 01989 01990 if ( stream->doConvertBuffer[mode] ) { 01991 01992 long buffer_bytes; 01993 bool makeBuffer = true; 01994 if ( mode == OUTPUT ) 01995 buffer_bytes = stream->nDeviceChannels[0] * formatBytes(stream->deviceFormat[0]); 01996 else { // mode == INPUT 01997 buffer_bytes = stream->nDeviceChannels[1] * formatBytes(stream->deviceFormat[1]); 01998 if ( stream->mode == OUTPUT && stream->deviceBuffer ) { 01999 long bytes_out = stream->nDeviceChannels[0] * formatBytes(stream->deviceFormat[0]); 02000 if ( buffer_bytes < bytes_out ) makeBuffer = false; 02001 } 02002 } 02003 02004 if ( makeBuffer ) { 02005 buffer_bytes *= *bufferSize; 02006 if (stream->deviceBuffer) free(stream->deviceBuffer); 02007 stream->deviceBuffer = (char *) calloc(buffer_bytes, 1); 02008 if (stream->deviceBuffer == NULL) 02009 goto memory_error; 02010 } 02011 } 02012 02013 stream->device[mode] = device; 02014 stream->state = STREAM_STOPPED; 02015 if ( stream->mode == OUTPUT && mode == INPUT ) 02016 // We had already set up an output stream. 02017 stream->mode = DUPLEX; 02018 else 02019 stream->mode = mode; 02020 stream->nBuffers = periods; 02021 stream->sampleRate = sampleRate; 02022 02023 return SUCCESS; 02024 02025 memory_error: 02026 if (stream->handle[0]) { 02027 snd_pcm_close(stream->handle[0]); 02028 stream->handle[0] = 0; 02029 } 02030 if (stream->handle[1]) { 02031 snd_pcm_close(stream->handle[1]); 02032 stream->handle[1] = 0; 02033 } 02034 if (stream->userBuffer) { 02035 free(stream->userBuffer); 02036 stream->userBuffer = 0; 02037 } 02038 sprintf(message, "RtAudio: ALSA error allocating buffer memory (%s).", name); 02039 error(RtError::WARNING); 02040 return FAILURE; 02041 } 02042 02043 void RtAudio :: closeStream(int streamId) 02044 { 02045 // We don't want an exception to be thrown here because this 02046 // function is called by our class destructor. So, do our own 02047 // streamId check. 02048 if ( streams.find( streamId ) == streams.end() ) { 02049 sprintf(message, "RtAudio: invalid stream identifier!"); 02050 error(RtError::WARNING); 02051 return; 02052 } 02053 02054 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) streams[streamId]; 02055 02056 if (stream->callbackInfo.usingCallback) { 02057 pthread_cancel(stream->callbackInfo.thread); 02058 pthread_join(stream->callbackInfo.thread, NULL); 02059 } 02060 02061 if (stream->state == STREAM_RUNNING) { 02062 if (stream->mode == OUTPUT || stream->mode == DUPLEX) 02063 snd_pcm_drop(stream->handle[0]); 02064 if (stream->mode == INPUT || stream->mode == DUPLEX) 02065 snd_pcm_drop(stream->handle[1]); 02066 } 02067 02068 pthread_mutex_destroy(&stream->mutex); 02069 02070 if (stream->handle[0]) 02071 snd_pcm_close(stream->handle[0]); 02072 02073 if (stream->handle[1]) 02074 snd_pcm_close(stream->handle[1]); 02075 02076 if (stream->userBuffer) 02077 free(stream->userBuffer); 02078 02079 if (stream->deviceBuffer) 02080 free(stream->deviceBuffer); 02081 02082 free(stream); 02083 streams.erase(streamId); 02084 } 02085 02086 void RtAudio :: startStream(int streamId) 02087 { 02088 // This method calls snd_pcm_prepare if the device isn't already in that state. 02089 02090 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId); 02091 02092 MUTEX_LOCK(&stream->mutex); 02093 02094 if (stream->state == STREAM_RUNNING) 02095 goto unlock; 02096 02097 int err; 02098 snd_pcm_state_t state; 02099 if (stream->mode == OUTPUT || stream->mode == DUPLEX) { 02100 state = snd_pcm_state(stream->handle[0]); 02101 if (state != SND_PCM_STATE_PREPARED) { 02102 err = snd_pcm_prepare(stream->handle[0]); 02103 if (err < 0) { 02104 sprintf(message, "RtAudio: ALSA error preparing pcm device (%s): %s.", 02105 devices[stream->device[0]].name, snd_strerror(err)); 02106 MUTEX_UNLOCK(&stream->mutex); 02107 error(RtError::DRIVER_ERROR); 02108 } 02109 } 02110 } 02111 02112 if (stream->mode == INPUT || stream->mode == DUPLEX) { 02113 state = snd_pcm_state(stream->handle[1]); 02114 if (state != SND_PCM_STATE_PREPARED) { 02115 err = snd_pcm_prepare(stream->handle[1]); 02116 if (err < 0) { 02117 sprintf(message, "RtAudio: ALSA error preparing pcm device (%s): %s.", 02118 devices[stream->device[1]].name, snd_strerror(err)); 02119 MUTEX_UNLOCK(&stream->mutex); 02120 error(RtError::DRIVER_ERROR); 02121 } 02122 } 02123 } 02124 stream->state = STREAM_RUNNING; 02125 02126 unlock: 02127 MUTEX_UNLOCK(&stream->mutex); 02128 } 02129 02130 void RtAudio :: stopStream(int streamId) 02131 { 02132 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId); 02133 02134 MUTEX_LOCK(&stream->mutex); 02135 02136 if (stream->state == STREAM_STOPPED) 02137 goto unlock; 02138 02139 int err; 02140 if (stream->mode == OUTPUT || stream->mode == DUPLEX) { 02141 err = snd_pcm_drain(stream->handle[0]); 02142 if (err < 0) { 02143 sprintf(message, "RtAudio: ALSA error draining pcm device (%s): %s.", 02144 devices[stream->device[0]].name, snd_strerror(err)); 02145 MUTEX_UNLOCK(&stream->mutex); 02146 error(RtError::DRIVER_ERROR); 02147 } 02148 } 02149 02150 if (stream->mode == INPUT || stream->mode == DUPLEX) { 02151 err = snd_pcm_drain(stream->handle[1]); 02152 if (err < 0) { 02153 sprintf(message, "RtAudio: ALSA error draining pcm device (%s): %s.", 02154 devices[stream->device[1]].name, snd_strerror(err)); 02155 MUTEX_UNLOCK(&stream->mutex); 02156 error(RtError::DRIVER_ERROR); 02157 } 02158 } 02159 stream->state = STREAM_STOPPED; 02160 02161 unlock: 02162 MUTEX_UNLOCK(&stream->mutex); 02163 } 02164 02165 void RtAudio :: abortStream(int streamId) 02166 { 02167 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId); 02168 02169 MUTEX_LOCK(&stream->mutex); 02170 02171 if (stream->state == STREAM_STOPPED) 02172 goto unlock; 02173 02174 int err; 02175 if (stream->mode == OUTPUT || stream->mode == DUPLEX) { 02176 err = snd_pcm_drop(stream->handle[0]); 02177 if (err < 0) { 02178 sprintf(message, "RtAudio: ALSA error draining pcm device (%s): %s.", 02179 devices[stream->device[0]].name, snd_strerror(err)); 02180 MUTEX_UNLOCK(&stream->mutex); 02181 error(RtError::DRIVER_ERROR); 02182 } 02183 } 02184 02185 if (stream->mode == INPUT || stream->mode == DUPLEX) { 02186 err = snd_pcm_drop(stream->handle[1]); 02187 if (err < 0) { 02188 sprintf(message, "RtAudio: ALSA error draining pcm device (%s): %s.", 02189 devices[stream->device[1]].name, snd_strerror(err)); 02190 MUTEX_UNLOCK(&stream->mutex); 02191 error(RtError::DRIVER_ERROR); 02192 } 02193 } 02194 stream->state = STREAM_STOPPED; 02195 02196 unlock: 02197 MUTEX_UNLOCK(&stream->mutex); 02198 } 02199 02200 int RtAudio :: streamWillBlock(int streamId) 02201 { 02202 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId); 02203 02204 MUTEX_LOCK(&stream->mutex); 02205 02206 int err = 0, frames = 0; 02207 if (stream->state == STREAM_STOPPED) 02208 goto unlock; 02209 02210 if (stream->mode == OUTPUT || stream->mode == DUPLEX) { 02211 err = snd_pcm_avail_update(stream->handle[0]); 02212 if (err < 0) { 02213 sprintf(message, "RtAudio: ALSA error getting available frames for device (%s): %s.", 02214 devices[stream->device[0]].name, snd_strerror(err)); 02215 MUTEX_UNLOCK(&stream->mutex); 02216 error(RtError::DRIVER_ERROR); 02217 } 02218 } 02219 02220 frames = err; 02221 02222 if (stream->mode == INPUT || stream->mode == DUPLEX) { 02223 err = snd_pcm_avail_update(stream->handle[1]); 02224 if (err < 0) { 02225 sprintf(message, "RtAudio: ALSA error getting available frames for device (%s): %s.", 02226 devices[stream->device[1]].name, snd_strerror(err)); 02227 MUTEX_UNLOCK(&stream->mutex); 02228 error(RtError::DRIVER_ERROR); 02229 } 02230 if (frames > err) frames = err; 02231 } 02232 02233 frames = stream->bufferSize - frames; 02234 if (frames < 0) frames = 0; 02235 02236 unlock: 02237 MUTEX_UNLOCK(&stream->mutex); 02238 return frames; 02239 } 02240 02241 void RtAudio :: tickStream(int streamId) 02242 { 02243 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId); 02244 02245 int stopStream = 0; 02246 if (stream->state == STREAM_STOPPED) { 02247 if (stream->callbackInfo.usingCallback) usleep(50000); // sleep 50 milliseconds 02248 return; 02249 } 02250 else if (stream->callbackInfo.usingCallback) { 02251 RTAUDIO_CALLBACK callback = (RTAUDIO_CALLBACK) stream->callbackInfo.callback; 02252 stopStream = callback(stream->userBuffer, stream->bufferSize, stream->callbackInfo.userData); 02253 } 02254 02255 MUTEX_LOCK(&stream->mutex); 02256 02257 // The state might change while waiting on a mutex. 02258 if (stream->state == STREAM_STOPPED) 02259 goto unlock; 02260 02261 int err; 02262 char *buffer; 02263 int channels; 02264 RTAUDIO_FORMAT format; 02265 if (stream->mode == OUTPUT || stream->mode == DUPLEX) { 02266 02267 // Setup parameters and do buffer conversion if necessary. 02268 if (stream->doConvertBuffer[0]) { 02269 convertStreamBuffer(stream, OUTPUT); 02270 buffer = stream->deviceBuffer; 02271 channels = stream->nDeviceChannels[0]; 02272 format = stream->deviceFormat[0]; 02273 } 02274 else { 02275 buffer = stream->userBuffer; 02276 channels = stream->nUserChannels[0]; 02277 format = stream->userFormat; 02278 } 02279 02280 // Do byte swapping if necessary. 02281 if (stream->doByteSwap[0]) 02282 byteSwapBuffer(buffer, stream->bufferSize * channels, format); 02283 02284 // Write samples to device in interleaved/non-interleaved format. 02285 if (stream->deInterleave[0]) { 02286 void *bufs[channels]; 02287 size_t offset = stream->bufferSize * formatBytes(format); 02288 for (int i=0; i<channels; i++) 02289 bufs[i] = (void *) (buffer + (i * offset)); 02290 err = snd_pcm_writen(stream->handle[0], bufs, stream->bufferSize); 02291 } 02292 else 02293 err = snd_pcm_writei(stream->handle[0], buffer, stream->bufferSize); 02294 02295 if (err < stream->bufferSize) { 02296 // Either an error or underrun occured. 02297 if (err == -EPIPE) { 02298 snd_pcm_state_t state = snd_pcm_state(stream->handle[0]); 02299 if (state == SND_PCM_STATE_XRUN) { 02300 sprintf(message, "RtAudio: ALSA underrun detected."); 02301 error(RtError::WARNING); 02302 err = snd_pcm_prepare(stream->handle[0]); 02303 if (err < 0) { 02304 sprintf(message, "RtAudio: ALSA error preparing handle after underrun: %s.", 02305 snd_strerror(err)); 02306 MUTEX_UNLOCK(&stream->mutex); 02307 error(RtError::DRIVER_ERROR); 02308 } 02309 } 02310 else { 02311 sprintf(message, "RtAudio: ALSA error, current state is %s.", 02312 snd_pcm_state_name(state)); 02313 MUTEX_UNLOCK(&stream->mutex); 02314 error(RtError::DRIVER_ERROR); 02315 } 02316 goto unlock; 02317 } 02318 else { 02319 sprintf(message, "RtAudio: ALSA audio write error for device (%s): %s.", 02320 devices[stream->device[0]].name, snd_strerror(err)); 02321 MUTEX_UNLOCK(&stream->mutex); 02322 error(RtError::DRIVER_ERROR); 02323 } 02324 } 02325 } 02326 02327 if (stream->mode == INPUT || stream->mode == DUPLEX) { 02328 02329 // Setup parameters. 02330 if (stream->doConvertBuffer[1]) { 02331 buffer = stream->deviceBuffer; 02332 channels = stream->nDeviceChannels[1]; 02333 format = stream->deviceFormat[1]; 02334 } 02335 else { 02336 buffer = stream->userBuffer; 02337 channels = stream->nUserChannels[1]; 02338 format = stream->userFormat; 02339 } 02340 02341 // Read samples from device in interleaved/non-interleaved format. 02342 if (stream->deInterleave[1]) { 02343 void *bufs[channels]; 02344 size_t offset = stream->bufferSize * formatBytes(format); 02345 for (int i=0; i<channels; i++) 02346 bufs[i] = (void *) (buffer + (i * offset)); 02347 err = snd_pcm_readn(stream->handle[1], bufs, stream->bufferSize); 02348 } 02349 else 02350 err = snd_pcm_readi(stream->handle[1], buffer, stream->bufferSize); 02351 02352 if (err < stream->bufferSize) { 02353 // Either an error or underrun occured. 02354 if (err == -EPIPE) { 02355 snd_pcm_state_t state = snd_pcm_state(stream->handle[1]); 02356 if (state == SND_PCM_STATE_XRUN) { 02357 sprintf(message, "RtAudio: ALSA overrun detected."); 02358 error(RtError::WARNING); 02359 err = snd_pcm_prepare(stream->handle[1]); 02360 if (err < 0) { 02361 sprintf(message, "RtAudio: ALSA error preparing handle after overrun: %s.", 02362 snd_strerror(err)); 02363 MUTEX_UNLOCK(&stream->mutex); 02364 error(RtError::DRIVER_ERROR); 02365 } 02366 } 02367 else { 02368 sprintf(message, "RtAudio: ALSA error, current state is %s.", 02369 snd_pcm_state_name(state)); 02370 MUTEX_UNLOCK(&stream->mutex); 02371 error(RtError::DRIVER_ERROR); 02372 } 02373 goto unlock; 02374 } 02375 else { 02376 sprintf(message, "RtAudio: ALSA audio read error for device (%s): %s.", 02377 devices[stream->device[1]].name, snd_strerror(err)); 02378 MUTEX_UNLOCK(&stream->mutex); 02379 error(RtError::DRIVER_ERROR); 02380 } 02381 } 02382 02383 // Do byte swapping if necessary. 02384 if (stream->doByteSwap[1]) 02385 byteSwapBuffer(buffer, stream->bufferSize * channels, format); 02386 02387 // Do buffer conversion if necessary. 02388 if (stream->doConvertBuffer[1]) 02389 convertStreamBuffer(stream, INPUT); 02390 } 02391 02392 unlock: 02393 MUTEX_UNLOCK(&stream->mutex); 02394 02395 if (stream->callbackInfo.usingCallback && stopStream) 02396 this->stopStream(streamId); 02397 } 02398 02399 extern "C" void *callbackHandler(void *ptr) 02400 { 02401 CALLBACK_INFO *info = (CALLBACK_INFO *) ptr; 02402 RtAudio *object = (RtAudio *) info->object; 02403 int stream = info->streamId; 02404 bool *usingCallback = &info->usingCallback; 02405 02406 while ( *usingCallback ) { 02407 pthread_testcancel(); 02408 try { 02409 object->tickStream(stream); 02410 } 02411 catch (RtError &exception) { 02412 fprintf(stderr, "\nRtAudio: Callback thread error (%s) ... closing thread.\n\n", 02413 exception.getMessage()); 02414 break; 02415 } 02416 } 02417 02418 return 0; 02419 } 02420 02421 //******************** End of __LINUX_ALSA__ *********************// 02422 02423 #elif defined(__LINUX_OSS__) 02424 02425 #include <sys/stat.h> 02426 #include <sys/types.h> 02427 #include <sys/ioctl.h> 02428 #include <unistd.h> 02429 #include <fcntl.h> 02430 #include <sys/soundcard.h> 02431 #include <errno.h> 02432 #include <math.h> 02433 02434 #define DAC_NAME "/dev/dsp" 02435 #define MAX_DEVICES 16 02436 #define MAX_CHANNELS 16 02437 02438 void RtAudio :: initialize(void) 02439 { 02440 // Count cards and devices 02441 nDevices = 0; 02442 02443 // We check /dev/dsp before probing devices. /dev/dsp is supposed to 02444 // be a link to the "default" audio device, of the form /dev/dsp0, 02445 // /dev/dsp1, etc... However, I've seen many cases where /dev/dsp was a 02446 // real device, so we need to check for that. Also, sometimes the 02447 // link is to /dev/dspx and other times just dspx. I'm not sure how 02448 // the latter works, but it does. 02449 char device_name[16]; 02450 struct stat dspstat; 02451 int dsplink = -1; 02452 int i = 0; 02453 if (lstat(DAC_NAME, &dspstat) == 0) { 02454 if (S_ISLNK(dspstat.st_mode)) { 02455 i = readlink(DAC_NAME, device_name, sizeof(device_name)); 02456 if (i > 0) { 02457 device_name[i] = '\0'; 02458 if (i > 8) { // check for "/dev/dspx" 02459 if (!strncmp(DAC_NAME, device_name, 8)) 02460 dsplink = atoi(&device_name[8]); 02461 } 02462 else if (i > 3) { // check for "dspx" 02463 if (!strncmp("dsp", device_name, 3)) 02464 dsplink = atoi(&device_name[3]); 02465 } 02466 } 02467 else { 02468 sprintf(message, "RtAudio: cannot read value of symbolic link %s.", DAC_NAME); 02469 error(RtError::SYSTEM_ERROR); 02470 } 02471 } 02472 } 02473 else { 02474 sprintf(message, "RtAudio: cannot stat %s.", DAC_NAME); 02475 error(RtError::SYSTEM_ERROR); 02476 } 02477 02478 // The OSS API doesn't provide a routine for determining the number 02479 // of devices. Thus, we'll just pursue a brute force method. The 02480 // idea is to start with /dev/dsp(0) and continue with higher device 02481 // numbers until we reach MAX_DSP_DEVICES. This should tell us how 02482 // many devices we have ... it is not a fullproof scheme, but hopefully 02483 // it will work most of the time. 02484 02485 int fd = 0; 02486 char names[MAX_DEVICES][16]; 02487 for (i=-1; i<MAX_DEVICES; i++) { 02488 02489 // Probe /dev/dsp first, since it is supposed to be the default device. 02490 if (i == -1) 02491 sprintf(device_name, "%s", DAC_NAME); 02492 else if (i == dsplink) 02493 continue; // We've aready probed this device via /dev/dsp link ... try next device. 02494 else 02495 sprintf(device_name, "%s%d", DAC_NAME, i); 02496 02497 // First try to open the device for playback, then record mode. 02498 fd = open(device_name, O_WRONLY | O_NONBLOCK); 02499 if (fd == -1) { 02500 // Open device for playback failed ... either busy or doesn't exist. 02501 if (errno != EBUSY && errno != EAGAIN) { 02502 // Try to open for capture 02503 fd = open(device_name, O_RDONLY | O_NONBLOCK); 02504 if (fd == -1) { 02505 // Open device for record failed. 02506 if (errno != EBUSY && errno != EAGAIN) 02507 continue; 02508 else { 02509 sprintf(message, "RtAudio: OSS record device (%s) is busy.", device_name); 02510 error(RtError::WARNING); 02511 // still count it for now 02512 } 02513 } 02514 } 02515 else { 02516 sprintf(message, "RtAudio: OSS playback device (%s) is busy.", device_name); 02517 error(RtError::WARNING); 02518 // still count it for now 02519 } 02520 } 02521 02522 if (fd >= 0) close(fd); 02523 strncpy(names[nDevices], device_name, 16); 02524 nDevices++; 02525 } 02526 02527 if (nDevices == 0) return; 02528 02529 // Allocate the RTAUDIO_DEVICE structures. 02530 devices = (RTAUDIO_DEVICE *) calloc(nDevices, sizeof(RTAUDIO_DEVICE)); 02531 if (devices == NULL) { 02532 sprintf(message, "RtAudio: memory allocation error!"); 02533 error(RtError::MEMORY_ERROR); 02534 } 02535 02536 // Write device ascii identifiers to device control structure and then probe capabilities. 02537 for (i=0; i<nDevices; i++) { 02538 strncpy(devices[i].name, names[i], 16); 02539 //probeDeviceInfo(&devices[i]); 02540 } 02541 02542 return; 02543 } 02544 02545 int RtAudio :: getDefaultInputDevice(void) 02546 { 02547 // No OSS API functions for default devices. 02548 return 0; 02549 } 02550 02551 int RtAudio :: getDefaultOutputDevice(void) 02552 { 02553 // No OSS API functions for default devices. 02554 return 0; 02555 } 02556 02557 void RtAudio :: probeDeviceInfo(RTAUDIO_DEVICE *info) 02558 { 02559 int i, fd, channels, mask; 02560 02561 // The OSS API doesn't provide a means for probing the capabilities 02562 // of devices. Thus, we'll just pursue a brute force method. 02563 02564 // First try for playback 02565 fd = open(info->name, O_WRONLY | O_NONBLOCK); 02566 if (fd == -1) { 02567 // Open device failed ... either busy or doesn't exist 02568 if (errno == EBUSY || errno == EAGAIN) 02569 sprintf(message, "RtAudio: OSS playback device (%s) is busy and cannot be probed.", 02570 info->name); 02571 else 02572 sprintf(message, "RtAudio: OSS playback device (%s) open error.", info->name); 02573 error(RtError::DEBUG_WARNING); 02574 goto capture_probe; 02575 } 02576 02577 // We have an open device ... see how many channels it can handle 02578 for (i=MAX_CHANNELS; i>0; i--) { 02579 channels = i; 02580 if (ioctl(fd, SNDCTL_DSP_CHANNELS, &channels) == -1) { 02581 // This would normally indicate some sort of hardware error, but under ALSA's 02582 // OSS emulation, it sometimes indicates an invalid channel value. Further, 02583 // the returned channel value is not changed. So, we'll ignore the possible 02584 // hardware error. 02585 continue; // try next channel number 02586 } 02587 // Check to see whether the device supports the requested number of channels 02588 if (channels != i ) continue; // try next channel number 02589 // If here, we found the largest working channel value 02590 break; 02591 } 02592 info->maxOutputChannels = i; 02593 02594 // Now find the minimum number of channels it can handle 02595 for (i=1; i<=info->maxOutputChannels; i++) { 02596 channels = i; 02597 if (ioctl(fd, SNDCTL_DSP_CHANNELS, &channels) == -1 || channels != i) 02598 continue; // try next channel number 02599 // If here, we found the smallest working channel value 02600 break; 02601 } 02602 info->minOutputChannels = i; 02603 close(fd); 02604 02605 capture_probe: 02606 // Now try for capture 02607 fd = open(info->name, O_RDONLY | O_NONBLOCK); 02608 if (fd == -1) { 02609 // Open device for capture failed ... either busy or doesn't exist 02610 if (errno == EBUSY || errno == EAGAIN) 02611 sprintf(message, "RtAudio: OSS capture device (%s) is busy and cannot be probed.", 02612 info->name); 02613 else 02614 sprintf(message, "RtAudio: OSS capture device (%s) open error.", info->name); 02615 error(RtError::DEBUG_WARNING); 02616 if (info->maxOutputChannels == 0) 02617 // didn't open for playback either ... device invalid 02618 return; 02619 goto probe_parameters; 02620 } 02621 02622 // We have the device open for capture ... see how many channels it can handle 02623 for (i=MAX_CHANNELS; i>0; i--) { 02624 channels = i; 02625 if (ioctl(fd, SNDCTL_DSP_CHANNELS, &channels) == -1 || channels != i) { 02626 continue; // as above 02627 } 02628 // If here, we found a working channel value 02629 break; 02630 } 02631 info->maxInputChannels = i; 02632 02633 // Now find the minimum number of channels it can handle 02634 for (i=1; i<=info->maxInputChannels; i++) { 02635 channels = i; 02636 if (ioctl(fd, SNDCTL_DSP_CHANNELS, &channels) == -1 || channels != i) 02637 continue; // try next channel number 02638 // If here, we found the smallest working channel value 02639 break; 02640 } 02641 info->minInputChannels = i; 02642 close(fd); 02643 02644 if (info->maxOutputChannels == 0 && info->maxInputChannels == 0) { 02645 sprintf(message, "RtAudio: OSS device (%s) reports zero channels for input and output.", 02646 info->name); 02647 error(RtError::DEBUG_WARNING); 02648 return; 02649 } 02650 02651 // If device opens for both playback and capture, we determine the channels. 02652 if (info->maxOutputChannels == 0 || info->maxInputChannels == 0) 02653 goto probe_parameters; 02654 02655 fd = open(info->name, O_RDWR | O_NONBLOCK); 02656 if (fd == -1) 02657 goto probe_parameters; 02658 02659 ioctl(fd, SNDCTL_DSP_SETDUPLEX, 0); 02660 ioctl(fd, SNDCTL_DSP_GETCAPS, &mask); 02661 if (mask & DSP_CAP_DUPLEX) { 02662 info->hasDuplexSupport = true; 02663 // We have the device open for duplex ... see how many channels it can handle 02664 for (i=MAX_CHANNELS; i>0; i--) { 02665 channels = i; 02666 if (ioctl(fd, SNDCTL_DSP_CHANNELS, &channels) == -1 || channels != i) 02667 continue; // as above 02668 // If here, we found a working channel value 02669 break; 02670 } 02671 info->maxDuplexChannels = i; 02672 02673 // Now find the minimum number of channels it can handle 02674 for (i=1; i<=info->maxDuplexChannels; i++) { 02675 channels = i; 02676 if (ioctl(fd, SNDCTL_DSP_CHANNELS, &channels) == -1 || channels != i) 02677 continue; // try next channel number 02678 // If here, we found the smallest working channel value 02679 break; 02680 } 02681 info->minDuplexChannels = i; 02682 } 02683 close(fd); 02684 02685 probe_parameters: 02686 // At this point, we need to figure out the supported data formats 02687 // and sample rates. We'll proceed by openning the device in the 02688 // direction with the maximum number of channels, or playback if 02689 // they are equal. This might limit our sample rate options, but so 02690 // be it. 02691 02692 if (info->maxOutputChannels >= info->maxInputChannels) { 02693 fd = open(info->name, O_WRONLY | O_NONBLOCK); 02694 channels = info->maxOutputChannels; 02695 } 02696 else { 02697 fd = open(info->name, O_RDONLY | O_NONBLOCK); 02698 channels = info->maxInputChannels; 02699 } 02700 02701 if (fd == -1) { 02702 // We've got some sort of conflict ... abort 02703 sprintf(message, "RtAudio: OSS device (%s) won't reopen during probe.", 02704 info->name); 02705 error(RtError::DEBUG_WARNING); 02706 return; 02707 } 02708 02709 // We have an open device ... set to maximum channels. 02710 i = channels; 02711 if (ioctl(fd, SNDCTL_DSP_CHANNELS, &channels) == -1 || channels != i) { 02712 // We've got some sort of conflict ... abort 02713 close(fd); 02714 sprintf(message, "RtAudio: OSS device (%s) won't revert to previous channel setting.", 02715 info->name); 02716 error(RtError::DEBUG_WARNING); 02717 return; 02718 } 02719 02720 if (ioctl(fd, SNDCTL_DSP_GETFMTS, &mask) == -1) { 02721 close(fd); 02722 sprintf(message, "RtAudio: OSS device (%s) can't get supported audio formats.", 02723 info->name); 02724 error(RtError::DEBUG_WARNING); 02725 return; 02726 } 02727 02728 // Probe the supported data formats ... we don't care about endian-ness just yet. 02729 int format; 02730 info->nativeFormats = 0; 02731 #if defined (AFMT_S32_BE) 02732 // This format does not seem to be in the 2.4 kernel version of OSS soundcard.h 02733 if (mask & AFMT_S32_BE) { 02734 format = AFMT_S32_BE; 02735 info->nativeFormats |= RTAUDIO_SINT32; 02736 } 02737 #endif 02738 #if defined (AFMT_S32_LE) 02739 /* This format is not in the 2.4.4 kernel version of OSS soundcard.h */ 02740 if (mask & AFMT_S32_LE) { 02741 format = AFMT_S32_LE; 02742 info->nativeFormats |= RTAUDIO_SINT32; 02743 } 02744 #endif 02745 if (mask & AFMT_S8) { 02746 format = AFMT_S8; 02747 info->nativeFormats |= RTAUDIO_SINT8; 02748 } 02749 if (mask & AFMT_S16_BE) { 02750 format = AFMT_S16_BE; 02751 info->nativeFormats |= RTAUDIO_SINT16; 02752 } 02753 if (mask & AFMT_S16_LE) { 02754 format = AFMT_S16_LE; 02755 info->nativeFormats |= RTAUDIO_SINT16; 02756 } 02757 02758 // Check that we have at least one supported format 02759 if (info->nativeFormats == 0) { 02760 close(fd); 02761 sprintf(message, "RtAudio: OSS device (%s) data format not supported by RtAudio.", 02762 info->name); 02763 error(RtError::DEBUG_WARNING); 02764 return; 02765 } 02766 02767 // Set the format 02768 i = format; 02769 if (ioctl(fd, SNDCTL_DSP_SETFMT, &format) == -1 || format != i) { 02770 close(fd); 02771 sprintf(message, "RtAudio: OSS device (%s) error setting data format.", 02772 info->name); 02773 error(RtError::DEBUG_WARNING); 02774 return; 02775 } 02776 02777 // Probe the supported sample rates ... first get lower limit 02778 int speed = 1; 02779 if (ioctl(fd, SNDCTL_DSP_SPEED, &speed) == -1) { 02780 // If we get here, we're probably using an ALSA driver with OSS-emulation, 02781 // which doesn't conform to the OSS specification. In this case, 02782 // we'll probe our predefined list of sample rates for working values. 02783 info->nSampleRates = 0; 02784 for (i=0; i<MAX_SAMPLE_RATES; i++) { 02785 speed = SAMPLE_RATES[i]; 02786 if (ioctl(fd, SNDCTL_DSP_SPEED, &speed) != -1) { 02787 info->sampleRates[info->nSampleRates] = SAMPLE_RATES[i]; 02788 info->nSampleRates++; 02789 } 02790 } 02791 if (info->nSampleRates == 0) { 02792 close(fd); 02793 return; 02794 } 02795 goto finished; 02796 } 02797 info->sampleRates[0] = speed; 02798 02799 // Now get upper limit 02800 speed = 1000000; 02801 if (ioctl(fd, SNDCTL_DSP_SPEED, &speed) == -1) { 02802 close(fd); 02803 sprintf(message, "RtAudio: OSS device (%s) error setting sample rate.", 02804 info->name); 02805 error(RtError::DEBUG_WARNING); 02806 return; 02807 } 02808 info->sampleRates[1] = speed; 02809 info->nSampleRates = -1; 02810 02811 finished: // That's all ... close the device and return 02812 close(fd); 02813 info->probed = true; 02814 return; 02815 } 02816 02817 bool RtAudio :: probeDeviceOpen(int device, RTAUDIO_STREAM *stream, 02818 STREAM_MODE mode, int channels, 02819 int sampleRate, RTAUDIO_FORMAT format, 02820 int *bufferSize, int numberOfBuffers) 02821 { 02822 int buffers, buffer_bytes, device_channels, device_format; 02823 int srate, temp, fd; 02824 02825 const char *name = devices[device].name; 02826 02827 if (mode == OUTPUT) 02828 fd = open(name, O_WRONLY | O_NONBLOCK); 02829 else { // mode == INPUT 02830 if (stream->mode == OUTPUT && stream->device[0] == device) { 02831 // We just set the same device for playback ... close and reopen for duplex (OSS only). 02832 close(stream->handle[0]); 02833 stream->handle[0] = 0; 02834 // First check that the number previously set channels is the same. 02835 if (stream->nUserChannels[0] != channels) { 02836 sprintf(message, "RtAudio: input/output channels must be equal for OSS duplex device (%s).", name); 02837 goto error; 02838 } 02839 fd = open(name, O_RDWR | O_NONBLOCK); 02840 } 02841 else 02842 fd = open(name, O_RDONLY | O_NONBLOCK); 02843 } 02844 02845 if (fd == -1) { 02846 if (errno == EBUSY || errno == EAGAIN) 02847 sprintf(message, "RtAudio: OSS device (%s) is busy and cannot be opened.", 02848 name); 02849 else 02850 sprintf(message, "RtAudio: OSS device (%s) cannot be opened.", name); 02851 goto error; 02852 } 02853 02854 // Now reopen in blocking mode. 02855 close(fd); 02856 if (mode == OUTPUT) 02857 fd = open(name, O_WRONLY | O_SYNC); 02858 else { // mode == INPUT 02859 if (stream->mode == OUTPUT && stream->device[0] == device) 02860 fd = open(name, O_RDWR | O_SYNC); 02861 else 02862 fd = open(name, O_RDONLY | O_SYNC); 02863 } 02864 02865 if (fd == -1) { 02866 sprintf(message, "RtAudio: OSS device (%s) cannot be opened.", name); 02867 goto error; 02868 } 02869 02870 // Get the sample format mask 02871 int mask; 02872 if (ioctl(fd, SNDCTL_DSP_GETFMTS, &mask) == -1) { 02873 close(fd); 02874 sprintf(message, "RtAudio: OSS device (%s) can't get supported audio formats.", 02875 name); 02876 goto error; 02877 } 02878 02879 // Determine how to set the device format. 02880 stream->userFormat = format; 02881 device_format = -1; 02882 stream->doByteSwap[mode] = false; 02883 if (format == RTAUDIO_SINT8) { 02884 if (mask & AFMT_S8) { 02885 device_format = AFMT_S8; 02886 stream->deviceFormat[mode] = RTAUDIO_SINT8; 02887 } 02888 } 02889 else if (format == RTAUDIO_SINT16) { 02890 if (mask & AFMT_S16_NE) { 02891 device_format = AFMT_S16_NE; 02892 stream->deviceFormat[mode] = RTAUDIO_SINT16; 02893 } 02894 #if BYTE_ORDER == LITTLE_ENDIAN 02895 else if (mask & AFMT_S16_BE) { 02896 device_format = AFMT_S16_BE; 02897 stream->deviceFormat[mode] = RTAUDIO_SINT16; 02898 stream->doByteSwap[mode] = true; 02899 } 02900 #else 02901 else if (mask & AFMT_S16_LE) { 02902 device_format = AFMT_S16_LE; 02903 stream->deviceFormat[mode] = RTAUDIO_SINT16; 02904 stream->doByteSwap[mode] = true; 02905 } 02906 #endif 02907 } 02908 #if defined (AFMT_S32_NE) && defined (AFMT_S32_LE) && defined (AFMT_S32_BE) 02909 else if (format == RTAUDIO_SINT32) { 02910 if (mask & AFMT_S32_NE) { 02911 device_format = AFMT_S32_NE; 02912 stream->deviceFormat[mode] = RTAUDIO_SINT32; 02913 } 02914 #if BYTE_ORDER == LITTLE_ENDIAN 02915 else if (mask & AFMT_S32_BE) { 02916 device_format = AFMT_S32_BE; 02917 stream->deviceFormat[mode] = RTAUDIO_SINT32; 02918 stream->doByteSwap[mode] = true; 02919 } 02920 #else 02921 else if (mask & AFMT_S32_LE) { 02922 device_format = AFMT_S32_LE; 02923 stream->deviceFormat[mode] = RTAUDIO_SINT32; 02924 stream->doByteSwap[mode] = true; 02925 } 02926 #endif 02927 } 02928 #endif 02929 02930 if (device_format == -1) { 02931 // The user requested format is not natively supported by the device. 02932 if (mask & AFMT_S16_NE) { 02933 device_format = AFMT_S16_NE; 02934 stream->deviceFormat[mode] = RTAUDIO_SINT16; 02935 } 02936 #if BYTE_ORDER == LITTLE_ENDIAN 02937 else if (mask & AFMT_S16_BE) { 02938 device_format = AFMT_S16_BE; 02939 stream->deviceFormat[mode] = RTAUDIO_SINT16; 02940 stream->doByteSwap[mode] = true; 02941 } 02942 #else 02943 else if (mask & AFMT_S16_LE) { 02944 device_format = AFMT_S16_LE; 02945 stream->deviceFormat[mode] = RTAUDIO_SINT16; 02946 stream->doByteSwap[mode] = true; 02947 } 02948 #endif 02949 #if defined (AFMT_S32_NE) && defined (AFMT_S32_LE) && defined (AFMT_S32_BE) 02950 else if (mask & AFMT_S32_NE) { 02951 device_format = AFMT_S32_NE; 02952 stream->deviceFormat[mode] = RTAUDIO_SINT32; 02953 } 02954 #if BYTE_ORDER == LITTLE_ENDIAN 02955 else if (mask & AFMT_S32_BE) { 02956 device_format = AFMT_S32_BE; 02957 stream->deviceFormat[mode] = RTAUDIO_SINT32; 02958 stream->doByteSwap[mode] = true; 02959 } 02960 #else 02961 else if (mask & AFMT_S32_LE) { 02962 device_format = AFMT_S32_LE; 02963 stream->deviceFormat[mode] = RTAUDIO_SINT32; 02964 stream->doByteSwap[mode] = true; 02965 } 02966 #endif 02967 #endif 02968 else if (mask & AFMT_S8) { 02969 device_format = AFMT_S8; 02970 stream->deviceFormat[mode] = RTAUDIO_SINT8; 02971 } 02972 } 02973 02974 if (stream->deviceFormat[mode] == 0) { 02975 // This really shouldn't happen ... 02976 close(fd); 02977 sprintf(message, "RtAudio: OSS device (%s) data format not supported by RtAudio.", 02978 name); 02979 goto error; 02980 } 02981 02982 // Determine the number of channels for this device. Note that the 02983 // channel value requested by the user might be < min_X_Channels. 02984 stream->nUserChannels[mode] = channels; 02985 device_channels = channels; 02986 if (mode == OUTPUT) { 02987 if (channels < devices[device].minOutputChannels) 02988 device_channels = devices[device].minOutputChannels; 02989 } 02990 else { // mode == INPUT 02991 if (stream->mode == OUTPUT && stream->device[0] == device) { 02992 // We're doing duplex setup here. 02993 if (channels < devices[device].minDuplexChannels) 02994 device_channels = devices[device].minDuplexChannels; 02995 } 02996 else { 02997 if (channels < devices[device].minInputChannels) 02998 device_channels = devices[device].minInputChannels; 02999 } 03000 } 03001 stream->nDeviceChannels[mode] = device_channels; 03002 03003 // Attempt to set the buffer size. According to OSS, the minimum 03004 // number of buffers is two. The supposed minimum buffer size is 16 03005 // bytes, so that will be our lower bound. The argument to this 03006 // call is in the form 0xMMMMSSSS (hex), where the buffer size (in 03007 // bytes) is given as 2^SSSS and the number of buffers as 2^MMMM. 03008 // We'll check the actual value used near the end of the setup 03009 // procedure. 03010 buffer_bytes = *bufferSize * formatBytes(stream->deviceFormat[mode]) * device_channels; 03011 if (buffer_bytes < 16) buffer_bytes = 16; 03012 buffers = numberOfBuffers; 03013 if (buffers < 2) buffers = 2; 03014 temp = ((int) buffers << 16) + (int)(log10((double)buffer_bytes)/log10(2.0)); 03015 if (ioctl(fd, SNDCTL_DSP_SETFRAGMENT, &temp)) { 03016 close(fd); 03017 sprintf(message, "RtAudio: OSS error setting fragment size for device (%s).", 03018 name); 03019 goto error; 03020 } 03021 stream->nBuffers = buffers; 03022 03023 // Set the data format. 03024 temp = device_format; 03025 if (ioctl(fd, SNDCTL_DSP_SETFMT, &device_format) == -1 || device_format != temp) { 03026 close(fd); 03027 sprintf(message, "RtAudio: OSS error setting data format for device (%s).", 03028 name); 03029 goto error; 03030 } 03031 03032 // Set the number of channels. 03033 temp = device_channels; 03034 if (ioctl(fd, SNDCTL_DSP_CHANNELS, &device_channels) == -1 || device_channels != temp) { 03035 close(fd); 03036 sprintf(message, "RtAudio: OSS error setting %d channels on device (%s).", 03037 temp, name); 03038 goto error; 03039 } 03040 03041 // Set the sample rate. 03042 srate = sampleRate; 03043 temp = srate; 03044 if (ioctl(fd, SNDCTL_DSP_SPEED, &srate) == -1) { 03045 close(fd); 03046 sprintf(message, "RtAudio: OSS error setting sample rate = %d on device (%s).", 03047 temp, name); 03048 goto error; 03049 } 03050 03051 // Verify the sample rate setup worked. 03052 if (abs(srate - temp) > 100) { 03053 close(fd); 03054 sprintf(message, "RtAudio: OSS error ... audio device (%s) doesn't support sample rate of %d.", 03055 name, temp); 03056 goto error; 03057 } 03058 stream->sampleRate = sampleRate; 03059 03060 if (ioctl(fd, SNDCTL_DSP_GETBLKSIZE, &buffer_bytes) == -1) { 03061 close(fd); 03062 sprintf(message, "RtAudio: OSS error getting buffer size for device (%s).", 03063 name); 03064 goto error; 03065 } 03066 03067 // Save buffer size (in sample frames). 03068 *bufferSize = buffer_bytes / (formatBytes(stream->deviceFormat[mode]) * device_channels); 03069 stream->bufferSize = *bufferSize; 03070 03071 if (mode == INPUT && stream->mode == OUTPUT && 03072 stream->device[0] == device) { 03073 // We're doing duplex setup here. 03074 stream->deviceFormat[0] = stream->deviceFormat[1]; 03075 stream->nDeviceChannels[0] = device_channels; 03076 } 03077 03078 // Set flags for buffer conversion 03079 stream->doConvertBuffer[mode] = false; 03080 if (stream->userFormat != stream->deviceFormat[mode]) 03081 stream->doConvertBuffer[mode] = true; 03082 if (stream->nUserChannels[mode] < stream->nDeviceChannels[mode]) 03083 stream->doConvertBuffer[mode] = true; 03084 03085 // Allocate necessary internal buffers 03086 if ( stream->nUserChannels[0] != stream->nUserChannels[1] ) { 03087 03088 long buffer_bytes; 03089 if (stream->nUserChannels[0] >= stream->nUserChannels[1]) 03090 buffer_bytes = stream->nUserChannels[0]; 03091 else 03092 buffer_bytes = stream->nUserChannels[1]; 03093 03094 buffer_bytes *= *bufferSize * formatBytes(stream->userFormat); 03095 if (stream->userBuffer) free(stream->userBuffer); 03096 stream->userBuffer = (char *) calloc(buffer_bytes, 1); 03097 if (stream->userBuffer == NULL) { 03098 close(fd); 03099 sprintf(message, "RtAudio: OSS error allocating user buffer memory (%s).", 03100 name); 03101 goto error; 03102 } 03103 } 03104 03105 if ( stream->doConvertBuffer[mode] ) { 03106 03107 long buffer_bytes; 03108 bool makeBuffer = true; 03109 if ( mode == OUTPUT ) 03110 buffer_bytes = stream->nDeviceChannels[0] * formatBytes(stream->deviceFormat[0]); 03111 else { // mode == INPUT 03112 buffer_bytes = stream->nDeviceChannels[1] * formatBytes(stream->deviceFormat[1]); 03113 if ( stream->mode == OUTPUT && stream->deviceBuffer ) { 03114 long bytes_out = stream->nDeviceChannels[0] * formatBytes(stream->deviceFormat[0]); 03115 if ( buffer_bytes < bytes_out ) makeBuffer = false; 03116 } 03117 } 03118 03119 if ( makeBuffer ) { 03120 buffer_bytes *= *bufferSize; 03121 if (stream->deviceBuffer) free(stream->deviceBuffer); 03122 stream->deviceBuffer = (char *) calloc(buffer_bytes, 1); 03123 if (stream->deviceBuffer == NULL) { 03124 close(fd); 03125 free(stream->userBuffer); 03126 sprintf(message, "RtAudio: OSS error allocating device buffer memory (%s).", 03127 name); 03128 goto error; 03129 } 03130 } 03131 } 03132 03133 stream->device[mode] = device; 03134 stream->handle[mode] = fd; 03135 stream->state = STREAM_STOPPED; 03136 if ( stream->mode == OUTPUT && mode == INPUT ) { 03137 stream->mode = DUPLEX; 03138 if (stream->device[0] == device) 03139 stream->handle[0] = fd; 03140 } 03141 else 03142 stream->mode = mode; 03143 03144 return SUCCESS; 03145 03146 error: 03147 if (stream->handle[0]) { 03148 close(stream->handle[0]); 03149 stream->handle[0] = 0; 03150 } 03151 error(RtError::WARNING); 03152 return FAILURE; 03153 } 03154 03155 void RtAudio :: closeStream(int streamId) 03156 { 03157 // We don't want an exception to be thrown here because this 03158 // function is called by our class destructor. So, do our own 03159 // streamId check. 03160 if ( streams.find( streamId ) == streams.end() ) { 03161 sprintf(message, "RtAudio: invalid stream identifier!"); 03162 error(RtError::WARNING); 03163 return; 03164 } 03165 03166 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) streams[streamId]; 03167 03168 if (stream->callbackInfo.usingCallback) { 03169 pthread_cancel(stream->callbackInfo.thread); 03170 pthread_join(stream->callbackInfo.thread, NULL); 03171 } 03172 03173 if (stream->state == STREAM_RUNNING) { 03174 if (stream->mode == OUTPUT || stream->mode == DUPLEX) 03175 ioctl(stream->handle[0], SNDCTL_DSP_RESET, 0); 03176 if (stream->mode == INPUT || stream->mode == DUPLEX) 03177 ioctl(stream->handle[1], SNDCTL_DSP_RESET, 0); 03178 } 03179 03180 pthread_mutex_destroy(&stream->mutex); 03181 03182 if (stream->handle[0]) 03183 close(stream->handle[0]); 03184 03185 if (stream->handle[1]) 03186 close(stream->handle[1]); 03187 03188 if (stream->userBuffer) 03189 free(stream->userBuffer); 03190 03191 if (stream->deviceBuffer) 03192 free(stream->deviceBuffer); 03193 03194 free(stream); 03195 streams.erase(streamId); 03196 } 03197 03198 void RtAudio :: startStream(int streamId) 03199 { 03200 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId); 03201 03202 MUTEX_LOCK(&stream->mutex); 03203 03204 stream->state = STREAM_RUNNING; 03205 03206 // No need to do anything else here ... OSS automatically starts 03207 // when fed samples. 03208 03209 MUTEX_UNLOCK(&stream->mutex); 03210 } 03211 03212 void RtAudio :: stopStream(int streamId) 03213 { 03214 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId); 03215 03216 MUTEX_LOCK(&stream->mutex); 03217 03218 if (stream->state == STREAM_STOPPED) 03219 goto unlock; 03220 03221 int err; 03222 if (stream->mode == OUTPUT || stream->mode == DUPLEX) { 03223 err = ioctl(stream->handle[0], SNDCTL_DSP_SYNC, 0); 03224 if (err < -1) { 03225 sprintf(message, "RtAudio: OSS error stopping device (%s).", 03226 devices[stream->device[0]].name); 03227 error(RtError::DRIVER_ERROR); 03228 } 03229 } 03230 else { 03231 err = ioctl(stream->handle[1], SNDCTL_DSP_SYNC, 0); 03232 if (err < -1) { 03233 sprintf(message, "RtAudio: OSS error stopping device (%s).", 03234 devices[stream->device[1]].name); 03235 error(RtError::DRIVER_ERROR); 03236 } 03237 } 03238 stream->state = STREAM_STOPPED; 03239 03240 unlock: 03241 MUTEX_UNLOCK(&stream->mutex); 03242 } 03243 03244 void RtAudio :: abortStream(int streamId) 03245 { 03246 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId); 03247 03248 MUTEX_LOCK(&stream->mutex); 03249 03250 if (stream->state == STREAM_STOPPED) 03251 goto unlock; 03252 03253 int err; 03254 if (stream->mode == OUTPUT || stream->mode == DUPLEX) { 03255 err = ioctl(stream->handle[0], SNDCTL_DSP_RESET, 0); 03256 if (err < -1) { 03257 sprintf(message, "RtAudio: OSS error aborting device (%s).", 03258 devices[stream->device[0]].name); 03259 error(RtError::DRIVER_ERROR); 03260 } 03261 } 03262 else { 03263 err = ioctl(stream->handle[1], SNDCTL_DSP_RESET, 0); 03264 if (err < -1) { 03265 sprintf(message, "RtAudio: OSS error aborting device (%s).", 03266 devices[stream->device[1]].name); 03267 error(RtError::DRIVER_ERROR); 03268 } 03269 } 03270 stream->state = STREAM_STOPPED; 03271 03272 unlock: 03273 MUTEX_UNLOCK(&stream->mutex); 03274 } 03275 03276 int RtAudio :: streamWillBlock(int streamId) 03277 { 03278 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId); 03279 03280 MUTEX_LOCK(&stream->mutex); 03281 03282 int bytes = 0, channels = 0, frames = 0; 03283 if (stream->state == STREAM_STOPPED) 03284 goto unlock; 03285 03286 audio_buf_info info; 03287 if (stream->mode == OUTPUT || stream->mode == DUPLEX) { 03288 ioctl(stream->handle[0], SNDCTL_DSP_GETOSPACE, &info); 03289 bytes = info.bytes; 03290 channels = stream->nDeviceChannels[0]; 03291 } 03292 03293 if (stream->mode == INPUT || stream->mode == DUPLEX) { 03294 ioctl(stream->handle[1], SNDCTL_DSP_GETISPACE, &info); 03295 if (stream->mode == DUPLEX ) { 03296 bytes = (bytes < info.bytes) ? bytes : info.bytes; 03297 channels = stream->nDeviceChannels[0]; 03298 } 03299 else { 03300 bytes = info.bytes; 03301 channels = stream->nDeviceChannels[1]; 03302 } 03303 } 03304 03305 frames = (int) (bytes / (channels * formatBytes(stream->deviceFormat[0]))); 03306 frames -= stream->bufferSize; 03307 if (frames < 0) frames = 0; 03308 03309 unlock: 03310 MUTEX_UNLOCK(&stream->mutex); 03311 return frames; 03312 } 03313 03314 void RtAudio :: tickStream(int streamId) 03315 { 03316 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId); 03317 03318 int stopStream = 0; 03319 if (stream->state == STREAM_STOPPED) { 03320 if (stream->callbackInfo.usingCallback) usleep(50000); // sleep 50 milliseconds 03321 return; 03322 } 03323 else if (stream->callbackInfo.usingCallback) { 03324 RTAUDIO_CALLBACK callback = (RTAUDIO_CALLBACK) stream->callbackInfo.callback; 03325 stopStream = callback(stream->userBuffer, stream->bufferSize, stream->callbackInfo.userData); 03326 } 03327 03328 MUTEX_LOCK(&stream->mutex); 03329 03330 // The state might change while waiting on a mutex. 03331 if (stream->state == STREAM_STOPPED) 03332 goto unlock; 03333 03334 int result; 03335 char *buffer; 03336 int samples; 03337 RTAUDIO_FORMAT format; 03338 if (stream->mode == OUTPUT || stream->mode == DUPLEX) { 03339 03340 // Setup parameters and do buffer conversion if necessary. 03341 if (stream->doConvertBuffer[0]) { 03342 convertStreamBuffer(stream, OUTPUT); 03343 buffer = stream->deviceBuffer; 03344 samples = stream->bufferSize * stream->nDeviceChannels[0]; 03345 format = stream->deviceFormat[0]; 03346 } 03347 else { 03348 buffer = stream->userBuffer; 03349 samples = stream->bufferSize * stream->nUserChannels[0]; 03350 format = stream->userFormat; 03351 } 03352 03353 // Do byte swapping if necessary. 03354 if (stream->doByteSwap[0]) 03355 byteSwapBuffer(buffer, samples, format); 03356 03357 // Write samples to device. 03358 result = write(stream->handle[0], buffer, samples * formatBytes(format)); 03359 03360 if (result == -1) { 03361 // This could be an underrun, but the basic OSS API doesn't provide a means for determining that. 03362 sprintf(message, "RtAudio: OSS audio write error for device (%s).", 03363 devices[stream->device[0]].name); 03364 error(RtError::DRIVER_ERROR); 03365 } 03366 } 03367 03368 if (stream->mode == INPUT || stream->mode == DUPLEX) { 03369 03370 // Setup parameters. 03371 if (stream->doConvertBuffer[1]) { 03372 buffer = stream->deviceBuffer; 03373 samples = stream->bufferSize * stream->nDeviceChannels[1]; 03374 format = stream->deviceFormat[1]; 03375 } 03376 else { 03377 buffer = stream->userBuffer; 03378 samples = stream->bufferSize * stream->nUserChannels[1]; 03379 format = stream->userFormat; 03380 } 03381 03382 // Read samples from device. 03383 result = read(stream->handle[1], buffer, samples * formatBytes(format)); 03384 03385 if (result == -1) { 03386 // This could be an overrun, but the basic OSS API doesn't provide a means for determining that. 03387 sprintf(message, "RtAudio: OSS audio read error for device (%s).", 03388 devices[stream->device[1]].name); 03389 error(RtError::DRIVER_ERROR); 03390 } 03391 03392 // Do byte swapping if necessary. 03393 if (stream->doByteSwap[1]) 03394 byteSwapBuffer(buffer, samples, format); 03395 03396 // Do buffer conversion if necessary. 03397 if (stream->doConvertBuffer[1]) 03398 convertStreamBuffer(stream, INPUT); 03399 } 03400 03401 unlock: 03402 MUTEX_UNLOCK(&stream->mutex); 03403 03404 if (stream->callbackInfo.usingCallback && stopStream) 03405 this->stopStream(streamId); 03406 } 03407 03408 extern "C" void *callbackHandler(void *ptr) 03409 { 03410 CALLBACK_INFO *info = (CALLBACK_INFO *) ptr; 03411 RtAudio *object = (RtAudio *) info->object; 03412 int stream = info->streamId; 03413 bool *usingCallback = &info->usingCallback; 03414 03415 while ( *usingCallback ) { 03416 pthread_testcancel(); 03417 try { 03418 object->tickStream(stream); 03419 } 03420 catch (RtError &exception) { 03421 fprintf(stderr, "\nRtAudio: Callback thread error (%s) ... closing thread.\n\n", 03422 exception.getMessage()); 03423 break; 03424 } 03425 } 03426 03427 return 0; 03428 } 03429 03430 03431 //******************** End of __LINUX_OSS__ *********************// 03432 03433 #elif defined(__WINDOWS_ASIO__) // ASIO API on Windows 03434 03435 // The ASIO API is designed around a callback scheme, so this 03436 // implementation is similar to that used for OS X CoreAudio. The 03437 // primary constraint with ASIO is that it only allows access to a 03438 // single driver at a time. Thus, it is not possible to have more 03439 // than one simultaneous RtAudio stream. 03440 // 03441 // This implementation also requires a number of external ASIO files 03442 // and a few global variables. The ASIO callback scheme does not 03443 // allow for the passing of user data, so we must create a global 03444 // pointer to our callbackInfo structure. 03445 03446 #include "asio/asiosys.h" 03447 #include "asio/asio.h" 03448 #include "asio/asiodrivers.h" 03449 #include <math.h> 03450 03451 AsioDrivers drivers; 03452 ASIOCallbacks asioCallbacks; 03453 CALLBACK_INFO *asioCallbackInfo; 03454 ASIODriverInfo driverInfo; 03455 03456 void RtAudio :: initialize(void) 03457 { 03458 nDevices = drivers.asioGetNumDev(); 03459 if (nDevices <= 0) return; 03460 03461 // Allocate the RTAUDIO_DEVICE structures. 03462 devices = (RTAUDIO_DEVICE *) calloc(nDevices, sizeof(RTAUDIO_DEVICE)); 03463 if (devices == NULL) { 03464 sprintf(message, "RtAudio: memory allocation error!"); 03465 error(RtError::MEMORY_ERROR); 03466 } 03467 03468 // Write device driver names to device structures and then probe the 03469 // device capabilities. 03470 for (int i=0; i<nDevices; i++) { 03471 if ( drivers.asioGetDriverName( i, devices[i].name, 128 ) == 0 ) 03472 //probeDeviceInfo(&devices[i]); 03473 ; 03474 else { 03475 sprintf(message, "RtAudio: error getting ASIO driver name for device index %d!", i); 03476 error(RtError::WARNING); 03477 } 03478 } 03479 03480 drivers.removeCurrentDriver(); 03481 driverInfo.asioVersion = 2; 03482 // See note in DirectSound implementation about GetDesktopWindow(). 03483 driverInfo.sysRef = GetForegroundWindow(); 03484 } 03485 03486 int RtAudio :: getDefaultInputDevice(void) 03487 { 03488 return 0; 03489 } 03490 03491 int RtAudio :: getDefaultOutputDevice(void) 03492 { 03493 return 0; 03494 } 03495 03496 void RtAudio :: probeDeviceInfo(RTAUDIO_DEVICE *info) 03497 { 03498 // Don't probe if a stream is already open. 03499 if ( streams.size() > 0 ) { 03500 sprintf(message, "RtAudio: unable to probe ASIO driver while a stream is open."); 03501 error(RtError::DEBUG_WARNING); 03502 return; 03503 } 03504 03505 if ( !drivers.loadDriver( info->name ) ) { 03506 sprintf(message, "RtAudio: ASIO error loading driver (%s).", info->name); 03507 error(RtError::DEBUG_WARNING); 03508 return; 03509 } 03510 03511 ASIOError result = ASIOInit( &driverInfo ); 03512 if ( result != ASE_OK ) { 03513 char details[32]; 03514 if ( result == ASE_HWMalfunction ) 03515 sprintf(details, "hardware malfunction"); 03516 else if ( result == ASE_NoMemory ) 03517 sprintf(details, "no memory"); 03518 else if ( result == ASE_NotPresent ) 03519 sprintf(details, "driver/hardware not present"); 03520 else 03521 sprintf(details, "unspecified"); 03522 sprintf(message, "RtAudio: ASIO error (%s) initializing driver (%s).", details, info->name); 03523 error(RtError::DEBUG_WARNING); 03524 return; 03525 } 03526 03527 // Determine the device channel information. 03528 long inputChannels, outputChannels; 03529 result = ASIOGetChannels( &inputChannels, &outputChannels ); 03530 if ( result != ASE_OK ) { 03531 drivers.removeCurrentDriver(); 03532 sprintf(message, "RtAudio: ASIO error getting input/output channel count (%s).", info->name); 03533 error(RtError::DEBUG_WARNING); 03534 return; 03535 } 03536 03537 info->maxOutputChannels = outputChannels; 03538 if ( outputChannels > 0 ) info->minOutputChannels = 1; 03539 03540 info->maxInputChannels = inputChannels; 03541 if ( inputChannels > 0 ) info->minInputChannels = 1; 03542 03543 // If device opens for both playback and capture, we determine the channels. 03544 if (info->maxOutputChannels > 0 && info->maxInputChannels > 0) { 03545 info->hasDuplexSupport = true; 03546 info->maxDuplexChannels = (info->maxOutputChannels > info->maxInputChannels) ? 03547 info->maxInputChannels : info->maxOutputChannels; 03548 info->minDuplexChannels = (info->minOutputChannels > info->minInputChannels) ? 03549 info->minInputChannels : info->minOutputChannels; 03550 } 03551 03552 // Determine the supported sample rates. 03553 info->nSampleRates = 0; 03554 for (int i=0; i<MAX_SAMPLE_RATES; i++) { 03555 result = ASIOCanSampleRate( (ASIOSampleRate) SAMPLE_RATES[i] ); 03556 if ( result == ASE_OK ) 03557 info->sampleRates[info->nSampleRates++] = SAMPLE_RATES[i]; 03558 } 03559 03560 if (info->nSampleRates == 0) { 03561 drivers.removeCurrentDriver(); 03562 sprintf( message, "RtAudio: No supported sample rates found for ASIO driver (%s).", info->name ); 03563 error(RtError::DEBUG_WARNING); 03564 return; 03565 } 03566 03567 // Determine supported data types ... just check first channel and assume rest are the same. 03568 ASIOChannelInfo channelInfo; 03569 channelInfo.channel = 0; 03570 channelInfo.isInput = true; 03571 if ( info->maxInputChannels <= 0 ) channelInfo.isInput = false; 03572 result = ASIOGetChannelInfo( &channelInfo ); 03573 if ( result != ASE_OK ) { 03574 drivers.removeCurrentDriver(); 03575 sprintf(message, "RtAudio: ASIO error getting driver (%s) channel information.", info->name); 03576 error(RtError::DEBUG_WARNING); 03577 return; 03578 } 03579 03580 if ( channelInfo.type == ASIOSTInt16MSB || channelInfo.type == ASIOSTInt16LSB ) 03581 info->nativeFormats |= RTAUDIO_SINT16; 03582 else if ( channelInfo.type == ASIOSTInt32MSB || channelInfo.type == ASIOSTInt32LSB ) 03583 info->nativeFormats |= RTAUDIO_SINT32; 03584 else if ( channelInfo.type == ASIOSTFloat32MSB || channelInfo.type == ASIOSTFloat32LSB ) 03585 info->nativeFormats |= RTAUDIO_FLOAT32; 03586 else if ( channelInfo.type == ASIOSTFloat64MSB || channelInfo.type == ASIOSTFloat64LSB ) 03587 info->nativeFormats |= RTAUDIO_FLOAT64; 03588 03589 // Check that we have at least one supported format. 03590 if (info->nativeFormats == 0) { 03591 drivers.removeCurrentDriver(); 03592 sprintf(message, "RtAudio: ASIO driver (%s) data format not supported by RtAudio.", 03593 info->name); 03594 error(RtError::DEBUG_WARNING); 03595 return; 03596 } 03597 03598 info->probed = true; 03599 drivers.removeCurrentDriver(); 03600 } 03601 03602 void bufferSwitch(long index, ASIOBool processNow) 03603 { 03604 RtAudio *object = (RtAudio *) asioCallbackInfo->object; 03605 try { 03606 object->callbackEvent( asioCallbackInfo->streamId, index, (void *)NULL, (void *)NULL ); 03607 } 03608 catch (RtError &exception) { 03609 fprintf(stderr, "\nCallback handler error (%s)!\n\n", exception.getMessage()); 03610 return; 03611 } 03612 03613 return; 03614 } 03615 03616 void sampleRateChanged(ASIOSampleRate sRate) 03617 { 03618 // The ASIO documentation says that this usually only happens during 03619 // external sync. Audio processing is not stopped by the driver, 03620 // actual sample rate might not have even changed, maybe only the 03621 // sample rate status of an AES/EBU or S/PDIF digital input at the 03622 // audio device. 03623 03624 RtAudio *object = (RtAudio *) asioCallbackInfo->object; 03625 try { 03626 object->stopStream( asioCallbackInfo->streamId ); 03627 } 03628 catch (RtError &exception) { 03629 fprintf(stderr, "\nRtAudio: sampleRateChanged() error (%s)!\n\n", exception.getMessage()); 03630 return; 03631 } 03632 03633 fprintf(stderr, "\nRtAudio: ASIO driver reports sample rate changed to %d ... stream stopped!!!", (int) sRate); 03634 } 03635 03636 long asioMessages(long selector, long value, void* message, double* opt) 03637 { 03638 long ret = 0; 03639 switch(selector) { 03640 case kAsioSelectorSupported: 03641 if(value == kAsioResetRequest 03642 || value == kAsioEngineVersion 03643 || value == kAsioResyncRequest 03644 || value == kAsioLatenciesChanged 03645 // The following three were added for ASIO 2.0, you don't 03646 // necessarily have to support them. 03647 || value == kAsioSupportsTimeInfo 03648 || value == kAsioSupportsTimeCode 03649 || value == kAsioSupportsInputMonitor) 03650 ret = 1L; 03651 break; 03652 case kAsioResetRequest: 03653 // Defer the task and perform the reset of the driver during the 03654 // next "safe" situation. You cannot reset the driver right now, 03655 // as this code is called from the driver. Reset the driver is 03656 // done by completely destruct is. I.e. ASIOStop(), 03657 // ASIODisposeBuffers(), Destruction Afterwards you initialize the 03658 // driver again. 03659 fprintf(stderr, "\nRtAudio: ASIO driver reset requested!!!"); 03660 ret = 1L; 03661 break; 03662 case kAsioResyncRequest: 03663 // This informs the application that the driver encountered some 03664 // non-fatal data loss. It is used for synchronization purposes 03665 // of different media. Added mainly to work around the Win16Mutex 03666 // problems in Windows 95/98 with the Windows Multimedia system, 03667 // which could lose data because the Mutex was held too long by 03668 // another thread. However a driver can issue it in other 03669 // situations, too. 03670 fprintf(stderr, "\nRtAudio: ASIO driver resync requested!!!"); 03671 ret = 1L; 03672 break; 03673 case kAsioLatenciesChanged: 03674 // This will inform the host application that the drivers were 03675 // latencies changed. Beware, it this does not mean that the 03676 // buffer sizes have changed! You might need to update internal 03677 // delay data. 03678 fprintf(stderr, "\nRtAudio: ASIO driver latency may have changed!!!"); 03679 ret = 1L; 03680 break; 03681 case kAsioEngineVersion: 03682 // Return the supported ASIO version of the host application. If 03683 // a host application does not implement this selector, ASIO 1.0 03684 // is assumed by the driver. 03685 ret = 2L; 03686 break; 03687 case kAsioSupportsTimeInfo: 03688 // Informs the driver whether the 03689 // asioCallbacks.bufferSwitchTimeInfo() callback is supported. 03690 // For compatibility with ASIO 1.0 drivers the host application 03691 // should always support the "old" bufferSwitch method, too. 03692 ret = 0; 03693 break; 03694 case kAsioSupportsTimeCode: 03695 // Informs the driver wether application is interested in time 03696 // code info. If an application does not need to know about time 03697 // code, the driver has less work to do. 03698 ret = 0; 03699 break; 03700 } 03701 return ret; 03702 } 03703 03704 bool RtAudio :: probeDeviceOpen(int device, RTAUDIO_STREAM *stream, 03705 STREAM_MODE mode, int channels, 03706 int sampleRate, RTAUDIO_FORMAT format, 03707 int *bufferSize, int numberOfBuffers) 03708 { 03709 // Don't attempt to load another driver if a stream is already open. 03710 if ( streams.size() > 0 ) { 03711 sprintf(message, "RtAudio: unable to load ASIO driver while a stream is open."); 03712 error(RtError::WARNING); 03713 return FAILURE; 03714 } 03715 03716 // For ASIO, a duplex stream MUST use the same driver. 03717 if ( mode == INPUT && stream->mode == OUTPUT && stream->device[0] != device ) { 03718 sprintf(message, "RtAudio: ASIO duplex stream must use the same device for input and output."); 03719 error(RtError::WARNING); 03720 return FAILURE; 03721 } 03722 03723 // Only load the driver once for duplex stream. 03724 ASIOError result; 03725 if ( mode != INPUT || stream->mode != OUTPUT ) { 03726 if ( !drivers.loadDriver( devices[device].name ) ) { 03727 sprintf(message, "RtAudio: ASIO error loading driver (%s).", devices[device].name); 03728 error(RtError::DEBUG_WARNING); 03729 return FAILURE; 03730 } 03731 03732 result = ASIOInit( &driverInfo ); 03733 if ( result != ASE_OK ) { 03734 char details[32]; 03735 if ( result == ASE_HWMalfunction ) 03736 sprintf(details, "hardware malfunction"); 03737 else if ( result == ASE_NoMemory ) 03738 sprintf(details, "no memory"); 03739 else if ( result == ASE_NotPresent ) 03740 sprintf(details, "driver/hardware not present"); 03741 else 03742 sprintf(details, "unspecified"); 03743 sprintf(message, "RtAudio: ASIO error (%s) initializing driver (%s).", details, devices[device].name); 03744 error(RtError::DEBUG_WARNING); 03745 return FAILURE; 03746 } 03747 } 03748 03749 // Check the device channel count. 03750 long inputChannels, outputChannels; 03751 result = ASIOGetChannels( &inputChannels, &outputChannels ); 03752 if ( result != ASE_OK ) { 03753 drivers.removeCurrentDriver(); 03754 sprintf(message, "RtAudio: ASIO error getting input/output channel count (%s).", 03755 devices[device].name); 03756 error(RtError::DEBUG_WARNING); 03757 return FAILURE; 03758 } 03759 03760 if ( ( mode == OUTPUT && channels > outputChannels) || 03761 ( mode == INPUT && channels > inputChannels) ) { 03762 drivers.removeCurrentDriver(); 03763 sprintf(message, "RtAudio: ASIO driver (%s) does not support requested channel count (%d).", 03764 devices[device].name, channels); 03765 error(RtError::DEBUG_WARNING); 03766 return FAILURE; 03767 } 03768 stream->nDeviceChannels[mode] = channels; 03769 stream->nUserChannels[mode] = channels; 03770 03771 // Verify the sample rate is supported. 03772 result = ASIOCanSampleRate( (ASIOSampleRate) sampleRate ); 03773 if ( result != ASE_OK ) { 03774 drivers.removeCurrentDriver(); 03775 sprintf(message, "RtAudio: ASIO driver (%s) does not support requested sample rate (%d).", 03776 devices[device].name, sampleRate); 03777 error(RtError::DEBUG_WARNING); 03778 return FAILURE; 03779 } 03780 03781 // Set the sample rate. 03782 result = ASIOSetSampleRate( (ASIOSampleRate) sampleRate ); 03783 if ( result != ASE_OK ) { 03784 drivers.removeCurrentDriver(); 03785 sprintf(message, "RtAudio: ASIO driver (%s) error setting sample rate (%d).", 03786 devices[device].name, sampleRate); 03787 error(RtError::DEBUG_WARNING); 03788 return FAILURE; 03789 } 03790 03791 // Determine the driver data type. 03792 ASIOChannelInfo channelInfo; 03793 channelInfo.channel = 0; 03794 if ( mode == OUTPUT ) channelInfo.isInput = false; 03795 else channelInfo.isInput = true; 03796 result = ASIOGetChannelInfo( &channelInfo ); 03797 if ( result != ASE_OK ) { 03798 drivers.removeCurrentDriver(); 03799 sprintf(message, "RtAudio: ASIO driver (%s) error getting data format.", 03800 devices[device].name); 03801 error(RtError::DEBUG_WARNING); 03802 return FAILURE; 03803 } 03804 03805 // Assuming WINDOWS host is always little-endian. 03806 stream->doByteSwap[mode] = false; 03807 stream->userFormat = format; 03808 stream->deviceFormat[mode] = 0; 03809 if ( channelInfo.type == ASIOSTInt16MSB || channelInfo.type == ASIOSTInt16LSB ) { 03810 stream->deviceFormat[mode] = RTAUDIO_SINT16; 03811 if ( channelInfo.type == ASIOSTInt16MSB ) stream->doByteSwap[mode] = true; 03812 } 03813 else if ( channelInfo.type == ASIOSTInt32MSB || channelInfo.type == ASIOSTInt32LSB ) { 03814 stream->deviceFormat[mode] = RTAUDIO_SINT32; 03815 if ( channelInfo.type == ASIOSTInt32MSB ) stream->doByteSwap[mode] = true; 03816 } 03817 else if ( channelInfo.type == ASIOSTFloat32MSB || channelInfo.type == ASIOSTFloat32LSB ) { 03818 stream->deviceFormat[mode] = RTAUDIO_FLOAT32; 03819 if ( channelInfo.type == ASIOSTFloat32MSB ) stream->doByteSwap[mode] = true; 03820 } 03821 else if ( channelInfo.type == ASIOSTFloat64MSB || channelInfo.type == ASIOSTFloat64LSB ) { 03822 stream->deviceFormat[mode] = RTAUDIO_FLOAT64; 03823 if ( channelInfo.type == ASIOSTFloat64MSB ) stream->doByteSwap[mode] = true; 03824 } 03825 03826 if ( stream->deviceFormat[mode] == 0 ) { 03827 drivers.removeCurrentDriver(); 03828 sprintf(message, "RtAudio: ASIO driver (%s) data format not supported by RtAudio.", 03829 devices[device].name); 03830 error(RtError::DEBUG_WARNING); 03831 return FAILURE; 03832 } 03833 03834 // Set the buffer size. For a duplex stream, this will end up 03835 // setting the buffer size based on the input constraints, which 03836 // should be ok. 03837 long minSize, maxSize, preferSize, granularity; 03838 result = ASIOGetBufferSize( &minSize, &maxSize, &preferSize, &granularity ); 03839 if ( result != ASE_OK ) { 03840 drivers.removeCurrentDriver(); 03841 sprintf(message, "RtAudio: ASIO driver (%s) error getting buffer size.", 03842 devices[device].name); 03843 error(RtError::DEBUG_WARNING); 03844 return FAILURE; 03845 } 03846 03847 if ( *bufferSize < minSize ) *bufferSize = minSize; 03848 else if ( *bufferSize > maxSize ) *bufferSize = maxSize; 03849 else if ( granularity == -1 ) { 03850 // Make sure bufferSize is a power of two. 03851 double power = log10( *bufferSize ) / log10( 2.0 ); 03852 *bufferSize = pow( 2.0, floor(power+0.5) ); 03853 if ( *bufferSize < minSize ) *bufferSize = minSize; 03854 else if ( *bufferSize > maxSize ) *bufferSize = maxSize; 03855 else *bufferSize = preferSize; 03856 } 03857 03858 if ( mode == INPUT && stream->mode == OUTPUT && stream->bufferSize != *bufferSize ) 03859 cout << "possible input/output buffersize discrepancy" << endl; 03860 03861 stream->bufferSize = *bufferSize; 03862 stream->nBuffers = 2; 03863 03864 // ASIO always uses deinterleaved channels. 03865 stream->deInterleave[mode] = true; 03866 03867 // Create the ASIO internal buffers. Since RtAudio sets up input 03868 // and output separately, we'll have to dispose of previously 03869 // created output buffers for a duplex stream. 03870 if ( mode == INPUT && stream->mode == OUTPUT ) { 03871 free(stream->callbackInfo.buffers); 03872 result = ASIODisposeBuffers(); 03873 if ( result != ASE_OK ) { 03874 drivers.removeCurrentDriver(); 03875 sprintf(message, "RtAudio: ASIO driver (%s) error disposing previously allocated buffers.", 03876 devices[device].name); 03877 error(RtError::DEBUG_WARNING); 03878 return FAILURE; 03879 } 03880 } 03881 03882 // Allocate, initialize, and save the bufferInfos in our stream callbackInfo structure. 03883 int i, nChannels = stream->nDeviceChannels[0] + stream->nDeviceChannels[1]; 03884 stream->callbackInfo.buffers = 0; 03885 ASIOBufferInfo *bufferInfos = (ASIOBufferInfo *) malloc( nChannels * sizeof(ASIOBufferInfo) ); 03886 stream->callbackInfo.buffers = (void *) bufferInfos; 03887 ASIOBufferInfo *infos = bufferInfos; 03888 for ( i=0; i<stream->nDeviceChannels[1]; i++, infos++ ) { 03889 infos->isInput = ASIOTrue; 03890 infos->channelNum = i; 03891 infos->buffers[0] = infos->buffers[1] = 0; 03892 } 03893 03894 for ( i=0; i<stream->nDeviceChannels[0]; i++, infos++ ) { 03895 infos->isInput = ASIOFalse; 03896 infos->channelNum = i; 03897 infos->buffers[0] = infos->buffers[1] = 0; 03898 } 03899 03900 // Set up the ASIO callback structure and create the ASIO data buffers. 03901 asioCallbacks.bufferSwitch = &bufferSwitch; 03902 asioCallbacks.sampleRateDidChange = &sampleRateChanged; 03903 asioCallbacks.asioMessage = &asioMessages; 03904 asioCallbacks.bufferSwitchTimeInfo = NULL; 03905 result = ASIOCreateBuffers( bufferInfos, nChannels, stream->bufferSize, &asioCallbacks); 03906 if ( result != ASE_OK ) { 03907 drivers.removeCurrentDriver(); 03908 sprintf(message, "RtAudio: ASIO driver (%s) error creating buffers.", 03909 devices[device].name); 03910 error(RtError::DEBUG_WARNING); 03911 return FAILURE; 03912 } 03913 03914 // Set flags for buffer conversion. 03915 stream->doConvertBuffer[mode] = false; 03916 if (stream->userFormat != stream->deviceFormat[mode]) 03917 stream->doConvertBuffer[mode] = true; 03918 if (stream->nUserChannels[mode] < stream->nDeviceChannels[mode]) 03919 stream->doConvertBuffer[mode] = true; 03920 if (stream->nUserChannels[mode] > 1 && stream->deInterleave[mode]) 03921 stream->doConvertBuffer[mode] = true; 03922 03923 // Allocate necessary internal buffers 03924 if ( stream->nUserChannels[0] != stream->nUserChannels[1] ) { 03925 03926 long buffer_bytes; 03927 if (stream->nUserChannels[0] >= stream->nUserChannels[1]) 03928 buffer_bytes = stream->nUserChannels[0]; 03929 else 03930 buffer_bytes = stream->nUserChannels[1]; 03931 03932 buffer_bytes *= *bufferSize * formatBytes(stream->userFormat); 03933 if (stream->userBuffer) free(stream->userBuffer); 03934 stream->userBuffer = (char *) calloc(buffer_bytes, 1); 03935 if (stream->userBuffer == NULL) 03936 goto memory_error; 03937 } 03938 03939 if ( stream->doConvertBuffer[mode] ) { 03940 03941 long buffer_bytes; 03942 bool makeBuffer = true; 03943 if ( mode == OUTPUT ) 03944 buffer_bytes = stream->nDeviceChannels[0] * formatBytes(stream->deviceFormat[0]); 03945 else { // mode == INPUT 03946 buffer_bytes = stream->nDeviceChannels[1] * formatBytes(stream->deviceFormat[1]); 03947 if ( stream->mode == OUTPUT && stream->deviceBuffer ) { 03948 long bytes_out = stream->nDeviceChannels[0] * formatBytes(stream->deviceFormat[0]); 03949 if ( buffer_bytes < bytes_out ) makeBuffer = false; 03950 } 03951 } 03952 03953 if ( makeBuffer ) { 03954 buffer_bytes *= *bufferSize; 03955 if (stream->deviceBuffer) free(stream->deviceBuffer); 03956 stream->deviceBuffer = (char *) calloc(buffer_bytes, 1); 03957 if (stream->deviceBuffer == NULL) 03958 goto memory_error; 03959 } 03960 } 03961 03962 stream->device[mode] = device; 03963 stream->state = STREAM_STOPPED; 03964 if ( stream->mode == OUTPUT && mode == INPUT ) 03965 // We had already set up an output stream. 03966 stream->mode = DUPLEX; 03967 else 03968 stream->mode = mode; 03969 stream->sampleRate = sampleRate; 03970 asioCallbackInfo = &stream->callbackInfo; 03971 stream->callbackInfo.object = (void *) this; 03972 stream->callbackInfo.waitTime = (unsigned long) (200.0 * stream->bufferSize / stream->sampleRate); 03973 03974 return SUCCESS; 03975 03976 memory_error: 03977 ASIODisposeBuffers(); 03978 drivers.removeCurrentDriver(); 03979 03980 if (stream->callbackInfo.buffers) 03981 free(stream->callbackInfo.buffers); 03982 stream->callbackInfo.buffers = 0; 03983 03984 if (stream->userBuffer) { 03985 free(stream->userBuffer); 03986 stream->userBuffer = 0; 03987 } 03988 sprintf(message, "RtAudio: error allocating buffer memory (%s).", 03989 devices[device].name); 03990 error(RtError::WARNING); 03991 return FAILURE; 03992 } 03993 03994 void RtAudio :: cancelStreamCallback(int streamId) 03995 { 03996 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId); 03997 03998 if (stream->callbackInfo.usingCallback) { 03999 04000 if (stream->state == STREAM_RUNNING) 04001 stopStream( streamId ); 04002 04003 MUTEX_LOCK(&stream->mutex); 04004 04005 stream->callbackInfo.usingCallback = false; 04006 stream->callbackInfo.userData = NULL; 04007 stream->state = STREAM_STOPPED; 04008 stream->callbackInfo.callback = NULL; 04009 04010 MUTEX_UNLOCK(&stream->mutex); 04011 } 04012 } 04013 04014 void RtAudio :: closeStream(int streamId) 04015 { 04016 // We don't want an exception to be thrown here because this 04017 // function is called by our class destructor. So, do our own 04018 // streamId check. 04019 if ( streams.find( streamId ) == streams.end() ) { 04020 sprintf(message, "RtAudio: invalid stream identifier!"); 04021 error(RtError::WARNING); 04022 return; 04023 } 04024 04025 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) streams[streamId]; 04026 04027 if (stream->state == STREAM_RUNNING) 04028 ASIOStop(); 04029 04030 ASIODisposeBuffers(); 04031 //ASIOExit(); 04032 drivers.removeCurrentDriver(); 04033 04034 DeleteCriticalSection(&stream->mutex); 04035 04036 if (stream->callbackInfo.buffers) 04037 free(stream->callbackInfo.buffers); 04038 04039 if (stream->userBuffer) 04040 free(stream->userBuffer); 04041 04042 if (stream->deviceBuffer) 04043 free(stream->deviceBuffer); 04044 04045 free(stream); 04046 streams.erase(streamId); 04047 } 04048 04049 void RtAudio :: startStream(int streamId) 04050 { 04051 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId); 04052 04053 MUTEX_LOCK(&stream->mutex); 04054 04055 if (stream->state == STREAM_RUNNING) { 04056 MUTEX_UNLOCK(&stream->mutex); 04057 return; 04058 } 04059 04060 stream->callbackInfo.blockTick = true; 04061 stream->callbackInfo.stopStream = false; 04062 stream->callbackInfo.streamId = streamId; 04063 ASIOError result = ASIOStart(); 04064 if ( result != ASE_OK ) { 04065 sprintf(message, "RtAudio: ASIO error starting device (%s).", 04066 devices[stream->device[0]].name); 04067 MUTEX_UNLOCK(&stream->mutex); 04068 error(RtError::DRIVER_ERROR); 04069 } 04070 stream->state = STREAM_RUNNING; 04071 04072 MUTEX_UNLOCK(&stream->mutex); 04073 } 04074 04075 void RtAudio :: stopStream(int streamId) 04076 { 04077 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId); 04078 04079 MUTEX_LOCK(&stream->mutex); 04080 04081 if (stream->state == STREAM_STOPPED) { 04082 MUTEX_UNLOCK(&stream->mutex); 04083 return; 04084 } 04085 04086 ASIOError result = ASIOStop(); 04087 if ( result != ASE_OK ) { 04088 sprintf(message, "RtAudio: ASIO error stopping device (%s).", 04089 devices[stream->device[0]].name); 04090 MUTEX_UNLOCK(&stream->mutex); 04091 error(RtError::DRIVER_ERROR); 04092 } 04093 stream->state = STREAM_STOPPED; 04094 04095 MUTEX_UNLOCK(&stream->mutex); 04096 } 04097 04098 void RtAudio :: abortStream(int streamId) 04099 { 04100 stopStream( streamId ); 04101 } 04102 04103 // I don't know how this function can be implemented. 04104 int RtAudio :: streamWillBlock(int streamId) 04105 { 04106 sprintf(message, "RtAudio: streamWillBlock() cannot be implemented for ASIO."); 04107 error(RtError::WARNING); 04108 return 0; 04109 } 04110 04111 void RtAudio :: tickStream(int streamId) 04112 { 04113 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId); 04114 04115 if (stream->state == STREAM_STOPPED) 04116 return; 04117 04118 if (stream->callbackInfo.usingCallback) { 04119 sprintf(message, "RtAudio: tickStream() should not be used when a callback function is set!"); 04120 error(RtError::WARNING); 04121 return; 04122 } 04123 04124 // Block waiting here until the user data is processed in callbackEvent(). 04125 while ( stream->callbackInfo.blockTick ) 04126 Sleep(stream->callbackInfo.waitTime); 04127 04128 MUTEX_LOCK(&stream->mutex); 04129 04130 stream->callbackInfo.blockTick = true; 04131 04132 MUTEX_UNLOCK(&stream->mutex); 04133 } 04134 04135 void RtAudio :: callbackEvent(int streamId, int bufferIndex, void *inData, void *outData) 04136 { 04137 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId); 04138 04139 CALLBACK_INFO *info = asioCallbackInfo; 04140 if ( !info->usingCallback ) { 04141 // Block waiting here until we get new user data in tickStream(). 04142 while ( !info->blockTick ) 04143 Sleep(info->waitTime); 04144 } 04145 else if ( info->stopStream ) { 04146 // Check if the stream should be stopped (via the previous user 04147 // callback return value). We stop the stream here, rather than 04148 // after the function call, so that output data can first be 04149 // processed. 04150 this->stopStream(asioCallbackInfo->streamId); 04151 return; 04152 } 04153 04154 MUTEX_LOCK(&stream->mutex); 04155 04156 // Invoke user callback first, to get fresh output data. 04157 if ( info->usingCallback ) { 04158 RTAUDIO_CALLBACK callback = (RTAUDIO_CALLBACK) info->callback; 04159 if ( callback(stream->userBuffer, stream->bufferSize, info->userData) ) 04160 info->stopStream = true; 04161 } 04162 04163 int nChannels = stream->nDeviceChannels[0] + stream->nDeviceChannels[1]; 04164 int bufferBytes; 04165 ASIOBufferInfo *bufferInfos = (ASIOBufferInfo *) info->buffers; 04166 if ( stream->mode == OUTPUT || stream->mode == DUPLEX ) { 04167 04168 bufferBytes = stream->bufferSize * formatBytes(stream->deviceFormat[0]); 04169 if (stream->doConvertBuffer[0]) { 04170 04171 convertStreamBuffer(stream, OUTPUT); 04172 if ( stream->doByteSwap[0] ) 04173 byteSwapBuffer(stream->deviceBuffer, 04174 stream->bufferSize * stream->nDeviceChannels[0], 04175 stream->deviceFormat[0]); 04176 04177 // Always de-interleave ASIO output data. 04178 for ( int i=0; i<stream->nDeviceChannels[0]; i++, bufferInfos++ ) { 04179 memcpy(bufferInfos->buffers[bufferIndex], 04180 &stream->deviceBuffer[i*bufferBytes], bufferBytes ); 04181 } 04182 } 04183 else { // single channel only 04184 04185 if (stream->doByteSwap[0]) 04186 byteSwapBuffer(stream->userBuffer, 04187 stream->bufferSize * stream->nUserChannels[0], 04188 stream->userFormat); 04189 04190 memcpy(bufferInfos->buffers[bufferIndex], stream->userBuffer, bufferBytes ); 04191 } 04192 } 04193 04194 if ( stream->mode == INPUT || stream->mode == DUPLEX ) { 04195 04196 bufferBytes = stream->bufferSize * formatBytes(stream->deviceFormat[1]); 04197 if (stream->doConvertBuffer[1]) { 04198 04199 // Always interleave ASIO input data. 04200 for ( int i=0; i<stream->nDeviceChannels[1]; i++, bufferInfos++ ) 04201 memcpy(&stream->deviceBuffer[i*bufferBytes], bufferInfos->buffers[bufferIndex], bufferBytes ); 04202 04203 if ( stream->doByteSwap[1] ) 04204 byteSwapBuffer(stream->deviceBuffer, 04205 stream->bufferSize * stream->nDeviceChannels[1], 04206 stream->deviceFormat[1]); 04207 convertStreamBuffer(stream, INPUT); 04208 04209 } 04210 else { // single channel only 04211 memcpy(stream->userBuffer, bufferInfos->buffers[bufferIndex], bufferBytes ); 04212 04213 if (stream->doByteSwap[1]) 04214 byteSwapBuffer(stream->userBuffer, 04215 stream->bufferSize * stream->nUserChannels[1], 04216 stream->userFormat); 04217 } 04218 } 04219 04220 if ( !info->usingCallback ) 04221 info->blockTick = false; 04222 04223 MUTEX_UNLOCK(&stream->mutex); 04224 } 04225 04226 void RtAudio :: setStreamCallback(int streamId, RTAUDIO_CALLBACK callback, void *userData) 04227 { 04228 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId); 04229 04230 stream->callbackInfo.callback = (void *) callback; 04231 stream->callbackInfo.userData = userData; 04232 stream->callbackInfo.usingCallback = true; 04233 } 04234 04235 //******************** End of __WINDOWS_ASIO__ *********************// 04236 04237 #elif defined(__WINDOWS_DS__) // Windows DirectSound API 04238 04239 #include <dsound.h> 04240 04241 // Declarations for utility functions, callbacks, and structures 04242 // specific to the DirectSound implementation. 04243 static bool CALLBACK deviceCountCallback(LPGUID lpguid, 04244 LPCSTR lpcstrDescription, 04245 LPCSTR lpcstrModule, 04246 LPVOID lpContext); 04247 04248 static bool CALLBACK deviceInfoCallback(LPGUID lpguid, 04249 LPCSTR lpcstrDescription, 04250 LPCSTR lpcstrModule, 04251 LPVOID lpContext); 04252 04253 static bool CALLBACK defaultDeviceCallback(LPGUID lpguid, 04254 LPCSTR lpcstrDescription, 04255 LPCSTR lpcstrModule, 04256 LPVOID lpContext); 04257 04258 static bool CALLBACK deviceIdCallback(LPGUID lpguid, 04259 LPCSTR lpcstrDescription, 04260 LPCSTR lpcstrModule, 04261 LPVOID lpContext); 04262 04263 static char* getErrorString(int code); 04264 04265 struct enum_info { 04266 char name[64]; 04267 LPGUID id; 04268 bool isInput; 04269 bool isValid; 04270 }; 04271 04272 int RtAudio :: getDefaultInputDevice(void) 04273 { 04274 enum_info info; 04275 info.name[0] = '\0'; 04276 04277 // Enumerate through devices to find the default output. 04278 HRESULT result = DirectSoundCaptureEnumerate((LPDSENUMCALLBACK)defaultDeviceCallback, &info); 04279 if ( FAILED(result) ) { 04280 sprintf(message, "RtAudio: Error performing default input device enumeration: %s.", 04281 getErrorString(result)); 04282 error(RtError::WARNING); 04283 return 0; 04284 } 04285 04286 for ( int i=0; i<nDevices; i++ ) 04287 if ( strncmp( devices[i].name, info.name, 64 ) == 0 ) return i; 04288 04289 return 0; 04290 } 04291 04292 int RtAudio :: getDefaultOutputDevice(void) 04293 { 04294 enum_info info; 04295 info.name[0] = '\0'; 04296 04297 // Enumerate through devices to find the default output. 04298 HRESULT result = DirectSoundEnumerate((LPDSENUMCALLBACK)defaultDeviceCallback, &info); 04299 if ( FAILED(result) ) { 04300 sprintf(message, "RtAudio: Error performing default output device enumeration: %s.", 04301 getErrorString(result)); 04302 error(RtError::WARNING); 04303 return 0; 04304 } 04305 04306 for ( int i=0; i<nDevices; i++ ) 04307 if ( strncmp(devices[i].name, info.name, 64 ) == 0 ) return i; 04308 04309 return 0; 04310 } 04311 04312 void RtAudio :: initialize(void) 04313 { 04314 int i, ins = 0, outs = 0, count = 0; 04315 HRESULT result; 04316 nDevices = 0; 04317 04318 // Count DirectSound devices. 04319 result = DirectSoundEnumerate((LPDSENUMCALLBACK)deviceCountCallback, &outs); 04320 if ( FAILED(result) ) { 04321 sprintf(message, "RtAudio: Unable to enumerate through sound playback devices: %s.", 04322 getErrorString(result)); 04323 error(RtError::DRIVER_ERROR); 04324 } 04325 04326 // Count DirectSoundCapture devices. 04327 result = DirectSoundCaptureEnumerate((LPDSENUMCALLBACK)deviceCountCallback, &ins); 04328 if ( FAILED(result) ) { 04329 sprintf(message, "RtAudio: Unable to enumerate through sound capture devices: %s.", 04330 getErrorString(result)); 04331 error(RtError::DRIVER_ERROR); 04332 } 04333 04334 count = ins + outs; 04335 if (count == 0) return; 04336 04337 std::vector<enum_info> info(count); 04338 for (i=0; i<count; i++) { 04339 info[i].name[0] = '\0'; 04340 if (i < outs) info[i].isInput = false; 04341 else info[i].isInput = true; 04342 } 04343 04344 // Get playback device info and check capabilities. 04345 result = DirectSoundEnumerate((LPDSENUMCALLBACK)deviceInfoCallback, &info[0]); 04346 if ( FAILED(result) ) { 04347 sprintf(message, "RtAudio: Unable to enumerate through sound playback devices: %s.", 04348 getErrorString(result)); 04349 error(RtError::DRIVER_ERROR); 04350 } 04351 04352 // Get capture device info and check capabilities. 04353 result = DirectSoundCaptureEnumerate((LPDSENUMCALLBACK)deviceInfoCallback, &info[0]); 04354 if ( FAILED(result) ) { 04355 sprintf(message, "RtAudio: Unable to enumerate through sound capture devices: %s.", 04356 getErrorString(result)); 04357 error(RtError::DRIVER_ERROR); 04358 } 04359 04360 // Parse the devices and check validity. Devices are considered 04361 // invalid if they cannot be opened, they report < 1 supported 04362 // channels, or they report no supported data (capture only). 04363 for (i=0; i<count; i++) 04364 if ( info[i].isValid ) nDevices++; 04365 04366 if (nDevices == 0) return; 04367 04368 // Allocate the RTAUDIO_DEVICE structures. 04369 devices = (RTAUDIO_DEVICE *) calloc(nDevices, sizeof(RTAUDIO_DEVICE)); 04370 if (devices == NULL) { 04371 sprintf(message, "RtAudio: memory allocation error!"); 04372 error(RtError::MEMORY_ERROR); 04373 } 04374 04375 // Copy the names to our devices structures. 04376 int index = 0; 04377 for (i=0; i<count; i++) { 04378 if ( info[i].isValid ) 04379 strncpy(devices[index++].name, info[i].name, 64); 04380 } 04381 04382 //for (i=0;i<nDevices; i++) 04383 //probeDeviceInfo(&devices[i]); 04384 04385 return; 04386 } 04387 04388 void RtAudio :: probeDeviceInfo(RTAUDIO_DEVICE *info) 04389 { 04390 enum_info dsinfo; 04391 strncpy( dsinfo.name, info->name, 64 ); 04392 dsinfo.isValid = false; 04393 04394 // Enumerate through input devices to find the id (if it exists). 04395 HRESULT result = DirectSoundCaptureEnumerate((LPDSENUMCALLBACK)deviceIdCallback, &dsinfo); 04396 if ( FAILED(result) ) { 04397 sprintf(message, "RtAudio: Error performing input device id enumeration: %s.", 04398 getErrorString(result)); 04399 error(RtError::WARNING); 04400 return; 04401 } 04402 04403 // Do capture probe first. 04404 if ( dsinfo.isValid == false ) 04405 goto playback_probe; 04406 04407 LPDIRECTSOUNDCAPTURE input; 04408 result = DirectSoundCaptureCreate( dsinfo.id, &input, NULL ); 04409 if ( FAILED(result) ) { 04410 sprintf(message, "RtAudio: Could not create DirectSound capture object (%s): %s.", 04411 info->name, getErrorString(result)); 04412 error(RtError::WARNING); 04413 goto playback_probe; 04414 } 04415 04416 DSCCAPS in_caps; 04417 in_caps.dwSize = sizeof(in_caps); 04418 result = input->GetCaps( &in_caps ); 04419 if ( FAILED(result) ) { 04420 input->Release(); 04421 sprintf(message, "RtAudio: Could not get DirectSound capture capabilities (%s): %s.", 04422 info->name, getErrorString(result)); 04423 error(RtError::WARNING); 04424 goto playback_probe; 04425 } 04426 04427 // Get input channel information. 04428 info->minInputChannels = 1; 04429 info->maxInputChannels = in_caps.dwChannels; 04430 04431 // Get sample rate and format information. 04432 if( in_caps.dwChannels == 2 ) { 04433 if( in_caps.dwFormats & WAVE_FORMAT_1S16 ) info->nativeFormats |= RTAUDIO_SINT16; 04434 if( in_caps.dwFormats & WAVE_FORMAT_2S16 ) info->nativeFormats |= RTAUDIO_SINT16; 04435 if( in_caps.dwFormats & WAVE_FORMAT_4S16 ) info->nativeFormats |= RTAUDIO_SINT16; 04436 if( in_caps.dwFormats & WAVE_FORMAT_1S08 ) info->nativeFormats |= RTAUDIO_SINT8; 04437 if( in_caps.dwFormats & WAVE_FORMAT_2S08 ) info->nativeFormats |= RTAUDIO_SINT8; 04438 if( in_caps.dwFormats & WAVE_FORMAT_4S08 ) info->nativeFormats |= RTAUDIO_SINT8; 04439 04440 if ( info->nativeFormats & RTAUDIO_SINT16 ) { 04441 if( in_caps.dwFormats & WAVE_FORMAT_1S16 ) info->sampleRates[info->nSampleRates++] = 11025; 04442 if( in_caps.dwFormats & WAVE_FORMAT_2S16 ) info->sampleRates[info->nSampleRates++] = 22050; 04443 if( in_caps.dwFormats & WAVE_FORMAT_4S16 ) info->sampleRates[info->nSampleRates++] = 44100; 04444 } 04445 else if ( info->nativeFormats & RTAUDIO_SINT8 ) { 04446 if( in_caps.dwFormats & WAVE_FORMAT_1S08 ) info->sampleRates[info->nSampleRates++] = 11025; 04447 if( in_caps.dwFormats & WAVE_FORMAT_2S08 ) info->sampleRates[info->nSampleRates++] = 22050; 04448 if( in_caps.dwFormats & WAVE_FORMAT_4S08 ) info->sampleRates[info->nSampleRates++] = 44100; 04449 } 04450 } 04451 else if ( in_caps.dwChannels == 1 ) { 04452 if( in_caps.dwFormats & WAVE_FORMAT_1M16 ) info->nativeFormats |= RTAUDIO_SINT16; 04453 if( in_caps.dwFormats & WAVE_FORMAT_2M16 ) info->nativeFormats |= RTAUDIO_SINT16; 04454 if( in_caps.dwFormats & WAVE_FORMAT_4M16 ) info->nativeFormats |= RTAUDIO_SINT16; 04455 if( in_caps.dwFormats & WAVE_FORMAT_1M08 ) info->nativeFormats |= RTAUDIO_SINT8; 04456 if( in_caps.dwFormats & WAVE_FORMAT_2M08 ) info->nativeFormats |= RTAUDIO_SINT8; 04457 if( in_caps.dwFormats & WAVE_FORMAT_4M08 ) info->nativeFormats |= RTAUDIO_SINT8; 04458 04459 if ( info->nativeFormats & RTAUDIO_SINT16 ) { 04460 if( in_caps.dwFormats & WAVE_FORMAT_1M16 ) info->sampleRates[info->nSampleRates++] = 11025; 04461 if( in_caps.dwFormats & WAVE_FORMAT_2M16 ) info->sampleRates[info->nSampleRates++] = 22050; 04462 if( in_caps.dwFormats & WAVE_FORMAT_4M16 ) info->sampleRates[info->nSampleRates++] = 44100; 04463 } 04464 else if ( info->nativeFormats & RTAUDIO_SINT8 ) { 04465 if( in_caps.dwFormats & WAVE_FORMAT_1M08 ) info->sampleRates[info->nSampleRates++] = 11025; 04466 if( in_caps.dwFormats & WAVE_FORMAT_2M08 ) info->sampleRates[info->nSampleRates++] = 22050; 04467 if( in_caps.dwFormats & WAVE_FORMAT_4M08 ) info->sampleRates[info->nSampleRates++] = 44100; 04468 } 04469 } 04470 else info->minInputChannels = 0; // technically, this would be an error 04471 04472 input->Release(); 04473 04474 playback_probe: 04475 04476 dsinfo.isValid = false; 04477 04478 // Enumerate through output devices to find the id (if it exists). 04479 result = DirectSoundEnumerate((LPDSENUMCALLBACK)deviceIdCallback, &dsinfo); 04480 if ( FAILED(result) ) { 04481 sprintf(message, "RtAudio: Error performing output device id enumeration: %s.", 04482 getErrorString(result)); 04483 error(RtError::WARNING); 04484 return; 04485 } 04486 04487 // Now do playback probe. 04488 if ( dsinfo.isValid == false ) 04489 goto check_parameters; 04490 04491 LPDIRECTSOUND output; 04492 DSCAPS out_caps; 04493 result = DirectSoundCreate( dsinfo.id, &output, NULL ); 04494 if ( FAILED(result) ) { 04495 sprintf(message, "RtAudio: Could not create DirectSound playback object (%s): %s.", 04496 info->name, getErrorString(result)); 04497 error(RtError::WARNING); 04498 goto check_parameters; 04499 } 04500 04501 out_caps.dwSize = sizeof(out_caps); 04502 result = output->GetCaps( &out_caps ); 04503 if ( FAILED(result) ) { 04504 output->Release(); 04505 sprintf(message, "RtAudio: Could not get DirectSound playback capabilities (%s): %s.", 04506 info->name, getErrorString(result)); 04507 error(RtError::WARNING); 04508 goto check_parameters; 04509 } 04510 04511 // Get output channel information. 04512 info->minOutputChannels = 1; 04513 info->maxOutputChannels = ( out_caps.dwFlags & DSCAPS_PRIMARYSTEREO ) ? 2 : 1; 04514 04515 // Get sample rate information. Use capture device rate information 04516 // if it exists. 04517 if ( info->nSampleRates == 0 ) { 04518 info->sampleRates[0] = (int) out_caps.dwMinSecondarySampleRate; 04519 info->sampleRates[1] = (int) out_caps.dwMaxSecondarySampleRate; 04520 if ( out_caps.dwFlags & DSCAPS_CONTINUOUSRATE ) 04521 info->nSampleRates = -1; 04522 else if ( out_caps.dwMinSecondarySampleRate == out_caps.dwMaxSecondarySampleRate ) { 04523 if ( out_caps.dwMinSecondarySampleRate == 0 ) { 04524 // This is a bogus driver report ... fake the range and cross 04525 // your fingers. 04526 info->sampleRates[0] = 11025; 04527 info->sampleRates[1] = 48000; 04528 info->nSampleRates = -1; /* continuous range */ 04529 sprintf(message, "RtAudio: bogus sample rates reported by DirectSound driver ... using defaults (%s).", 04530 info->name); 04531 error(RtError::DEBUG_WARNING); 04532 } 04533 else { 04534 info->nSampleRates = 1; 04535 } 04536 } 04537 else if ( (out_caps.dwMinSecondarySampleRate < 1000.0) && 04538 (out_caps.dwMaxSecondarySampleRate > 50000.0) ) { 04539 // This is a bogus driver report ... support for only two 04540 // distant rates. We'll assume this is a range. 04541 info->nSampleRates = -1; 04542 sprintf(message, "RtAudio: bogus sample rates reported by DirectSound driver ... using range (%s).", 04543 info->name); 04544 error(RtError::WARNING); 04545 } 04546 else info->nSampleRates = 2; 04547 } 04548 else { 04549 // Check input rates against output rate range 04550 for ( int i=info->nSampleRates-1; i>=0; i-- ) { 04551 if ( info->sampleRates[i] <= out_caps.dwMaxSecondarySampleRate ) 04552 break; 04553 info->nSampleRates--; 04554 } 04555 while ( info->sampleRates[0] < out_caps.dwMinSecondarySampleRate ) { 04556 info->nSampleRates--; 04557 for ( int i=0; i<info->nSampleRates; i++) 04558 info->sampleRates[i] = info->sampleRates[i+1]; 04559 if ( info->nSampleRates <= 0 ) break; 04560 } 04561 } 04562 04563 // Get format information. 04564 if ( out_caps.dwFlags & DSCAPS_PRIMARY16BIT ) info->nativeFormats |= RTAUDIO_SINT16; 04565 if ( out_caps.dwFlags & DSCAPS_PRIMARY8BIT ) info->nativeFormats |= RTAUDIO_SINT8; 04566 04567 output->Release(); 04568 04569 check_parameters: 04570 if ( info->maxInputChannels == 0 && info->maxOutputChannels == 0 ) 04571 return; 04572 if ( info->nSampleRates == 0 || info->nativeFormats == 0 ) 04573 return; 04574 04575 // Determine duplex status. 04576 if (info->maxInputChannels < info->maxOutputChannels) 04577 info->maxDuplexChannels = info->maxInputChannels; 04578 else 04579 info->maxDuplexChannels = info->maxOutputChannels; 04580 if (info->minInputChannels < info->minOutputChannels) 04581 info->minDuplexChannels = info->minInputChannels; 04582 else 04583 info->minDuplexChannels = info->minOutputChannels; 04584 04585 if ( info->maxDuplexChannels > 0 ) info->hasDuplexSupport = true; 04586 else info->hasDuplexSupport = false; 04587 04588 info->probed = true; 04589 04590 return; 04591 } 04592 04593 bool RtAudio :: probeDeviceOpen(int device, RTAUDIO_STREAM *stream, 04594 STREAM_MODE mode, int channels, 04595 int sampleRate, RTAUDIO_FORMAT format, 04596 int *bufferSize, int numberOfBuffers) 04597 { 04598 HRESULT result; 04599 HWND hWnd = GetForegroundWindow(); 04600 // According to a note in PortAudio, using GetDesktopWindow() 04601 // instead of GetForegroundWindow() is supposed to avoid problems 04602 // that occur when the application's window is not the foreground 04603 // window. Also, if the application window closes before the 04604 // DirectSound buffer, DirectSound can crash. However, for console 04605 // applications, no sound was produced when using GetDesktopWindow(). 04606 long buffer_size; 04607 LPVOID audioPtr; 04608 DWORD dataLen; 04609 int nBuffers; 04610 04611 // Check the numberOfBuffers parameter and limit the lowest value to 04612 // two. This is a judgement call and a value of two is probably too 04613 // low for capture, but it should work for playback. 04614 if (numberOfBuffers < 2) 04615 nBuffers = 2; 04616 else 04617 nBuffers = numberOfBuffers; 04618 04619 // Define the wave format structure (16-bit PCM, srate, channels) 04620 WAVEFORMATEX waveFormat; 04621 ZeroMemory(&waveFormat, sizeof(WAVEFORMATEX)); 04622 waveFormat.wFormatTag = WAVE_FORMAT_PCM; 04623 waveFormat.nChannels = channels; 04624 waveFormat.nSamplesPerSec = (unsigned long) sampleRate; 04625 04626 // Determine the data format. 04627 if ( devices[device].nativeFormats ) { // 8-bit and/or 16-bit support 04628 if ( format == RTAUDIO_SINT8 ) { 04629 if ( devices[device].nativeFormats & RTAUDIO_SINT8 ) 04630 waveFormat.wBitsPerSample = 8; 04631 else 04632 waveFormat.wBitsPerSample = 16; 04633 } 04634 else { 04635 if ( devices[device].nativeFormats & RTAUDIO_SINT16 ) 04636 waveFormat.wBitsPerSample = 16; 04637 else 04638 waveFormat.wBitsPerSample = 8; 04639 } 04640 } 04641 else { 04642 sprintf(message, "RtAudio: no reported data formats for DirectSound device (%s).", 04643 devices[device].name); 04644 error(RtError::DEBUG_WARNING); 04645 return FAILURE; 04646 } 04647 04648 waveFormat.nBlockAlign = waveFormat.nChannels * waveFormat.wBitsPerSample / 8; 04649 waveFormat.nAvgBytesPerSec = waveFormat.nSamplesPerSec * waveFormat.nBlockAlign; 04650 04651 enum_info dsinfo; 04652 strncpy( dsinfo.name, devices[device].name, 64 ); 04653 dsinfo.isValid = false; 04654 if ( mode == OUTPUT ) { 04655 04656 if ( devices[device].maxOutputChannels < channels ) 04657 return FAILURE; 04658 04659 // Enumerate through output devices to find the id (if it exists). 04660 result = DirectSoundEnumerate((LPDSENUMCALLBACK)deviceIdCallback, &dsinfo); 04661 if ( FAILED(result) ) { 04662 sprintf(message, "RtAudio: Error performing output device id enumeration: %s.", 04663 getErrorString(result)); 04664 error(RtError::DEBUG_WARNING); 04665 return FAILURE; 04666 } 04667 04668 if ( dsinfo.isValid == false ) { 04669 sprintf(message, "RtAudio: DS output device (%s) id not found!", devices[device].name); 04670 error(RtError::DEBUG_WARNING); 04671 return FAILURE; 04672 } 04673 04674 LPGUID id = dsinfo.id; 04675 LPDIRECTSOUND object; 04676 LPDIRECTSOUNDBUFFER buffer; 04677 DSBUFFERDESC bufferDescription; 04678 04679 result = DirectSoundCreate( id, &object, NULL ); 04680 if ( FAILED(result) ) { 04681 sprintf(message, "RtAudio: Could not create DirectSound playback object (%s): %s.", 04682 devices[device].name, getErrorString(result)); 04683 error(RtError::DEBUG_WARNING); 04684 return FAILURE; 04685 } 04686 04687 // Set cooperative level to DSSCL_EXCLUSIVE 04688 result = object->SetCooperativeLevel(hWnd, DSSCL_EXCLUSIVE); 04689 if ( FAILED(result) ) { 04690 object->Release(); 04691 sprintf(message, "RtAudio: Unable to set DirectSound cooperative level (%s): %s.", 04692 devices[device].name, getErrorString(result)); 04693 error(RtError::WARNING); 04694 return FAILURE; 04695 } 04696 04697 // Even though we will write to the secondary buffer, we need to 04698 // access the primary buffer to set the correct output format. 04699 // The default is 8-bit, 22 kHz! 04700 // Setup the DS primary buffer description. 04701 ZeroMemory(&bufferDescription, sizeof(DSBUFFERDESC)); 04702 bufferDescription.dwSize = sizeof(DSBUFFERDESC); 04703 bufferDescription.dwFlags = DSBCAPS_PRIMARYBUFFER; 04704 // Obtain the primary buffer 04705 result = object->CreateSoundBuffer(&bufferDescription, &buffer, NULL); 04706 if ( FAILED(result) ) { 04707 object->Release(); 04708 sprintf(message, "RtAudio: Unable to access DS primary buffer (%s): %s.", 04709 devices[device].name, getErrorString(result)); 04710 error(RtError::WARNING); 04711 return FAILURE; 04712 } 04713 04714 // Set the primary DS buffer sound format. 04715 result = buffer->SetFormat(&waveFormat); 04716 if ( FAILED(result) ) { 04717 object->Release(); 04718 sprintf(message, "RtAudio: Unable to set DS primary buffer format (%s): %s.", 04719 devices[device].name, getErrorString(result)); 04720 error(RtError::WARNING); 04721 return FAILURE; 04722 } 04723 04724 // Setup the secondary DS buffer description. 04725 buffer_size = channels * *bufferSize * nBuffers * waveFormat.wBitsPerSample / 8; 04726 ZeroMemory(&bufferDescription, sizeof(DSBUFFERDESC)); 04727 bufferDescription.dwSize = sizeof(DSBUFFERDESC); 04728 bufferDescription.dwFlags = ( DSBCAPS_STICKYFOCUS | 04729 DSBCAPS_GETCURRENTPOSITION2 | 04730 DSBCAPS_LOCHARDWARE ); // Force hardware mixing 04731 bufferDescription.dwBufferBytes = buffer_size; 04732 bufferDescription.lpwfxFormat = &waveFormat; 04733 04734 // Try to create the secondary DS buffer. If that doesn't work, 04735 // try to use software mixing. Otherwise, there's a problem. 04736 result = object->CreateSoundBuffer(&bufferDescription, &buffer, NULL); 04737 if ( FAILED(result) ) { 04738 bufferDescription.dwFlags = ( DSBCAPS_STICKYFOCUS | 04739 DSBCAPS_GETCURRENTPOSITION2 | 04740 DSBCAPS_LOCSOFTWARE ); // Force software mixing 04741 result = object->CreateSoundBuffer(&bufferDescription, &buffer, NULL); 04742 if ( FAILED(result) ) { 04743 object->Release(); 04744 sprintf(message, "RtAudio: Unable to create secondary DS buffer (%s): %s.", 04745 devices[device].name, getErrorString(result)); 04746 error(RtError::WARNING); 04747 return FAILURE; 04748 } 04749 } 04750 04751 // Get the buffer size ... might be different from what we specified. 04752 DSBCAPS dsbcaps; 04753 dsbcaps.dwSize = sizeof(DSBCAPS); 04754 buffer->GetCaps(&dsbcaps); 04755 buffer_size = dsbcaps.dwBufferBytes; 04756 04757 // Lock the DS buffer 04758 result = buffer->Lock(0, buffer_size, &audioPtr, &dataLen, NULL, NULL, 0); 04759 if ( FAILED(result) ) { 04760 object->Release(); 04761 sprintf(message, "RtAudio: Unable to lock DS buffer (%s): %s.", 04762 devices[device].name, getErrorString(result)); 04763 error(RtError::WARNING); 04764 return FAILURE; 04765 } 04766 04767 // Zero the DS buffer 04768 ZeroMemory(audioPtr, dataLen); 04769 04770 // Unlock the DS buffer 04771 result = buffer->Unlock(audioPtr, dataLen, NULL, 0); 04772 if ( FAILED(result) ) { 04773 object->Release(); 04774 sprintf(message, "RtAudio: Unable to unlock DS buffer(%s): %s.", 04775 devices[device].name, getErrorString(result)); 04776 error(RtError::WARNING); 04777 return FAILURE; 04778 } 04779 04780 stream->handle[0].object = (void *) object; 04781 stream->handle[0].buffer = (void *) buffer; 04782 stream->nDeviceChannels[0] = channels; 04783 } 04784 04785 if ( mode == INPUT ) { 04786 04787 if ( devices[device].maxInputChannels < channels ) 04788 return FAILURE; 04789 04790 // Enumerate through input devices to find the id (if it exists). 04791 result = DirectSoundCaptureEnumerate((LPDSENUMCALLBACK)deviceIdCallback, &dsinfo); 04792 if ( FAILED(result) ) { 04793 sprintf(message, "RtAudio: Error performing input device id enumeration: %s.", 04794 getErrorString(result)); 04795 error(RtError::DEBUG_WARNING); 04796 return FAILURE; 04797 } 04798 04799 if ( dsinfo.isValid == false ) { 04800 sprintf(message, "RtAudio: DS input device (%s) id not found!", devices[device].name); 04801 error(RtError::DEBUG_WARNING); 04802 return FAILURE; 04803 } 04804 04805 LPGUID id = dsinfo.id; 04806 LPDIRECTSOUNDCAPTURE object; 04807 LPDIRECTSOUNDCAPTUREBUFFER buffer; 04808 DSCBUFFERDESC bufferDescription; 04809 04810 result = DirectSoundCaptureCreate( id, &object, NULL ); 04811 if ( FAILED(result) ) { 04812 sprintf(message, "RtAudio: Could not create DirectSound capture object (%s): %s.", 04813 devices[device].name, getErrorString(result)); 04814 error(RtError::WARNING); 04815 return FAILURE; 04816 } 04817 04818 // Setup the secondary DS buffer description. 04819 buffer_size = channels * *bufferSize * nBuffers * waveFormat.wBitsPerSample / 8; 04820 ZeroMemory(&bufferDescription, sizeof(DSCBUFFERDESC)); 04821 bufferDescription.dwSize = sizeof(DSCBUFFERDESC); 04822 bufferDescription.dwFlags = 0; 04823 bufferDescription.dwReserved = 0; 04824 bufferDescription.dwBufferBytes = buffer_size; 04825 bufferDescription.lpwfxFormat = &waveFormat; 04826 04827 // Create the capture buffer. 04828 result = object->CreateCaptureBuffer(&bufferDescription, &buffer, NULL); 04829 if ( FAILED(result) ) { 04830 object->Release(); 04831 sprintf(message, "RtAudio: Unable to create DS capture buffer (%s): %s.", 04832 devices[device].name, getErrorString(result)); 04833 error(RtError::WARNING); 04834 return FAILURE; 04835 } 04836 04837 // Lock the capture buffer 04838 result = buffer->Lock(0, buffer_size, &audioPtr, &dataLen, NULL, NULL, 0); 04839 if ( FAILED(result) ) { 04840 object->Release(); 04841 sprintf(message, "RtAudio: Unable to lock DS capture buffer (%s): %s.", 04842 devices[device].name, getErrorString(result)); 04843 error(RtError::WARNING); 04844 return FAILURE; 04845 } 04846 04847 // Zero the buffer 04848 ZeroMemory(audioPtr, dataLen); 04849 04850 // Unlock the buffer 04851 result = buffer->Unlock(audioPtr, dataLen, NULL, 0); 04852 if ( FAILED(result) ) { 04853 object->Release(); 04854 sprintf(message, "RtAudio: Unable to unlock DS capture buffer (%s): %s.", 04855 devices[device].name, getErrorString(result)); 04856 error(RtError::WARNING); 04857 return FAILURE; 04858 } 04859 04860 stream->handle[1].object = (void *) object; 04861 stream->handle[1].buffer = (void *) buffer; 04862 stream->nDeviceChannels[1] = channels; 04863 } 04864 04865 stream->userFormat = format; 04866 if ( waveFormat.wBitsPerSample == 8 ) 04867 stream->deviceFormat[mode] = RTAUDIO_SINT8; 04868 else 04869 stream->deviceFormat[mode] = RTAUDIO_SINT16; 04870 stream->nUserChannels[mode] = channels; 04871 *bufferSize = buffer_size / (channels * nBuffers * waveFormat.wBitsPerSample / 8); 04872 stream->bufferSize = *bufferSize; 04873 04874 // Set flags for buffer conversion 04875 stream->doConvertBuffer[mode] = false; 04876 if (stream->userFormat != stream->deviceFormat[mode]) 04877 stream->doConvertBuffer[mode] = true; 04878 if (stream->nUserChannels[mode] < stream->nDeviceChannels[mode]) 04879 stream->doConvertBuffer[mode] = true; 04880 04881 // Allocate necessary internal buffers 04882 if ( stream->nUserChannels[0] != stream->nUserChannels[1] ) { 04883 04884 long buffer_bytes; 04885 if (stream->nUserChannels[0] >= stream->nUserChannels[1]) 04886 buffer_bytes = stream->nUserChannels[0]; 04887 else 04888 buffer_bytes = stream->nUserChannels[1]; 04889 04890 buffer_bytes *= *bufferSize * formatBytes(stream->userFormat); 04891 if (stream->userBuffer) free(stream->userBuffer); 04892 stream->userBuffer = (char *) calloc(buffer_bytes, 1); 04893 if (stream->userBuffer == NULL) 04894 goto memory_error; 04895 } 04896 04897 if ( stream->doConvertBuffer[mode] ) { 04898 04899 long buffer_bytes; 04900 bool makeBuffer = true; 04901 if ( mode == OUTPUT ) 04902 buffer_bytes = stream->nDeviceChannels[0] * formatBytes(stream->deviceFormat[0]); 04903 else { // mode == INPUT 04904 buffer_bytes = stream->nDeviceChannels[1] * formatBytes(stream->deviceFormat[1]); 04905 if ( stream->mode == OUTPUT && stream->deviceBuffer ) { 04906 long bytes_out = stream->nDeviceChannels[0] * formatBytes(stream->deviceFormat[0]); 04907 if ( buffer_bytes < bytes_out ) makeBuffer = false; 04908 } 04909 } 04910 04911 if ( makeBuffer ) { 04912 buffer_bytes *= *bufferSize; 04913 if (stream->deviceBuffer) free(stream->deviceBuffer); 04914 stream->deviceBuffer = (char *) calloc(buffer_bytes, 1); 04915 if (stream->deviceBuffer == NULL) 04916 goto memory_error; 04917 } 04918 } 04919 04920 stream->device[mode] = device; 04921 stream->state = STREAM_STOPPED; 04922 if ( stream->mode == OUTPUT && mode == INPUT ) 04923 // We had already set up an output stream. 04924 stream->mode = DUPLEX; 04925 else 04926 stream->mode = mode; 04927 stream->nBuffers = nBuffers; 04928 stream->sampleRate = sampleRate; 04929 04930 return SUCCESS; 04931 04932 memory_error: 04933 if (stream->handle[0].object) { 04934 LPDIRECTSOUND object = (LPDIRECTSOUND) stream->handle[0].object; 04935 LPDIRECTSOUNDBUFFER buffer = (LPDIRECTSOUNDBUFFER) stream->handle[0].buffer; 04936 if (buffer) { 04937 buffer->Release(); 04938 stream->handle[0].buffer = NULL; 04939 } 04940 object->Release(); 04941 stream->handle[0].object = NULL; 04942 } 04943 if (stream->handle[1].object) { 04944 LPDIRECTSOUNDCAPTURE object = (LPDIRECTSOUNDCAPTURE) stream->handle[1].object; 04945 LPDIRECTSOUNDCAPTUREBUFFER buffer = (LPDIRECTSOUNDCAPTUREBUFFER) stream->handle[1].buffer; 04946 if (buffer) { 04947 buffer->Release(); 04948 stream->handle[1].buffer = NULL; 04949 } 04950 object->Release(); 04951 stream->handle[1].object = NULL; 04952 } 04953 if (stream->userBuffer) { 04954 free(stream->userBuffer); 04955 stream->userBuffer = 0; 04956 } 04957 sprintf(message, "RtAudio: error allocating buffer memory (%s).", 04958 devices[device].name); 04959 error(RtError::WARNING); 04960 return FAILURE; 04961 } 04962 04963 void RtAudio :: cancelStreamCallback(int streamId) 04964 { 04965 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId); 04966 04967 if (stream->callbackInfo.usingCallback) { 04968 04969 if (stream->state == STREAM_RUNNING) 04970 stopStream( streamId ); 04971 04972 MUTEX_LOCK(&stream->mutex); 04973 04974 stream->callbackInfo.usingCallback = false; 04975 WaitForSingleObject( (HANDLE)stream->callbackInfo.thread, INFINITE ); 04976 CloseHandle( (HANDLE)stream->callbackInfo.thread ); 04977 stream->callbackInfo.thread = 0; 04978 stream->callbackInfo.callback = NULL; 04979 stream->callbackInfo.userData = NULL; 04980 04981 MUTEX_UNLOCK(&stream->mutex); 04982 } 04983 } 04984 04985 void RtAudio :: closeStream(int streamId) 04986 { 04987 // We don't want an exception to be thrown here because this 04988 // function is called by our class destructor. So, do our own 04989 // streamId check. 04990 if ( streams.find( streamId ) == streams.end() ) { 04991 sprintf(message, "RtAudio: invalid stream identifier!"); 04992 error(RtError::WARNING); 04993 return; 04994 } 04995 04996 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) streams[streamId]; 04997 04998 if (stream->callbackInfo.usingCallback) { 04999 stream->callbackInfo.usingCallback = false; 05000 WaitForSingleObject( (HANDLE)stream->callbackInfo.thread, INFINITE ); 05001 CloseHandle( (HANDLE)stream->callbackInfo.thread ); 05002 } 05003 05004 DeleteCriticalSection(&stream->mutex); 05005 05006 if (stream->handle[0].object) { 05007 LPDIRECTSOUND object = (LPDIRECTSOUND) stream->handle[0].object; 05008 LPDIRECTSOUNDBUFFER buffer = (LPDIRECTSOUNDBUFFER) stream->handle[0].buffer; 05009 if (buffer) { 05010 buffer->Stop(); 05011 buffer->Release(); 05012 } 05013 object->Release(); 05014 } 05015 05016 if (stream->handle[1].object) { 05017 LPDIRECTSOUNDCAPTURE object = (LPDIRECTSOUNDCAPTURE) stream->handle[1].object; 05018 LPDIRECTSOUNDCAPTUREBUFFER buffer = (LPDIRECTSOUNDCAPTUREBUFFER) stream->handle[1].buffer; 05019 if (buffer) { 05020 buffer->Stop(); 05021 buffer->Release(); 05022 } 05023 object->Release(); 05024 } 05025 05026 if (stream->userBuffer) 05027 free(stream->userBuffer); 05028 05029 if (stream->deviceBuffer) 05030 free(stream->deviceBuffer); 05031 05032 free(stream); 05033 streams.erase(streamId); 05034 } 05035 05036 void RtAudio :: startStream(int streamId) 05037 { 05038 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId); 05039 05040 MUTEX_LOCK(&stream->mutex); 05041 05042 if (stream->state == STREAM_RUNNING) 05043 goto unlock; 05044 05045 HRESULT result; 05046 if (stream->mode == OUTPUT || stream->mode == DUPLEX) { 05047 LPDIRECTSOUNDBUFFER buffer = (LPDIRECTSOUNDBUFFER) stream->handle[0].buffer; 05048 result = buffer->Play(0, 0, DSBPLAY_LOOPING ); 05049 if ( FAILED(result) ) { 05050 sprintf(message, "RtAudio: Unable to start DS buffer (%s): %s.", 05051 devices[stream->device[0]].name, getErrorString(result)); 05052 error(RtError::DRIVER_ERROR); 05053 } 05054 } 05055 05056 if (stream->mode == INPUT || stream->mode == DUPLEX) { 05057 LPDIRECTSOUNDCAPTUREBUFFER buffer = (LPDIRECTSOUNDCAPTUREBUFFER) stream->handle[1].buffer; 05058 result = buffer->Start(DSCBSTART_LOOPING ); 05059 if ( FAILED(result) ) { 05060 sprintf(message, "RtAudio: Unable to start DS capture buffer (%s): %s.", 05061 devices[stream->device[1]].name, getErrorString(result)); 05062 error(RtError::DRIVER_ERROR); 05063 } 05064 } 05065 stream->state = STREAM_RUNNING; 05066 05067 unlock: 05068 MUTEX_UNLOCK(&stream->mutex); 05069 } 05070 05071 void RtAudio :: stopStream(int streamId) 05072 { 05073 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId); 05074 05075 MUTEX_LOCK(&stream->mutex); 05076 05077 if (stream->state == STREAM_STOPPED) { 05078 MUTEX_UNLOCK(&stream->mutex); 05079 return; 05080 } 05081 05082 // There is no specific DirectSound API call to "drain" a buffer 05083 // before stopping. We can hack this for playback by writing zeroes 05084 // for another bufferSize * nBuffers frames. For capture, the 05085 // concept is less clear so we'll repeat what we do in the 05086 // abortStream() case. 05087 HRESULT result; 05088 DWORD dsBufferSize; 05089 LPVOID buffer1 = NULL; 05090 LPVOID buffer2 = NULL; 05091 DWORD bufferSize1 = 0; 05092 DWORD bufferSize2 = 0; 05093 if (stream->mode == OUTPUT || stream->mode == DUPLEX) { 05094 05095 DWORD currentPos, safePos; 05096 long buffer_bytes = stream->bufferSize * stream->nDeviceChannels[0]; 05097 buffer_bytes *= formatBytes(stream->deviceFormat[0]); 05098 05099 LPDIRECTSOUNDBUFFER dsBuffer = (LPDIRECTSOUNDBUFFER) stream->handle[0].buffer; 05100 UINT nextWritePos = stream->handle[0].bufferPointer; 05101 dsBufferSize = buffer_bytes * stream->nBuffers; 05102 05103 // Write zeroes for nBuffer counts. 05104 for (int i=0; i<stream->nBuffers; i++) { 05105 05106 // Find out where the read and "safe write" pointers are. 05107 result = dsBuffer->GetCurrentPosition(¤tPos, &safePos); 05108 if ( FAILED(result) ) { 05109 sprintf(message, "RtAudio: Unable to get current DS position (%s): %s.", 05110 devices[stream->device[0]].name, getErrorString(result)); 05111 error(RtError::DRIVER_ERROR); 05112 } 05113 05114 if ( currentPos < nextWritePos ) currentPos += dsBufferSize; // unwrap offset 05115 DWORD endWrite = nextWritePos + buffer_bytes; 05116 05117 // Check whether the entire write region is behind the play pointer. 05118 while ( currentPos < endWrite ) { 05119 float millis = (endWrite - currentPos) * 900.0; 05120 millis /= ( formatBytes(stream->deviceFormat[0]) * stream->sampleRate); 05121 if ( millis < 1.0 ) millis = 1.0; 05122 Sleep( (DWORD) millis ); 05123 05124 // Wake up, find out where we are now 05125 result = dsBuffer->GetCurrentPosition( ¤tPos, &safePos ); 05126 if ( FAILED(result) ) { 05127 sprintf(message, "RtAudio: Unable to get current DS position (%s): %s.", 05128 devices[stream->device[0]].name, getErrorString(result)); 05129 error(RtError::DRIVER_ERROR); 05130 } 05131 if ( currentPos < nextWritePos ) currentPos += dsBufferSize; // unwrap offset 05132 } 05133 05134 // Lock free space in the buffer 05135 result = dsBuffer->Lock (nextWritePos, buffer_bytes, &buffer1, 05136 &bufferSize1, &buffer2, &bufferSize2, 0); 05137 if ( FAILED(result) ) { 05138 sprintf(message, "RtAudio: Unable to lock DS buffer during playback (%s): %s.", 05139 devices[stream->device[0]].name, getErrorString(result)); 05140 error(RtError::DRIVER_ERROR); 05141 } 05142 05143 // Zero the free space 05144 ZeroMemory(buffer1, bufferSize1); 05145 if (buffer2 != NULL) ZeroMemory(buffer2, bufferSize2); 05146 05147 // Update our buffer offset and unlock sound buffer 05148 dsBuffer->Unlock (buffer1, bufferSize1, buffer2, bufferSize2); 05149 if ( FAILED(result) ) { 05150 sprintf(message, "RtAudio: Unable to unlock DS buffer during playback (%s): %s.", 05151 devices[stream->device[0]].name, getErrorString(result)); 05152 error(RtError::DRIVER_ERROR); 05153 } 05154 nextWritePos = (nextWritePos + bufferSize1 + bufferSize2) % dsBufferSize; 05155 stream->handle[0].bufferPointer = nextWritePos; 05156 } 05157 05158 // If we play again, start at the beginning of the buffer. 05159 stream->handle[0].bufferPointer = 0; 05160 } 05161 05162 if (stream->mode == INPUT || stream->mode == DUPLEX) { 05163 LPDIRECTSOUNDCAPTUREBUFFER buffer = (LPDIRECTSOUNDCAPTUREBUFFER) stream->handle[1].buffer; 05164 buffer1 = NULL; 05165 bufferSize1 = 0; 05166 05167 result = buffer->Stop(); 05168 if ( FAILED(result) ) { 05169 sprintf(message, "RtAudio: Unable to stop DS capture buffer (%s): %s", 05170 devices[stream->device[1]].name, getErrorString(result)); 05171 error(RtError::DRIVER_ERROR); 05172 } 05173 05174 dsBufferSize = stream->bufferSize * stream->nDeviceChannels[1]; 05175 dsBufferSize *= formatBytes(stream->deviceFormat[1]) * stream->nBuffers; 05176 05177 // Lock the buffer and clear it so that if we start to play again, 05178 // we won't have old data playing. 05179 result = buffer->Lock(0, dsBufferSize, &buffer1, &bufferSize1, NULL, NULL, 0); 05180 if ( FAILED(result) ) { 05181 sprintf(message, "RtAudio: Unable to lock DS capture buffer (%s): %s.", 05182 devices[stream->device[1]].name, getErrorString(result)); 05183 error(RtError::DRIVER_ERROR); 05184 } 05185 05186 // Zero the DS buffer 05187 ZeroMemory(buffer1, bufferSize1); 05188 05189 // Unlock the DS buffer 05190 result = buffer->Unlock(buffer1, bufferSize1, NULL, 0); 05191 if ( FAILED(result) ) { 05192 sprintf(message, "RtAudio: Unable to unlock DS capture buffer (%s): %s.", 05193 devices[stream->device[1]].name, getErrorString(result)); 05194 error(RtError::DRIVER_ERROR); 05195 } 05196 05197 // If we start recording again, we must begin at beginning of buffer. 05198 stream->handle[1].bufferPointer = 0; 05199 } 05200 stream->state = STREAM_STOPPED; 05201 05202 MUTEX_UNLOCK(&stream->mutex); 05203 } 05204 05205 void RtAudio :: abortStream(int streamId) 05206 { 05207 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId); 05208 05209 MUTEX_LOCK(&stream->mutex); 05210 05211 if (stream->state == STREAM_STOPPED) 05212 goto unlock; 05213 05214 HRESULT result; 05215 long dsBufferSize; 05216 LPVOID audioPtr; 05217 DWORD dataLen; 05218 if (stream->mode == OUTPUT || stream->mode == DUPLEX) { 05219 LPDIRECTSOUNDBUFFER buffer = (LPDIRECTSOUNDBUFFER) stream->handle[0].buffer; 05220 result = buffer->Stop(); 05221 if ( FAILED(result) ) { 05222 sprintf(message, "RtAudio: Unable to stop DS buffer (%s): %s", 05223 devices[stream->device[0]].name, getErrorString(result)); 05224 error(RtError::DRIVER_ERROR); 05225 } 05226 05227 dsBufferSize = stream->bufferSize * stream->nDeviceChannels[0]; 05228 dsBufferSize *= formatBytes(stream->deviceFormat[0]) * stream->nBuffers; 05229 05230 // Lock the buffer and clear it so that if we start to play again, 05231 // we won't have old data playing. 05232 result = buffer->Lock(0, dsBufferSize, &audioPtr, &dataLen, NULL, NULL, 0); 05233 if ( FAILED(result) ) { 05234 sprintf(message, "RtAudio: Unable to lock DS buffer (%s): %s.", 05235 devices[stream->device[0]].name, getErrorString(result)); 05236 error(RtError::DRIVER_ERROR); 05237 } 05238 05239 // Zero the DS buffer 05240 ZeroMemory(audioPtr, dataLen); 05241 05242 // Unlock the DS buffer 05243 result = buffer->Unlock(audioPtr, dataLen, NULL, 0); 05244 if ( FAILED(result) ) { 05245 sprintf(message, "RtAudio: Unable to unlock DS buffer (%s): %s.", 05246 devices[stream->device[0]].name, getErrorString(result)); 05247 error(RtError::DRIVER_ERROR); 05248 } 05249 05250 // If we start playing again, we must begin at beginning of buffer. 05251 stream->handle[0].bufferPointer = 0; 05252 } 05253 05254 if (stream->mode == INPUT || stream->mode == DUPLEX) { 05255 LPDIRECTSOUNDCAPTUREBUFFER buffer = (LPDIRECTSOUNDCAPTUREBUFFER) stream->handle[1].buffer; 05256 audioPtr = NULL; 05257 dataLen = 0; 05258 05259 result = buffer->Stop(); 05260 if ( FAILED(result) ) { 05261 sprintf(message, "RtAudio: Unable to stop DS capture buffer (%s): %s", 05262 devices[stream->device[1]].name, getErrorString(result)); 05263 error(RtError::DRIVER_ERROR); 05264 } 05265 05266 dsBufferSize = stream->bufferSize * stream->nDeviceChannels[1]; 05267 dsBufferSize *= formatBytes(stream->deviceFormat[1]) * stream->nBuffers; 05268 05269 // Lock the buffer and clear it so that if we start to play again, 05270 // we won't have old data playing. 05271 result = buffer->Lock(0, dsBufferSize, &audioPtr, &dataLen, NULL, NULL, 0); 05272 if ( FAILED(result) ) { 05273 sprintf(message, "RtAudio: Unable to lock DS capture buffer (%s): %s.", 05274 devices[stream->device[1]].name, getErrorString(result)); 05275 error(RtError::DRIVER_ERROR); 05276 } 05277 05278 // Zero the DS buffer 05279 ZeroMemory(audioPtr, dataLen); 05280 05281 // Unlock the DS buffer 05282 result = buffer->Unlock(audioPtr, dataLen, NULL, 0); 05283 if ( FAILED(result) ) { 05284 sprintf(message, "RtAudio: Unable to unlock DS capture buffer (%s): %s.", 05285 devices[stream->device[1]].name, getErrorString(result)); 05286 error(RtError::DRIVER_ERROR); 05287 } 05288 05289 // If we start recording again, we must begin at beginning of buffer. 05290 stream->handle[1].bufferPointer = 0; 05291 } 05292 stream->state = STREAM_STOPPED; 05293 05294 unlock: 05295 MUTEX_UNLOCK(&stream->mutex); 05296 } 05297 05298 int RtAudio :: streamWillBlock(int streamId) 05299 { 05300 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId); 05301 05302 MUTEX_LOCK(&stream->mutex); 05303 05304 int channels; 05305 int frames = 0; 05306 if (stream->state == STREAM_STOPPED) 05307 goto unlock; 05308 05309 HRESULT result; 05310 DWORD currentPos, safePos; 05311 channels = 1; 05312 if (stream->mode == OUTPUT || stream->mode == DUPLEX) { 05313 05314 LPDIRECTSOUNDBUFFER dsBuffer = (LPDIRECTSOUNDBUFFER) stream->handle[0].buffer; 05315 UINT nextWritePos = stream->handle[0].bufferPointer; 05316 channels = stream->nDeviceChannels[0]; 05317 DWORD dsBufferSize = stream->bufferSize * channels; 05318 dsBufferSize *= formatBytes(stream->deviceFormat[0]) * stream->nBuffers; 05319 05320 // Find out where the read and "safe write" pointers are. 05321 result = dsBuffer->GetCurrentPosition(¤tPos, &safePos); 05322 if ( FAILED(result) ) { 05323 sprintf(message, "RtAudio: Unable to get current DS position (%s): %s.", 05324 devices[stream->device[0]].name, getErrorString(result)); 05325 error(RtError::DRIVER_ERROR); 05326 } 05327 05328 if ( currentPos < nextWritePos ) currentPos += dsBufferSize; // unwrap offset 05329 frames = currentPos - nextWritePos; 05330 frames /= channels * formatBytes(stream->deviceFormat[0]); 05331 } 05332 05333 if (stream->mode == INPUT || stream->mode == DUPLEX) { 05334 05335 LPDIRECTSOUNDCAPTUREBUFFER dsBuffer = (LPDIRECTSOUNDCAPTUREBUFFER) stream->handle[1].buffer; 05336 UINT nextReadPos = stream->handle[1].bufferPointer; 05337 channels = stream->nDeviceChannels[1]; 05338 DWORD dsBufferSize = stream->bufferSize * channels; 05339 dsBufferSize *= formatBytes(stream->deviceFormat[1]) * stream->nBuffers; 05340 05341 // Find out where the write and "safe read" pointers are. 05342 result = dsBuffer->GetCurrentPosition(¤tPos, &safePos); 05343 if ( FAILED(result) ) { 05344 sprintf(message, "RtAudio: Unable to get current DS capture position (%s): %s.", 05345 devices[stream->device[1]].name, getErrorString(result)); 05346 error(RtError::DRIVER_ERROR); 05347 } 05348 05349 if ( safePos < nextReadPos ) safePos += dsBufferSize; // unwrap offset 05350 05351 if (stream->mode == DUPLEX ) { 05352 // Take largest value of the two. 05353 int temp = safePos - nextReadPos; 05354 temp /= channels * formatBytes(stream->deviceFormat[1]); 05355 frames = ( temp > frames ) ? temp : frames; 05356 } 05357 else { 05358 frames = safePos - nextReadPos; 05359 frames /= channels * formatBytes(stream->deviceFormat[1]); 05360 } 05361 } 05362 05363 frames = stream->bufferSize - frames; 05364 if (frames < 0) frames = 0; 05365 05366 unlock: 05367 MUTEX_UNLOCK(&stream->mutex); 05368 return frames; 05369 } 05370 05371 void RtAudio :: tickStream(int streamId) 05372 { 05373 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId); 05374 05375 int stopStream = 0; 05376 if (stream->state == STREAM_STOPPED) { 05377 if (stream->callbackInfo.usingCallback) Sleep(50); // sleep 50 milliseconds 05378 return; 05379 } 05380 else if (stream->callbackInfo.usingCallback) { 05381 RTAUDIO_CALLBACK callback = (RTAUDIO_CALLBACK) stream->callbackInfo.callback; 05382 stopStream = callback(stream->userBuffer, stream->bufferSize, stream->callbackInfo.userData); 05383 } 05384 05385 MUTEX_LOCK(&stream->mutex); 05386 05387 // The state might change while waiting on a mutex. 05388 if (stream->state == STREAM_STOPPED) { 05389 MUTEX_UNLOCK(&stream->mutex); 05390 return; 05391 } 05392 05393 HRESULT result; 05394 DWORD currentPos, safePos; 05395 LPVOID buffer1 = NULL; 05396 LPVOID buffer2 = NULL; 05397 DWORD bufferSize1 = 0; 05398 DWORD bufferSize2 = 0; 05399 char *buffer; 05400 long buffer_bytes; 05401 if (stream->mode == OUTPUT || stream->mode == DUPLEX) { 05402 05403 // Setup parameters and do buffer conversion if necessary. 05404 if (stream->doConvertBuffer[0]) { 05405 convertStreamBuffer(stream, OUTPUT); 05406 buffer = stream->deviceBuffer; 05407 buffer_bytes = stream->bufferSize * stream->nDeviceChannels[0]; 05408 buffer_bytes *= formatBytes(stream->deviceFormat[0]); 05409 } 05410 else { 05411 buffer = stream->userBuffer; 05412 buffer_bytes = stream->bufferSize * stream->nUserChannels[0]; 05413 buffer_bytes *= formatBytes(stream->userFormat); 05414 } 05415 05416 // No byte swapping necessary in DirectSound implementation. 05417 05418 LPDIRECTSOUNDBUFFER dsBuffer = (LPDIRECTSOUNDBUFFER) stream->handle[0].buffer; 05419 UINT nextWritePos = stream->handle[0].bufferPointer; 05420 DWORD dsBufferSize = buffer_bytes * stream->nBuffers; 05421 05422 // Find out where the read and "safe write" pointers are. 05423 result = dsBuffer->GetCurrentPosition(¤tPos, &safePos); 05424 if ( FAILED(result) ) { 05425 sprintf(message, "RtAudio: Unable to get current DS position (%s): %s.", 05426 devices[stream->device[0]].name, getErrorString(result)); 05427 error(RtError::DRIVER_ERROR); 05428 } 05429 05430 if ( currentPos < nextWritePos ) currentPos += dsBufferSize; // unwrap offset 05431 DWORD endWrite = nextWritePos + buffer_bytes; 05432 05433 // Check whether the entire write region is behind the play pointer. 05434 while ( currentPos < endWrite ) { 05435 // If we are here, then we must wait until the play pointer gets 05436 // beyond the write region. The approach here is to use the 05437 // Sleep() function to suspend operation until safePos catches 05438 // up. Calculate number of milliseconds to wait as: 05439 // time = distance * (milliseconds/second) * fudgefactor / 05440 // ((bytes/sample) * (samples/second)) 05441 // A "fudgefactor" less than 1 is used because it was found 05442 // that sleeping too long was MUCH worse than sleeping for 05443 // several shorter periods. 05444 float millis = (endWrite - currentPos) * 900.0; 05445 millis /= ( formatBytes(stream->deviceFormat[0]) * stream->sampleRate); 05446 if ( millis < 1.0 ) millis = 1.0; 05447 Sleep( (DWORD) millis ); 05448 05449 // Wake up, find out where we are now 05450 result = dsBuffer->GetCurrentPosition( ¤tPos, &safePos ); 05451 if ( FAILED(result) ) { 05452 sprintf(message, "RtAudio: Unable to get current DS position (%s): %s.", 05453 devices[stream->device[0]].name, getErrorString(result)); 05454 error(RtError::DRIVER_ERROR); 05455 } 05456 if ( currentPos < nextWritePos ) currentPos += dsBufferSize; // unwrap offset 05457 } 05458 05459 // Lock free space in the buffer 05460 result = dsBuffer->Lock (nextWritePos, buffer_bytes, &buffer1, 05461 &bufferSize1, &buffer2, &bufferSize2, 0); 05462 if ( FAILED(result) ) { 05463 sprintf(message, "RtAudio: Unable to lock DS buffer during playback (%s): %s.", 05464 devices[stream->device[0]].name, getErrorString(result)); 05465 error(RtError::DRIVER_ERROR); 05466 } 05467 05468 // Copy our buffer into the DS buffer 05469 CopyMemory(buffer1, buffer, bufferSize1); 05470 if (buffer2 != NULL) CopyMemory(buffer2, buffer+bufferSize1, bufferSize2); 05471 05472 // Update our buffer offset and unlock sound buffer 05473 dsBuffer->Unlock (buffer1, bufferSize1, buffer2, bufferSize2); 05474 if ( FAILED(result) ) { 05475 sprintf(message, "RtAudio: Unable to unlock DS buffer during playback (%s): %s.", 05476 devices[stream->device[0]].name, getErrorString(result)); 05477 error(RtError::DRIVER_ERROR); 05478 } 05479 nextWritePos = (nextWritePos + bufferSize1 + bufferSize2) % dsBufferSize; 05480 stream->handle[0].bufferPointer = nextWritePos; 05481 } 05482 05483 if (stream->mode == INPUT || stream->mode == DUPLEX) { 05484 05485 // Setup parameters. 05486 if (stream->doConvertBuffer[1]) { 05487 buffer = stream->deviceBuffer; 05488 buffer_bytes = stream->bufferSize * stream->nDeviceChannels[1]; 05489 buffer_bytes *= formatBytes(stream->deviceFormat[1]); 05490 } 05491 else { 05492 buffer = stream->userBuffer; 05493 buffer_bytes = stream->bufferSize * stream->nUserChannels[1]; 05494 buffer_bytes *= formatBytes(stream->userFormat); 05495 } 05496 05497 LPDIRECTSOUNDCAPTUREBUFFER dsBuffer = (LPDIRECTSOUNDCAPTUREBUFFER) stream->handle[1].buffer; 05498 UINT nextReadPos = stream->handle[1].bufferPointer; 05499 DWORD dsBufferSize = buffer_bytes * stream->nBuffers; 05500 05501 // Find out where the write and "safe read" pointers are. 05502 result = dsBuffer->GetCurrentPosition(¤tPos, &safePos); 05503 if ( FAILED(result) ) { 05504 sprintf(message, "RtAudio: Unable to get current DS capture position (%s): %s.", 05505 devices[stream->device[1]].name, getErrorString(result)); 05506 error(RtError::DRIVER_ERROR); 05507 } 05508 05509 if ( safePos < nextReadPos ) safePos += dsBufferSize; // unwrap offset 05510 DWORD endRead = nextReadPos + buffer_bytes; 05511 05512 // Check whether the entire write region is behind the play pointer. 05513 while ( safePos < endRead ) { 05514 // See comments for playback. 05515 float millis = (endRead - safePos) * 900.0; 05516 millis /= ( formatBytes(stream->deviceFormat[1]) * stream->sampleRate); 05517 if ( millis < 1.0 ) millis = 1.0; 05518 Sleep( (DWORD) millis ); 05519 05520 // Wake up, find out where we are now 05521 result = dsBuffer->GetCurrentPosition( ¤tPos, &safePos ); 05522 if ( FAILED(result) ) { 05523 sprintf(message, "RtAudio: Unable to get current DS capture position (%s): %s.", 05524 devices[stream->device[1]].name, getErrorString(result)); 05525 error(RtError::DRIVER_ERROR); 05526 } 05527 05528 if ( safePos < nextReadPos ) safePos += dsBufferSize; // unwrap offset 05529 } 05530 05531 // Lock free space in the buffer 05532 result = dsBuffer->Lock (nextReadPos, buffer_bytes, &buffer1, 05533 &bufferSize1, &buffer2, &bufferSize2, 0); 05534 if ( FAILED(result) ) { 05535 sprintf(message, "RtAudio: Unable to lock DS buffer during capture (%s): %s.", 05536 devices[stream->device[1]].name, getErrorString(result)); 05537 error(RtError::DRIVER_ERROR); 05538 } 05539 05540 // Copy our buffer into the DS buffer 05541 CopyMemory(buffer, buffer1, bufferSize1); 05542 if (buffer2 != NULL) CopyMemory(buffer+bufferSize1, buffer2, bufferSize2); 05543 05544 // Update our buffer offset and unlock sound buffer 05545 nextReadPos = (nextReadPos + bufferSize1 + bufferSize2) % dsBufferSize; 05546 dsBuffer->Unlock (buffer1, bufferSize1, buffer2, bufferSize2); 05547 if ( FAILED(result) ) { 05548 sprintf(message, "RtAudio: Unable to unlock DS buffer during capture (%s): %s.", 05549 devices[stream->device[1]].name, getErrorString(result)); 05550 error(RtError::DRIVER_ERROR); 05551 } 05552 stream->handle[1].bufferPointer = nextReadPos; 05553 05554 // No byte swapping necessary in DirectSound implementation. 05555 05556 // Do buffer conversion if necessary. 05557 if (stream->doConvertBuffer[1]) 05558 convertStreamBuffer(stream, INPUT); 05559 } 05560 05561 MUTEX_UNLOCK(&stream->mutex); 05562 05563 if (stream->callbackInfo.usingCallback && stopStream) 05564 this->stopStream(streamId); 05565 } 05566 05567 // Definitions for utility functions and callbacks 05568 // specific to the DirectSound implementation. 05569 05570 extern "C" unsigned __stdcall callbackHandler(void *ptr) 05571 { 05572 CALLBACK_INFO *info = (CALLBACK_INFO *) ptr; 05573 RtAudio *object = (RtAudio *) info->object; 05574 int stream = info->streamId; 05575 bool *usingCallback = &info->usingCallback; 05576 05577 while ( *usingCallback ) { 05578 try { 05579 object->tickStream(stream); 05580 } 05581 catch (RtError &exception) { 05582 fprintf(stderr, "\nRtAudio: Callback thread error (%s) ... closing thread.\n\n", 05583 exception.getMessage()); 05584 break; 05585 } 05586 } 05587 05588 _endthreadex( 0 ); 05589 return 0; 05590 } 05591 05592 void RtAudio :: setStreamCallback(int streamId, RTAUDIO_CALLBACK callback, void *userData) 05593 { 05594 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId); 05595 05596 CALLBACK_INFO *info = (CALLBACK_INFO *) &stream->callbackInfo; 05597 if ( info->usingCallback ) { 05598 sprintf(message, "RtAudio: A callback is already set for this stream!"); 05599 error(RtError::WARNING); 05600 return; 05601 } 05602 05603 info->callback = (void *) callback; 05604 info->userData = userData; 05605 info->usingCallback = true; 05606 info->object = (void *) this; 05607 info->streamId = streamId; 05608 05609 unsigned thread_id; 05610 info->thread = _beginthreadex(NULL, 0, &callbackHandler, 05611 &stream->callbackInfo, 0, &thread_id); 05612 if (info->thread == 0) { 05613 info->usingCallback = false; 05614 sprintf(message, "RtAudio: error starting callback thread!"); 05615 error(RtError::THREAD_ERROR); 05616 } 05617 05618 // When spawning multiple threads in quick succession, it appears to be 05619 // necessary to wait a bit for each to initialize ... another windoism! 05620 Sleep(1); 05621 } 05622 05623 static bool CALLBACK deviceCountCallback(LPGUID lpguid, 05624 LPCSTR lpcstrDescription, 05625 LPCSTR lpcstrModule, 05626 LPVOID lpContext) 05627 { 05628 int *pointer = ((int *) lpContext); 05629 (*pointer)++; 05630 05631 return true; 05632 } 05633 05634 static bool CALLBACK deviceInfoCallback(LPGUID lpguid, 05635 LPCSTR lpcstrDescription, 05636 LPCSTR lpcstrModule, 05637 LPVOID lpContext) 05638 { 05639 enum_info *info = ((enum_info *) lpContext); 05640 while (strlen(info->name) > 0) info++; 05641 05642 strncpy(info->name, lpcstrDescription, 64); 05643 info->id = lpguid; 05644 05645 HRESULT hr; 05646 info->isValid = false; 05647 if (info->isInput == true) { 05648 DSCCAPS caps; 05649 LPDIRECTSOUNDCAPTURE object; 05650 05651 hr = DirectSoundCaptureCreate( lpguid, &object, NULL ); 05652 if( hr != DS_OK ) return true; 05653 05654 caps.dwSize = sizeof(caps); 05655 hr = object->GetCaps( &caps ); 05656 if( hr == DS_OK ) { 05657 if (caps.dwChannels > 0 && caps.dwFormats > 0) 05658 info->isValid = true; 05659 } 05660 object->Release(); 05661 } 05662 else { 05663 DSCAPS caps; 05664 LPDIRECTSOUND object; 05665 hr = DirectSoundCreate( lpguid, &object, NULL ); 05666 if( hr != DS_OK ) return true; 05667 05668 caps.dwSize = sizeof(caps); 05669 hr = object->GetCaps( &caps ); 05670 if( hr == DS_OK ) { 05671 if ( caps.dwFlags & DSCAPS_PRIMARYMONO || caps.dwFlags & DSCAPS_PRIMARYSTEREO ) 05672 info->isValid = true; 05673 } 05674 object->Release(); 05675 } 05676 05677 return true; 05678 } 05679 05680 static bool CALLBACK defaultDeviceCallback(LPGUID lpguid, 05681 LPCSTR lpcstrDescription, 05682 LPCSTR lpcstrModule, 05683 LPVOID lpContext) 05684 { 05685 enum_info *info = ((enum_info *) lpContext); 05686 05687 if ( lpguid == NULL ) { 05688 strncpy(info->name, lpcstrDescription, 64); 05689 return false; 05690 } 05691 05692 return true; 05693 } 05694 05695 static bool CALLBACK deviceIdCallback(LPGUID lpguid, 05696 LPCSTR lpcstrDescription, 05697 LPCSTR lpcstrModule, 05698 LPVOID lpContext) 05699 { 05700 enum_info *info = ((enum_info *) lpContext); 05701 05702 if ( strncmp( info->name, lpcstrDescription, 64 ) == 0 ) { 05703 info->id = lpguid; 05704 info->isValid = true; 05705 return false; 05706 } 05707 05708 return true; 05709 } 05710 05711 static char* getErrorString(int code) 05712 { 05713 switch (code) { 05714 05715 case DSERR_ALLOCATED: 05716 return "Direct Sound already allocated"; 05717 05718 case DSERR_CONTROLUNAVAIL: 05719 return "Direct Sound control unavailable"; 05720 05721 case DSERR_INVALIDPARAM: 05722 return "Direct Sound invalid parameter"; 05723 05724 case DSERR_INVALIDCALL: 05725 return "Direct Sound invalid call"; 05726 05727 case DSERR_GENERIC: 05728 return "Direct Sound generic error"; 05729 05730 case DSERR_PRIOLEVELNEEDED: 05731 return "Direct Sound Priority level needed"; 05732 05733 case DSERR_OUTOFMEMORY: 05734 return "Direct Sound out of memory"; 05735 05736 case DSERR_BADFORMAT: 05737 return "Direct Sound bad format"; 05738 05739 case DSERR_UNSUPPORTED: 05740 return "Direct Sound unsupported error"; 05741 05742 case DSERR_NODRIVER: 05743 return "Direct Sound no driver error"; 05744 05745 case DSERR_ALREADYINITIALIZED: 05746 return "Direct Sound already initialized"; 05747 05748 case DSERR_NOAGGREGATION: 05749 return "Direct Sound no aggregation"; 05750 05751 case DSERR_BUFFERLOST: 05752 return "Direct Sound buffer lost"; 05753 05754 case DSERR_OTHERAPPHASPRIO: 05755 return "Direct Sound other app has priority"; 05756 05757 case DSERR_UNINITIALIZED: 05758 return "Direct Sound uninitialized"; 05759 05760 default: 05761 return "Direct Sound unknown error"; 05762 } 05763 } 05764 05765 //******************** End of __WINDOWS_DS__ *********************// 05766 05767 #elif defined(__IRIX_AL__) // SGI's AL API for IRIX 05768 05769 #include <unistd.h> 05770 #include <errno.h> 05771 05772 void RtAudio :: initialize(void) 05773 { 05774 // Count cards and devices 05775 nDevices = 0; 05776 05777 // Determine the total number of input and output devices. 05778 nDevices = alQueryValues(AL_SYSTEM, AL_DEVICES, 0, 0, 0, 0); 05779 if (nDevices < 0) { 05780 sprintf(message, "RtAudio: AL error counting devices: %s.", 05781 alGetErrorString(oserror())); 05782 error(RtError::DRIVER_ERROR); 05783 } 05784 05785 if (nDevices <= 0) return; 05786 05787 ALvalue *vls = (ALvalue *) new ALvalue[nDevices]; 05788 05789 // Allocate the RTAUDIO_DEVICE structures. 05790 devices = (RTAUDIO_DEVICE *) calloc(nDevices, sizeof(RTAUDIO_DEVICE)); 05791 if (devices == NULL) { 05792 sprintf(message, "RtAudio: memory allocation error!"); 05793 error(RtError::MEMORY_ERROR); 05794 } 05795 05796 // Write device ascii identifiers and resource ids to device info 05797 // structure. 05798 char name[32]; 05799 int outs, ins, i; 05800 ALpv pvs[1]; 05801 pvs[0].param = AL_NAME; 05802 pvs[0].value.ptr = name; 05803 pvs[0].sizeIn = 32; 05804 05805 outs = alQueryValues(AL_SYSTEM, AL_DEFAULT_OUTPUT, vls, nDevices, 0, 0); 05806 if (outs < 0) { 05807 sprintf(message, "RtAudio: AL error getting output devices: %s.", 05808 alGetErrorString(oserror())); 05809 error(RtError::DRIVER_ERROR); 05810 } 05811 05812 for (i=0; i<outs; i++) { 05813 if (alGetParams(vls[i].i, pvs, 1) < 0) { 05814 sprintf(message, "RtAudio: AL error querying output devices: %s.", 05815 alGetErrorString(oserror())); 05816 error(RtError::DRIVER_ERROR); 05817 } 05818 strncpy(devices[i].name, name, 32); 05819 devices[i].id[0] = vls[i].i; 05820 } 05821 05822 ins = alQueryValues(AL_SYSTEM, AL_DEFAULT_INPUT, &vls[outs], nDevices-outs, 0, 0); 05823 if (ins < 0) { 05824 sprintf(message, "RtAudio: AL error getting input devices: %s.", 05825 alGetErrorString(oserror())); 05826 error(RtError::DRIVER_ERROR); 05827 } 05828 05829 for (i=outs; i<ins+outs; i++) { 05830 if (alGetParams(vls[i].i, pvs, 1) < 0) { 05831 sprintf(message, "RtAudio: AL error querying input devices: %s.", 05832 alGetErrorString(oserror())); 05833 error(RtError::DRIVER_ERROR); 05834 } 05835 strncpy(devices[i].name, name, 32); 05836 devices[i].id[1] = vls[i].i; 05837 } 05838 05839 delete [] vls; 05840 05841 return; 05842 } 05843 05844 int RtAudio :: getDefaultInputDevice(void) 05845 { 05846 ALvalue value; 05847 int result = alQueryValues(AL_SYSTEM, AL_DEFAULT_INPUT, &value, 1, 0, 0); 05848 if (result < 0) { 05849 sprintf(message, "RtAudio: AL error getting default input device id: %s.", 05850 alGetErrorString(oserror())); 05851 error(RtError::WARNING); 05852 } 05853 else { 05854 for ( int i=0; i<nDevices; i++ ) 05855 if ( devices[i].id[1] == value.i ) return i; 05856 } 05857 05858 return 0; 05859 } 05860 05861 int RtAudio :: getDefaultOutputDevice(void) 05862 { 05863 ALvalue value; 05864 int result = alQueryValues(AL_SYSTEM, AL_DEFAULT_OUTPUT, &value, 1, 0, 0); 05865 if (result < 0) { 05866 sprintf(message, "RtAudio: AL error getting default output device id: %s.", 05867 alGetErrorString(oserror())); 05868 error(RtError::WARNING); 05869 } 05870 else { 05871 for ( int i=0; i<nDevices; i++ ) 05872 if ( devices[i].id[0] == value.i ) return i; 05873 } 05874 05875 return 0; 05876 } 05877 05878 void RtAudio :: probeDeviceInfo(RTAUDIO_DEVICE *info) 05879 { 05880 int resource, result, i; 05881 ALvalue value; 05882 ALparamInfo pinfo; 05883 05884 // Get output resource ID if it exists. 05885 resource = info->id[0]; 05886 if (resource > 0) { 05887 05888 // Probe output device parameters. 05889 result = alQueryValues(resource, AL_CHANNELS, &value, 1, 0, 0); 05890 if (result < 0) { 05891 sprintf(message, "RtAudio: AL error getting device (%s) channels: %s.", 05892 info->name, alGetErrorString(oserror())); 05893 error(RtError::WARNING); 05894 } 05895 else { 05896 info->maxOutputChannels = value.i; 05897 info->minOutputChannels = 1; 05898 } 05899 05900 result = alGetParamInfo(resource, AL_RATE, &pinfo); 05901 if (result < 0) { 05902 sprintf(message, "RtAudio: AL error getting device (%s) rates: %s.", 05903 info->name, alGetErrorString(oserror())); 05904 error(RtError::WARNING); 05905 } 05906 else { 05907 info->nSampleRates = 0; 05908 for (i=0; i<MAX_SAMPLE_RATES; i++) { 05909 if ( SAMPLE_RATES[i] >= pinfo.min.i && SAMPLE_RATES[i] <= pinfo.max.i ) { 05910 info->sampleRates[info->nSampleRates] = SAMPLE_RATES[i]; 05911 info->nSampleRates++; 05912 } 05913 } 05914 } 05915 05916 // The AL library supports all our formats, except 24-bit and 32-bit ints. 05917 info->nativeFormats = (RTAUDIO_FORMAT) 51; 05918 } 05919 05920 // Now get input resource ID if it exists. 05921 resource = info->id[1]; 05922 if (resource > 0) { 05923 05924 // Probe input device parameters. 05925 result = alQueryValues(resource, AL_CHANNELS, &value, 1, 0, 0); 05926 if (result < 0) { 05927 sprintf(message, "RtAudio: AL error getting device (%s) channels: %s.", 05928 info->name, alGetErrorString(oserror())); 05929 error(RtError::WARNING); 05930 } 05931 else { 05932 info->maxInputChannels = value.i; 05933 info->minInputChannels = 1; 05934 } 05935 05936 result = alGetParamInfo(resource, AL_RATE, &pinfo); 05937 if (result < 0) { 05938 sprintf(message, "RtAudio: AL error getting device (%s) rates: %s.", 05939 info->name, alGetErrorString(oserror())); 05940 error(RtError::WARNING); 05941 } 05942 else { 05943 // In the case of the default device, these values will 05944 // overwrite the rates determined for the output device. Since 05945 // the input device is most likely to be more limited than the 05946 // output device, this is ok. 05947 info->nSampleRates = 0; 05948 for (i=0; i<MAX_SAMPLE_RATES; i++) { 05949 if ( SAMPLE_RATES[i] >= pinfo.min.i && SAMPLE_RATES[i] <= pinfo.max.i ) { 05950 info->sampleRates[info->nSampleRates] = SAMPLE_RATES[i]; 05951 info->nSampleRates++; 05952 } 05953 } 05954 } 05955 05956 // The AL library supports all our formats, except 24-bit and 32-bit ints. 05957 info->nativeFormats = (RTAUDIO_FORMAT) 51; 05958 } 05959 05960 if ( info->maxInputChannels == 0 && info->maxOutputChannels == 0 ) 05961 return; 05962 if ( info->nSampleRates == 0 ) 05963 return; 05964 05965 // Determine duplex status. 05966 if (info->maxInputChannels < info->maxOutputChannels) 05967 info->maxDuplexChannels = info->maxInputChannels; 05968 else 05969 info->maxDuplexChannels = info->maxOutputChannels; 05970 if (info->minInputChannels < info->minOutputChannels) 05971 info->minDuplexChannels = info->minInputChannels; 05972 else 05973 info->minDuplexChannels = info->minOutputChannels; 05974 05975 if ( info->maxDuplexChannels > 0 ) info->hasDuplexSupport = true; 05976 else info->hasDuplexSupport = false; 05977 05978 info->probed = true; 05979 05980 return; 05981 } 05982 05983 bool RtAudio :: probeDeviceOpen(int device, RTAUDIO_STREAM *stream, 05984 STREAM_MODE mode, int channels, 05985 int sampleRate, RTAUDIO_FORMAT format, 05986 int *bufferSize, int numberOfBuffers) 05987 { 05988 int result, resource, nBuffers; 05989 ALconfig al_config; 05990 ALport port; 05991 ALpv pvs[2]; 05992 05993 // Get a new ALconfig structure. 05994 al_config = alNewConfig(); 05995 if ( !al_config ) { 05996 sprintf(message,"RtAudio: can't get AL config: %s.", 05997 alGetErrorString(oserror())); 05998 error(RtError::WARNING); 05999 return FAILURE; 06000 } 06001 06002 // Set the channels. 06003 result = alSetChannels(al_config, channels); 06004 if ( result < 0 ) { 06005 sprintf(message,"RtAudio: can't set %d channels in AL config: %s.", 06006 channels, alGetErrorString(oserror())); 06007 error(RtError::WARNING); 06008 return FAILURE; 06009 } 06010 06011 // Attempt to set the queue size. The al API doesn't provide a 06012 // means for querying the minimum/maximum buffer size of a device, 06013 // so if the specified size doesn't work, take whatever the 06014 // al_config structure returns. 06015 if ( numberOfBuffers < 1 ) 06016 nBuffers = 1; 06017 else 06018 nBuffers = numberOfBuffers; 06019 long buffer_size = *bufferSize * nBuffers; 06020 result = alSetQueueSize(al_config, buffer_size); // in sample frames 06021 if ( result < 0 ) { 06022 // Get the buffer size specified by the al_config and try that. 06023 buffer_size = alGetQueueSize(al_config); 06024 result = alSetQueueSize(al_config, buffer_size); 06025 if ( result < 0 ) { 06026 sprintf(message,"RtAudio: can't set buffer size (%ld) in AL config: %s.", 06027 buffer_size, alGetErrorString(oserror())); 06028 error(RtError::WARNING); 06029 return FAILURE; 06030 } 06031 *bufferSize = buffer_size / nBuffers; 06032 } 06033 06034 // Set the data format. 06035 stream->userFormat = format; 06036 stream->deviceFormat[mode] = format; 06037 if (format == RTAUDIO_SINT8) { 06038 result = alSetSampFmt(al_config, AL_SAMPFMT_TWOSCOMP); 06039 result = alSetWidth(al_config, AL_SAMPLE_8); 06040 } 06041 else if (format == RTAUDIO_SINT16) { 06042 result = alSetSampFmt(al_config, AL_SAMPFMT_TWOSCOMP); 06043 result = alSetWidth(al_config, AL_SAMPLE_16); 06044 } 06045 else if (format == RTAUDIO_SINT24) { 06046 // Our 24-bit format assumes the upper 3 bytes of a 4 byte word. 06047 // The AL library uses the lower 3 bytes, so we'll need to do our 06048 // own conversion. 06049 result = alSetSampFmt(al_config, AL_SAMPFMT_FLOAT); 06050 stream->deviceFormat[mode] = RTAUDIO_FLOAT32; 06051 } 06052 else if (format == RTAUDIO_SINT32) { 06053 // The AL library doesn't seem to support the 32-bit integer 06054 // format, so we'll need to do our own conversion. 06055 result = alSetSampFmt(al_config, AL_SAMPFMT_FLOAT); 06056 stream->deviceFormat[mode] = RTAUDIO_FLOAT32; 06057 } 06058 else if (format == RTAUDIO_FLOAT32) 06059 result = alSetSampFmt(al_config, AL_SAMPFMT_FLOAT); 06060 else if (format == RTAUDIO_FLOAT64) 06061 result = alSetSampFmt(al_config, AL_SAMPFMT_DOUBLE); 06062 06063 if ( result == -1 ) { 06064 sprintf(message,"RtAudio: AL error setting sample format in AL config: %s.", 06065 alGetErrorString(oserror())); 06066 error(RtError::WARNING); 06067 return FAILURE; 06068 } 06069 06070 if (mode == OUTPUT) { 06071 06072 // Set our device. 06073 if (device == 0) 06074 resource = AL_DEFAULT_OUTPUT; 06075 else 06076 resource = devices[device].id[0]; 06077 result = alSetDevice(al_config, resource); 06078 if ( result == -1 ) { 06079 sprintf(message,"RtAudio: AL error setting device (%s) in AL config: %s.", 06080 devices[device].name, alGetErrorString(oserror())); 06081 error(RtError::WARNING); 06082 return FAILURE; 06083 } 06084 06085 // Open the port. 06086 port = alOpenPort("RtAudio Output Port", "w", al_config); 06087 if( !port ) { 06088 sprintf(message,"RtAudio: AL error opening output port: %s.", 06089 alGetErrorString(oserror())); 06090 error(RtError::WARNING); 06091 return FAILURE; 06092 } 06093 06094 // Set the sample rate 06095 pvs[0].param = AL_MASTER_CLOCK; 06096 pvs[0].value.i = AL_CRYSTAL_MCLK_TYPE; 06097 pvs[1].param = AL_RATE; 06098 pvs[1].value.ll = alDoubleToFixed((double)sampleRate); 06099 result = alSetParams(resource, pvs, 2); 06100 if ( result < 0 ) { 06101 alClosePort(port); 06102 sprintf(message,"RtAudio: AL error setting sample rate (%d) for device (%s): %s.", 06103 sampleRate, devices[device].name, alGetErrorString(oserror())); 06104 error(RtError::WARNING); 06105 return FAILURE; 06106 } 06107 } 06108 else { // mode == INPUT 06109 06110 // Set our device. 06111 if (device == 0) 06112 resource = AL_DEFAULT_INPUT; 06113 else 06114 resource = devices[device].id[1]; 06115 result = alSetDevice(al_config, resource); 06116 if ( result == -1 ) { 06117 sprintf(message,"RtAudio: AL error setting device (%s) in AL config: %s.", 06118 devices[device].name, alGetErrorString(oserror())); 06119 error(RtError::WARNING); 06120 return FAILURE; 06121 } 06122 06123 // Open the port. 06124 port = alOpenPort("RtAudio Output Port", "r", al_config); 06125 if( !port ) { 06126 sprintf(message,"RtAudio: AL error opening input port: %s.", 06127 alGetErrorString(oserror())); 06128 error(RtError::WARNING); 06129 return FAILURE; 06130 } 06131 06132 // Set the sample rate 06133 pvs[0].param = AL_MASTER_CLOCK; 06134 pvs[0].value.i = AL_CRYSTAL_MCLK_TYPE; 06135 pvs[1].param = AL_RATE; 06136 pvs[1].value.ll = alDoubleToFixed((double)sampleRate); 06137 result = alSetParams(resource, pvs, 2); 06138 if ( result < 0 ) { 06139 alClosePort(port); 06140 sprintf(message,"RtAudio: AL error setting sample rate (%d) for device (%s): %s.", 06141 sampleRate, devices[device].name, alGetErrorString(oserror())); 06142 error(RtError::WARNING); 06143 return FAILURE; 06144 } 06145 } 06146 06147 alFreeConfig(al_config); 06148 06149 stream->nUserChannels[mode] = channels; 06150 stream->nDeviceChannels[mode] = channels; 06151 06152 // Set handle and flags for buffer conversion 06153 stream->handle[mode] = port; 06154 stream->doConvertBuffer[mode] = false; 06155 if (stream->userFormat != stream->deviceFormat[mode]) 06156 stream->doConvertBuffer[mode] = true; 06157 06158 // Allocate necessary internal buffers 06159 if ( stream->nUserChannels[0] != stream->nUserChannels[1] ) { 06160 06161 long buffer_bytes; 06162 if (stream->nUserChannels[0] >= stream->nUserChannels[1]) 06163 buffer_bytes = stream->nUserChannels[0]; 06164 else 06165 buffer_bytes = stream->nUserChannels[1]; 06166 06167 buffer_bytes *= *bufferSize * formatBytes(stream->userFormat); 06168 if (stream->userBuffer) free(stream->userBuffer); 06169 stream->userBuffer = (char *) calloc(buffer_bytes, 1); 06170 if (stream->userBuffer == NULL) 06171 goto memory_error; 06172 } 06173 06174 if ( stream->doConvertBuffer[mode] ) { 06175 06176 long buffer_bytes; 06177 bool makeBuffer = true; 06178 if ( mode == OUTPUT ) 06179 buffer_bytes = stream->nDeviceChannels[0] * formatBytes(stream->deviceFormat[0]); 06180 else { // mode == INPUT 06181 buffer_bytes = stream->nDeviceChannels[1] * formatBytes(stream->deviceFormat[1]); 06182 if ( stream->mode == OUTPUT && stream->deviceBuffer ) { 06183 long bytes_out = stream->nDeviceChannels[0] * formatBytes(stream->deviceFormat[0]); 06184 if ( buffer_bytes < bytes_out ) makeBuffer = false; 06185 } 06186 } 06187 06188 if ( makeBuffer ) { 06189 buffer_bytes *= *bufferSize; 06190 if (stream->deviceBuffer) free(stream->deviceBuffer); 06191 stream->deviceBuffer = (char *) calloc(buffer_bytes, 1); 06192 if (stream->deviceBuffer == NULL) 06193 goto memory_error; 06194 } 06195 } 06196 06197 stream->device[mode] = device; 06198 stream->state = STREAM_STOPPED; 06199 if ( stream->mode == OUTPUT && mode == INPUT ) 06200 // We had already set up an output stream. 06201 stream->mode = DUPLEX; 06202 else 06203 stream->mode = mode; 06204 stream->nBuffers = nBuffers; 06205 stream->bufferSize = *bufferSize; 06206 stream->sampleRate = sampleRate; 06207 06208 return SUCCESS; 06209 06210 memory_error: 06211 if (stream->handle[0]) { 06212 alClosePort(stream->handle[0]); 06213 stream->handle[0] = 0; 06214 } 06215 if (stream->handle[1]) { 06216 alClosePort(stream->handle[1]); 06217 stream->handle[1] = 0; 06218 } 06219 if (stream->userBuffer) { 06220 free(stream->userBuffer); 06221 stream->userBuffer = 0; 06222 } 06223 sprintf(message, "RtAudio: ALSA error allocating buffer memory for device (%s).", 06224 devices[device].name); 06225 error(RtError::WARNING); 06226 return FAILURE; 06227 } 06228 06229 void RtAudio :: closeStream(int streamId) 06230 { 06231 // We don't want an exception to be thrown here because this 06232 // function is called by our class destructor. So, do our own 06233 // streamId check. 06234 if ( streams.find( streamId ) == streams.end() ) { 06235 sprintf(message, "RtAudio: invalid stream identifier!"); 06236 error(RtError::WARNING); 06237 return; 06238 } 06239 06240 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) streams[streamId]; 06241 06242 if (stream->callbackInfo.usingCallback) { 06243 pthread_cancel(stream->callbackInfo.thread); 06244 pthread_join(stream->callbackInfo.thread, NULL); 06245 } 06246 06247 pthread_mutex_destroy(&stream->mutex); 06248 06249 if (stream->handle[0]) 06250 alClosePort(stream->handle[0]); 06251 06252 if (stream->handle[1]) 06253 alClosePort(stream->handle[1]); 06254 06255 if (stream->userBuffer) 06256 free(stream->userBuffer); 06257 06258 if (stream->deviceBuffer) 06259 free(stream->deviceBuffer); 06260 06261 free(stream); 06262 streams.erase(streamId); 06263 } 06264 06265 void RtAudio :: startStream(int streamId) 06266 { 06267 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId); 06268 06269 if (stream->state == STREAM_RUNNING) 06270 return; 06271 06272 // The AL port is ready as soon as it is opened. 06273 stream->state = STREAM_RUNNING; 06274 } 06275 06276 void RtAudio :: stopStream(int streamId) 06277 { 06278 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId); 06279 06280 MUTEX_LOCK(&stream->mutex); 06281 06282 if (stream->state == STREAM_STOPPED) 06283 goto unlock; 06284 06285 int result; 06286 int buffer_size = stream->bufferSize * stream->nBuffers; 06287 06288 if (stream->mode == OUTPUT || stream->mode == DUPLEX) 06289 alZeroFrames(stream->handle[0], buffer_size); 06290 06291 if (stream->mode == INPUT || stream->mode == DUPLEX) { 06292 result = alDiscardFrames(stream->handle[1], buffer_size); 06293 if (result == -1) { 06294 sprintf(message, "RtAudio: AL error draining stream device (%s): %s.", 06295 devices[stream->device[1]].name, alGetErrorString(oserror())); 06296 error(RtError::DRIVER_ERROR); 06297 } 06298 } 06299 stream->state = STREAM_STOPPED; 06300 06301 unlock: 06302 MUTEX_UNLOCK(&stream->mutex); 06303 } 06304 06305 void RtAudio :: abortStream(int streamId) 06306 { 06307 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId); 06308 06309 MUTEX_LOCK(&stream->mutex); 06310 06311 if (stream->state == STREAM_STOPPED) 06312 goto unlock; 06313 06314 if (stream->mode == OUTPUT || stream->mode == DUPLEX) { 06315 06316 int buffer_size = stream->bufferSize * stream->nBuffers; 06317 int result = alDiscardFrames(stream->handle[0], buffer_size); 06318 if (result == -1) { 06319 sprintf(message, "RtAudio: AL error aborting stream device (%s): %s.", 06320 devices[stream->device[0]].name, alGetErrorString(oserror())); 06321 error(RtError::DRIVER_ERROR); 06322 } 06323 } 06324 06325 // There is no clear action to take on the input stream, since the 06326 // port will continue to run in any event. 06327 stream->state = STREAM_STOPPED; 06328 06329 unlock: 06330 MUTEX_UNLOCK(&stream->mutex); 06331 } 06332 06333 int RtAudio :: streamWillBlock(int streamId) 06334 { 06335 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId); 06336 06337 MUTEX_LOCK(&stream->mutex); 06338 06339 int frames = 0; 06340 if (stream->state == STREAM_STOPPED) 06341 goto unlock; 06342 06343 int err = 0; 06344 if (stream->mode == OUTPUT || stream->mode == DUPLEX) { 06345 err = alGetFillable(stream->handle[0]); 06346 if (err < 0) { 06347 sprintf(message, "RtAudio: AL error getting available frames for stream (%s): %s.", 06348 devices[stream->device[0]].name, alGetErrorString(oserror())); 06349 error(RtError::DRIVER_ERROR); 06350 } 06351 } 06352 06353 frames = err; 06354 06355 if (stream->mode == INPUT || stream->mode == DUPLEX) { 06356 err = alGetFilled(stream->handle[1]); 06357 if (err < 0) { 06358 sprintf(message, "RtAudio: AL error getting available frames for stream (%s): %s.", 06359 devices[stream->device[1]].name, alGetErrorString(oserror())); 06360 error(RtError::DRIVER_ERROR); 06361 } 06362 if (frames > err) frames = err; 06363 } 06364 06365 frames = stream->bufferSize - frames; 06366 if (frames < 0) frames = 0; 06367 06368 unlock: 06369 MUTEX_UNLOCK(&stream->mutex); 06370 return frames; 06371 } 06372 06373 void RtAudio :: tickStream(int streamId) 06374 { 06375 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId); 06376 06377 int stopStream = 0; 06378 if (stream->state == STREAM_STOPPED) { 06379 if (stream->callbackInfo.usingCallback) usleep(50000); // sleep 50 milliseconds 06380 return; 06381 } 06382 else if (stream->callbackInfo.usingCallback) { 06383 RTAUDIO_CALLBACK callback = (RTAUDIO_CALLBACK) stream->callbackInfo.callback; 06384 stopStream = callback(stream->userBuffer, stream->bufferSize, stream->callbackInfo.userData); 06385 } 06386 06387 MUTEX_LOCK(&stream->mutex); 06388 06389 // The state might change while waiting on a mutex. 06390 if (stream->state == STREAM_STOPPED) 06391 goto unlock; 06392 06393 char *buffer; 06394 int channels; 06395 RTAUDIO_FORMAT format; 06396 if (stream->mode == OUTPUT || stream->mode == DUPLEX) { 06397 06398 // Setup parameters and do buffer conversion if necessary. 06399 if (stream->doConvertBuffer[0]) { 06400 convertStreamBuffer(stream, OUTPUT); 06401 buffer = stream->deviceBuffer; 06402 channels = stream->nDeviceChannels[0]; 06403 format = stream->deviceFormat[0]; 06404 } 06405 else { 06406 buffer = stream->userBuffer; 06407 channels = stream->nUserChannels[0]; 06408 format = stream->userFormat; 06409 } 06410 06411 // Do byte swapping if necessary. 06412 if (stream->doByteSwap[0]) 06413 byteSwapBuffer(buffer, stream->bufferSize * channels, format); 06414 06415 // Write interleaved samples to device. 06416 alWriteFrames(stream->handle[0], buffer, stream->bufferSize); 06417 } 06418 06419 if (stream->mode == INPUT || stream->mode == DUPLEX) { 06420 06421 // Setup parameters. 06422 if (stream->doConvertBuffer[1]) { 06423 buffer = stream->deviceBuffer; 06424 channels = stream->nDeviceChannels[1]; 06425 format = stream->deviceFormat[1]; 06426 } 06427 else { 06428 buffer = stream->userBuffer; 06429 channels = stream->nUserChannels[1]; 06430 format = stream->userFormat; 06431 } 06432 06433 // Read interleaved samples from device. 06434 alReadFrames(stream->handle[1], buffer, stream->bufferSize); 06435 06436 // Do byte swapping if necessary. 06437 if (stream->doByteSwap[1]) 06438 byteSwapBuffer(buffer, stream->bufferSize * channels, format); 06439 06440 // Do buffer conversion if necessary. 06441 if (stream->doConvertBuffer[1]) 06442 convertStreamBuffer(stream, INPUT); 06443 } 06444 06445 unlock: 06446 MUTEX_UNLOCK(&stream->mutex); 06447 06448 if (stream->callbackInfo.usingCallback && stopStream) 06449 this->stopStream(streamId); 06450 } 06451 06452 extern "C" void *callbackHandler(void *ptr) 06453 { 06454 CALLBACK_INFO *info = (CALLBACK_INFO *) ptr; 06455 RtAudio *object = (RtAudio *) info->object; 06456 int stream = info->streamId; 06457 bool *usingCallback = &info->usingCallback; 06458 06459 while ( *usingCallback ) { 06460 pthread_testcancel(); 06461 try { 06462 object->tickStream(stream); 06463 } 06464 catch (RtError &exception) { 06465 fprintf(stderr, "\nRtAudio: Callback thread error (%s) ... closing thread.\n\n", 06466 exception.getMessage()); 06467 break; 06468 } 06469 } 06470 06471 return 0; 06472 } 06473 06474 //******************** End of __IRIX_AL__ *********************// 06475 06476 #endif 06477 06478 06479 // *************************************************** // 06480 // 06481 // Private common (OS-independent) RtAudio methods. 06482 // 06483 // *************************************************** // 06484 06485 // This method can be modified to control the behavior of error 06486 // message reporting and throwing. 06487 void RtAudio :: error(RtError::TYPE type) 06488 { 06489 if (type == RtError::WARNING) { 06490 fprintf(stderr, "\n%s\n\n", message); 06491 } 06492 else if (type == RtError::DEBUG_WARNING) { 06493 #if defined(__RTAUDIO_DEBUG__) 06494 fprintf(stderr, "\n%s\n\n", message); 06495 #endif 06496 } 06497 else { 06498 fprintf(stderr, "\n%s\n\n", message); 06499 throw RtError(message, type); 06500 } 06501 } 06502 06503 void *RtAudio :: verifyStream(int streamId) 06504 { 06505 // Verify the stream key. 06506 if ( streams.find( streamId ) == streams.end() ) { 06507 sprintf(message, "RtAudio: invalid stream identifier!"); 06508 error(RtError::INVALID_STREAM); 06509 } 06510 06511 return streams[streamId]; 06512 } 06513 06514 void RtAudio :: clearDeviceInfo(RTAUDIO_DEVICE *info) 06515 { 06516 // Don't clear the name or DEVICE_ID fields here ... they are 06517 // typically set prior to a call of this function. 06518 info->probed = false; 06519 info->maxOutputChannels = 0; 06520 info->maxInputChannels = 0; 06521 info->maxDuplexChannels = 0; 06522 info->minOutputChannels = 0; 06523 info->minInputChannels = 0; 06524 info->minDuplexChannels = 0; 06525 info->hasDuplexSupport = false; 06526 info->nSampleRates = 0; 06527 for (int i=0; i<MAX_SAMPLE_RATES; i++) 06528 info->sampleRates[i] = 0; 06529 info->nativeFormats = 0; 06530 } 06531 06532 int RtAudio :: formatBytes(RTAUDIO_FORMAT format) 06533 { 06534 if (format == RTAUDIO_SINT16) 06535 return 2; 06536 else if (format == RTAUDIO_SINT24 || format == RTAUDIO_SINT32 || 06537 format == RTAUDIO_FLOAT32) 06538 return 4; 06539 else if (format == RTAUDIO_FLOAT64) 06540 return 8; 06541 else if (format == RTAUDIO_SINT8) 06542 return 1; 06543 06544 sprintf(message,"RtAudio: undefined format in formatBytes()."); 06545 error(RtError::WARNING); 06546 06547 return 0; 06548 } 06549 06550 void RtAudio :: convertStreamBuffer(RTAUDIO_STREAM *stream, STREAM_MODE mode) 06551 { 06552 // This method does format conversion, input/output channel compensation, and 06553 // data interleaving/deinterleaving. 24-bit integers are assumed to occupy 06554 // the upper three bytes of a 32-bit integer. 06555 06556 int j, jump_in, jump_out, channels; 06557 RTAUDIO_FORMAT format_in, format_out; 06558 char *input, *output; 06559 06560 if (mode == INPUT) { // convert device to user buffer 06561 input = stream->deviceBuffer; 06562 output = stream->userBuffer; 06563 jump_in = stream->nDeviceChannels[1]; 06564 jump_out = stream->nUserChannels[1]; 06565 format_in = stream->deviceFormat[1]; 06566 format_out = stream->userFormat; 06567 } 06568 else { // convert user to device buffer 06569 input = stream->userBuffer; 06570 output = stream->deviceBuffer; 06571 jump_in = stream->nUserChannels[0]; 06572 jump_out = stream->nDeviceChannels[0]; 06573 format_in = stream->userFormat; 06574 format_out = stream->deviceFormat[0]; 06575 06576 // clear our device buffer when in/out duplex device channels are different 06577 if ( stream->mode == DUPLEX && 06578 stream->nDeviceChannels[0] != stream->nDeviceChannels[1] ) 06579 memset(output, 0, stream->bufferSize * jump_out * formatBytes(format_out)); 06580 } 06581 06582 channels = (jump_in < jump_out) ? jump_in : jump_out; 06583 06584 // Set up the interleave/deinterleave offsets 06585 std::vector<int> offset_in(channels); 06586 std::vector<int> offset_out(channels); 06587 if (mode == INPUT && stream->deInterleave[1]) { 06588 for (int k=0; k<channels; k++) { 06589 offset_in[k] = k * stream->bufferSize; 06590 offset_out[k] = k; 06591 jump_in = 1; 06592 } 06593 } 06594 else if (mode == OUTPUT && stream->deInterleave[0]) { 06595 for (int k=0; k<channels; k++) { 06596 offset_in[k] = k; 06597 offset_out[k] = k * stream->bufferSize; 06598 jump_out = 1; 06599 } 06600 } 06601 else { 06602 for (int k=0; k<channels; k++) { 06603 offset_in[k] = k; 06604 offset_out[k] = k; 06605 } 06606 } 06607 06608 if (format_out == RTAUDIO_FLOAT64) { 06609 FLOAT64 scale; 06610 FLOAT64 *out = (FLOAT64 *)output; 06611 06612 if (format_in == RTAUDIO_SINT8) { 06613 signed char *in = (signed char *)input; 06614 scale = 1.0 / 128.0; 06615 for (int i=0; i<stream->bufferSize; i++) { 06616 for (j=0; j<channels; j++) { 06617 out[offset_out[j]] = (FLOAT64) in[offset_in[j]]; 06618 out[offset_out[j]] *= scale; 06619 } 06620 in += jump_in; 06621 out += jump_out; 06622 } 06623 } 06624 else if (format_in == RTAUDIO_SINT16) { 06625 INT16 *in = (INT16 *)input; 06626 scale = 1.0 / 32768.0; 06627 for (int i=0; i<stream->bufferSize; i++) { 06628 for (j=0; j<channels; j++) { 06629 out[offset_out[j]] = (FLOAT64) in[offset_in[j]]; 06630 out[offset_out[j]] *= scale; 06631 } 06632 in += jump_in; 06633 out += jump_out; 06634 } 06635 } 06636 else if (format_in == RTAUDIO_SINT24) { 06637 INT32 *in = (INT32 *)input; 06638 scale = 1.0 / 2147483648.0; 06639 for (int i=0; i<stream->bufferSize; i++) { 06640 for (j=0; j<channels; j++) { 06641 out[offset_out[j]] = (FLOAT64) (in[offset_in[j]] & 0xffffff00); 06642 out[offset_out[j]] *= scale; 06643 } 06644 in += jump_in; 06645 out += jump_out; 06646 } 06647 } 06648 else if (format_in == RTAUDIO_SINT32) { 06649 INT32 *in = (INT32 *)input; 06650 scale = 1.0 / 2147483648.0; 06651 for (int i=0; i<stream->bufferSize; i++) { 06652 for (j=0; j<channels; j++) { 06653 out[offset_out[j]] = (FLOAT64) in[offset_in[j]]; 06654 out[offset_out[j]] *= scale; 06655 } 06656 in += jump_in; 06657 out += jump_out; 06658 } 06659 } 06660 else if (format_in == RTAUDIO_FLOAT32) { 06661 FLOAT32 *in = (FLOAT32 *)input; 06662 for (int i=0; i<stream->bufferSize; i++) { 06663 for (j=0; j<channels; j++) { 06664 out[offset_out[j]] = (FLOAT64) in[offset_in[j]]; 06665 } 06666 in += jump_in; 06667 out += jump_out; 06668 } 06669 } 06670 else if (format_in == RTAUDIO_FLOAT64) { 06671 // Channel compensation and/or (de)interleaving only. 06672 FLOAT64 *in = (FLOAT64 *)input; 06673 for (int i=0; i<stream->bufferSize; i++) { 06674 for (j=0; j<channels; j++) { 06675 out[offset_out[j]] = in[offset_in[j]]; 06676 } 06677 in += jump_in; 06678 out += jump_out; 06679 } 06680 } 06681 } 06682 else if (format_out == RTAUDIO_FLOAT32) { 06683 FLOAT32 scale; 06684 FLOAT32 *out = (FLOAT32 *)output; 06685 06686 if (format_in == RTAUDIO_SINT8) { 06687 signed char *in = (signed char *)input; 06688 scale = 1.0 / 128.0; 06689 for (int i=0; i<stream->bufferSize; i++) { 06690 for (j=0; j<channels; j++) { 06691 out[offset_out[j]] = (FLOAT32) in[offset_in[j]]; 06692 out[offset_out[j]] *= scale; 06693 } 06694 in += jump_in; 06695 out += jump_out; 06696 } 06697 } 06698 else if (format_in == RTAUDIO_SINT16) { 06699 INT16 *in = (INT16 *)input; 06700 scale = 1.0 / 32768.0; 06701 for (int i=0; i<stream->bufferSize; i++) { 06702 for (j=0; j<channels; j++) { 06703 out[offset_out[j]] = (FLOAT32) in[offset_in[j]]; 06704 out[offset_out[j]] *= scale; 06705 } 06706 in += jump_in; 06707 out += jump_out; 06708 } 06709 } 06710 else if (format_in == RTAUDIO_SINT24) { 06711 INT32 *in = (INT32 *)input; 06712 scale = 1.0 / 2147483648.0; 06713 for (int i=0; i<stream->bufferSize; i++) { 06714 for (j=0; j<channels; j++) { 06715 out[offset_out[j]] = (FLOAT32) (in[offset_in[j]] & 0xffffff00); 06716 out[offset_out[j]] *= scale; 06717 } 06718 in += jump_in; 06719 out += jump_out; 06720 } 06721 } 06722 else if (format_in == RTAUDIO_SINT32) { 06723 INT32 *in = (INT32 *)input; 06724 scale = 1.0 / 2147483648.0; 06725 for (int i=0; i<stream->bufferSize; i++) { 06726 for (j=0; j<channels; j++) { 06727 out[offset_out[j]] = (FLOAT32) in[offset_in[j]]; 06728 out[offset_out[j]] *= scale; 06729 } 06730 in += jump_in; 06731 out += jump_out; 06732 } 06733 } 06734 else if (format_in == RTAUDIO_FLOAT32) { 06735 // Channel compensation and/or (de)interleaving only. 06736 FLOAT32 *in = (FLOAT32 *)input; 06737 for (int i=0; i<stream->bufferSize; i++) { 06738 for (j=0; j<channels; j++) { 06739 out[offset_out[j]] = in[offset_in[j]]; 06740 } 06741 in += jump_in; 06742 out += jump_out; 06743 } 06744 } 06745 else if (format_in == RTAUDIO_FLOAT64) { 06746 FLOAT64 *in = (FLOAT64 *)input; 06747 for (int i=0; i<stream->bufferSize; i++) { 06748 for (j=0; j<channels; j++) { 06749 out[offset_out[j]] = (FLOAT32) in[offset_in[j]]; 06750 } 06751 in += jump_in; 06752 out += jump_out; 06753 } 06754 } 06755 } 06756 else if (format_out == RTAUDIO_SINT32) { 06757 INT32 *out = (INT32 *)output; 06758 if (format_in == RTAUDIO_SINT8) { 06759 signed char *in = (signed char *)input; 06760 for (int i=0; i<stream->bufferSize; i++) { 06761 for (j=0; j<channels; j++) { 06762 out[offset_out[j]] = (INT32) in[offset_in[j]]; 06763 out[offset_out[j]] <<= 24; 06764 } 06765 in += jump_in; 06766 out += jump_out; 06767 } 06768 } 06769 else if (format_in == RTAUDIO_SINT16) { 06770 INT16 *in = (INT16 *)input; 06771 for (int i=0; i<stream->bufferSize; i++) { 06772 for (j=0; j<channels; j++) { 06773 out[offset_out[j]] = (INT32) in[offset_in[j]]; 06774 out[offset_out[j]] <<= 16; 06775 } 06776 in += jump_in; 06777 out += jump_out; 06778 } 06779 } 06780 else if (format_in == RTAUDIO_SINT24) { 06781 INT32 *in = (INT32 *)input; 06782 for (int i=0; i<stream->bufferSize; i++) { 06783 for (j=0; j<channels; j++) { 06784 out[offset_out[j]] = (INT32) in[offset_in[j]]; 06785 } 06786 in += jump_in; 06787 out += jump_out; 06788 } 06789 } 06790 else if (format_in == RTAUDIO_SINT32) { 06791 // Channel compensation and/or (de)interleaving only. 06792 INT32 *in = (INT32 *)input; 06793 for (int i=0; i<stream->bufferSize; i++) { 06794 for (j=0; j<channels; j++) { 06795 out[offset_out[j]] = in[offset_in[j]]; 06796 } 06797 in += jump_in; 06798 out += jump_out; 06799 } 06800 } 06801 else if (format_in == RTAUDIO_FLOAT32) { 06802 FLOAT32 *in = (FLOAT32 *)input; 06803 for (int i=0; i<stream->bufferSize; i++) { 06804 for (j=0; j<channels; j++) { 06805 out[offset_out[j]] = (INT32) (in[offset_in[j]] * 2147483647.0); 06806 } 06807 in += jump_in; 06808 out += jump_out; 06809 } 06810 } 06811 else if (format_in == RTAUDIO_FLOAT64) { 06812 FLOAT64 *in = (FLOAT64 *)input; 06813 for (int i=0; i<stream->bufferSize; i++) { 06814 for (j=0; j<channels; j++) { 06815 out[offset_out[j]] = (INT32) (in[offset_in[j]] * 2147483647.0); 06816 } 06817 in += jump_in; 06818 out += jump_out; 06819 } 06820 } 06821 } 06822 else if (format_out == RTAUDIO_SINT24) { 06823 INT32 *out = (INT32 *)output; 06824 if (format_in == RTAUDIO_SINT8) { 06825 signed char *in = (signed char *)input; 06826 for (int i=0; i<stream->bufferSize; i++) { 06827 for (j=0; j<channels; j++) { 06828 out[offset_out[j]] = (INT32) in[offset_in[j]]; 06829 out[offset_out[j]] <<= 24; 06830 } 06831 in += jump_in; 06832 out += jump_out; 06833 } 06834 } 06835 else if (format_in == RTAUDIO_SINT16) { 06836 INT16 *in = (INT16 *)input; 06837 for (int i=0; i<stream->bufferSize; i++) { 06838 for (j=0; j<channels; j++) { 06839 out[offset_out[j]] = (INT32) in[offset_in[j]]; 06840 out[offset_out[j]] <<= 16; 06841 } 06842 in += jump_in; 06843 out += jump_out; 06844 } 06845 } 06846 else if (format_in == RTAUDIO_SINT24) { 06847 // Channel compensation and/or (de)interleaving only. 06848 INT32 *in = (INT32 *)input; 06849 for (int i=0; i<stream->bufferSize; i++) { 06850 for (j=0; j<channels; j++) { 06851 out[offset_out[j]] = in[offset_in[j]]; 06852 } 06853 in += jump_in; 06854 out += jump_out; 06855 } 06856 } 06857 else if (format_in == RTAUDIO_SINT32) { 06858 INT32 *in = (INT32 *)input; 06859 for (int i=0; i<stream->bufferSize; i++) { 06860 for (j=0; j<channels; j++) { 06861 out[offset_out[j]] = (INT32) (in[offset_in[j]] & 0xffffff00); 06862 } 06863 in += jump_in; 06864 out += jump_out; 06865 } 06866 } 06867 else if (format_in == RTAUDIO_FLOAT32) { 06868 FLOAT32 *in = (FLOAT32 *)input; 06869 for (int i=0; i<stream->bufferSize; i++) { 06870 for (j=0; j<channels; j++) { 06871 out[offset_out[j]] = (INT32) (in[offset_in[j]] * 2147483647.0); 06872 } 06873 in += jump_in; 06874 out += jump_out; 06875 } 06876 } 06877 else if (format_in == RTAUDIO_FLOAT64) { 06878 FLOAT64 *in = (FLOAT64 *)input; 06879 for (int i=0; i<stream->bufferSize; i++) { 06880 for (j=0; j<channels; j++) { 06881 out[offset_out[j]] = (INT32) (in[offset_in[j]] * 2147483647.0); 06882 } 06883 in += jump_in; 06884 out += jump_out; 06885 } 06886 } 06887 } 06888 else if (format_out == RTAUDIO_SINT16) { 06889 INT16 *out = (INT16 *)output; 06890 if (format_in == RTAUDIO_SINT8) { 06891 signed char *in = (signed char *)input; 06892 for (int i=0; i<stream->bufferSize; i++) { 06893 for (j=0; j<channels; j++) { 06894 out[offset_out[j]] = (INT16) in[offset_in[j]]; 06895 out[offset_out[j]] <<= 8; 06896 } 06897 in += jump_in; 06898 out += jump_out; 06899 } 06900 } 06901 else if (format_in == RTAUDIO_SINT16) { 06902 // Channel compensation and/or (de)interleaving only. 06903 INT16 *in = (INT16 *)input; 06904 for (int i=0; i<stream->bufferSize; i++) { 06905 for (j=0; j<channels; j++) { 06906 out[offset_out[j]] = in[offset_in[j]]; 06907 } 06908 in += jump_in; 06909 out += jump_out; 06910 } 06911 } 06912 else if (format_in == RTAUDIO_SINT24) { 06913 INT32 *in = (INT32 *)input; 06914 for (int i=0; i<stream->bufferSize; i++) { 06915 for (j=0; j<channels; j++) { 06916 out[offset_out[j]] = (INT16) ((in[offset_in[j]] >> 16) & 0x0000ffff); 06917 } 06918 in += jump_in; 06919 out += jump_out; 06920 } 06921 } 06922 else if (format_in == RTAUDIO_SINT32) { 06923 INT32 *in = (INT32 *)input; 06924 for (int i=0; i<stream->bufferSize; i++) { 06925 for (j=0; j<channels; j++) { 06926 out[offset_out[j]] = (INT16) ((in[offset_in[j]] >> 16) & 0x0000ffff); 06927 } 06928 in += jump_in; 06929 out += jump_out; 06930 } 06931 } 06932 else if (format_in == RTAUDIO_FLOAT32) { 06933 FLOAT32 *in = (FLOAT32 *)input; 06934 for (int i=0; i<stream->bufferSize; i++) { 06935 for (j=0; j<channels; j++) { 06936 out[offset_out[j]] = (INT16) (in[offset_in[j]] * 32767.0); 06937 } 06938 in += jump_in; 06939 out += jump_out; 06940 } 06941 } 06942 else if (format_in == RTAUDIO_FLOAT64) { 06943 FLOAT64 *in = (FLOAT64 *)input; 06944 for (int i=0; i<stream->bufferSize; i++) { 06945 for (j=0; j<channels; j++) { 06946 out[offset_out[j]] = (INT16) (in[offset_in[j]] * 32767.0); 06947 } 06948 in += jump_in; 06949 out += jump_out; 06950 } 06951 } 06952 } 06953 else if (format_out == RTAUDIO_SINT8) { 06954 signed char *out = (signed char *)output; 06955 if (format_in == RTAUDIO_SINT8) { 06956 // Channel compensation and/or (de)interleaving only. 06957 signed char *in = (signed char *)input; 06958 for (int i=0; i<stream->bufferSize; i++) { 06959 for (j=0; j<channels; j++) { 06960 out[offset_out[j]] = in[offset_in[j]]; 06961 } 06962 in += jump_in; 06963 out += jump_out; 06964 } 06965 } 06966 if (format_in == RTAUDIO_SINT16) { 06967 INT16 *in = (INT16 *)input; 06968 for (int i=0; i<stream->bufferSize; i++) { 06969 for (j=0; j<channels; j++) { 06970 out[offset_out[j]] = (signed char) ((in[offset_in[j]] >> 8) & 0x00ff); 06971 } 06972 in += jump_in; 06973 out += jump_out; 06974 } 06975 } 06976 else if (format_in == RTAUDIO_SINT24) { 06977 INT32 *in = (INT32 *)input; 06978 for (int i=0; i<stream->bufferSize; i++) { 06979 for (j=0; j<channels; j++) { 06980 out[offset_out[j]] = (signed char) ((in[offset_in[j]] >> 24) & 0x000000ff); 06981 } 06982 in += jump_in; 06983 out += jump_out; 06984 } 06985 } 06986 else if (format_in == RTAUDIO_SINT32) { 06987 INT32 *in = (INT32 *)input; 06988 for (int i=0; i<stream->bufferSize; i++) { 06989 for (j=0; j<channels; j++) { 06990 out[offset_out[j]] = (signed char) ((in[offset_in[j]] >> 24) & 0x000000ff); 06991 } 06992 in += jump_in; 06993 out += jump_out; 06994 } 06995 } 06996 else if (format_in == RTAUDIO_FLOAT32) { 06997 FLOAT32 *in = (FLOAT32 *)input; 06998 for (int i=0; i<stream->bufferSize; i++) { 06999 for (j=0; j<channels; j++) { 07000 out[offset_out[j]] = (signed char) (in[offset_in[j]] * 127.0); 07001 } 07002 in += jump_in; 07003 out += jump_out; 07004 } 07005 } 07006 else if (format_in == RTAUDIO_FLOAT64) { 07007 FLOAT64 *in = (FLOAT64 *)input; 07008 for (int i=0; i<stream->bufferSize; i++) { 07009 for (j=0; j<channels; j++) { 07010 out[offset_out[j]] = (signed char) (in[offset_in[j]] * 127.0); 07011 } 07012 in += jump_in; 07013 out += jump_out; 07014 } 07015 } 07016 } 07017 } 07018 07019 void RtAudio :: byteSwapBuffer(char *buffer, int samples, RTAUDIO_FORMAT format) 07020 { 07021 register char val; 07022 register char *ptr; 07023 07024 ptr = buffer; 07025 if (format == RTAUDIO_SINT16) { 07026 for (int i=0; i<samples; i++) { 07027 // Swap 1st and 2nd bytes. 07028 val = *(ptr); 07029 *(ptr) = *(ptr+1); 07030 *(ptr+1) = val; 07031 07032 // Increment 2 bytes. 07033 ptr += 2; 07034 } 07035 } 07036 else if (format == RTAUDIO_SINT24 || 07037 format == RTAUDIO_SINT32 || 07038 format == RTAUDIO_FLOAT32) { 07039 for (int i=0; i<samples; i++) { 07040 // Swap 1st and 4th bytes. 07041 val = *(ptr); 07042 *(ptr) = *(ptr+3); 07043 *(ptr+3) = val; 07044 07045 // Swap 2nd and 3rd bytes. 07046 ptr += 1; 07047 val = *(ptr); 07048 *(ptr) = *(ptr+1); 07049 *(ptr+1) = val; 07050 07051 // Increment 4 bytes. 07052 ptr += 4; 07053 } 07054 } 07055 else if (format == RTAUDIO_FLOAT64) { 07056 for (int i=0; i<samples; i++) { 07057 // Swap 1st and 8th bytes 07058 val = *(ptr); 07059 *(ptr) = *(ptr+7); 07060 *(ptr+7) = val; 07061 07062 // Swap 2nd and 7th bytes 07063 ptr += 1; 07064 val = *(ptr); 07065 *(ptr) = *(ptr+5); 07066 *(ptr+5) = val; 07067 07068 // Swap 3rd and 6th bytes 07069 ptr += 1; 07070 val = *(ptr); 07071 *(ptr) = *(ptr+3); 07072 *(ptr+3) = val; 07073 07074 // Swap 4th and 5th bytes 07075 ptr += 1; 07076 val = *(ptr); 07077 *(ptr) = *(ptr+1); 07078 *(ptr+1) = val; 07079 07080 // Increment 8 bytes. 07081 ptr += 8; 07082 } 07083 } 07084 } 07085 07086 07087 // *************************************************** // 07088 // 07089 // RtError class definition. 07090 // 07091 // *************************************************** // 07092 07093 RtError :: RtError(const char *p, TYPE tipe) 07094 { 07095 type = tipe; 07096 strncpy(error_message, p, 256); 07097 } 07098 07099 RtError :: ~RtError() 07100 { 07101 } 07102 07103 void RtError :: printMessage() 07104 { 07105 printf("\n%s\n\n", error_message); 07106 } 07107