00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00059
00060
00061
00062
00063 #include "RtAudio.hxx"
00064 #include <vector>
00065 #include <cstdio>
00066 #include <iostream>
00067
00068
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
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
00125 if (devices) free(devices);
00126 throw exception;
00127 }
00128 }
00129
00130 RtAudio :: ~RtAudio()
00131 {
00132
00133 while ( streams.size() )
00134 closeStream( streams.begin()->first );
00135
00136
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;
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
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 ) {
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
00203
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 ) {
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
00234
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
00251
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
00278 if (devices[deviceIndex].probed == false) {
00279 clearDeviceInfo(&devices[deviceIndex]);
00280 probeDeviceInfo(&devices[deviceIndex]);
00281 }
00282
00283
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
00378
00379
00380
00381 #if defined(__MACOSX_CORE__)
00382
00383
00384
00385
00386
00387
00388
00389
00390
00391
00392
00393
00394
00395
00396
00397
00398
00399
00400
00401
00402
00403
00404
00405
00406 void RtAudio :: initialize(void)
00407 {
00408 OSStatus err = noErr;
00409 UInt32 dataSize;
00410 AudioDeviceID *deviceList = NULL;
00411 nDevices = 0;
00412
00413
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
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
00431 deviceList = (AudioDeviceID *) malloc( dataSize );
00432 if (deviceList == NULL) {
00433 sprintf(message, "RtAudio: memory allocation error!");
00434 error(RtError::MEMORY_ERROR);
00435 }
00436
00437
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
00446
00447 for (int i=0; i<nDevices; i++) {
00448 devices[i].id[0] = deviceList[i];
00449
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
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
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
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
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
00646
00647
00648
00649
00650
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
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
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
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
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
00778
00779
00780
00781
00782
00783
00784
00785
00786
00787
00788
00789
00790
00791
00792
00793
00794
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
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
00816 bool isInput = false;
00817 AudioDeviceID id = devices[device].id[0];
00818 if ( mode == INPUT ) isInput = true;
00819
00820
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
00849
00850
00851
00852
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
00888 deviceChannels = bufferList->mBuffers[iStream].mNumberChannels;
00889 free (bufferList);
00890
00891
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
00909
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
00923
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
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
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
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
00980
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
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
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 {
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
01038
01039
01040
01041
01042
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
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
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
01106
01107
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
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
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
01272 while ( !info->blockTick )
01273 usleep(info->waitTime);
01274 }
01275 else if ( info->stopStream ) {
01276
01277
01278
01279
01280 this->stopStream(info->streamId);
01281 return;
01282 }
01283
01284 MUTEX_LOCK(&stream->mutex);
01285
01286
01287
01288
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
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
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
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
01447
01448 for (int i=0; i<nDevices; i++) {
01449 strncpy(devices[i].name, deviceNames[i], 32);
01450
01451 }
01452 }
01453
01454 int RtAudio :: getDefaultInputDevice(void)
01455 {
01456
01457 return 0;
01458 }
01459
01460 int RtAudio :: getDefaultOutputDevice(void)
01461 {
01462
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
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
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
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
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
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
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
01572 return;
01573 goto probe_parameters;
01574 }
01575
01576
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
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
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
01607
01608
01609
01610
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
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
01636 int dir = 0;
01637 if (snd_pcm_hw_params_test_rate(handle, params, 35500, dir) == 0) {
01638
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
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
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
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
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
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
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
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
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
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
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
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
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
01866
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
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
01892 int dir;
01893 int periods = numberOfBuffers;
01894
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
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
01924
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
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
01951
01952
01953
01954
01955
01956
01957
01958
01959
01960
01961
01962
01963
01964
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
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 {
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
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
02046
02047
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
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);
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
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
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
02281 if (stream->doByteSwap[0])
02282 byteSwapBuffer(buffer, stream->bufferSize * channels, format);
02283
02284
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
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
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
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
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
02384 if (stream->doByteSwap[1])
02385 byteSwapBuffer(buffer, stream->bufferSize * channels, format);
02386
02387
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
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
02441 nDevices = 0;
02442
02443
02444
02445
02446
02447
02448
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) {
02459 if (!strncmp(DAC_NAME, device_name, 8))
02460 dsplink = atoi(&device_name[8]);
02461 }
02462 else if (i > 3) {
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
02479
02480
02481
02482
02483
02484
02485 int fd = 0;
02486 char names[MAX_DEVICES][16];
02487 for (i=-1; i<MAX_DEVICES; i++) {
02488
02489
02490 if (i == -1)
02491 sprintf(device_name, "%s", DAC_NAME);
02492 else if (i == dsplink)
02493 continue;
02494 else
02495 sprintf(device_name, "%s%d", DAC_NAME, i);
02496
02497
02498 fd = open(device_name, O_WRONLY | O_NONBLOCK);
02499 if (fd == -1) {
02500
02501 if (errno != EBUSY && errno != EAGAIN) {
02502
02503 fd = open(device_name, O_RDONLY | O_NONBLOCK);
02504 if (fd == -1) {
02505
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
02512 }
02513 }
02514 }
02515 else {
02516 sprintf(message, "RtAudio: OSS playback device (%s) is busy.", device_name);
02517 error(RtError::WARNING);
02518
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
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
02537 for (i=0; i<nDevices; i++) {
02538 strncpy(devices[i].name, names[i], 16);
02539
02540 }
02541
02542 return;
02543 }
02544
02545 int RtAudio :: getDefaultInputDevice(void)
02546 {
02547
02548 return 0;
02549 }
02550
02551 int RtAudio :: getDefaultOutputDevice(void)
02552 {
02553
02554 return 0;
02555 }
02556
02557 void RtAudio :: probeDeviceInfo(RTAUDIO_DEVICE *info)
02558 {
02559 int i, fd, channels, mask;
02560
02561
02562
02563
02564
02565 fd = open(info->name, O_WRONLY | O_NONBLOCK);
02566 if (fd == -1) {
02567
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
02578 for (i=MAX_CHANNELS; i>0; i--) {
02579 channels = i;
02580 if (ioctl(fd, SNDCTL_DSP_CHANNELS, &channels) == -1) {
02581
02582
02583
02584
02585 continue;
02586 }
02587
02588 if (channels != i ) continue;
02589
02590 break;
02591 }
02592 info->maxOutputChannels = i;
02593
02594
02595 for (i=1; i<=info->maxOutputChannels; i++) {
02596 channels = i;
02597 if (ioctl(fd, SNDCTL_DSP_CHANNELS, &channels) == -1 || channels != i)
02598 continue;
02599
02600 break;
02601 }
02602 info->minOutputChannels = i;
02603 close(fd);
02604
02605 capture_probe:
02606
02607 fd = open(info->name, O_RDONLY | O_NONBLOCK);
02608 if (fd == -1) {
02609
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
02618 return;
02619 goto probe_parameters;
02620 }
02621
02622
02623 for (i=MAX_CHANNELS; i>0; i--) {
02624 channels = i;
02625 if (ioctl(fd, SNDCTL_DSP_CHANNELS, &channels) == -1 || channels != i) {
02626 continue;
02627 }
02628
02629 break;
02630 }
02631 info->maxInputChannels = i;
02632
02633
02634 for (i=1; i<=info->maxInputChannels; i++) {
02635 channels = i;
02636 if (ioctl(fd, SNDCTL_DSP_CHANNELS, &channels) == -1 || channels != i)
02637 continue;
02638
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
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
02664 for (i=MAX_CHANNELS; i>0; i--) {
02665 channels = i;
02666 if (ioctl(fd, SNDCTL_DSP_CHANNELS, &channels) == -1 || channels != i)
02667 continue;
02668
02669 break;
02670 }
02671 info->maxDuplexChannels = i;
02672
02673
02674 for (i=1; i<=info->maxDuplexChannels; i++) {
02675 channels = i;
02676 if (ioctl(fd, SNDCTL_DSP_CHANNELS, &channels) == -1 || channels != i)
02677 continue;
02678
02679 break;
02680 }
02681 info->minDuplexChannels = i;
02682 }
02683 close(fd);
02684
02685 probe_parameters:
02686
02687
02688
02689
02690
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
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
02710 i = channels;
02711 if (ioctl(fd, SNDCTL_DSP_CHANNELS, &channels) == -1 || channels != i) {
02712
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
02729 int format;
02730 info->nativeFormats = 0;
02731 #if defined (AFMT_S32_BE)
02732
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
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
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
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
02778 int speed = 1;
02779 if (ioctl(fd, SNDCTL_DSP_SPEED, &speed) == -1) {
02780
02781
02782
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
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:
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 {
02830 if (stream->mode == OUTPUT && stream->device[0] == device) {
02831
02832 close(stream->handle[0]);
02833 stream->handle[0] = 0;
02834
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
02855 close(fd);
02856 if (mode == OUTPUT)
02857 fd = open(name, O_WRONLY | O_SYNC);
02858 else {
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
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
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
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
02976 close(fd);
02977 sprintf(message, "RtAudio: OSS device (%s) data format not supported by RtAudio.",
02978 name);
02979 goto error;
02980 }
02981
02982
02983
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 {
02991 if (stream->mode == OUTPUT && stream->device[0] == device) {
02992
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
03004
03005
03006
03007
03008
03009
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
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
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
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
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
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
03074 stream->deviceFormat[0] = stream->deviceFormat[1];
03075 stream->nDeviceChannels[0] = device_channels;
03076 }
03077
03078
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
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 {
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
03158
03159
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
03207
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);
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
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
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
03354 if (stream->doByteSwap[0])
03355 byteSwapBuffer(buffer, samples, format);
03356
03357
03358 result = write(stream->handle[0], buffer, samples * formatBytes(format));
03359
03360 if (result == -1) {
03361
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
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
03383 result = read(stream->handle[1], buffer, samples * formatBytes(format));
03384
03385 if (result == -1) {
03386
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
03393 if (stream->doByteSwap[1])
03394 byteSwapBuffer(buffer, samples, format);
03395
03396
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
03432
03433 #elif defined(__WINDOWS_ASIO__) // ASIO API on Windows
03434
03435
03436
03437
03438
03439
03440
03441
03442
03443
03444
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
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
03469
03470 for (int i=0; i<nDevices; i++) {
03471 if ( drivers.asioGetDriverName( i, devices[i].name, 128 ) == 0 )
03472
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
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
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
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
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
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
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
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
03619
03620
03621
03622
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
03646
03647 || value == kAsioSupportsTimeInfo
03648 || value == kAsioSupportsTimeCode
03649 || value == kAsioSupportsInputMonitor)
03650 ret = 1L;
03651 break;
03652 case kAsioResetRequest:
03653
03654
03655
03656
03657
03658
03659 fprintf(stderr, "\nRtAudio: ASIO driver reset requested!!!");
03660 ret = 1L;
03661 break;
03662 case kAsioResyncRequest:
03663
03664
03665
03666
03667
03668
03669
03670 fprintf(stderr, "\nRtAudio: ASIO driver resync requested!!!");
03671 ret = 1L;
03672 break;
03673 case kAsioLatenciesChanged:
03674
03675
03676
03677
03678 fprintf(stderr, "\nRtAudio: ASIO driver latency may have changed!!!");
03679 ret = 1L;
03680 break;
03681 case kAsioEngineVersion:
03682
03683
03684
03685 ret = 2L;
03686 break;
03687 case kAsioSupportsTimeInfo:
03688
03689
03690
03691
03692 ret = 0;
03693 break;
03694 case kAsioSupportsTimeCode:
03695
03696
03697
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
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
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
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
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
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
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
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
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
03835
03836
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
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
03865 stream->deInterleave[mode] = true;
03866
03867
03868
03869
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
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
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
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
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 {
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
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
04017
04018
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
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
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
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
04142 while ( !info->blockTick )
04143 Sleep(info->waitTime);
04144 }
04145 else if ( info->stopStream ) {
04146
04147
04148
04149
04150 this->stopStream(asioCallbackInfo->streamId);
04151 return;
04152 }
04153
04154 MUTEX_LOCK(&stream->mutex);
04155
04156
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
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 {
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
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 {
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
04236
04237 #elif defined(__WINDOWS_DS__) // Windows DirectSound API
04238
04239 #include <dsound.h>
04240
04241
04242
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
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
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
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
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
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
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
04361
04362
04363 for (i=0; i<count; i++)
04364 if ( info[i].isValid ) nDevices++;
04365
04366 if (nDevices == 0) return;
04367
04368
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
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
04383
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
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
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
04428 info->minInputChannels = 1;
04429 info->maxInputChannels = in_caps.dwChannels;
04430
04431
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;
04471
04472 input->Release();
04473
04474 playback_probe:
04475
04476 dsinfo.isValid = false;
04477
04478
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
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
04512 info->minOutputChannels = 1;
04513 info->maxOutputChannels = ( out_caps.dwFlags & DSCAPS_PRIMARYSTEREO ) ? 2 : 1;
04514
04515
04516
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
04525
04526 info->sampleRates[0] = 11025;
04527 info->sampleRates[1] = 48000;
04528 info->nSampleRates = -1;
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
04540
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
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
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
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
04601
04602
04603
04604
04605
04606 long buffer_size;
04607 LPVOID audioPtr;
04608 DWORD dataLen;
04609 int nBuffers;
04610
04611
04612
04613
04614 if (numberOfBuffers < 2)
04615 nBuffers = 2;
04616 else
04617 nBuffers = numberOfBuffers;
04618
04619
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
04627 if ( devices[device].nativeFormats ) {
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
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
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
04698
04699
04700
04701 ZeroMemory(&bufferDescription, sizeof(DSBUFFERDESC));
04702 bufferDescription.dwSize = sizeof(DSBUFFERDESC);
04703 bufferDescription.dwFlags = DSBCAPS_PRIMARYBUFFER;
04704
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
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
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 );
04731 bufferDescription.dwBufferBytes = buffer_size;
04732 bufferDescription.lpwfxFormat = &waveFormat;
04733
04734
04735
04736 result = object->CreateSoundBuffer(&bufferDescription, &buffer, NULL);
04737 if ( FAILED(result) ) {
04738 bufferDescription.dwFlags = ( DSBCAPS_STICKYFOCUS |
04739 DSBCAPS_GETCURRENTPOSITION2 |
04740 DSBCAPS_LOCSOFTWARE );
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
04752 DSBCAPS dsbcaps;
04753 dsbcaps.dwSize = sizeof(DSBCAPS);
04754 buffer->GetCaps(&dsbcaps);
04755 buffer_size = dsbcaps.dwBufferBytes;
04756
04757
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
04768 ZeroMemory(audioPtr, dataLen);
04769
04770
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
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
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
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
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
04848 ZeroMemory(audioPtr, dataLen);
04849
04850
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
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
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 {
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
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
04988
04989
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
05083
05084
05085
05086
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
05104 for (int i=0; i<stream->nBuffers; i++) {
05105
05106
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;
05115 DWORD endWrite = nextWritePos + buffer_bytes;
05116
05117
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
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;
05132 }
05133
05134
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
05144 ZeroMemory(buffer1, bufferSize1);
05145 if (buffer2 != NULL) ZeroMemory(buffer2, bufferSize2);
05146
05147
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
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
05178
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
05187 ZeroMemory(buffer1, bufferSize1);
05188
05189
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
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
05231
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
05240 ZeroMemory(audioPtr, dataLen);
05241
05242
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
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
05270
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
05279 ZeroMemory(audioPtr, dataLen);
05280
05281
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
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
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;
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
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;
05350
05351 if (stream->mode == DUPLEX ) {
05352
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);
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
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
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
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
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;
05431 DWORD endWrite = nextWritePos + buffer_bytes;
05432
05433
05434 while ( currentPos < endWrite ) {
05435
05436
05437
05438
05439
05440
05441
05442
05443
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
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;
05457 }
05458
05459
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
05469 CopyMemory(buffer1, buffer, bufferSize1);
05470 if (buffer2 != NULL) CopyMemory(buffer2, buffer+bufferSize1, bufferSize2);
05471
05472
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
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
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;
05510 DWORD endRead = nextReadPos + buffer_bytes;
05511
05512
05513 while ( safePos < endRead ) {
05514
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
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;
05529 }
05530
05531
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
05541 CopyMemory(buffer, buffer1, bufferSize1);
05542 if (buffer2 != NULL) CopyMemory(buffer+bufferSize1, buffer2, bufferSize2);
05543
05544
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
05555
05556
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
05568
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
05619
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
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
05775 nDevices = 0;
05776
05777
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
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
05797
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
05885 resource = info->id[0];
05886 if (resource > 0) {
05887
05888
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
05917 info->nativeFormats = (RTAUDIO_FORMAT) 51;
05918 }
05919
05920
05921 resource = info->id[1];
05922 if (resource > 0) {
05923
05924
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
05944
05945
05946
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
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
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
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
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
06012
06013
06014
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);
06021 if ( result < 0 ) {
06022
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
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
06047
06048
06049 result = alSetSampFmt(al_config, AL_SAMPFMT_FLOAT);
06050 stream->deviceFormat[mode] = RTAUDIO_FLOAT32;
06051 }
06052 else if (format == RTAUDIO_SINT32) {
06053
06054
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
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
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
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 {
06109
06110
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
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
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
06153 stream->handle[mode] = port;
06154 stream->doConvertBuffer[mode] = false;
06155 if (stream->userFormat != stream->deviceFormat[mode])
06156 stream->doConvertBuffer[mode] = true;
06157
06158
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 {
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
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
06232
06233
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
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
06326
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);
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
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
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
06412 if (stream->doByteSwap[0])
06413 byteSwapBuffer(buffer, stream->bufferSize * channels, format);
06414
06415
06416 alWriteFrames(stream->handle[0], buffer, stream->bufferSize);
06417 }
06418
06419 if (stream->mode == INPUT || stream->mode == DUPLEX) {
06420
06421
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
06434 alReadFrames(stream->handle[1], buffer, stream->bufferSize);
06435
06436
06437 if (stream->doByteSwap[1])
06438 byteSwapBuffer(buffer, stream->bufferSize * channels, format);
06439
06440
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
06475
06476 #endif
06477
06478
06479
06480
06481
06482
06483
06484
06485
06486
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
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
06517
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
06553
06554
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) {
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 {
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
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
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
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
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
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
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
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
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
07028 val = *(ptr);
07029 *(ptr) = *(ptr+1);
07030 *(ptr+1) = val;
07031
07032
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
07041 val = *(ptr);
07042 *(ptr) = *(ptr+3);
07043 *(ptr+3) = val;
07044
07045
07046 ptr += 1;
07047 val = *(ptr);
07048 *(ptr) = *(ptr+1);
07049 *(ptr+1) = val;
07050
07051
07052 ptr += 4;
07053 }
07054 }
07055 else if (format == RTAUDIO_FLOAT64) {
07056 for (int i=0; i<samples; i++) {
07057
07058 val = *(ptr);
07059 *(ptr) = *(ptr+7);
07060 *(ptr+7) = val;
07061
07062
07063 ptr += 1;
07064 val = *(ptr);
07065 *(ptr) = *(ptr+5);
07066 *(ptr+5) = val;
07067
07068
07069 ptr += 1;
07070 val = *(ptr);
07071 *(ptr) = *(ptr+3);
07072 *(ptr+3) = val;
07073
07074
07075 ptr += 1;
07076 val = *(ptr);
07077 *(ptr) = *(ptr+1);
07078 *(ptr+1) = val;
07079
07080
07081 ptr += 8;
07082 }
07083 }
07084 }
07085
07086
07087
07088
07089
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