CLAM-Development
1.1
|
00001 /******************************************/ 00002 /* 00003 RtAudio - realtime sound I/O C++ class 00004 by Gary P. Scavone, 2001-2002. 00005 */ 00006 /******************************************/ 00007 00008 #include "RtAudio.h" 00009 #include <vector> 00010 #include <stdio.h> 00011 00012 // Static variable definitions. 00013 const unsigned int RtAudio :: SAMPLE_RATES[] = { 00014 4000, 5512, 8000, 9600, 11025, 16000, 22050, 00015 32000, 44100, 48000, 88200, 96000, 176400, 192000 00016 }; 00017 const RtAudio::RTAUDIO_FORMAT RtAudio :: RTAUDIO_SINT8 = 1; 00018 const RtAudio::RTAUDIO_FORMAT RtAudio :: RTAUDIO_SINT16 = 2; 00019 const RtAudio::RTAUDIO_FORMAT RtAudio :: RTAUDIO_SINT24 = 4; 00020 const RtAudio::RTAUDIO_FORMAT RtAudio :: RTAUDIO_SINT32 = 8; 00021 const RtAudio::RTAUDIO_FORMAT RtAudio :: RTAUDIO_FLOAT32 = 16; 00022 const RtAudio::RTAUDIO_FORMAT RtAudio :: RTAUDIO_FLOAT64 = 32; 00023 00024 #if defined(__WINDOWS_DS__) 00025 #define MUTEX_INITIALIZE(A) InitializeCriticalSection(A) 00026 #define MUTEX_LOCK(A) EnterCriticalSection(A) 00027 #define MUTEX_UNLOCK(A) LeaveCriticalSection(A) 00028 typedef unsigned THREAD_RETURN; 00029 typedef unsigned (__stdcall THREAD_FUNCTION)(void *); 00030 #else // pthread API 00031 #define MUTEX_INITIALIZE(A) pthread_mutex_init(A, NULL) 00032 #define MUTEX_LOCK(A) pthread_mutex_lock(A) 00033 #define MUTEX_UNLOCK(A) pthread_mutex_unlock(A) 00034 typedef void * THREAD_RETURN; 00035 #endif 00036 00037 // *************************************************** // 00038 // 00039 // Public common (OS-independent) methods. 00040 // 00041 // *************************************************** // 00042 00043 RtAudio :: RtAudio() 00044 { 00045 initialize(); 00046 00047 if (nDevices <= 0) { 00048 sprintf(message, "RtAudio: no audio devices found!"); 00049 error(RtError::NO_DEVICES_FOUND); 00050 } 00051 } 00052 00053 RtAudio :: RtAudio(int *streamId, 00054 int outputDevice, int outputChannels, 00055 int inputDevice, int inputChannels, 00056 RTAUDIO_FORMAT format, int sampleRate, 00057 int *bufferSize, int numberOfBuffers) 00058 { 00059 initialize(); 00060 00061 if (nDevices <= 0) { 00062 sprintf(message, "RtAudio: no audio devices found!"); 00063 error(RtError::NO_DEVICES_FOUND); 00064 } 00065 00066 try { 00067 *streamId = openStream(outputDevice, outputChannels, inputDevice, inputChannels, 00068 format, sampleRate, bufferSize, numberOfBuffers); 00069 } 00070 catch (RtError &exception) { 00071 // deallocate the RTAUDIO_DEVICE structures 00072 if (devices) free(devices); 00073 error(exception.getType()); 00074 } 00075 } 00076 00077 RtAudio :: ~RtAudio() 00078 { 00079 // close any existing streams 00080 while ( streams.size() ) 00081 closeStream( streams.begin()->first ); 00082 00083 // deallocate the RTAUDIO_DEVICE structures 00084 if (devices) free(devices); 00085 } 00086 00087 int RtAudio :: openStream(int outputDevice, int outputChannels, 00088 int inputDevice, int inputChannels, 00089 RTAUDIO_FORMAT format, int sampleRate, 00090 int *bufferSize, int numberOfBuffers) 00091 { 00092 static int streamKey = 0; // Unique stream identifier ... OK for multiple instances. 00093 00094 if (outputChannels < 1 && inputChannels < 1) { 00095 sprintf(message,"RtAudio: one or both 'channel' parameters must be greater than zero."); 00096 error(RtError::INVALID_PARAMETER); 00097 } 00098 00099 if ( formatBytes(format) == 0 ) { 00100 sprintf(message,"RtAudio: 'format' parameter value is undefined."); 00101 error(RtError::INVALID_PARAMETER); 00102 } 00103 00104 if ( outputChannels > 0 ) { 00105 if (outputDevice >= nDevices || outputDevice < 0) { 00106 sprintf(message,"RtAudio: 'outputDevice' parameter value (%d) is invalid.", outputDevice); 00107 error(RtError::INVALID_PARAMETER); 00108 } 00109 } 00110 00111 if ( inputChannels > 0 ) { 00112 if (inputDevice >= nDevices || inputDevice < 0) { 00113 sprintf(message,"RtAudio: 'inputDevice' parameter value (%d) is invalid.", inputDevice); 00114 error(RtError::INVALID_PARAMETER); 00115 } 00116 } 00117 00118 // Allocate a new stream structure. 00119 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) calloc(1, sizeof(RTAUDIO_STREAM)); 00120 if (stream == NULL) { 00121 sprintf(message, "RtAudio: memory allocation error!"); 00122 error(RtError::MEMORY_ERROR); 00123 } 00124 streams[++streamKey] = (void *) stream; 00125 stream->mode = UNINITIALIZED; 00126 MUTEX_INITIALIZE(&stream->mutex); 00127 00128 bool result = SUCCESS; 00129 int device; 00130 STREAM_MODE mode; 00131 int channels; 00132 if ( outputChannels > 0 ) { 00133 00134 device = outputDevice; 00135 mode = PLAYBACK; 00136 channels = outputChannels; 00137 00138 if (device == 0) { // Try default device first. 00139 for (int i=0; i<nDevices; i++) { 00140 if (devices[i].probed == false) { 00141 // If the device wasn't successfully probed before, try it 00142 // again now. 00143 clearDeviceInfo(&devices[i]); 00144 probeDeviceInfo(&devices[i]); 00145 if (devices[i].probed == false) 00146 continue; 00147 } 00148 result = probeDeviceOpen(i, stream, mode, channels, sampleRate, 00149 format, bufferSize, numberOfBuffers); 00150 if (result == SUCCESS) 00151 break; 00152 } 00153 } 00154 else { 00155 result = probeDeviceOpen(device, stream, mode, channels, sampleRate, 00156 format, bufferSize, numberOfBuffers); 00157 } 00158 } 00159 00160 if ( inputChannels > 0 && result == SUCCESS ) { 00161 00162 device = inputDevice; 00163 mode = RECORD; 00164 channels = inputChannels; 00165 00166 if (device == 0) { // Try default device first. 00167 for (int i=0; i<nDevices; i++) { 00168 if (devices[i].probed == false) { 00169 // If the device wasn't successfully probed before, try it 00170 // again now. 00171 clearDeviceInfo(&devices[i]); 00172 probeDeviceInfo(&devices[i]); 00173 if (devices[i].probed == false) 00174 continue; 00175 } 00176 result = probeDeviceOpen(i, stream, mode, channels, sampleRate, 00177 format, bufferSize, numberOfBuffers); 00178 if (result == SUCCESS) 00179 break; 00180 } 00181 } 00182 else { 00183 result = probeDeviceOpen(device, stream, mode, channels, sampleRate, 00184 format, bufferSize, numberOfBuffers); 00185 } 00186 } 00187 00188 if ( result == SUCCESS ) 00189 return streamKey; 00190 00191 // If we get here, all attempted probes failed. Close any opened 00192 // devices and delete the allocated stream. 00193 closeStream(streamKey); 00194 sprintf(message,"RtAudio: no devices found for given parameters."); 00195 error(RtError::INVALID_PARAMETER); 00196 00197 return -1; 00198 } 00199 00200 int RtAudio :: getDeviceCount(void) 00201 { 00202 return nDevices; 00203 } 00204 00205 void RtAudio :: getDeviceInfo(int device, RTAUDIO_DEVICE *info) 00206 { 00207 if (device >= nDevices || device < 0) { 00208 sprintf(message, "RtAudio: invalid device specifier (%d)!", device); 00209 error(RtError::INVALID_DEVICE); 00210 } 00211 00212 // If the device wasn't successfully probed before, try it again. 00213 if (devices[device].probed == false) { 00214 clearDeviceInfo(&devices[device]); 00215 probeDeviceInfo(&devices[device]); 00216 } 00217 00218 // Clear the info structure. 00219 memset(info, 0, sizeof(RTAUDIO_DEVICE)); 00220 00221 strncpy(info->name, devices[device].name, 128); 00222 info->probed = devices[device].probed; 00223 if ( info->probed == true ) { 00224 info->maxOutputChannels = devices[device].maxOutputChannels; 00225 info->maxInputChannels = devices[device].maxInputChannels; 00226 info->maxDuplexChannels = devices[device].maxDuplexChannels; 00227 info->minOutputChannels = devices[device].minOutputChannels; 00228 info->minInputChannels = devices[device].minInputChannels; 00229 info->minDuplexChannels = devices[device].minDuplexChannels; 00230 info->hasDuplexSupport = devices[device].hasDuplexSupport; 00231 info->nSampleRates = devices[device].nSampleRates; 00232 if (info->nSampleRates == -1) { 00233 info->sampleRates[0] = devices[device].sampleRates[0]; 00234 info->sampleRates[1] = devices[device].sampleRates[1]; 00235 } 00236 else { 00237 for (int i=0; i<info->nSampleRates; i++) 00238 info->sampleRates[i] = devices[device].sampleRates[i]; 00239 } 00240 info->nativeFormats = devices[device].nativeFormats; 00241 } 00242 00243 return; 00244 } 00245 00246 char * const RtAudio :: getStreamBuffer(int streamId) 00247 { 00248 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId); 00249 00250 return stream->userBuffer; 00251 } 00252 00253 // This global structure is used to pass information to the thread 00254 // function. I tried other methods but had intermittent errors due to 00255 // variable persistence during thread startup. 00256 struct { 00257 RtAudio *object; 00258 int streamId; 00259 } thread_info; 00260 00261 extern "C" THREAD_RETURN THREAD_TYPE callbackHandler(void * ptr); 00262 00263 void RtAudio :: setStreamCallback(int streamId, RTAUDIO_CALLBACK callback, void *userData) 00264 { 00265 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId); 00266 00267 stream->callback = callback; 00268 stream->userData = userData; 00269 stream->usingCallback = true; 00270 thread_info.object = this; 00271 thread_info.streamId = streamId; 00272 00273 int err = 0; 00274 #if defined(__WINDOWS_DS__) 00275 unsigned thread_id; 00276 stream->thread = _beginthreadex(NULL, 0, &callbackHandler, 00277 &stream->usingCallback, 0, &thread_id); 00278 if (stream->thread == 0) err = -1; 00279 // When spawning multiple threads in quick succession, it appears to be 00280 // necessary to wait a bit for each to initialize ... another windism! 00281 Sleep(1); 00282 #else 00283 err = pthread_create(&stream->thread, NULL, callbackHandler, &stream->usingCallback); 00284 #endif 00285 00286 if (err) { 00287 stream->usingCallback = false; 00288 sprintf(message, "RtAudio: error starting callback thread!"); 00289 error(RtError::THREAD_ERROR); 00290 } 00291 } 00292 00293 // *************************************************** // 00294 // 00295 // OS/API-specific methods. 00296 // 00297 // *************************************************** // 00298 00299 #if defined(__LINUX_ALSA__) 00300 00301 #define MAX_DEVICES 16 00302 00303 void RtAudio :: initialize(void) 00304 { 00305 int card, result, device; 00306 char name[32]; 00307 char deviceNames[MAX_DEVICES][32]; 00308 snd_ctl_t *handle; 00309 snd_ctl_card_info_t *info; 00310 snd_ctl_card_info_alloca(&info); 00311 00312 // Count cards and devices 00313 nDevices = 0; 00314 card = -1; 00315 snd_card_next(&card); 00316 while ( card >= 0 ) { 00317 sprintf(name, "hw:%d", card); 00318 result = snd_ctl_open(&handle, name, 0); 00319 if (result < 0) { 00320 sprintf(message, "RtAudio: ALSA control open (%i): %s.", card, snd_strerror(result)); 00321 error(RtError::WARNING); 00322 goto next_card; 00323 } 00324 result = snd_ctl_card_info(handle, info); 00325 if (result < 0) { 00326 sprintf(message, "RtAudio: ALSA control hardware info (%i): %s.", card, snd_strerror(result)); 00327 error(RtError::WARNING); 00328 goto next_card; 00329 } 00330 device = -1; 00331 while (1) { 00332 result = snd_ctl_pcm_next_device(handle, &device); 00333 if (result < 0) { 00334 sprintf(message, "RtAudio: ALSA control next device (%i): %s.", card, snd_strerror(result)); 00335 error(RtError::WARNING); 00336 break; 00337 } 00338 if (device < 0) 00339 break; 00340 sprintf( deviceNames[nDevices++], "hw:%d,%d", card, device ); 00341 if ( nDevices > MAX_DEVICES ) break; 00342 } 00343 if ( nDevices > MAX_DEVICES ) break; 00344 next_card: 00345 snd_ctl_close(handle); 00346 snd_card_next(&card); 00347 } 00348 00349 if (nDevices == 0) return; 00350 00351 // Allocate the RTAUDIO_DEVICE structures. 00352 devices = (RTAUDIO_DEVICE *) calloc(nDevices, sizeof(RTAUDIO_DEVICE)); 00353 if (devices == NULL) { 00354 sprintf(message, "RtAudio: memory allocation error!"); 00355 error(RtError::MEMORY_ERROR); 00356 } 00357 00358 // Write device ascii identifiers to device structures and then 00359 // probe the device capabilities. 00360 for (int i=0; i<nDevices; i++) { 00361 strncpy(devices[i].name, deviceNames[i], 32); 00362 probeDeviceInfo(&devices[i]); 00363 } 00364 00365 return; 00366 } 00367 00368 void RtAudio :: probeDeviceInfo(RTAUDIO_DEVICE *info) 00369 { 00370 int err; 00371 int open_mode = SND_PCM_ASYNC; 00372 snd_pcm_t *handle; 00373 snd_pcm_stream_t stream; 00374 00375 // First try for playback 00376 stream = SND_PCM_STREAM_PLAYBACK; 00377 err = snd_pcm_open(&handle, info->name, stream, open_mode); 00378 if (err < 0) { 00379 sprintf(message, "RtAudio: ALSA pcm playback open (%s): %s.", 00380 info->name, snd_strerror(err)); 00381 error(RtError::WARNING); 00382 goto capture_probe; 00383 } 00384 00385 snd_pcm_hw_params_t *params; 00386 snd_pcm_hw_params_alloca(¶ms); 00387 00388 // We have an open device ... allocate the parameter structure. 00389 err = snd_pcm_hw_params_any(handle, params); 00390 if (err < 0) { 00391 snd_pcm_close(handle); 00392 sprintf(message, "RtAudio: ALSA hardware probe error (%s): %s.", 00393 info->name, snd_strerror(err)); 00394 error(RtError::WARNING); 00395 goto capture_probe; 00396 } 00397 00398 // Get output channel information. 00399 info->minOutputChannels = snd_pcm_hw_params_get_channels_min(params); 00400 info->maxOutputChannels = snd_pcm_hw_params_get_channels_max(params); 00401 00402 snd_pcm_close(handle); 00403 00404 capture_probe: 00405 // Now try for capture 00406 stream = SND_PCM_STREAM_CAPTURE; 00407 err = snd_pcm_open(&handle, info->name, stream, open_mode); 00408 if (err < 0) { 00409 sprintf(message, "RtAudio: ALSA pcm capture open (%s): %s.", 00410 info->name, snd_strerror(err)); 00411 error(RtError::WARNING); 00412 if (info->maxOutputChannels == 0) 00413 // didn't open for playback either ... device invalid 00414 return; 00415 goto probe_parameters; 00416 } 00417 00418 // We have an open capture device ... allocate the parameter structure. 00419 err = snd_pcm_hw_params_any(handle, params); 00420 if (err < 0) { 00421 snd_pcm_close(handle); 00422 sprintf(message, "RtAudio: ALSA hardware probe error (%s): %s.", 00423 info->name, snd_strerror(err)); 00424 error(RtError::WARNING); 00425 if (info->maxOutputChannels > 0) 00426 goto probe_parameters; 00427 else 00428 return; 00429 } 00430 00431 // Get input channel information. 00432 info->minInputChannels = snd_pcm_hw_params_get_channels_min(params); 00433 info->maxInputChannels = snd_pcm_hw_params_get_channels_max(params); 00434 00435 // If device opens for both playback and capture, we determine the channels. 00436 if (info->maxOutputChannels == 0 || info->maxInputChannels == 0) 00437 goto probe_parameters; 00438 00439 info->hasDuplexSupport = true; 00440 info->maxDuplexChannels = (info->maxOutputChannels > info->maxInputChannels) ? 00441 info->maxInputChannels : info->maxOutputChannels; 00442 info->minDuplexChannels = (info->minOutputChannels > info->minInputChannels) ? 00443 info->minInputChannels : info->minOutputChannels; 00444 00445 snd_pcm_close(handle); 00446 00447 probe_parameters: 00448 // At this point, we just need to figure out the supported data 00449 // formats and sample rates. We'll proceed by opening the device in 00450 // the direction with the maximum number of channels, or playback if 00451 // they are equal. This might limit our sample rate options, but so 00452 // be it. 00453 00454 if (info->maxOutputChannels >= info->maxInputChannels) 00455 stream = SND_PCM_STREAM_PLAYBACK; 00456 else 00457 stream = SND_PCM_STREAM_CAPTURE; 00458 00459 err = snd_pcm_open(&handle, info->name, stream, open_mode); 00460 if (err < 0) { 00461 sprintf(message, "RtAudio: ALSA pcm (%s) won't reopen during probe: %s.", 00462 info->name, snd_strerror(err)); 00463 error(RtError::WARNING); 00464 return; 00465 } 00466 00467 // We have an open device ... allocate the parameter structure. 00468 err = snd_pcm_hw_params_any(handle, params); 00469 if (err < 0) { 00470 snd_pcm_close(handle); 00471 sprintf(message, "RtAudio: ALSA hardware reopen probe error (%s): %s.", 00472 info->name, snd_strerror(err)); 00473 error(RtError::WARNING); 00474 return; 00475 } 00476 00477 // Test a non-standard sample rate to see if continuous rate is supported. 00478 int dir = 0; 00479 if (snd_pcm_hw_params_test_rate(handle, params, 35500, dir) == 0) { 00480 // It appears that continuous sample rate support is available. 00481 info->nSampleRates = -1; 00482 info->sampleRates[0] = snd_pcm_hw_params_get_rate_min(params, &dir); 00483 info->sampleRates[1] = snd_pcm_hw_params_get_rate_max(params, &dir); 00484 } 00485 else { 00486 // No continuous rate support ... test our discrete set of sample rate values. 00487 info->nSampleRates = 0; 00488 for (int i=0; i<MAX_SAMPLE_RATES; i++) { 00489 if (snd_pcm_hw_params_test_rate(handle, params, SAMPLE_RATES[i], dir) == 0) { 00490 info->sampleRates[info->nSampleRates] = SAMPLE_RATES[i]; 00491 info->nSampleRates++; 00492 } 00493 } 00494 if (info->nSampleRates == 0) { 00495 snd_pcm_close(handle); 00496 return; 00497 } 00498 } 00499 00500 // Probe the supported data formats ... we don't care about endian-ness just yet 00501 snd_pcm_format_t format; 00502 info->nativeFormats = 0; 00503 format = SND_PCM_FORMAT_S8; 00504 if (snd_pcm_hw_params_test_format(handle, params, format) == 0) 00505 info->nativeFormats |= RTAUDIO_SINT8; 00506 format = SND_PCM_FORMAT_S16; 00507 if (snd_pcm_hw_params_test_format(handle, params, format) == 0) 00508 info->nativeFormats |= RTAUDIO_SINT16; 00509 format = SND_PCM_FORMAT_S24; 00510 if (snd_pcm_hw_params_test_format(handle, params, format) == 0) 00511 info->nativeFormats |= RTAUDIO_SINT24; 00512 format = SND_PCM_FORMAT_S32; 00513 if (snd_pcm_hw_params_test_format(handle, params, format) == 0) 00514 info->nativeFormats |= RTAUDIO_SINT32; 00515 format = SND_PCM_FORMAT_FLOAT; 00516 if (snd_pcm_hw_params_test_format(handle, params, format) == 0) 00517 info->nativeFormats |= RTAUDIO_FLOAT32; 00518 format = SND_PCM_FORMAT_FLOAT64; 00519 if (snd_pcm_hw_params_test_format(handle, params, format) == 0) 00520 info->nativeFormats |= RTAUDIO_FLOAT64; 00521 00522 // Check that we have at least one supported format 00523 if (info->nativeFormats == 0) { 00524 snd_pcm_close(handle); 00525 sprintf(message, "RtAudio: ALSA PCM device (%s) data format not supported by RtAudio.", 00526 info->name); 00527 error(RtError::WARNING); 00528 return; 00529 } 00530 00531 // That's all ... close the device and return 00532 snd_pcm_close(handle); 00533 info->probed = true; 00534 return; 00535 } 00536 00537 bool RtAudio :: probeDeviceOpen(int device, RTAUDIO_STREAM *stream, 00538 STREAM_MODE mode, int channels, 00539 int sampleRate, RTAUDIO_FORMAT format, 00540 int *bufferSize, int numberOfBuffers) 00541 { 00542 #if defined(RTAUDIO_DEBUG) 00543 snd_output_t *out; 00544 snd_output_stdio_attach(&out, stderr, 0); 00545 #endif 00546 00547 // I'm not using the "plug" interface ... too much inconsistent behavior. 00548 const char *name = devices[device].name; 00549 00550 snd_pcm_stream_t alsa_stream; 00551 if (mode == PLAYBACK) 00552 alsa_stream = SND_PCM_STREAM_PLAYBACK; 00553 else 00554 alsa_stream = SND_PCM_STREAM_CAPTURE; 00555 00556 int err; 00557 snd_pcm_t *handle; 00558 int alsa_open_mode = SND_PCM_ASYNC; 00559 err = snd_pcm_open(&handle, name, alsa_stream, alsa_open_mode); 00560 if (err < 0) { 00561 sprintf(message,"RtAudio: ALSA pcm device (%s) won't open: %s.", 00562 name, snd_strerror(err)); 00563 error(RtError::WARNING); 00564 return FAILURE; 00565 } 00566 00567 // Fill the parameter structure. 00568 snd_pcm_hw_params_t *hw_params; 00569 snd_pcm_hw_params_alloca(&hw_params); 00570 err = snd_pcm_hw_params_any(handle, hw_params); 00571 if (err < 0) { 00572 snd_pcm_close(handle); 00573 sprintf(message, "RtAudio: ALSA error getting parameter handle (%s): %s.", 00574 name, snd_strerror(err)); 00575 error(RtError::WARNING); 00576 return FAILURE; 00577 } 00578 00579 #if defined(RTAUDIO_DEBUG) 00580 fprintf(stderr, "\nRtAudio: ALSA dump hardware params just after device open:\n\n"); 00581 snd_pcm_hw_params_dump(hw_params, out); 00582 #endif 00583 00584 // Set access ... try interleaved access first, then non-interleaved 00585 err = snd_pcm_hw_params_set_access(handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED); 00586 if (err < 0) { 00587 // No interleave support ... try non-interleave. 00588 err = snd_pcm_hw_params_set_access(handle, hw_params, SND_PCM_ACCESS_RW_NONINTERLEAVED); 00589 if (err < 0) { 00590 snd_pcm_close(handle); 00591 sprintf(message, "RtAudio: ALSA error setting access ( (%s): %s.", 00592 name, snd_strerror(err)); 00593 error(RtError::WARNING); 00594 return FAILURE; 00595 } 00596 stream->deInterleave[mode] = true; 00597 } 00598 00599 // Determine how to set the device format. 00600 stream->userFormat = format; 00601 snd_pcm_format_t device_format; 00602 00603 if (format == RTAUDIO_SINT8) 00604 device_format = SND_PCM_FORMAT_S8; 00605 else if (format == RTAUDIO_SINT16) 00606 device_format = SND_PCM_FORMAT_S16; 00607 else if (format == RTAUDIO_SINT24) 00608 device_format = SND_PCM_FORMAT_S24; 00609 else if (format == RTAUDIO_SINT32) 00610 device_format = SND_PCM_FORMAT_S32; 00611 else if (format == RTAUDIO_FLOAT32) 00612 device_format = SND_PCM_FORMAT_FLOAT; 00613 else if (format == RTAUDIO_FLOAT64) 00614 device_format = SND_PCM_FORMAT_FLOAT64; 00615 00616 if (snd_pcm_hw_params_test_format(handle, hw_params, device_format) == 0) { 00617 stream->deviceFormat[mode] = format; 00618 goto set_format; 00619 } 00620 00621 // The user requested format is not natively supported by the device. 00622 device_format = SND_PCM_FORMAT_FLOAT64; 00623 if (snd_pcm_hw_params_test_format(handle, hw_params, device_format) == 0) { 00624 stream->deviceFormat[mode] = RTAUDIO_FLOAT64; 00625 goto set_format; 00626 } 00627 00628 device_format = SND_PCM_FORMAT_FLOAT; 00629 if (snd_pcm_hw_params_test_format(handle, hw_params, device_format) == 0) { 00630 stream->deviceFormat[mode] = RTAUDIO_FLOAT32; 00631 goto set_format; 00632 } 00633 00634 device_format = SND_PCM_FORMAT_S32; 00635 if (snd_pcm_hw_params_test_format(handle, hw_params, device_format) == 0) { 00636 stream->deviceFormat[mode] = RTAUDIO_SINT32; 00637 goto set_format; 00638 } 00639 00640 device_format = SND_PCM_FORMAT_S24; 00641 if (snd_pcm_hw_params_test_format(handle, hw_params, device_format) == 0) { 00642 stream->deviceFormat[mode] = RTAUDIO_SINT24; 00643 goto set_format; 00644 } 00645 00646 device_format = SND_PCM_FORMAT_S16; 00647 if (snd_pcm_hw_params_test_format(handle, hw_params, device_format) == 0) { 00648 stream->deviceFormat[mode] = RTAUDIO_SINT16; 00649 goto set_format; 00650 } 00651 00652 device_format = SND_PCM_FORMAT_S8; 00653 if (snd_pcm_hw_params_test_format(handle, hw_params, device_format) == 0) { 00654 stream->deviceFormat[mode] = RTAUDIO_SINT8; 00655 goto set_format; 00656 } 00657 00658 // If we get here, no supported format was found. 00659 sprintf(message,"RtAudio: ALSA pcm device (%s) data format not supported by RtAudio.", name); 00660 snd_pcm_close(handle); 00661 error(RtError::WARNING); 00662 return FAILURE; 00663 00664 set_format: 00665 err = snd_pcm_hw_params_set_format(handle, hw_params, device_format); 00666 if (err < 0) { 00667 snd_pcm_close(handle); 00668 sprintf(message, "RtAudio: ALSA error setting format (%s): %s.", 00669 name, snd_strerror(err)); 00670 error(RtError::WARNING); 00671 return FAILURE; 00672 } 00673 00674 // Determine whether byte-swaping is necessary. 00675 stream->doByteSwap[mode] = false; 00676 if (device_format != SND_PCM_FORMAT_S8) { 00677 err = snd_pcm_format_cpu_endian(device_format); 00678 if (err == 0) 00679 stream->doByteSwap[mode] = true; 00680 else if (err < 0) { 00681 snd_pcm_close(handle); 00682 sprintf(message, "RtAudio: ALSA error getting format endian-ness (%s): %s.", 00683 name, snd_strerror(err)); 00684 error(RtError::WARNING); 00685 return FAILURE; 00686 } 00687 } 00688 00689 // Determine the number of channels for this device. We support a possible 00690 // minimum device channel number > than the value requested by the user. 00691 stream->nUserChannels[mode] = channels; 00692 int device_channels = snd_pcm_hw_params_get_channels_max(hw_params); 00693 if (device_channels < channels) { 00694 snd_pcm_close(handle); 00695 sprintf(message, "RtAudio: channels (%d) not supported by device (%s).", 00696 channels, name); 00697 error(RtError::WARNING); 00698 return FAILURE; 00699 } 00700 00701 device_channels = snd_pcm_hw_params_get_channels_min(hw_params); 00702 if (device_channels < channels) device_channels = channels; 00703 stream->nDeviceChannels[mode] = device_channels; 00704 00705 // Set the device channels. 00706 err = snd_pcm_hw_params_set_channels(handle, hw_params, device_channels); 00707 if (err < 0) { 00708 snd_pcm_close(handle); 00709 sprintf(message, "RtAudio: ALSA error setting channels (%d) on device (%s): %s.", 00710 device_channels, name, snd_strerror(err)); 00711 error(RtError::WARNING); 00712 return FAILURE; 00713 } 00714 00715 // Set the sample rate. 00716 err = snd_pcm_hw_params_set_rate(handle, hw_params, (unsigned int)sampleRate, 0); 00717 if (err < 0) { 00718 snd_pcm_close(handle); 00719 sprintf(message, "RtAudio: ALSA error setting sample rate (%d) on device (%s): %s.", 00720 sampleRate, name, snd_strerror(err)); 00721 error(RtError::WARNING); 00722 return FAILURE; 00723 } 00724 00725 // Set the buffer number, which in ALSA is referred to as the "period". 00726 int dir; 00727 int periods = numberOfBuffers; 00728 // Even though the hardware might allow 1 buffer, it won't work reliably. 00729 if (periods < 2) periods = 2; 00730 err = snd_pcm_hw_params_get_periods_min(hw_params, &dir); 00731 if (err > periods) periods = err; 00732 00733 err = snd_pcm_hw_params_set_periods(handle, hw_params, periods, 0); 00734 if (err < 0) { 00735 snd_pcm_close(handle); 00736 sprintf(message, "RtAudio: ALSA error setting periods (%s): %s.", 00737 name, snd_strerror(err)); 00738 error(RtError::WARNING); 00739 return FAILURE; 00740 } 00741 00742 // Set the buffer (or period) size. 00743 err = snd_pcm_hw_params_get_period_size_min(hw_params, &dir); 00744 if (err > *bufferSize) *bufferSize = err; 00745 00746 err = snd_pcm_hw_params_set_period_size(handle, hw_params, *bufferSize, 0); 00747 if (err < 0) { 00748 snd_pcm_close(handle); 00749 sprintf(message, "RtAudio: ALSA error setting period size (%s): %s.", 00750 name, snd_strerror(err)); 00751 error(RtError::WARNING); 00752 return FAILURE; 00753 } 00754 00755 stream->bufferSize = *bufferSize; 00756 00757 // Install the hardware configuration 00758 err = snd_pcm_hw_params(handle, hw_params); 00759 if (err < 0) { 00760 snd_pcm_close(handle); 00761 sprintf(message, "RtAudio: ALSA error installing hardware configuration (%s): %s.", 00762 name, snd_strerror(err)); 00763 error(RtError::WARNING); 00764 return FAILURE; 00765 } 00766 00767 #if defined(RTAUDIO_DEBUG) 00768 fprintf(stderr, "\nRtAudio: ALSA dump hardware params after installation:\n\n"); 00769 snd_pcm_hw_params_dump(hw_params, out); 00770 #endif 00771 00772 /* 00773 // Install the software configuration 00774 snd_pcm_sw_params_t *sw_params = NULL; 00775 snd_pcm_sw_params_alloca(&sw_params); 00776 snd_pcm_sw_params_current(handle, sw_params); 00777 err = snd_pcm_sw_params(handle, sw_params); 00778 if (err < 0) { 00779 snd_pcm_close(handle); 00780 sprintf(message, "RtAudio: ALSA error installing software configuration (%s): %s.", 00781 name, snd_strerror(err)); 00782 error(RtError::WARNING); 00783 return FAILURE; 00784 } 00785 */ 00786 00787 // Set handle and flags for buffer conversion 00788 stream->handle[mode] = handle; 00789 stream->doConvertBuffer[mode] = false; 00790 if (stream->userFormat != stream->deviceFormat[mode]) 00791 stream->doConvertBuffer[mode] = true; 00792 if (stream->nUserChannels[mode] < stream->nDeviceChannels[mode]) 00793 stream->doConvertBuffer[mode] = true; 00794 if (stream->nUserChannels[mode] > 1 && stream->deInterleave[mode]) 00795 stream->doConvertBuffer[mode] = true; 00796 00797 // Allocate necessary internal buffers 00798 if ( stream->nUserChannels[0] != stream->nUserChannels[1] ) { 00799 00800 long buffer_bytes; 00801 if (stream->nUserChannels[0] >= stream->nUserChannels[1]) 00802 buffer_bytes = stream->nUserChannels[0]; 00803 else 00804 buffer_bytes = stream->nUserChannels[1]; 00805 00806 buffer_bytes *= *bufferSize * formatBytes(stream->userFormat); 00807 if (stream->userBuffer) free(stream->userBuffer); 00808 stream->userBuffer = (char *) calloc(buffer_bytes, 1); 00809 if (stream->userBuffer == NULL) 00810 goto memory_error; 00811 } 00812 00813 if ( stream->doConvertBuffer[mode] ) { 00814 00815 long buffer_bytes; 00816 bool makeBuffer = true; 00817 if ( mode == PLAYBACK ) 00818 buffer_bytes = stream->nDeviceChannels[0] * formatBytes(stream->deviceFormat[0]); 00819 else { // mode == RECORD 00820 buffer_bytes = stream->nDeviceChannels[1] * formatBytes(stream->deviceFormat[1]); 00821 if ( stream->mode == PLAYBACK ) { 00822 long bytes_out = stream->nDeviceChannels[0] * formatBytes(stream->deviceFormat[0]); 00823 if ( buffer_bytes > bytes_out ) 00824 buffer_bytes = (buffer_bytes > bytes_out) ? buffer_bytes : bytes_out; 00825 else 00826 makeBuffer = false; 00827 } 00828 } 00829 00830 if ( makeBuffer ) { 00831 buffer_bytes *= *bufferSize; 00832 if (stream->deviceBuffer) free(stream->deviceBuffer); 00833 stream->deviceBuffer = (char *) calloc(buffer_bytes, 1); 00834 if (stream->deviceBuffer == NULL) 00835 goto memory_error; 00836 } 00837 } 00838 00839 stream->device[mode] = device; 00840 stream->state = STREAM_STOPPED; 00841 if ( stream->mode == PLAYBACK && mode == RECORD ) 00842 // We had already set up an output stream. 00843 stream->mode = DUPLEX; 00844 else 00845 stream->mode = mode; 00846 stream->nBuffers = periods; 00847 stream->sampleRate = sampleRate; 00848 00849 return SUCCESS; 00850 00851 memory_error: 00852 if (stream->handle[0]) { 00853 snd_pcm_close(stream->handle[0]); 00854 stream->handle[0] = 0; 00855 } 00856 if (stream->handle[1]) { 00857 snd_pcm_close(stream->handle[1]); 00858 stream->handle[1] = 0; 00859 } 00860 if (stream->userBuffer) { 00861 free(stream->userBuffer); 00862 stream->userBuffer = 0; 00863 } 00864 sprintf(message, "RtAudio: ALSA error allocating buffer memory (%s).", name); 00865 error(RtError::WARNING); 00866 return FAILURE; 00867 } 00868 00869 void RtAudio :: cancelStreamCallback(int streamId) 00870 { 00871 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId); 00872 00873 if (stream->usingCallback) { 00874 stream->usingCallback = false; 00875 pthread_cancel(stream->thread); 00876 pthread_join(stream->thread, NULL); 00877 stream->thread = 0; 00878 stream->callback = NULL; 00879 stream->userData = NULL; 00880 } 00881 } 00882 00883 void RtAudio :: closeStream(int streamId) 00884 { 00885 // We don't want an exception to be thrown here because this 00886 // function is called by our class destructor. So, do our own 00887 // streamId check. 00888 if ( streams.find( streamId ) == streams.end() ) { 00889 sprintf(message, "RtAudio: invalid stream identifier!"); 00890 error(RtError::WARNING); 00891 return; 00892 } 00893 00894 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) streams[streamId]; 00895 00896 if (stream->usingCallback) { 00897 pthread_cancel(stream->thread); 00898 pthread_join(stream->thread, NULL); 00899 } 00900 00901 if (stream->state == STREAM_RUNNING) { 00902 if (stream->mode == PLAYBACK || stream->mode == DUPLEX) 00903 snd_pcm_drop(stream->handle[0]); 00904 if (stream->mode == RECORD || stream->mode == DUPLEX) 00905 snd_pcm_drop(stream->handle[1]); 00906 } 00907 00908 pthread_mutex_destroy(&stream->mutex); 00909 00910 if (stream->handle[0]) 00911 snd_pcm_close(stream->handle[0]); 00912 00913 if (stream->handle[1]) 00914 snd_pcm_close(stream->handle[1]); 00915 00916 if (stream->userBuffer) 00917 free(stream->userBuffer); 00918 00919 if (stream->deviceBuffer) 00920 free(stream->deviceBuffer); 00921 00922 free(stream); 00923 streams.erase(streamId); 00924 } 00925 00926 void RtAudio :: startStream(int streamId) 00927 { 00928 // This method calls snd_pcm_prepare if the device isn't already in that state. 00929 00930 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId); 00931 00932 MUTEX_LOCK(&stream->mutex); 00933 00934 if (stream->state == STREAM_RUNNING) 00935 goto unlock; 00936 00937 int err; 00938 snd_pcm_state_t state; 00939 if (stream->mode == PLAYBACK || stream->mode == DUPLEX) { 00940 state = snd_pcm_state(stream->handle[0]); 00941 if (state != SND_PCM_STATE_PREPARED) { 00942 err = snd_pcm_prepare(stream->handle[0]); 00943 if (err < 0) { 00944 sprintf(message, "RtAudio: ALSA error preparing pcm device (%s): %s.", 00945 devices[stream->device[0]].name, snd_strerror(err)); 00946 MUTEX_UNLOCK(&stream->mutex); 00947 error(RtError::DRIVER_ERROR); 00948 } 00949 } 00950 } 00951 00952 if (stream->mode == RECORD || stream->mode == DUPLEX) { 00953 state = snd_pcm_state(stream->handle[1]); 00954 if (state != SND_PCM_STATE_PREPARED) { 00955 err = snd_pcm_prepare(stream->handle[1]); 00956 if (err < 0) { 00957 sprintf(message, "RtAudio: ALSA error preparing pcm device (%s): %s.", 00958 devices[stream->device[1]].name, snd_strerror(err)); 00959 MUTEX_UNLOCK(&stream->mutex); 00960 error(RtError::DRIVER_ERROR); 00961 } 00962 } 00963 } 00964 stream->state = STREAM_RUNNING; 00965 00966 unlock: 00967 MUTEX_UNLOCK(&stream->mutex); 00968 } 00969 00970 void RtAudio :: stopStream(int streamId) 00971 { 00972 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId); 00973 00974 MUTEX_LOCK(&stream->mutex); 00975 00976 if (stream->state == STREAM_STOPPED) 00977 goto unlock; 00978 00979 int err; 00980 if (stream->mode == PLAYBACK || stream->mode == DUPLEX) { 00981 err = snd_pcm_drain(stream->handle[0]); 00982 if (err < 0) { 00983 sprintf(message, "RtAudio: ALSA error draining pcm device (%s): %s.", 00984 devices[stream->device[0]].name, snd_strerror(err)); 00985 MUTEX_UNLOCK(&stream->mutex); 00986 error(RtError::DRIVER_ERROR); 00987 } 00988 } 00989 00990 if (stream->mode == RECORD || stream->mode == DUPLEX) { 00991 err = snd_pcm_drain(stream->handle[1]); 00992 if (err < 0) { 00993 sprintf(message, "RtAudio: ALSA error draining pcm device (%s): %s.", 00994 devices[stream->device[1]].name, snd_strerror(err)); 00995 MUTEX_UNLOCK(&stream->mutex); 00996 error(RtError::DRIVER_ERROR); 00997 } 00998 } 00999 stream->state = STREAM_STOPPED; 01000 01001 unlock: 01002 MUTEX_UNLOCK(&stream->mutex); 01003 } 01004 01005 void RtAudio :: abortStream(int streamId) 01006 { 01007 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId); 01008 01009 MUTEX_LOCK(&stream->mutex); 01010 01011 if (stream->state == STREAM_STOPPED) 01012 goto unlock; 01013 01014 int err; 01015 if (stream->mode == PLAYBACK || stream->mode == DUPLEX) { 01016 err = snd_pcm_drop(stream->handle[0]); 01017 if (err < 0) { 01018 sprintf(message, "RtAudio: ALSA error draining pcm device (%s): %s.", 01019 devices[stream->device[0]].name, snd_strerror(err)); 01020 MUTEX_UNLOCK(&stream->mutex); 01021 error(RtError::DRIVER_ERROR); 01022 } 01023 } 01024 01025 if (stream->mode == RECORD || stream->mode == DUPLEX) { 01026 err = snd_pcm_drop(stream->handle[1]); 01027 if (err < 0) { 01028 sprintf(message, "RtAudio: ALSA error draining pcm device (%s): %s.", 01029 devices[stream->device[1]].name, snd_strerror(err)); 01030 MUTEX_UNLOCK(&stream->mutex); 01031 error(RtError::DRIVER_ERROR); 01032 } 01033 } 01034 stream->state = STREAM_STOPPED; 01035 01036 unlock: 01037 MUTEX_UNLOCK(&stream->mutex); 01038 } 01039 01040 int RtAudio :: streamWillBlock(int streamId) 01041 { 01042 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId); 01043 01044 MUTEX_LOCK(&stream->mutex); 01045 01046 int err = 0, frames = 0; 01047 if (stream->state == STREAM_STOPPED) 01048 goto unlock; 01049 01050 if (stream->mode == PLAYBACK || stream->mode == DUPLEX) { 01051 err = snd_pcm_avail_update(stream->handle[0]); 01052 if (err < 0) { 01053 sprintf(message, "RtAudio: ALSA error getting available frames for device (%s): %s.", 01054 devices[stream->device[0]].name, snd_strerror(err)); 01055 MUTEX_UNLOCK(&stream->mutex); 01056 error(RtError::DRIVER_ERROR); 01057 } 01058 } 01059 01060 frames = err; 01061 01062 if (stream->mode == RECORD || stream->mode == DUPLEX) { 01063 err = snd_pcm_avail_update(stream->handle[1]); 01064 if (err < 0) { 01065 sprintf(message, "RtAudio: ALSA error getting available frames for device (%s): %s.", 01066 devices[stream->device[1]].name, snd_strerror(err)); 01067 MUTEX_UNLOCK(&stream->mutex); 01068 error(RtError::DRIVER_ERROR); 01069 } 01070 if (frames > err) frames = err; 01071 } 01072 01073 frames = stream->bufferSize - frames; 01074 if (frames < 0) frames = 0; 01075 01076 unlock: 01077 MUTEX_UNLOCK(&stream->mutex); 01078 return frames; 01079 } 01080 01081 void RtAudio :: tickStream(int streamId) 01082 { 01083 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId); 01084 01085 int stopStream = 0; 01086 if (stream->state == STREAM_STOPPED) { 01087 if (stream->usingCallback) usleep(50000); // sleep 50 milliseconds 01088 return; 01089 } 01090 else if (stream->usingCallback) { 01091 stopStream = stream->callback(stream->userBuffer, stream->bufferSize, stream->userData); 01092 } 01093 01094 MUTEX_LOCK(&stream->mutex); 01095 01096 // The state might change while waiting on a mutex. 01097 if (stream->state == STREAM_STOPPED) 01098 goto unlock; 01099 01100 int err; 01101 char *buffer; 01102 int channels; 01103 RTAUDIO_FORMAT format; 01104 if (stream->mode == PLAYBACK || stream->mode == DUPLEX) { 01105 01106 // Setup parameters and do buffer conversion if necessary. 01107 if (stream->doConvertBuffer[0]) { 01108 convertStreamBuffer(stream, PLAYBACK); 01109 buffer = stream->deviceBuffer; 01110 channels = stream->nDeviceChannels[0]; 01111 format = stream->deviceFormat[0]; 01112 } 01113 else { 01114 buffer = stream->userBuffer; 01115 channels = stream->nUserChannels[0]; 01116 format = stream->userFormat; 01117 } 01118 01119 // Do byte swapping if necessary. 01120 if (stream->doByteSwap[0]) 01121 byteSwapBuffer(buffer, stream->bufferSize * channels, format); 01122 01123 // Write samples to device in interleaved/non-interleaved format. 01124 if (stream->deInterleave[0]) { 01125 void *bufs[channels]; 01126 size_t offset = stream->bufferSize * formatBytes(format); 01127 for (int i=0; i<channels; i++) 01128 bufs[i] = (void *) (buffer + (i * offset)); 01129 err = snd_pcm_writen(stream->handle[0], bufs, stream->bufferSize); 01130 } 01131 else 01132 err = snd_pcm_writei(stream->handle[0], buffer, stream->bufferSize); 01133 01134 if (err < stream->bufferSize) { 01135 // Either an error or underrun occured. 01136 if (err == -EPIPE) { 01137 snd_pcm_state_t state = snd_pcm_state(stream->handle[0]); 01138 if (state == SND_PCM_STATE_XRUN) { 01139 sprintf(message, "RtAudio: ALSA underrun detected."); 01140 error(RtError::WARNING); 01141 err = snd_pcm_prepare(stream->handle[0]); 01142 if (err < 0) { 01143 sprintf(message, "RtAudio: ALSA error preparing handle after underrun: %s.", 01144 snd_strerror(err)); 01145 MUTEX_UNLOCK(&stream->mutex); 01146 error(RtError::DRIVER_ERROR); 01147 } 01148 } 01149 else { 01150 sprintf(message, "RtAudio: ALSA error, current state is %s.", 01151 snd_pcm_state_name(state)); 01152 MUTEX_UNLOCK(&stream->mutex); 01153 error(RtError::DRIVER_ERROR); 01154 } 01155 goto unlock; 01156 } 01157 else { 01158 sprintf(message, "RtAudio: ALSA audio write error for device (%s): %s.", 01159 devices[stream->device[0]].name, snd_strerror(err)); 01160 MUTEX_UNLOCK(&stream->mutex); 01161 error(RtError::DRIVER_ERROR); 01162 } 01163 } 01164 } 01165 01166 if (stream->mode == RECORD || stream->mode == DUPLEX) { 01167 01168 // Setup parameters. 01169 if (stream->doConvertBuffer[1]) { 01170 buffer = stream->deviceBuffer; 01171 channels = stream->nDeviceChannels[1]; 01172 format = stream->deviceFormat[1]; 01173 } 01174 else { 01175 buffer = stream->userBuffer; 01176 channels = stream->nUserChannels[1]; 01177 format = stream->userFormat; 01178 } 01179 01180 // Read samples from device in interleaved/non-interleaved format. 01181 if (stream->deInterleave[1]) { 01182 void *bufs[channels]; 01183 size_t offset = stream->bufferSize * formatBytes(format); 01184 for (int i=0; i<channels; i++) 01185 bufs[i] = (void *) (buffer + (i * offset)); 01186 err = snd_pcm_readn(stream->handle[1], bufs, stream->bufferSize); 01187 } 01188 else 01189 err = snd_pcm_readi(stream->handle[1], buffer, stream->bufferSize); 01190 01191 if (err < stream->bufferSize) { 01192 // Either an error or underrun occured. 01193 if (err == -EPIPE) { 01194 snd_pcm_state_t state = snd_pcm_state(stream->handle[1]); 01195 if (state == SND_PCM_STATE_XRUN) { 01196 sprintf(message, "RtAudio: ALSA overrun detected."); 01197 error(RtError::WARNING); 01198 err = snd_pcm_prepare(stream->handle[1]); 01199 if (err < 0) { 01200 sprintf(message, "RtAudio: ALSA error preparing handle after overrun: %s.", 01201 snd_strerror(err)); 01202 MUTEX_UNLOCK(&stream->mutex); 01203 error(RtError::DRIVER_ERROR); 01204 } 01205 } 01206 else { 01207 sprintf(message, "RtAudio: ALSA error, current state is %s.", 01208 snd_pcm_state_name(state)); 01209 MUTEX_UNLOCK(&stream->mutex); 01210 error(RtError::DRIVER_ERROR); 01211 } 01212 goto unlock; 01213 } 01214 else { 01215 sprintf(message, "RtAudio: ALSA audio read error for device (%s): %s.", 01216 devices[stream->device[1]].name, snd_strerror(err)); 01217 MUTEX_UNLOCK(&stream->mutex); 01218 error(RtError::DRIVER_ERROR); 01219 } 01220 } 01221 01222 // Do byte swapping if necessary. 01223 if (stream->doByteSwap[1]) 01224 byteSwapBuffer(buffer, stream->bufferSize * channels, format); 01225 01226 // Do buffer conversion if necessary. 01227 if (stream->doConvertBuffer[1]) 01228 convertStreamBuffer(stream, RECORD); 01229 } 01230 01231 unlock: 01232 MUTEX_UNLOCK(&stream->mutex); 01233 01234 if (stream->usingCallback && stopStream) 01235 this->stopStream(streamId); 01236 } 01237 01238 extern "C" void *callbackHandler(void *ptr) 01239 { 01240 RtAudio *object = thread_info.object; 01241 int stream = thread_info.streamId; 01242 bool *usingCallback = (bool *) ptr; 01243 01244 while ( *usingCallback ) { 01245 pthread_testcancel(); 01246 try { 01247 object->tickStream(stream); 01248 } 01249 catch (RtError &exception) { 01250 fprintf(stderr, "\nCallback thread error (%s) ... closing thread.\n\n", 01251 exception.getMessage()); 01252 break; 01253 } 01254 } 01255 01256 return 0; 01257 } 01258 01259 //******************** End of __LINUX_ALSA__ *********************// 01260 01261 #elif defined(__LINUX_OSS__) 01262 01263 #include <sys/stat.h> 01264 #include <sys/types.h> 01265 #include <sys/ioctl.h> 01266 #include <unistd.h> 01267 #include <fcntl.h> 01268 #include <sys/soundcard.h> 01269 #include <errno.h> 01270 #include <math.h> 01271 01272 #define DAC_NAME "/dev/dsp" 01273 #define MAX_DEVICES 16 01274 #define MAX_CHANNELS 16 01275 01276 void RtAudio :: initialize(void) 01277 { 01278 // Count cards and devices 01279 nDevices = 0; 01280 01281 // We check /dev/dsp before probing devices. /dev/dsp is supposed to 01282 // be a link to the "default" audio device, of the form /dev/dsp0, 01283 // /dev/dsp1, etc... However, I've seen one case where /dev/dsp was a 01284 // real device, so we need to check for that. Also, sometimes the 01285 // link is to /dev/dspx and other times just dspx. I'm not sure how 01286 // the latter works, but it does. 01287 char device_name[16]; 01288 struct stat dspstat; 01289 int dsplink = -1; 01290 int i = 0; 01291 if (lstat(DAC_NAME, &dspstat) == 0) { 01292 if (S_ISLNK(dspstat.st_mode)) { 01293 i = readlink(DAC_NAME, device_name, sizeof(device_name)); 01294 if (i > 0) { 01295 device_name[i] = '\0'; 01296 if (i > 8) { // check for "/dev/dspx" 01297 if (!strncmp(DAC_NAME, device_name, 8)) 01298 dsplink = atoi(&device_name[8]); 01299 } 01300 else if (i > 3) { // check for "dspx" 01301 if (!strncmp("dsp", device_name, 3)) 01302 dsplink = atoi(&device_name[3]); 01303 } 01304 } 01305 else { 01306 sprintf(message, "RtAudio: cannot read value of symbolic link %s.", DAC_NAME); 01307 error(RtError::SYSTEM_ERROR); 01308 } 01309 } 01310 } 01311 else { 01312 sprintf(message, "RtAudio: cannot stat %s.", DAC_NAME); 01313 error(RtError::SYSTEM_ERROR); 01314 } 01315 01316 // The OSS API doesn't provide a routine for determining the number 01317 // of devices. Thus, we'll just pursue a brute force method. The 01318 // idea is to start with /dev/dsp(0) and continue with higher device 01319 // numbers until we reach MAX_DSP_DEVICES. This should tell us how 01320 // many devices we have ... it is not a fullproof scheme, but hopefully 01321 // it will work most of the time. 01322 01323 int fd = 0; 01324 char names[MAX_DEVICES][16]; 01325 for (i=-1; i<MAX_DEVICES; i++) { 01326 01327 // Probe /dev/dsp first, since it is supposed to be the default device. 01328 if (i == -1) 01329 sprintf(device_name, "%s", DAC_NAME); 01330 else if (i == dsplink) 01331 continue; // We've aready probed this device via /dev/dsp link ... try next device. 01332 else 01333 sprintf(device_name, "%s%d", DAC_NAME, i); 01334 01335 // First try to open the device for playback, then record mode. 01336 fd = open(device_name, O_WRONLY | O_NONBLOCK); 01337 if (fd == -1) { 01338 // Open device for playback failed ... either busy or doesn't exist. 01339 if (errno != EBUSY && errno != EAGAIN) { 01340 // Try to open for capture 01341 fd = open(device_name, O_RDONLY | O_NONBLOCK); 01342 if (fd == -1) { 01343 // Open device for record failed. 01344 if (errno != EBUSY && errno != EAGAIN) 01345 continue; 01346 else { 01347 sprintf(message, "RtAudio: OSS record device (%s) is busy.", device_name); 01348 error(RtError::WARNING); 01349 // still count it for now 01350 } 01351 } 01352 } 01353 else { 01354 sprintf(message, "RtAudio: OSS playback device (%s) is busy.", device_name); 01355 error(RtError::WARNING); 01356 // still count it for now 01357 } 01358 } 01359 01360 if (fd >= 0) close(fd); 01361 strncpy(names[nDevices], device_name, 16); 01362 nDevices++; 01363 } 01364 01365 if (nDevices == 0) return; 01366 01367 // Allocate the RTAUDIO_DEVICE structures. 01368 devices = (RTAUDIO_DEVICE *) calloc(nDevices, sizeof(RTAUDIO_DEVICE)); 01369 if (devices == NULL) { 01370 sprintf(message, "RtAudio: memory allocation error!"); 01371 error(RtError::MEMORY_ERROR); 01372 } 01373 01374 // Write device ascii identifiers to device control structure and then probe capabilities. 01375 for (i=0; i<nDevices; i++) { 01376 strncpy(devices[i].name, names[i], 16); 01377 probeDeviceInfo(&devices[i]); 01378 } 01379 01380 return; 01381 } 01382 01383 void RtAudio :: probeDeviceInfo(RTAUDIO_DEVICE *info) 01384 { 01385 int i, fd, channels, mask; 01386 01387 // The OSS API doesn't provide a means for probing the capabilities 01388 // of devices. Thus, we'll just pursue a brute force method. 01389 01390 // First try for playback 01391 fd = open(info->name, O_WRONLY | O_NONBLOCK); 01392 if (fd == -1) { 01393 // Open device failed ... either busy or doesn't exist 01394 if (errno == EBUSY || errno == EAGAIN) 01395 sprintf(message, "RtAudio: OSS playback device (%s) is busy and cannot be probed.", 01396 info->name); 01397 else 01398 sprintf(message, "RtAudio: OSS playback device (%s) open error.", info->name); 01399 error(RtError::WARNING); 01400 goto capture_probe; 01401 } 01402 01403 // We have an open device ... see how many channels it can handle 01404 for (i=MAX_CHANNELS; i>0; i--) { 01405 channels = i; 01406 if (ioctl(fd, SNDCTL_DSP_CHANNELS, &channels) == -1) { 01407 // This would normally indicate some sort of hardware error, but under ALSA's 01408 // OSS emulation, it sometimes indicates an invalid channel value. Further, 01409 // the returned channel value is not changed. So, we'll ignore the possible 01410 // hardware error. 01411 continue; // try next channel number 01412 } 01413 // Check to see whether the device supports the requested number of channels 01414 if (channels != i ) continue; // try next channel number 01415 // If here, we found the largest working channel value 01416 break; 01417 } 01418 info->maxOutputChannels = channels; 01419 01420 // Now find the minimum number of channels it can handle 01421 for (i=1; i<=info->maxOutputChannels; i++) { 01422 channels = i; 01423 if (ioctl(fd, SNDCTL_DSP_CHANNELS, &channels) == -1 || channels != i) 01424 continue; // try next channel number 01425 // If here, we found the smallest working channel value 01426 break; 01427 } 01428 info->minOutputChannels = channels; 01429 close(fd); 01430 01431 capture_probe: 01432 // Now try for capture 01433 fd = open(info->name, O_RDONLY | O_NONBLOCK); 01434 if (fd == -1) { 01435 // Open device for capture failed ... either busy or doesn't exist 01436 if (errno == EBUSY || errno == EAGAIN) 01437 sprintf(message, "RtAudio: OSS capture device (%s) is busy and cannot be probed.", 01438 info->name); 01439 else 01440 sprintf(message, "RtAudio: OSS capture device (%s) open error.", info->name); 01441 error(RtError::WARNING); 01442 if (info->maxOutputChannels == 0) 01443 // didn't open for playback either ... device invalid 01444 return; 01445 goto probe_parameters; 01446 } 01447 01448 // We have the device open for capture ... see how many channels it can handle 01449 for (i=MAX_CHANNELS; i>0; i--) { 01450 channels = i; 01451 if (ioctl(fd, SNDCTL_DSP_CHANNELS, &channels) == -1 || channels != i) { 01452 continue; // as above 01453 } 01454 // If here, we found a working channel value 01455 break; 01456 } 01457 info->maxInputChannels = channels; 01458 01459 // Now find the minimum number of channels it can handle 01460 for (i=1; i<=info->maxInputChannels; i++) { 01461 channels = i; 01462 if (ioctl(fd, SNDCTL_DSP_CHANNELS, &channels) == -1 || channels != i) 01463 continue; // try next channel number 01464 // If here, we found the smallest working channel value 01465 break; 01466 } 01467 info->minInputChannels = channels; 01468 close(fd); 01469 01470 // If device opens for both playback and capture, we determine the channels. 01471 if (info->maxOutputChannels == 0 || info->maxInputChannels == 0) 01472 goto probe_parameters; 01473 01474 fd = open(info->name, O_RDWR | O_NONBLOCK); 01475 if (fd == -1) 01476 goto probe_parameters; 01477 01478 ioctl(fd, SNDCTL_DSP_SETDUPLEX, 0); 01479 ioctl(fd, SNDCTL_DSP_GETCAPS, &mask); 01480 if (mask & DSP_CAP_DUPLEX) { 01481 info->hasDuplexSupport = true; 01482 // We have the device open for duplex ... see how many channels it can handle 01483 for (i=MAX_CHANNELS; i>0; i--) { 01484 channels = i; 01485 if (ioctl(fd, SNDCTL_DSP_CHANNELS, &channels) == -1 || channels != i) 01486 continue; // as above 01487 // If here, we found a working channel value 01488 break; 01489 } 01490 info->maxDuplexChannels = channels; 01491 01492 // Now find the minimum number of channels it can handle 01493 for (i=1; i<=info->maxDuplexChannels; i++) { 01494 channels = i; 01495 if (ioctl(fd, SNDCTL_DSP_CHANNELS, &channels) == -1 || channels != i) 01496 continue; // try next channel number 01497 // If here, we found the smallest working channel value 01498 break; 01499 } 01500 info->minDuplexChannels = channels; 01501 } 01502 close(fd); 01503 01504 probe_parameters: 01505 // At this point, we need to figure out the supported data formats 01506 // and sample rates. We'll proceed by openning the device in the 01507 // direction with the maximum number of channels, or playback if 01508 // they are equal. This might limit our sample rate options, but so 01509 // be it. 01510 01511 if (info->maxOutputChannels >= info->maxInputChannels) { 01512 fd = open(info->name, O_WRONLY | O_NONBLOCK); 01513 channels = info->maxOutputChannels; 01514 } 01515 else { 01516 fd = open(info->name, O_RDONLY | O_NONBLOCK); 01517 channels = info->maxInputChannels; 01518 } 01519 01520 if (fd == -1) { 01521 // We've got some sort of conflict ... abort 01522 sprintf(message, "RtAudio: OSS device (%s) won't reopen during probe.", 01523 info->name); 01524 error(RtError::WARNING); 01525 return; 01526 } 01527 01528 // We have an open device ... set to maximum channels. 01529 i = channels; 01530 if (ioctl(fd, SNDCTL_DSP_CHANNELS, &channels) == -1 || channels != i) { 01531 // We've got some sort of conflict ... abort 01532 close(fd); 01533 sprintf(message, "RtAudio: OSS device (%s) won't revert to previous channel setting.", 01534 info->name); 01535 error(RtError::WARNING); 01536 return; 01537 } 01538 01539 if (ioctl(fd, SNDCTL_DSP_GETFMTS, &mask) == -1) { 01540 close(fd); 01541 sprintf(message, "RtAudio: OSS device (%s) can't get supported audio formats.", 01542 info->name); 01543 error(RtError::WARNING); 01544 return; 01545 } 01546 01547 // Probe the supported data formats ... we don't care about endian-ness just yet. 01548 int format; 01549 info->nativeFormats = 0; 01550 #if defined (AFMT_S32_BE) 01551 // This format does not seem to be in the 2.4 kernel version of OSS soundcard.h 01552 if (mask & AFMT_S32_BE) { 01553 format = AFMT_S32_BE; 01554 info->nativeFormats |= RTAUDIO_SINT32; 01555 } 01556 #endif 01557 #if defined (AFMT_S32_LE) 01558 /* This format is not in the 2.4.4 kernel version of OSS soundcard.h */ 01559 if (mask & AFMT_S32_LE) { 01560 format = AFMT_S32_LE; 01561 info->nativeFormats |= RTAUDIO_SINT32; 01562 } 01563 #endif 01564 if (mask & AFMT_S8) { 01565 format = AFMT_S8; 01566 info->nativeFormats |= RTAUDIO_SINT8; 01567 } 01568 if (mask & AFMT_S16_BE) { 01569 format = AFMT_S16_BE; 01570 info->nativeFormats |= RTAUDIO_SINT16; 01571 } 01572 if (mask & AFMT_S16_LE) { 01573 format = AFMT_S16_LE; 01574 info->nativeFormats |= RTAUDIO_SINT16; 01575 } 01576 01577 // Check that we have at least one supported format 01578 if (info->nativeFormats == 0) { 01579 close(fd); 01580 sprintf(message, "RtAudio: OSS device (%s) data format not supported by RtAudio.", 01581 info->name); 01582 error(RtError::WARNING); 01583 return; 01584 } 01585 01586 // Set the format 01587 i = format; 01588 if (ioctl(fd, SNDCTL_DSP_SETFMT, &format) == -1 || format != i) { 01589 close(fd); 01590 sprintf(message, "RtAudio: OSS device (%s) error setting data format.", 01591 info->name); 01592 error(RtError::WARNING); 01593 return; 01594 } 01595 01596 // Probe the supported sample rates ... first get lower limit 01597 int speed = 1; 01598 if (ioctl(fd, SNDCTL_DSP_SPEED, &speed) == -1) { 01599 // If we get here, we're probably using an ALSA driver with OSS-emulation, 01600 // which doesn't conform to the OSS specification. In this case, 01601 // we'll probe our predefined list of sample rates for working values. 01602 info->nSampleRates = 0; 01603 for (i=0; i<MAX_SAMPLE_RATES; i++) { 01604 speed = SAMPLE_RATES[i]; 01605 if (ioctl(fd, SNDCTL_DSP_SPEED, &speed) != -1) { 01606 info->sampleRates[info->nSampleRates] = SAMPLE_RATES[i]; 01607 info->nSampleRates++; 01608 } 01609 } 01610 if (info->nSampleRates == 0) { 01611 close(fd); 01612 return; 01613 } 01614 goto finished; 01615 } 01616 info->sampleRates[0] = speed; 01617 01618 // Now get upper limit 01619 speed = 1000000; 01620 if (ioctl(fd, SNDCTL_DSP_SPEED, &speed) == -1) { 01621 close(fd); 01622 sprintf(message, "RtAudio: OSS device (%s) error setting sample rate.", 01623 info->name); 01624 error(RtError::WARNING); 01625 return; 01626 } 01627 info->sampleRates[1] = speed; 01628 info->nSampleRates = -1; 01629 01630 finished: // That's all ... close the device and return 01631 close(fd); 01632 info->probed = true; 01633 return; 01634 } 01635 01636 bool RtAudio :: probeDeviceOpen(int device, RTAUDIO_STREAM *stream, 01637 STREAM_MODE mode, int channels, 01638 int sampleRate, RTAUDIO_FORMAT format, 01639 int *bufferSize, int numberOfBuffers) 01640 { 01641 int buffers, buffer_bytes, device_channels, device_format; 01642 int srate, temp, fd; 01643 01644 const char *name = devices[device].name; 01645 01646 if (mode == PLAYBACK) 01647 fd = open(name, O_WRONLY | O_NONBLOCK); 01648 else { // mode == RECORD 01649 if (stream->mode == PLAYBACK && stream->device[0] == device) { 01650 // We just set the same device for playback ... close and reopen for duplex (OSS only). 01651 close(stream->handle[0]); 01652 stream->handle[0] = 0; 01653 // First check that the number previously set channels is the same. 01654 if (stream->nUserChannels[0] != channels) { 01655 sprintf(message, "RtAudio: input/output channels must be equal for OSS duplex device (%s).", name); 01656 goto error; 01657 } 01658 fd = open(name, O_RDWR | O_NONBLOCK); 01659 } 01660 else 01661 fd = open(name, O_RDONLY | O_NONBLOCK); 01662 } 01663 01664 if (fd == -1) { 01665 if (errno == EBUSY || errno == EAGAIN) 01666 sprintf(message, "RtAudio: OSS device (%s) is busy and cannot be opened.", 01667 name); 01668 else 01669 sprintf(message, "RtAudio: OSS device (%s) cannot be opened.", name); 01670 goto error; 01671 } 01672 01673 // Now reopen in blocking mode. 01674 close(fd); 01675 if (mode == PLAYBACK) 01676 fd = open(name, O_WRONLY | O_SYNC); 01677 else { // mode == RECORD 01678 if (stream->mode == PLAYBACK && stream->device[0] == device) 01679 fd = open(name, O_RDWR | O_SYNC); 01680 else 01681 fd = open(name, O_RDONLY | O_SYNC); 01682 } 01683 01684 if (fd == -1) { 01685 sprintf(message, "RtAudio: OSS device (%s) cannot be opened.", name); 01686 goto error; 01687 } 01688 01689 // Get the sample format mask 01690 int mask; 01691 if (ioctl(fd, SNDCTL_DSP_GETFMTS, &mask) == -1) { 01692 close(fd); 01693 sprintf(message, "RtAudio: OSS device (%s) can't get supported audio formats.", 01694 name); 01695 goto error; 01696 } 01697 01698 // Determine how to set the device format. 01699 stream->userFormat = format; 01700 device_format = -1; 01701 stream->doByteSwap[mode] = false; 01702 if (format == RTAUDIO_SINT8) { 01703 if (mask & AFMT_S8) { 01704 device_format = AFMT_S8; 01705 stream->deviceFormat[mode] = RTAUDIO_SINT8; 01706 } 01707 } 01708 else if (format == RTAUDIO_SINT16) { 01709 if (mask & AFMT_S16_NE) { 01710 device_format = AFMT_S16_NE; 01711 stream->deviceFormat[mode] = RTAUDIO_SINT16; 01712 } 01713 #if BYTE_ORDER == LITTLE_ENDIAN 01714 else if (mask & AFMT_S16_BE) { 01715 device_format = AFMT_S16_BE; 01716 stream->deviceFormat[mode] = RTAUDIO_SINT16; 01717 stream->doByteSwap[mode] = true; 01718 } 01719 #else 01720 else if (mask & AFMT_S16_LE) { 01721 device_format = AFMT_S16_LE; 01722 stream->deviceFormat[mode] = RTAUDIO_SINT16; 01723 stream->doByteSwap[mode] = true; 01724 } 01725 #endif 01726 } 01727 #if defined (AFMT_S32_NE) && defined (AFMT_S32_LE) && defined (AFMT_S32_BE) 01728 else if (format == RTAUDIO_SINT32) { 01729 if (mask & AFMT_S32_NE) { 01730 device_format = AFMT_S32_NE; 01731 stream->deviceFormat[mode] = RTAUDIO_SINT32; 01732 } 01733 #if BYTE_ORDER == LITTLE_ENDIAN 01734 else if (mask & AFMT_S32_BE) { 01735 device_format = AFMT_S32_BE; 01736 stream->deviceFormat[mode] = RTAUDIO_SINT32; 01737 stream->doByteSwap[mode] = true; 01738 } 01739 #else 01740 else if (mask & AFMT_S32_LE) { 01741 device_format = AFMT_S32_LE; 01742 stream->deviceFormat[mode] = RTAUDIO_SINT32; 01743 stream->doByteSwap[mode] = true; 01744 } 01745 #endif 01746 } 01747 #endif 01748 01749 if (device_format == -1) { 01750 // The user requested format is not natively supported by the device. 01751 if (mask & AFMT_S16_NE) { 01752 device_format = AFMT_S16_NE; 01753 stream->deviceFormat[mode] = RTAUDIO_SINT16; 01754 } 01755 #if BYTE_ORDER == LITTLE_ENDIAN 01756 else if (mask & AFMT_S16_BE) { 01757 device_format = AFMT_S16_BE; 01758 stream->deviceFormat[mode] = RTAUDIO_SINT16; 01759 stream->doByteSwap[mode] = true; 01760 } 01761 #else 01762 else if (mask & AFMT_S16_LE) { 01763 device_format = AFMT_S16_LE; 01764 stream->deviceFormat[mode] = RTAUDIO_SINT16; 01765 stream->doByteSwap[mode] = true; 01766 } 01767 #endif 01768 #if defined (AFMT_S32_NE) && defined (AFMT_S32_LE) && defined (AFMT_S32_BE) 01769 else if (mask & AFMT_S32_NE) { 01770 device_format = AFMT_S32_NE; 01771 stream->deviceFormat[mode] = RTAUDIO_SINT32; 01772 } 01773 #if BYTE_ORDER == LITTLE_ENDIAN 01774 else if (mask & AFMT_S32_BE) { 01775 device_format = AFMT_S32_BE; 01776 stream->deviceFormat[mode] = RTAUDIO_SINT32; 01777 stream->doByteSwap[mode] = true; 01778 } 01779 #else 01780 else if (mask & AFMT_S32_LE) { 01781 device_format = AFMT_S32_LE; 01782 stream->deviceFormat[mode] = RTAUDIO_SINT32; 01783 stream->doByteSwap[mode] = true; 01784 } 01785 #endif 01786 #endif 01787 else if (mask & AFMT_S8) { 01788 device_format = AFMT_S8; 01789 stream->deviceFormat[mode] = RTAUDIO_SINT8; 01790 } 01791 } 01792 01793 if (stream->deviceFormat[mode] == 0) { 01794 // This really shouldn't happen ... 01795 close(fd); 01796 sprintf(message, "RtAudio: OSS device (%s) data format not supported by RtAudio.", 01797 name); 01798 goto error; 01799 } 01800 01801 // Determine the number of channels for this device. Note that the 01802 // channel value requested by the user might be < min_X_Channels. 01803 stream->nUserChannels[mode] = channels; 01804 device_channels = channels; 01805 if (mode == PLAYBACK) { 01806 if (channels < devices[device].minOutputChannels) 01807 device_channels = devices[device].minOutputChannels; 01808 } 01809 else { // mode == RECORD 01810 if (stream->mode == PLAYBACK && stream->device[0] == device) { 01811 // We're doing duplex setup here. 01812 if (channels < devices[device].minDuplexChannels) 01813 device_channels = devices[device].minDuplexChannels; 01814 } 01815 else { 01816 if (channels < devices[device].minInputChannels) 01817 device_channels = devices[device].minInputChannels; 01818 } 01819 } 01820 stream->nDeviceChannels[mode] = device_channels; 01821 01822 // Attempt to set the buffer size. According to OSS, the minimum 01823 // number of buffers is two. The supposed minimum buffer size is 16 01824 // bytes, so that will be our lower bound. The argument to this 01825 // call is in the form 0xMMMMSSSS (hex), where the buffer size (in 01826 // bytes) is given as 2^SSSS and the number of buffers as 2^MMMM. 01827 // We'll check the actual value used near the end of the setup 01828 // procedure. 01829 buffer_bytes = *bufferSize * formatBytes(stream->deviceFormat[mode]) * device_channels; 01830 if (buffer_bytes < 16) buffer_bytes = 16; 01831 buffers = numberOfBuffers; 01832 if (buffers < 2) buffers = 2; 01833 temp = ((int) buffers << 16) + (int)(log10((double)buffer_bytes)/log10(2.0)); 01834 if (ioctl(fd, SNDCTL_DSP_SETFRAGMENT, &temp)) { 01835 close(fd); 01836 sprintf(message, "RtAudio: OSS error setting fragment size for device (%s).", 01837 name); 01838 goto error; 01839 } 01840 stream->nBuffers = buffers; 01841 01842 // Set the data format. 01843 temp = device_format; 01844 if (ioctl(fd, SNDCTL_DSP_SETFMT, &device_format) == -1 || device_format != temp) { 01845 close(fd); 01846 sprintf(message, "RtAudio: OSS error setting data format for device (%s).", 01847 name); 01848 goto error; 01849 } 01850 01851 // Set the number of channels. 01852 temp = device_channels; 01853 if (ioctl(fd, SNDCTL_DSP_CHANNELS, &device_channels) == -1 || device_channels != temp) { 01854 close(fd); 01855 sprintf(message, "RtAudio: OSS error setting %d channels on device (%s).", 01856 temp, name); 01857 goto error; 01858 } 01859 01860 // Set the sample rate. 01861 srate = sampleRate; 01862 temp = srate; 01863 if (ioctl(fd, SNDCTL_DSP_SPEED, &srate) == -1) { 01864 close(fd); 01865 sprintf(message, "RtAudio: OSS error setting sample rate = %d on device (%s).", 01866 temp, name); 01867 goto error; 01868 } 01869 01870 // Verify the sample rate setup worked. 01871 if (abs(srate - temp) > 100) { 01872 close(fd); 01873 sprintf(message, "RtAudio: OSS error ... audio device (%s) doesn't support sample rate of %d.", 01874 name, temp); 01875 goto error; 01876 } 01877 stream->sampleRate = sampleRate; 01878 01879 if (ioctl(fd, SNDCTL_DSP_GETBLKSIZE, &buffer_bytes) == -1) { 01880 close(fd); 01881 sprintf(message, "RtAudio: OSS error getting buffer size for device (%s).", 01882 name); 01883 goto error; 01884 } 01885 01886 // Save buffer size (in sample frames). 01887 *bufferSize = buffer_bytes / (formatBytes(stream->deviceFormat[mode]) * device_channels); 01888 stream->bufferSize = *bufferSize; 01889 01890 if (mode == RECORD && stream->mode == PLAYBACK && 01891 stream->device[0] == device) { 01892 // We're doing duplex setup here. 01893 stream->deviceFormat[0] = stream->deviceFormat[1]; 01894 stream->nDeviceChannels[0] = device_channels; 01895 } 01896 01897 // Set flags for buffer conversion 01898 stream->doConvertBuffer[mode] = false; 01899 if (stream->userFormat != stream->deviceFormat[mode]) 01900 stream->doConvertBuffer[mode] = true; 01901 if (stream->nUserChannels[mode] < stream->nDeviceChannels[mode]) 01902 stream->doConvertBuffer[mode] = true; 01903 01904 // Allocate necessary internal buffers 01905 if ( stream->nUserChannels[0] != stream->nUserChannels[1] ) { 01906 01907 long buffer_bytes; 01908 if (stream->nUserChannels[0] >= stream->nUserChannels[1]) 01909 buffer_bytes = stream->nUserChannels[0]; 01910 else 01911 buffer_bytes = stream->nUserChannels[1]; 01912 01913 buffer_bytes *= *bufferSize * formatBytes(stream->userFormat); 01914 if (stream->userBuffer) free(stream->userBuffer); 01915 stream->userBuffer = (char *) calloc(buffer_bytes, 1); 01916 if (stream->userBuffer == NULL) { 01917 close(fd); 01918 sprintf(message, "RtAudio: OSS error allocating user buffer memory (%s).", 01919 name); 01920 goto error; 01921 } 01922 } 01923 01924 if ( stream->doConvertBuffer[mode] ) { 01925 01926 long buffer_bytes; 01927 bool makeBuffer = true; 01928 if ( mode == PLAYBACK ) 01929 buffer_bytes = stream->nDeviceChannels[0] * formatBytes(stream->deviceFormat[0]); 01930 else { // mode == RECORD 01931 buffer_bytes = stream->nDeviceChannels[1] * formatBytes(stream->deviceFormat[1]); 01932 if ( stream->mode == PLAYBACK ) { 01933 long bytes_out = stream->nDeviceChannels[0] * formatBytes(stream->deviceFormat[0]); 01934 if ( buffer_bytes > bytes_out ) 01935 buffer_bytes = (buffer_bytes > bytes_out) ? buffer_bytes : bytes_out; 01936 else 01937 makeBuffer = false; 01938 } 01939 } 01940 01941 if ( makeBuffer ) { 01942 buffer_bytes *= *bufferSize; 01943 if (stream->deviceBuffer) free(stream->deviceBuffer); 01944 stream->deviceBuffer = (char *) calloc(buffer_bytes, 1); 01945 if (stream->deviceBuffer == NULL) { 01946 close(fd); 01947 free(stream->userBuffer); 01948 sprintf(message, "RtAudio: OSS error allocating device buffer memory (%s).", 01949 name); 01950 goto error; 01951 } 01952 } 01953 } 01954 01955 stream->device[mode] = device; 01956 stream->handle[mode] = fd; 01957 stream->state = STREAM_STOPPED; 01958 if ( stream->mode == PLAYBACK && mode == RECORD ) { 01959 stream->mode = DUPLEX; 01960 if (stream->device[0] == device) 01961 stream->handle[0] = fd; 01962 } 01963 else 01964 stream->mode = mode; 01965 01966 return SUCCESS; 01967 01968 error: 01969 if (stream->handle[0]) { 01970 close(stream->handle[0]); 01971 stream->handle[0] = 0; 01972 } 01973 error(RtError::WARNING); 01974 return FAILURE; 01975 } 01976 01977 void RtAudio :: cancelStreamCallback(int streamId) 01978 { 01979 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId); 01980 01981 if (stream->usingCallback) { 01982 stream->usingCallback = false; 01983 pthread_cancel(stream->thread); 01984 pthread_join(stream->thread, NULL); 01985 stream->thread = 0; 01986 stream->callback = NULL; 01987 stream->userData = NULL; 01988 } 01989 } 01990 01991 void RtAudio :: closeStream(int streamId) 01992 { 01993 // We don't want an exception to be thrown here because this 01994 // function is called by our class destructor. So, do our own 01995 // streamId check. 01996 if ( streams.find( streamId ) == streams.end() ) { 01997 sprintf(message, "RtAudio: invalid stream identifier!"); 01998 error(RtError::WARNING); 01999 return; 02000 } 02001 02002 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) streams[streamId]; 02003 02004 if (stream->usingCallback) { 02005 pthread_cancel(stream->thread); 02006 pthread_join(stream->thread, NULL); 02007 } 02008 02009 if (stream->state == STREAM_RUNNING) { 02010 if (stream->mode == PLAYBACK || stream->mode == DUPLEX) 02011 ioctl(stream->handle[0], SNDCTL_DSP_RESET, 0); 02012 if (stream->mode == RECORD || stream->mode == DUPLEX) 02013 ioctl(stream->handle[1], SNDCTL_DSP_RESET, 0); 02014 } 02015 02016 pthread_mutex_destroy(&stream->mutex); 02017 02018 if (stream->handle[0]) 02019 close(stream->handle[0]); 02020 02021 if (stream->handle[1]) 02022 close(stream->handle[1]); 02023 02024 if (stream->userBuffer) 02025 free(stream->userBuffer); 02026 02027 if (stream->deviceBuffer) 02028 free(stream->deviceBuffer); 02029 02030 free(stream); 02031 streams.erase(streamId); 02032 } 02033 02034 void RtAudio :: startStream(int streamId) 02035 { 02036 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId); 02037 02038 stream->state = STREAM_RUNNING; 02039 02040 // No need to do anything else here ... OSS automatically starts when fed samples. 02041 } 02042 02043 void RtAudio :: stopStream(int streamId) 02044 { 02045 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId); 02046 02047 MUTEX_LOCK(&stream->mutex); 02048 02049 if (stream->state == STREAM_STOPPED) 02050 goto unlock; 02051 02052 int err; 02053 if (stream->mode == PLAYBACK || stream->mode == DUPLEX) { 02054 err = ioctl(stream->handle[0], SNDCTL_DSP_SYNC, 0); 02055 if (err < -1) { 02056 sprintf(message, "RtAudio: OSS error stopping device (%s).", 02057 devices[stream->device[0]].name); 02058 error(RtError::DRIVER_ERROR); 02059 } 02060 } 02061 else { 02062 err = ioctl(stream->handle[1], SNDCTL_DSP_SYNC, 0); 02063 if (err < -1) { 02064 sprintf(message, "RtAudio: OSS error stopping device (%s).", 02065 devices[stream->device[1]].name); 02066 error(RtError::DRIVER_ERROR); 02067 } 02068 } 02069 stream->state = STREAM_STOPPED; 02070 02071 unlock: 02072 MUTEX_UNLOCK(&stream->mutex); 02073 } 02074 02075 void RtAudio :: abortStream(int streamId) 02076 { 02077 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId); 02078 02079 MUTEX_LOCK(&stream->mutex); 02080 02081 if (stream->state == STREAM_STOPPED) 02082 goto unlock; 02083 02084 int err; 02085 if (stream->mode == PLAYBACK || stream->mode == DUPLEX) { 02086 err = ioctl(stream->handle[0], SNDCTL_DSP_RESET, 0); 02087 if (err < -1) { 02088 sprintf(message, "RtAudio: OSS error aborting device (%s).", 02089 devices[stream->device[0]].name); 02090 error(RtError::DRIVER_ERROR); 02091 } 02092 } 02093 else { 02094 err = ioctl(stream->handle[1], SNDCTL_DSP_RESET, 0); 02095 if (err < -1) { 02096 sprintf(message, "RtAudio: OSS error aborting device (%s).", 02097 devices[stream->device[1]].name); 02098 error(RtError::DRIVER_ERROR); 02099 } 02100 } 02101 stream->state = STREAM_STOPPED; 02102 02103 unlock: 02104 MUTEX_UNLOCK(&stream->mutex); 02105 } 02106 02107 int RtAudio :: streamWillBlock(int streamId) 02108 { 02109 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId); 02110 02111 MUTEX_LOCK(&stream->mutex); 02112 02113 int bytes = 0, channels = 0, frames = 0; 02114 if (stream->state == STREAM_STOPPED) 02115 goto unlock; 02116 02117 audio_buf_info info; 02118 if (stream->mode == PLAYBACK || stream->mode == DUPLEX) { 02119 ioctl(stream->handle[0], SNDCTL_DSP_GETOSPACE, &info); 02120 bytes = info.bytes; 02121 channels = stream->nDeviceChannels[0]; 02122 } 02123 02124 if (stream->mode == RECORD || stream->mode == DUPLEX) { 02125 ioctl(stream->handle[1], SNDCTL_DSP_GETISPACE, &info); 02126 if (stream->mode == DUPLEX ) { 02127 bytes = (bytes < info.bytes) ? bytes : info.bytes; 02128 channels = stream->nDeviceChannels[0]; 02129 } 02130 else { 02131 bytes = info.bytes; 02132 channels = stream->nDeviceChannels[1]; 02133 } 02134 } 02135 02136 frames = (int) (bytes / (channels * formatBytes(stream->deviceFormat[0]))); 02137 frames -= stream->bufferSize; 02138 if (frames < 0) frames = 0; 02139 02140 unlock: 02141 MUTEX_UNLOCK(&stream->mutex); 02142 return frames; 02143 } 02144 02145 void RtAudio :: tickStream(int streamId) 02146 { 02147 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId); 02148 02149 int stopStream = 0; 02150 if (stream->state == STREAM_STOPPED) { 02151 if (stream->usingCallback) usleep(50000); // sleep 50 milliseconds 02152 return; 02153 } 02154 else if (stream->usingCallback) { 02155 stopStream = stream->callback(stream->userBuffer, stream->bufferSize, stream->userData); 02156 } 02157 02158 MUTEX_LOCK(&stream->mutex); 02159 02160 // The state might change while waiting on a mutex. 02161 if (stream->state == STREAM_STOPPED) 02162 goto unlock; 02163 02164 int result; 02165 char *buffer; 02166 int samples; 02167 RTAUDIO_FORMAT format; 02168 if (stream->mode == PLAYBACK || stream->mode == DUPLEX) { 02169 02170 // Setup parameters and do buffer conversion if necessary. 02171 if (stream->doConvertBuffer[0]) { 02172 convertStreamBuffer(stream, PLAYBACK); 02173 buffer = stream->deviceBuffer; 02174 samples = stream->bufferSize * stream->nDeviceChannels[0]; 02175 format = stream->deviceFormat[0]; 02176 } 02177 else { 02178 buffer = stream->userBuffer; 02179 samples = stream->bufferSize * stream->nUserChannels[0]; 02180 format = stream->userFormat; 02181 } 02182 02183 // Do byte swapping if necessary. 02184 if (stream->doByteSwap[0]) 02185 byteSwapBuffer(buffer, samples, format); 02186 02187 // Write samples to device. 02188 result = write(stream->handle[0], buffer, samples * formatBytes(format)); 02189 02190 if (result == -1) { 02191 // This could be an underrun, but the basic OSS API doesn't provide a means for determining that. 02192 sprintf(message, "RtAudio: OSS audio write error for device (%s).", 02193 devices[stream->device[0]].name); 02194 error(RtError::DRIVER_ERROR); 02195 } 02196 } 02197 02198 if (stream->mode == RECORD || stream->mode == DUPLEX) { 02199 02200 // Setup parameters. 02201 if (stream->doConvertBuffer[1]) { 02202 buffer = stream->deviceBuffer; 02203 samples = stream->bufferSize * stream->nDeviceChannels[1]; 02204 format = stream->deviceFormat[1]; 02205 } 02206 else { 02207 buffer = stream->userBuffer; 02208 samples = stream->bufferSize * stream->nUserChannels[1]; 02209 format = stream->userFormat; 02210 } 02211 02212 // Read samples from device. 02213 result = read(stream->handle[1], buffer, samples * formatBytes(format)); 02214 02215 if (result == -1) { 02216 // This could be an overrun, but the basic OSS API doesn't provide a means for determining that. 02217 sprintf(message, "RtAudio: OSS audio read error for device (%s).", 02218 devices[stream->device[1]].name); 02219 error(RtError::DRIVER_ERROR); 02220 } 02221 02222 // Do byte swapping if necessary. 02223 if (stream->doByteSwap[1]) 02224 byteSwapBuffer(buffer, samples, format); 02225 02226 // Do buffer conversion if necessary. 02227 if (stream->doConvertBuffer[1]) 02228 convertStreamBuffer(stream, RECORD); 02229 } 02230 02231 unlock: 02232 MUTEX_UNLOCK(&stream->mutex); 02233 02234 if (stream->usingCallback && stopStream) 02235 this->stopStream(streamId); 02236 } 02237 02238 extern "C" void *callbackHandler(void *ptr) 02239 { 02240 RtAudio *object = thread_info.object; 02241 int stream = thread_info.streamId; 02242 bool *usingCallback = (bool *) ptr; 02243 02244 while ( *usingCallback ) { 02245 pthread_testcancel(); 02246 try { 02247 object->tickStream(stream); 02248 } 02249 catch (RtError &exception) { 02250 fprintf(stderr, "\nCallback thread error (%s) ... closing thread.\n\n", 02251 exception.getMessage()); 02252 break; 02253 } 02254 } 02255 02256 return 0; 02257 } 02258 02259 //******************** End of __LINUX_OSS__ *********************// 02260 02261 #elif defined(__WINDOWS_DS__) // Windows DirectSound API 02262 02263 #include <dsound.h> 02264 02265 // Declarations for utility functions, callbacks, and structures 02266 // specific to the DirectSound implementation. 02267 static bool CALLBACK deviceCountCallback(LPGUID lpguid, 02268 LPCSTR lpcstrDescription, 02269 LPCSTR lpcstrModule, 02270 LPVOID lpContext); 02271 02272 static bool CALLBACK deviceInfoCallback(LPGUID lpguid, 02273 LPCSTR lpcstrDescription, 02274 LPCSTR lpcstrModule, 02275 LPVOID lpContext); 02276 02277 static char* getErrorString(int code); 02278 02279 struct enum_info { 02280 char name[64]; 02281 LPGUID id; 02282 bool isInput; 02283 bool isValid; 02284 }; 02285 02286 // RtAudio methods for DirectSound implementation. 02287 void RtAudio :: initialize(void) 02288 { 02289 int i, ins = 0, outs = 0, count = 0; 02290 int index = 0; 02291 HRESULT result; 02292 nDevices = 0; 02293 02294 // Count DirectSound devices. 02295 result = DirectSoundEnumerate((LPDSENUMCALLBACK)deviceCountCallback, &outs); 02296 if ( FAILED(result) ) { 02297 sprintf(message, "RtAudio: Unable to enumerate through sound playback devices: %s.", 02298 getErrorString(result)); 02299 error(RtError::DRIVER_ERROR); 02300 } 02301 02302 // Count DirectSoundCapture devices. 02303 result = DirectSoundCaptureEnumerate((LPDSENUMCALLBACK)deviceCountCallback, &ins); 02304 if ( FAILED(result) ) { 02305 sprintf(message, "RtAudio: Unable to enumerate through sound capture devices: %s.", 02306 getErrorString(result)); 02307 error(RtError::DRIVER_ERROR); 02308 } 02309 02310 count = ins + outs; 02311 if (count == 0) return; 02312 02313 std::vector<enum_info> info(count); 02314 for (i=0; i<count; i++) { 02315 info[i].name[0] = '\0'; 02316 if (i < outs) info[i].isInput = false; 02317 else info[i].isInput = true; 02318 } 02319 02320 // Get playback device info and check capabilities. 02321 result = DirectSoundEnumerate((LPDSENUMCALLBACK)deviceInfoCallback, &info[0]); 02322 if ( FAILED(result) ) { 02323 sprintf(message, "RtAudio: Unable to enumerate through sound playback devices: %s.", 02324 getErrorString(result)); 02325 error(RtError::DRIVER_ERROR); 02326 } 02327 02328 // Get capture device info and check capabilities. 02329 result = DirectSoundCaptureEnumerate((LPDSENUMCALLBACK)deviceInfoCallback, &info[0]); 02330 if ( FAILED(result) ) { 02331 sprintf(message, "RtAudio: Unable to enumerate through sound capture devices: %s.", 02332 getErrorString(result)); 02333 error(RtError::DRIVER_ERROR); 02334 } 02335 02336 // Parse the devices and check validity. Devices are considered 02337 // invalid if they cannot be opened, they report no supported data 02338 // formats, or they report < 1 supported channels. 02339 for (i=0; i<count; i++) { 02340 if (info[i].isValid && info[i].id == NULL ) // default device 02341 nDevices++; 02342 } 02343 02344 // We group the default input and output devices together (as one 02345 // device) . 02346 if (nDevices > 0) { 02347 nDevices = 1; 02348 index = 1; 02349 } 02350 02351 // Non-default devices are listed separately. 02352 for (i=0; i<count; i++) { 02353 if (info[i].isValid && info[i].id != NULL ) 02354 nDevices++; 02355 } 02356 02357 if (nDevices == 0) return; 02358 02359 // Allocate the RTAUDIO_DEVICE structures. 02360 devices = (RTAUDIO_DEVICE *) calloc(nDevices, sizeof(RTAUDIO_DEVICE)); 02361 if (devices == NULL) { 02362 sprintf(message, "RtAudio: memory allocation error!"); 02363 error(RtError::MEMORY_ERROR); 02364 } 02365 02366 // Initialize the GUIDs to NULL for later validation. 02367 for (i=0; i<nDevices; i++) { 02368 devices[i].id[0] = NULL; 02369 devices[i].id[1] = NULL; 02370 } 02371 02372 // Rename the default device(s). 02373 if (index) 02374 strcpy(devices[0].name, "Default Input/Output Devices"); 02375 02376 // Copy the names and GUIDs to our devices structures. 02377 for (i=0; i<count; i++) { 02378 if (info[i].isValid && info[i].id != NULL ) { 02379 strncpy(devices[index].name, info[i].name, 64); 02380 if (info[i].isInput) 02381 devices[index].id[1] = info[i].id; 02382 else 02383 devices[index].id[0] = info[i].id; 02384 index++; 02385 } 02386 } 02387 02388 for (i=0;i<nDevices; i++) 02389 probeDeviceInfo(&devices[i]); 02390 02391 return; 02392 } 02393 02394 void RtAudio :: probeDeviceInfo(RTAUDIO_DEVICE *info) 02395 { 02396 HRESULT result; 02397 02398 // Get the device index so that we can check the device handle. 02399 int index; 02400 for (index=0; index<nDevices; index++) 02401 if ( info == &devices[index] ) break; 02402 02403 if ( index >= nDevices ) { 02404 sprintf(message, "RtAudio: device (%s) indexing error in DirectSound probeDeviceInfo().", 02405 info->name); 02406 error(RtError::WARNING); 02407 return; 02408 } 02409 02410 // Do capture probe first. If this is not the default device (index 02411 // = 0) _and_ GUID = NULL, then the capture handle is invalid. 02412 if ( index != 0 && info->id[1] == NULL ) 02413 goto playback_probe; 02414 02415 LPDIRECTSOUNDCAPTURE input; 02416 result = DirectSoundCaptureCreate( info->id[0], &input, NULL ); 02417 if ( FAILED(result) ) { 02418 sprintf(message, "RtAudio: Could not create DirectSound capture object (%s): %s.", 02419 info->name, getErrorString(result)); 02420 error(RtError::WARNING); 02421 goto playback_probe; 02422 } 02423 02424 DSCCAPS in_caps; 02425 in_caps.dwSize = sizeof(in_caps); 02426 result = input->GetCaps( &in_caps ); 02427 if ( FAILED(result) ) { 02428 input->Release(); 02429 sprintf(message, "RtAudio: Could not get DirectSound capture capabilities (%s): %s.", 02430 info->name, getErrorString(result)); 02431 error(RtError::WARNING); 02432 goto playback_probe; 02433 } 02434 02435 // Get input channel information. 02436 info->minInputChannels = 1; 02437 info->maxInputChannels = in_caps.dwChannels; 02438 02439 // Get sample rate and format information. 02440 if( in_caps.dwChannels == 2 ) { 02441 if( in_caps.dwFormats & WAVE_FORMAT_1S16 ) info->nativeFormats |= RTAUDIO_SINT16; 02442 if( in_caps.dwFormats & WAVE_FORMAT_2S16 ) info->nativeFormats |= RTAUDIO_SINT16; 02443 if( in_caps.dwFormats & WAVE_FORMAT_4S16 ) info->nativeFormats |= RTAUDIO_SINT16; 02444 if( in_caps.dwFormats & WAVE_FORMAT_1S08 ) info->nativeFormats |= RTAUDIO_SINT8; 02445 if( in_caps.dwFormats & WAVE_FORMAT_2S08 ) info->nativeFormats |= RTAUDIO_SINT8; 02446 if( in_caps.dwFormats & WAVE_FORMAT_4S08 ) info->nativeFormats |= RTAUDIO_SINT8; 02447 02448 if ( info->nativeFormats & RTAUDIO_SINT16 ) { 02449 if( in_caps.dwFormats & WAVE_FORMAT_1S16 ) info->sampleRates[info->nSampleRates++] = 11025; 02450 if( in_caps.dwFormats & WAVE_FORMAT_2S16 ) info->sampleRates[info->nSampleRates++] = 22050; 02451 if( in_caps.dwFormats & WAVE_FORMAT_4S16 ) info->sampleRates[info->nSampleRates++] = 44100; 02452 } 02453 else if ( info->nativeFormats & RTAUDIO_SINT8 ) { 02454 if( in_caps.dwFormats & WAVE_FORMAT_1S08 ) info->sampleRates[info->nSampleRates++] = 11025; 02455 if( in_caps.dwFormats & WAVE_FORMAT_2S08 ) info->sampleRates[info->nSampleRates++] = 22050; 02456 if( in_caps.dwFormats & WAVE_FORMAT_4S08 ) info->sampleRates[info->nSampleRates++] = 44100; 02457 } 02458 } 02459 else if ( in_caps.dwChannels == 1 ) { 02460 if( in_caps.dwFormats & WAVE_FORMAT_1M16 ) info->nativeFormats |= RTAUDIO_SINT16; 02461 if( in_caps.dwFormats & WAVE_FORMAT_2M16 ) info->nativeFormats |= RTAUDIO_SINT16; 02462 if( in_caps.dwFormats & WAVE_FORMAT_4M16 ) info->nativeFormats |= RTAUDIO_SINT16; 02463 if( in_caps.dwFormats & WAVE_FORMAT_1M08 ) info->nativeFormats |= RTAUDIO_SINT8; 02464 if( in_caps.dwFormats & WAVE_FORMAT_2M08 ) info->nativeFormats |= RTAUDIO_SINT8; 02465 if( in_caps.dwFormats & WAVE_FORMAT_4M08 ) info->nativeFormats |= RTAUDIO_SINT8; 02466 02467 if ( info->nativeFormats & RTAUDIO_SINT16 ) { 02468 if( in_caps.dwFormats & WAVE_FORMAT_1M16 ) info->sampleRates[info->nSampleRates++] = 11025; 02469 if( in_caps.dwFormats & WAVE_FORMAT_2M16 ) info->sampleRates[info->nSampleRates++] = 22050; 02470 if( in_caps.dwFormats & WAVE_FORMAT_4M16 ) info->sampleRates[info->nSampleRates++] = 44100; 02471 } 02472 else if ( info->nativeFormats & RTAUDIO_SINT8 ) { 02473 if( in_caps.dwFormats & WAVE_FORMAT_1M08 ) info->sampleRates[info->nSampleRates++] = 11025; 02474 if( in_caps.dwFormats & WAVE_FORMAT_2M08 ) info->sampleRates[info->nSampleRates++] = 22050; 02475 if( in_caps.dwFormats & WAVE_FORMAT_4M08 ) info->sampleRates[info->nSampleRates++] = 44100; 02476 } 02477 } 02478 else info->minInputChannels = 0; // technically, this would be an error 02479 02480 input->Release(); 02481 02482 playback_probe: 02483 LPDIRECTSOUND output; 02484 DSCAPS out_caps; 02485 02486 // Now do playback probe. If this is not the default device (index 02487 // = 0) _and_ GUID = NULL, then the playback handle is invalid. 02488 if ( index != 0 && info->id[0] == NULL ) 02489 goto check_parameters; 02490 02491 result = DirectSoundCreate( info->id[0], &output, NULL ); 02492 if ( FAILED(result) ) { 02493 sprintf(message, "RtAudio: Could not create DirectSound playback object (%s): %s.", 02494 info->name, getErrorString(result)); 02495 error(RtError::WARNING); 02496 goto check_parameters; 02497 } 02498 02499 out_caps.dwSize = sizeof(out_caps); 02500 result = output->GetCaps( &out_caps ); 02501 if ( FAILED(result) ) { 02502 output->Release(); 02503 sprintf(message, "RtAudio: Could not get DirectSound playback capabilities (%s): %s.", 02504 info->name, getErrorString(result)); 02505 error(RtError::WARNING); 02506 goto check_parameters; 02507 } 02508 02509 // Get output channel information. 02510 info->minOutputChannels = 1; 02511 info->maxOutputChannels = ( out_caps.dwFlags & DSCAPS_PRIMARYSTEREO ) ? 2 : 1; 02512 02513 // Get sample rate information. Use capture device rate information 02514 // if it exists. 02515 if ( info->nSampleRates == 0 ) { 02516 info->sampleRates[0] = (int) out_caps.dwMinSecondarySampleRate; 02517 info->sampleRates[1] = (int) out_caps.dwMaxSecondarySampleRate; 02518 if ( out_caps.dwFlags & DSCAPS_CONTINUOUSRATE ) 02519 info->nSampleRates = -1; 02520 else if ( out_caps.dwMinSecondarySampleRate == out_caps.dwMaxSecondarySampleRate ) { 02521 if ( out_caps.dwMinSecondarySampleRate == 0 ) { 02522 // This is a bogus driver report ... fake the range and cross 02523 // your fingers. 02524 info->sampleRates[0] = 11025; 02525 info->sampleRates[1] = 48000; 02526 info->nSampleRates = -1; /* continuous range */ 02527 sprintf(message, "RtAudio: bogus sample rates reported by DirectSound driver ... using defaults (%s).", 02528 info->name); 02529 error(RtError::WARNING); 02530 } 02531 else { 02532 info->nSampleRates = 1; 02533 } 02534 } 02535 else if ( (out_caps.dwMinSecondarySampleRate < 1000.0) && 02536 (out_caps.dwMaxSecondarySampleRate > 50000.0) ) { 02537 // This is a bogus driver report ... support for only two 02538 // distant rates. We'll assume this is a range. 02539 info->nSampleRates = -1; 02540 sprintf(message, "RtAudio: bogus sample rates reported by DirectSound driver ... using range (%s).", 02541 info->name); 02542 error(RtError::WARNING); 02543 } 02544 else info->nSampleRates = 2; 02545 } 02546 else { 02547 // Check input rates against output rate range 02548 for ( int i=info->nSampleRates-1; i>=0; i-- ) { 02549 if ( info->sampleRates[i] <= out_caps.dwMaxSecondarySampleRate ) 02550 break; 02551 info->nSampleRates--; 02552 } 02553 while ( info->sampleRates[0] < out_caps.dwMinSecondarySampleRate ) { 02554 info->nSampleRates--; 02555 for ( int i=0; i<info->nSampleRates; i++) 02556 info->sampleRates[i] = info->sampleRates[i+1]; 02557 if ( info->nSampleRates <= 0 ) break; 02558 } 02559 } 02560 02561 // Get format information. 02562 if ( out_caps.dwFlags & DSCAPS_PRIMARY16BIT ) info->nativeFormats |= RTAUDIO_SINT16; 02563 if ( out_caps.dwFlags & DSCAPS_PRIMARY8BIT ) info->nativeFormats |= RTAUDIO_SINT8; 02564 02565 output->Release(); 02566 02567 check_parameters: 02568 if ( info->maxInputChannels == 0 && info->maxOutputChannels == 0 ) 02569 return; 02570 if ( info->nSampleRates == 0 || info->nativeFormats == 0 ) 02571 return; 02572 02573 // Determine duplex status. 02574 if (info->maxInputChannels < info->maxOutputChannels) 02575 info->maxDuplexChannels = info->maxInputChannels; 02576 else 02577 info->maxDuplexChannels = info->maxOutputChannels; 02578 if (info->minInputChannels < info->minOutputChannels) 02579 info->minDuplexChannels = info->minInputChannels; 02580 else 02581 info->minDuplexChannels = info->minOutputChannels; 02582 02583 if ( info->maxDuplexChannels > 0 ) info->hasDuplexSupport = true; 02584 else info->hasDuplexSupport = false; 02585 02586 info->probed = true; 02587 02588 return; 02589 } 02590 02591 bool RtAudio :: probeDeviceOpen(int device, RTAUDIO_STREAM *stream, 02592 STREAM_MODE mode, int channels, 02593 int sampleRate, RTAUDIO_FORMAT format, 02594 int *bufferSize, int numberOfBuffers) 02595 { 02596 HRESULT result; 02597 HWND hWnd = GetForegroundWindow(); 02598 // According to a note in PortAudio, using GetDesktopWindow() 02599 // instead of GetForegroundWindow() is supposed to avoid problems 02600 // that occur when the application's window is not the foreground 02601 // window. Also, if the application window closes before the 02602 // DirectSound buffer, DirectSound can crash. However, for console 02603 // applications, no sound was produced when using GetDesktopWindow(). 02604 long buffer_size; 02605 LPVOID audioPtr; 02606 DWORD dataLen; 02607 int nBuffers; 02608 02609 // Check the numberOfBuffers parameter and limit the lowest value to 02610 // two. This is a judgement call and a value of two is probably too 02611 // low for capture, but it should work for playback. 02612 if (numberOfBuffers < 2) 02613 nBuffers = 2; 02614 else 02615 nBuffers = numberOfBuffers; 02616 02617 // Define the wave format structure (16-bit PCM, srate, channels) 02618 WAVEFORMATEX waveFormat; 02619 ZeroMemory(&waveFormat, sizeof(WAVEFORMATEX)); 02620 waveFormat.wFormatTag = WAVE_FORMAT_PCM; 02621 waveFormat.nChannels = channels; 02622 waveFormat.nSamplesPerSec = (unsigned long) sampleRate; 02623 02624 // Determine the data format. 02625 if ( devices[device].nativeFormats ) { // 8-bit and/or 16-bit support 02626 if ( format == RTAUDIO_SINT8 ) { 02627 if ( devices[device].nativeFormats & RTAUDIO_SINT8 ) 02628 waveFormat.wBitsPerSample = 8; 02629 else 02630 waveFormat.wBitsPerSample = 16; 02631 } 02632 else { 02633 if ( devices[device].nativeFormats & RTAUDIO_SINT16 ) 02634 waveFormat.wBitsPerSample = 16; 02635 else 02636 waveFormat.wBitsPerSample = 8; 02637 } 02638 } 02639 else { 02640 sprintf(message, "RtAudio: no reported data formats for DirectSound device (%s).", 02641 devices[device].name); 02642 error(RtError::WARNING); 02643 return FAILURE; 02644 } 02645 02646 waveFormat.nBlockAlign = waveFormat.nChannels * waveFormat.wBitsPerSample / 8; 02647 waveFormat.nAvgBytesPerSec = waveFormat.nSamplesPerSec * waveFormat.nBlockAlign; 02648 02649 if ( mode == PLAYBACK ) { 02650 02651 if ( devices[device].maxOutputChannels < channels ) 02652 return FAILURE; 02653 02654 LPGUID id = devices[device].id[0]; 02655 LPDIRECTSOUND object; 02656 LPDIRECTSOUNDBUFFER buffer; 02657 DSBUFFERDESC bufferDescription; 02658 02659 result = DirectSoundCreate( id, &object, NULL ); 02660 if ( FAILED(result) ) { 02661 sprintf(message, "RtAudio: Could not create DirectSound playback object (%s): %s.", 02662 devices[device].name, getErrorString(result)); 02663 error(RtError::WARNING); 02664 return FAILURE; 02665 } 02666 02667 // Set cooperative level to DSSCL_EXCLUSIVE 02668 result = object->SetCooperativeLevel(hWnd, DSSCL_EXCLUSIVE); 02669 if ( FAILED(result) ) { 02670 object->Release(); 02671 sprintf(message, "RtAudio: Unable to set DirectSound cooperative level (%s): %s.", 02672 devices[device].name, getErrorString(result)); 02673 error(RtError::WARNING); 02674 return FAILURE; 02675 } 02676 02677 // Even though we will write to the secondary buffer, we need to 02678 // access the primary buffer to set the correct output format. 02679 // The default is 8-bit, 22 kHz! 02680 // Setup the DS primary buffer description. 02681 ZeroMemory(&bufferDescription, sizeof(DSBUFFERDESC)); 02682 bufferDescription.dwSize = sizeof(DSBUFFERDESC); 02683 bufferDescription.dwFlags = DSBCAPS_PRIMARYBUFFER; 02684 // Obtain the primary buffer 02685 result = object->CreateSoundBuffer(&bufferDescription, &buffer, NULL); 02686 if ( FAILED(result) ) { 02687 object->Release(); 02688 sprintf(message, "RtAudio: Unable to access DS primary buffer (%s): %s.", 02689 devices[device].name, getErrorString(result)); 02690 error(RtError::WARNING); 02691 return FAILURE; 02692 } 02693 02694 // Set the primary DS buffer sound format. 02695 result = buffer->SetFormat(&waveFormat); 02696 if ( FAILED(result) ) { 02697 object->Release(); 02698 sprintf(message, "RtAudio: Unable to set DS primary buffer format (%s): %s.", 02699 devices[device].name, getErrorString(result)); 02700 error(RtError::WARNING); 02701 return FAILURE; 02702 } 02703 02704 // Setup the secondary DS buffer description. 02705 buffer_size = channels * *bufferSize * nBuffers * waveFormat.wBitsPerSample / 8; 02706 ZeroMemory(&bufferDescription, sizeof(DSBUFFERDESC)); 02707 bufferDescription.dwSize = sizeof(DSBUFFERDESC); 02708 bufferDescription.dwFlags = ( DSBCAPS_STICKYFOCUS | 02709 DSBCAPS_GETCURRENTPOSITION2 | 02710 DSBCAPS_LOCHARDWARE ); // Force hardware mixing 02711 bufferDescription.dwBufferBytes = buffer_size; 02712 bufferDescription.lpwfxFormat = &waveFormat; 02713 02714 // Try to create the secondary DS buffer. If that doesn't work, 02715 // try to use software mixing. Otherwise, there's a problem. 02716 result = object->CreateSoundBuffer(&bufferDescription, &buffer, NULL); 02717 if ( FAILED(result) ) { 02718 bufferDescription.dwFlags = ( DSBCAPS_STICKYFOCUS | 02719 DSBCAPS_GETCURRENTPOSITION2 | 02720 DSBCAPS_LOCSOFTWARE ); // Force software mixing 02721 result = object->CreateSoundBuffer(&bufferDescription, &buffer, NULL); 02722 if ( FAILED(result) ) { 02723 object->Release(); 02724 sprintf(message, "RtAudio: Unable to create secondary DS buffer (%s): %s.", 02725 devices[device].name, getErrorString(result)); 02726 error(RtError::WARNING); 02727 return FAILURE; 02728 } 02729 } 02730 02731 // Get the buffer size ... might be different from what we specified. 02732 DSBCAPS dsbcaps; 02733 dsbcaps.dwSize = sizeof(DSBCAPS); 02734 buffer->GetCaps(&dsbcaps); 02735 buffer_size = dsbcaps.dwBufferBytes; 02736 02737 // Lock the DS buffer 02738 result = buffer->Lock(0, buffer_size, &audioPtr, &dataLen, NULL, NULL, 0); 02739 if ( FAILED(result) ) { 02740 object->Release(); 02741 sprintf(message, "RtAudio: Unable to lock DS buffer (%s): %s.", 02742 devices[device].name, getErrorString(result)); 02743 error(RtError::WARNING); 02744 return FAILURE; 02745 } 02746 02747 // Zero the DS buffer 02748 ZeroMemory(audioPtr, dataLen); 02749 02750 // Unlock the DS buffer 02751 result = buffer->Unlock(audioPtr, dataLen, NULL, 0); 02752 if ( FAILED(result) ) { 02753 object->Release(); 02754 sprintf(message, "RtAudio: Unable to unlock DS buffer(%s): %s.", 02755 devices[device].name, getErrorString(result)); 02756 error(RtError::WARNING); 02757 return FAILURE; 02758 } 02759 02760 stream->handle[0].object = (void *) object; 02761 stream->handle[0].buffer = (void *) buffer; 02762 stream->nDeviceChannels[0] = channels; 02763 } 02764 02765 if ( mode == RECORD ) { 02766 02767 if ( devices[device].maxInputChannels < channels ) 02768 return FAILURE; 02769 02770 LPGUID id = devices[device].id[1]; 02771 LPDIRECTSOUNDCAPTURE object; 02772 LPDIRECTSOUNDCAPTUREBUFFER buffer; 02773 DSCBUFFERDESC bufferDescription; 02774 02775 result = DirectSoundCaptureCreate( id, &object, NULL ); 02776 if ( FAILED(result) ) { 02777 sprintf(message, "RtAudio: Could not create DirectSound capture object (%s): %s.", 02778 devices[device].name, getErrorString(result)); 02779 error(RtError::WARNING); 02780 return FAILURE; 02781 } 02782 02783 // Setup the secondary DS buffer description. 02784 buffer_size = channels * *bufferSize * nBuffers * waveFormat.wBitsPerSample / 8; 02785 ZeroMemory(&bufferDescription, sizeof(DSCBUFFERDESC)); 02786 bufferDescription.dwSize = sizeof(DSCBUFFERDESC); 02787 bufferDescription.dwFlags = 0; 02788 bufferDescription.dwReserved = 0; 02789 bufferDescription.dwBufferBytes = buffer_size; 02790 bufferDescription.lpwfxFormat = &waveFormat; 02791 02792 // Create the capture buffer. 02793 result = object->CreateCaptureBuffer(&bufferDescription, &buffer, NULL); 02794 if ( FAILED(result) ) { 02795 object->Release(); 02796 sprintf(message, "RtAudio: Unable to create DS capture buffer (%s): %s.", 02797 devices[device].name, getErrorString(result)); 02798 error(RtError::WARNING); 02799 return FAILURE; 02800 } 02801 02802 // Lock the capture buffer 02803 result = buffer->Lock(0, buffer_size, &audioPtr, &dataLen, NULL, NULL, 0); 02804 if ( FAILED(result) ) { 02805 object->Release(); 02806 sprintf(message, "RtAudio: Unable to lock DS capture buffer (%s): %s.", 02807 devices[device].name, getErrorString(result)); 02808 error(RtError::WARNING); 02809 return FAILURE; 02810 } 02811 02812 // Zero the buffer 02813 ZeroMemory(audioPtr, dataLen); 02814 02815 // Unlock the buffer 02816 result = buffer->Unlock(audioPtr, dataLen, NULL, 0); 02817 if ( FAILED(result) ) { 02818 object->Release(); 02819 sprintf(message, "RtAudio: Unable to unlock DS capture buffer (%s): %s.", 02820 devices[device].name, getErrorString(result)); 02821 error(RtError::WARNING); 02822 return FAILURE; 02823 } 02824 02825 stream->handle[1].object = (void *) object; 02826 stream->handle[1].buffer = (void *) buffer; 02827 stream->nDeviceChannels[1] = channels; 02828 } 02829 02830 stream->userFormat = format; 02831 if ( waveFormat.wBitsPerSample == 8 ) 02832 stream->deviceFormat[mode] = RTAUDIO_SINT8; 02833 else 02834 stream->deviceFormat[mode] = RTAUDIO_SINT16; 02835 stream->nUserChannels[mode] = channels; 02836 *bufferSize = buffer_size / (channels * nBuffers * waveFormat.wBitsPerSample / 8); 02837 stream->bufferSize = *bufferSize; 02838 02839 // Set flags for buffer conversion 02840 stream->doConvertBuffer[mode] = false; 02841 if (stream->userFormat != stream->deviceFormat[mode]) 02842 stream->doConvertBuffer[mode] = true; 02843 if (stream->nUserChannels[mode] < stream->nDeviceChannels[mode]) 02844 stream->doConvertBuffer[mode] = true; 02845 02846 // Allocate necessary internal buffers 02847 if ( stream->nUserChannels[0] != stream->nUserChannels[1] ) { 02848 02849 long buffer_bytes; 02850 if (stream->nUserChannels[0] >= stream->nUserChannels[1]) 02851 buffer_bytes = stream->nUserChannels[0]; 02852 else 02853 buffer_bytes = stream->nUserChannels[1]; 02854 02855 buffer_bytes *= *bufferSize * formatBytes(stream->userFormat); 02856 if (stream->userBuffer) free(stream->userBuffer); 02857 stream->userBuffer = (char *) calloc(buffer_bytes, 1); 02858 if (stream->userBuffer == NULL) 02859 goto memory_error; 02860 } 02861 02862 if ( stream->doConvertBuffer[mode] ) { 02863 02864 long buffer_bytes; 02865 bool makeBuffer = true; 02866 if ( mode == PLAYBACK ) 02867 buffer_bytes = stream->nDeviceChannels[0] * formatBytes(stream->deviceFormat[0]); 02868 else { // mode == RECORD 02869 buffer_bytes = stream->nDeviceChannels[1] * formatBytes(stream->deviceFormat[1]); 02870 if ( stream->mode == PLAYBACK ) { 02871 long bytes_out = stream->nDeviceChannels[0] * formatBytes(stream->deviceFormat[0]); 02872 if ( buffer_bytes > bytes_out ) 02873 buffer_bytes = (buffer_bytes > bytes_out) ? buffer_bytes : bytes_out; 02874 else 02875 makeBuffer = false; 02876 } 02877 } 02878 02879 if ( makeBuffer ) { 02880 buffer_bytes *= *bufferSize; 02881 if (stream->deviceBuffer) free(stream->deviceBuffer); 02882 stream->deviceBuffer = (char *) calloc(buffer_bytes, 1); 02883 if (stream->deviceBuffer == NULL) 02884 goto memory_error; 02885 } 02886 } 02887 02888 stream->device[mode] = device; 02889 stream->state = STREAM_STOPPED; 02890 if ( stream->mode == PLAYBACK && mode == RECORD ) 02891 // We had already set up an output stream. 02892 stream->mode = DUPLEX; 02893 else 02894 stream->mode = mode; 02895 stream->nBuffers = nBuffers; 02896 stream->sampleRate = sampleRate; 02897 02898 return SUCCESS; 02899 02900 memory_error: 02901 if (stream->handle[0].object) { 02902 LPDIRECTSOUND object = (LPDIRECTSOUND) stream->handle[0].object; 02903 LPDIRECTSOUNDBUFFER buffer = (LPDIRECTSOUNDBUFFER) stream->handle[0].buffer; 02904 if (buffer) { 02905 buffer->Release(); 02906 stream->handle[0].buffer = NULL; 02907 } 02908 object->Release(); 02909 stream->handle[0].object = NULL; 02910 } 02911 if (stream->handle[1].object) { 02912 LPDIRECTSOUNDCAPTURE object = (LPDIRECTSOUNDCAPTURE) stream->handle[1].object; 02913 LPDIRECTSOUNDCAPTUREBUFFER buffer = (LPDIRECTSOUNDCAPTUREBUFFER) stream->handle[1].buffer; 02914 if (buffer) { 02915 buffer->Release(); 02916 stream->handle[1].buffer = NULL; 02917 } 02918 object->Release(); 02919 stream->handle[1].object = NULL; 02920 } 02921 if (stream->userBuffer) { 02922 free(stream->userBuffer); 02923 stream->userBuffer = 0; 02924 } 02925 sprintf(message, "RtAudio: error allocating buffer memory (%s).", 02926 devices[device].name); 02927 error(RtError::WARNING); 02928 return FAILURE; 02929 } 02930 02931 void RtAudio :: cancelStreamCallback(int streamId) 02932 { 02933 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId); 02934 02935 if (stream->usingCallback) { 02936 stream->usingCallback = false; 02937 WaitForSingleObject( (HANDLE)stream->thread, INFINITE ); 02938 CloseHandle( (HANDLE)stream->thread ); 02939 stream->thread = 0; 02940 stream->callback = NULL; 02941 stream->userData = NULL; 02942 } 02943 } 02944 02945 void RtAudio :: closeStream(int streamId) 02946 { 02947 // We don't want an exception to be thrown here because this 02948 // function is called by our class destructor. So, do our own 02949 // streamId check. 02950 if ( streams.find( streamId ) == streams.end() ) { 02951 sprintf(message, "RtAudio: invalid stream identifier!"); 02952 error(RtError::WARNING); 02953 return; 02954 } 02955 02956 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) streams[streamId]; 02957 02958 if (stream->usingCallback) { 02959 stream->usingCallback = false; 02960 WaitForSingleObject( (HANDLE)stream->thread, INFINITE ); 02961 CloseHandle( (HANDLE)stream->thread ); 02962 } 02963 02964 DeleteCriticalSection(&stream->mutex); 02965 02966 if (stream->handle[0].object) { 02967 LPDIRECTSOUND object = (LPDIRECTSOUND) stream->handle[0].object; 02968 LPDIRECTSOUNDBUFFER buffer = (LPDIRECTSOUNDBUFFER) stream->handle[0].buffer; 02969 if (buffer) { 02970 buffer->Stop(); 02971 buffer->Release(); 02972 } 02973 object->Release(); 02974 } 02975 02976 if (stream->handle[1].object) { 02977 LPDIRECTSOUNDCAPTURE object = (LPDIRECTSOUNDCAPTURE) stream->handle[1].object; 02978 LPDIRECTSOUNDCAPTUREBUFFER buffer = (LPDIRECTSOUNDCAPTUREBUFFER) stream->handle[1].buffer; 02979 if (buffer) { 02980 buffer->Stop(); 02981 buffer->Release(); 02982 } 02983 object->Release(); 02984 } 02985 02986 if (stream->userBuffer) 02987 free(stream->userBuffer); 02988 02989 if (stream->deviceBuffer) 02990 free(stream->deviceBuffer); 02991 02992 free(stream); 02993 streams.erase(streamId); 02994 } 02995 02996 void RtAudio :: startStream(int streamId) 02997 { 02998 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId); 02999 03000 MUTEX_LOCK(&stream->mutex); 03001 03002 if (stream->state == STREAM_RUNNING) 03003 goto unlock; 03004 03005 HRESULT result; 03006 if (stream->mode == PLAYBACK || stream->mode == DUPLEX) { 03007 LPDIRECTSOUNDBUFFER buffer = (LPDIRECTSOUNDBUFFER) stream->handle[0].buffer; 03008 result = buffer->Play(0, 0, DSBPLAY_LOOPING ); 03009 if ( FAILED(result) ) { 03010 sprintf(message, "RtAudio: Unable to start DS buffer (%s): %s.", 03011 devices[stream->device[0]].name, getErrorString(result)); 03012 error(RtError::DRIVER_ERROR); 03013 } 03014 } 03015 03016 if (stream->mode == RECORD || stream->mode == DUPLEX) { 03017 LPDIRECTSOUNDCAPTUREBUFFER buffer = (LPDIRECTSOUNDCAPTUREBUFFER) stream->handle[1].buffer; 03018 result = buffer->Start(DSCBSTART_LOOPING ); 03019 if ( FAILED(result) ) { 03020 sprintf(message, "RtAudio: Unable to start DS capture buffer (%s): %s.", 03021 devices[stream->device[1]].name, getErrorString(result)); 03022 error(RtError::DRIVER_ERROR); 03023 } 03024 } 03025 stream->state = STREAM_RUNNING; 03026 03027 unlock: 03028 MUTEX_UNLOCK(&stream->mutex); 03029 } 03030 03031 void RtAudio :: stopStream(int streamId) 03032 { 03033 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId); 03034 03035 MUTEX_LOCK(&stream->mutex); 03036 03037 if (stream->state == STREAM_STOPPED) { 03038 MUTEX_UNLOCK(&stream->mutex); 03039 return; 03040 } 03041 03042 // There is no specific DirectSound API call to "drain" a buffer 03043 // before stopping. We can hack this for playback by writing zeroes 03044 // for another bufferSize * nBuffers frames. For capture, the 03045 // concept is less clear so we'll repeat what we do in the 03046 // abortStream() case. 03047 HRESULT result; 03048 DWORD dsBufferSize; 03049 LPVOID buffer1 = NULL; 03050 LPVOID buffer2 = NULL; 03051 DWORD bufferSize1 = 0; 03052 DWORD bufferSize2 = 0; 03053 if (stream->mode == PLAYBACK || stream->mode == DUPLEX) { 03054 03055 DWORD currentPos, safePos; 03056 long buffer_bytes = stream->bufferSize * stream->nDeviceChannels[0]; 03057 buffer_bytes *= formatBytes(stream->deviceFormat[0]); 03058 03059 LPDIRECTSOUNDBUFFER dsBuffer = (LPDIRECTSOUNDBUFFER) stream->handle[0].buffer; 03060 UINT nextWritePos = stream->handle[0].bufferPointer; 03061 dsBufferSize = buffer_bytes * stream->nBuffers; 03062 03063 // Write zeroes for nBuffer counts. 03064 for (int i=0; i<stream->nBuffers; i++) { 03065 03066 // Find out where the read and "safe write" pointers are. 03067 result = dsBuffer->GetCurrentPosition(¤tPos, &safePos); 03068 if ( FAILED(result) ) { 03069 sprintf(message, "RtAudio: Unable to get current DS position (%s): %s.", 03070 devices[stream->device[0]].name, getErrorString(result)); 03071 error(RtError::DRIVER_ERROR); 03072 } 03073 03074 if ( currentPos < nextWritePos ) currentPos += dsBufferSize; // unwrap offset 03075 DWORD endWrite = nextWritePos + buffer_bytes; 03076 03077 // Check whether the entire write region is behind the play pointer. 03078 while ( currentPos < endWrite ) { 03079 float millis = (endWrite - currentPos) * 900.0; 03080 millis /= ( formatBytes(stream->deviceFormat[0]) * stream->sampleRate); 03081 if ( millis < 1.0 ) millis = 1.0; 03082 Sleep( (DWORD) millis ); 03083 03084 // Wake up, find out where we are now 03085 result = dsBuffer->GetCurrentPosition( ¤tPos, &safePos ); 03086 if ( FAILED(result) ) { 03087 sprintf(message, "RtAudio: Unable to get current DS position (%s): %s.", 03088 devices[stream->device[0]].name, getErrorString(result)); 03089 error(RtError::DRIVER_ERROR); 03090 } 03091 if ( currentPos < nextWritePos ) currentPos += dsBufferSize; // unwrap offset 03092 } 03093 03094 // Lock free space in the buffer 03095 result = dsBuffer->Lock (nextWritePos, buffer_bytes, &buffer1, 03096 &bufferSize1, &buffer2, &bufferSize2, 0); 03097 if ( FAILED(result) ) { 03098 sprintf(message, "RtAudio: Unable to lock DS buffer during playback (%s): %s.", 03099 devices[stream->device[0]].name, getErrorString(result)); 03100 error(RtError::DRIVER_ERROR); 03101 } 03102 03103 // Zero the free space 03104 ZeroMemory(buffer1, bufferSize1); 03105 if (buffer2 != NULL) ZeroMemory(buffer2, bufferSize2); 03106 03107 // Update our buffer offset and unlock sound buffer 03108 dsBuffer->Unlock (buffer1, bufferSize1, buffer2, bufferSize2); 03109 if ( FAILED(result) ) { 03110 sprintf(message, "RtAudio: Unable to unlock DS buffer during playback (%s): %s.", 03111 devices[stream->device[0]].name, getErrorString(result)); 03112 error(RtError::DRIVER_ERROR); 03113 } 03114 nextWritePos = (nextWritePos + bufferSize1 + bufferSize2) % dsBufferSize; 03115 stream->handle[0].bufferPointer = nextWritePos; 03116 } 03117 03118 // If we play again, start at the beginning of the buffer. 03119 stream->handle[0].bufferPointer = 0; 03120 } 03121 03122 if (stream->mode == RECORD || stream->mode == DUPLEX) { 03123 LPDIRECTSOUNDCAPTUREBUFFER buffer = (LPDIRECTSOUNDCAPTUREBUFFER) stream->handle[1].buffer; 03124 buffer1 = NULL; 03125 bufferSize1 = 0; 03126 03127 result = buffer->Stop(); 03128 if ( FAILED(result) ) { 03129 sprintf(message, "RtAudio: Unable to stop DS capture buffer (%s): %s", 03130 devices[stream->device[1]].name, getErrorString(result)); 03131 error(RtError::DRIVER_ERROR); 03132 } 03133 03134 dsBufferSize = stream->bufferSize * stream->nDeviceChannels[1]; 03135 dsBufferSize *= formatBytes(stream->deviceFormat[1]) * stream->nBuffers; 03136 03137 // Lock the buffer and clear it so that if we start to play again, 03138 // we won't have old data playing. 03139 result = buffer->Lock(0, dsBufferSize, &buffer1, &bufferSize1, NULL, NULL, 0); 03140 if ( FAILED(result) ) { 03141 sprintf(message, "RtAudio: Unable to lock DS capture buffer (%s): %s.", 03142 devices[stream->device[1]].name, getErrorString(result)); 03143 error(RtError::DRIVER_ERROR); 03144 } 03145 03146 // Zero the DS buffer 03147 ZeroMemory(buffer1, bufferSize1); 03148 03149 // Unlock the DS buffer 03150 result = buffer->Unlock(buffer1, bufferSize1, NULL, 0); 03151 if ( FAILED(result) ) { 03152 sprintf(message, "RtAudio: Unable to unlock DS capture buffer (%s): %s.", 03153 devices[stream->device[1]].name, getErrorString(result)); 03154 error(RtError::DRIVER_ERROR); 03155 } 03156 03157 // If we start recording again, we must begin at beginning of buffer. 03158 stream->handle[1].bufferPointer = 0; 03159 } 03160 stream->state = STREAM_STOPPED; 03161 03162 MUTEX_UNLOCK(&stream->mutex); 03163 } 03164 03165 void RtAudio :: abortStream(int streamId) 03166 { 03167 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId); 03168 03169 MUTEX_LOCK(&stream->mutex); 03170 03171 if (stream->state == STREAM_STOPPED) 03172 goto unlock; 03173 03174 HRESULT result; 03175 long dsBufferSize; 03176 LPVOID audioPtr; 03177 DWORD dataLen; 03178 if (stream->mode == PLAYBACK || stream->mode == DUPLEX) { 03179 LPDIRECTSOUNDBUFFER buffer = (LPDIRECTSOUNDBUFFER) stream->handle[0].buffer; 03180 result = buffer->Stop(); 03181 if ( FAILED(result) ) { 03182 sprintf(message, "RtAudio: Unable to stop DS buffer (%s): %s", 03183 devices[stream->device[0]].name, getErrorString(result)); 03184 error(RtError::DRIVER_ERROR); 03185 } 03186 03187 dsBufferSize = stream->bufferSize * stream->nDeviceChannels[0]; 03188 dsBufferSize *= formatBytes(stream->deviceFormat[0]) * stream->nBuffers; 03189 03190 // Lock the buffer and clear it so that if we start to play again, 03191 // we won't have old data playing. 03192 result = buffer->Lock(0, dsBufferSize, &audioPtr, &dataLen, NULL, NULL, 0); 03193 if ( FAILED(result) ) { 03194 sprintf(message, "RtAudio: Unable to lock DS buffer (%s): %s.", 03195 devices[stream->device[0]].name, getErrorString(result)); 03196 error(RtError::DRIVER_ERROR); 03197 } 03198 03199 // Zero the DS buffer 03200 ZeroMemory(audioPtr, dataLen); 03201 03202 // Unlock the DS buffer 03203 result = buffer->Unlock(audioPtr, dataLen, NULL, 0); 03204 if ( FAILED(result) ) { 03205 sprintf(message, "RtAudio: Unable to unlock DS buffer (%s): %s.", 03206 devices[stream->device[0]].name, getErrorString(result)); 03207 error(RtError::DRIVER_ERROR); 03208 } 03209 03210 // If we start playing again, we must begin at beginning of buffer. 03211 stream->handle[0].bufferPointer = 0; 03212 } 03213 03214 if (stream->mode == RECORD || stream->mode == DUPLEX) { 03215 LPDIRECTSOUNDCAPTUREBUFFER buffer = (LPDIRECTSOUNDCAPTUREBUFFER) stream->handle[1].buffer; 03216 audioPtr = NULL; 03217 dataLen = 0; 03218 03219 result = buffer->Stop(); 03220 if ( FAILED(result) ) { 03221 sprintf(message, "RtAudio: Unable to stop DS capture buffer (%s): %s", 03222 devices[stream->device[1]].name, getErrorString(result)); 03223 error(RtError::DRIVER_ERROR); 03224 } 03225 03226 dsBufferSize = stream->bufferSize * stream->nDeviceChannels[1]; 03227 dsBufferSize *= formatBytes(stream->deviceFormat[1]) * stream->nBuffers; 03228 03229 // Lock the buffer and clear it so that if we start to play again, 03230 // we won't have old data playing. 03231 result = buffer->Lock(0, dsBufferSize, &audioPtr, &dataLen, NULL, NULL, 0); 03232 if ( FAILED(result) ) { 03233 sprintf(message, "RtAudio: Unable to lock DS capture buffer (%s): %s.", 03234 devices[stream->device[1]].name, getErrorString(result)); 03235 error(RtError::DRIVER_ERROR); 03236 } 03237 03238 // Zero the DS buffer 03239 ZeroMemory(audioPtr, dataLen); 03240 03241 // Unlock the DS buffer 03242 result = buffer->Unlock(audioPtr, dataLen, NULL, 0); 03243 if ( FAILED(result) ) { 03244 sprintf(message, "RtAudio: Unable to unlock DS capture buffer (%s): %s.", 03245 devices[stream->device[1]].name, getErrorString(result)); 03246 error(RtError::DRIVER_ERROR); 03247 } 03248 03249 // If we start recording again, we must begin at beginning of buffer. 03250 stream->handle[1].bufferPointer = 0; 03251 } 03252 stream->state = STREAM_STOPPED; 03253 03254 unlock: 03255 MUTEX_UNLOCK(&stream->mutex); 03256 } 03257 03258 int RtAudio :: streamWillBlock(int streamId) 03259 { 03260 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId); 03261 03262 MUTEX_LOCK(&stream->mutex); 03263 03264 int channels; 03265 int frames = 0; 03266 if (stream->state == STREAM_STOPPED) 03267 goto unlock; 03268 03269 HRESULT result; 03270 DWORD currentPos, safePos; 03271 channels = 1; 03272 if (stream->mode == PLAYBACK || stream->mode == DUPLEX) { 03273 03274 LPDIRECTSOUNDBUFFER dsBuffer = (LPDIRECTSOUNDBUFFER) stream->handle[0].buffer; 03275 UINT nextWritePos = stream->handle[0].bufferPointer; 03276 channels = stream->nDeviceChannels[0]; 03277 DWORD dsBufferSize = stream->bufferSize * channels; 03278 dsBufferSize *= formatBytes(stream->deviceFormat[0]) * stream->nBuffers; 03279 03280 // Find out where the read and "safe write" pointers are. 03281 result = dsBuffer->GetCurrentPosition(¤tPos, &safePos); 03282 if ( FAILED(result) ) { 03283 sprintf(message, "RtAudio: Unable to get current DS position (%s): %s.", 03284 devices[stream->device[0]].name, getErrorString(result)); 03285 error(RtError::DRIVER_ERROR); 03286 } 03287 03288 if ( currentPos < nextWritePos ) currentPos += dsBufferSize; // unwrap offset 03289 frames = currentPos - nextWritePos; 03290 frames /= channels * formatBytes(stream->deviceFormat[0]); 03291 } 03292 03293 if (stream->mode == RECORD || stream->mode == DUPLEX) { 03294 03295 LPDIRECTSOUNDCAPTUREBUFFER dsBuffer = (LPDIRECTSOUNDCAPTUREBUFFER) stream->handle[1].buffer; 03296 UINT nextReadPos = stream->handle[1].bufferPointer; 03297 channels = stream->nDeviceChannels[1]; 03298 DWORD dsBufferSize = stream->bufferSize * channels; 03299 dsBufferSize *= formatBytes(stream->deviceFormat[1]) * stream->nBuffers; 03300 03301 // Find out where the write and "safe read" pointers are. 03302 result = dsBuffer->GetCurrentPosition(¤tPos, &safePos); 03303 if ( FAILED(result) ) { 03304 sprintf(message, "RtAudio: Unable to get current DS capture position (%s): %s.", 03305 devices[stream->device[1]].name, getErrorString(result)); 03306 error(RtError::DRIVER_ERROR); 03307 } 03308 03309 if ( safePos < nextReadPos ) safePos += dsBufferSize; // unwrap offset 03310 03311 if (stream->mode == DUPLEX ) { 03312 // Take largest value of the two. 03313 int temp = safePos - nextReadPos; 03314 temp /= channels * formatBytes(stream->deviceFormat[1]); 03315 frames = ( temp > frames ) ? temp : frames; 03316 } 03317 else { 03318 frames = safePos - nextReadPos; 03319 frames /= channels * formatBytes(stream->deviceFormat[1]); 03320 } 03321 } 03322 03323 frames = stream->bufferSize - frames; 03324 if (frames < 0) frames = 0; 03325 03326 unlock: 03327 MUTEX_UNLOCK(&stream->mutex); 03328 return frames; 03329 } 03330 03331 void RtAudio :: tickStream(int streamId) 03332 { 03333 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId); 03334 03335 int stopStream = 0; 03336 if (stream->state == STREAM_STOPPED) { 03337 if (stream->usingCallback) Sleep(50); // sleep 50 milliseconds 03338 return; 03339 } 03340 else if (stream->usingCallback) { 03341 stopStream = stream->callback(stream->userBuffer, stream->bufferSize, stream->userData); 03342 } 03343 03344 MUTEX_LOCK(&stream->mutex); 03345 03346 // The state might change while waiting on a mutex. 03347 if (stream->state == STREAM_STOPPED) { 03348 MUTEX_UNLOCK(&stream->mutex); 03349 if (stream->usingCallback && stopStream) 03350 this->stopStream(streamId); 03351 } 03352 03353 HRESULT result; 03354 DWORD currentPos, safePos; 03355 LPVOID buffer1 = NULL; 03356 LPVOID buffer2 = NULL; 03357 DWORD bufferSize1 = 0; 03358 DWORD bufferSize2 = 0; 03359 char *buffer; 03360 long buffer_bytes; 03361 if (stream->mode == PLAYBACK || stream->mode == DUPLEX) { 03362 03363 // Setup parameters and do buffer conversion if necessary. 03364 if (stream->doConvertBuffer[0]) { 03365 convertStreamBuffer(stream, PLAYBACK); 03366 buffer = stream->deviceBuffer; 03367 buffer_bytes = stream->bufferSize * stream->nDeviceChannels[0]; 03368 buffer_bytes *= formatBytes(stream->deviceFormat[0]); 03369 } 03370 else { 03371 buffer = stream->userBuffer; 03372 buffer_bytes = stream->bufferSize * stream->nUserChannels[0]; 03373 buffer_bytes *= formatBytes(stream->userFormat); 03374 } 03375 03376 // No byte swapping necessary in DirectSound implementation. 03377 03378 LPDIRECTSOUNDBUFFER dsBuffer = (LPDIRECTSOUNDBUFFER) stream->handle[0].buffer; 03379 UINT nextWritePos = stream->handle[0].bufferPointer; 03380 DWORD dsBufferSize = buffer_bytes * stream->nBuffers; 03381 03382 // Find out where the read and "safe write" pointers are. 03383 result = dsBuffer->GetCurrentPosition(¤tPos, &safePos); 03384 if ( FAILED(result) ) { 03385 sprintf(message, "RtAudio: Unable to get current DS position (%s): %s.", 03386 devices[stream->device[0]].name, getErrorString(result)); 03387 error(RtError::DRIVER_ERROR); 03388 } 03389 03390 if ( currentPos < nextWritePos ) currentPos += dsBufferSize; // unwrap offset 03391 DWORD endWrite = nextWritePos + buffer_bytes; 03392 03393 // Check whether the entire write region is behind the play pointer. 03394 while ( currentPos < endWrite ) { 03395 // If we are here, then we must wait until the play pointer gets 03396 // beyond the write region. The approach here is to use the 03397 // Sleep() function to suspend operation until safePos catches 03398 // up. Calculate number of milliseconds to wait as: 03399 // time = distance * (milliseconds/second) * fudgefactor / 03400 // ((bytes/sample) * (samples/second)) 03401 // A "fudgefactor" less than 1 is used because it was found 03402 // that sleeping too long was MUCH worse than sleeping for 03403 // several shorter periods. 03404 float millis = (endWrite - currentPos) * 900.0; 03405 millis /= ( formatBytes(stream->deviceFormat[0]) * stream->sampleRate); 03406 if ( millis < 1.0 ) millis = 1.0; 03407 Sleep( (DWORD) millis ); 03408 03409 // Wake up, find out where we are now 03410 result = dsBuffer->GetCurrentPosition( ¤tPos, &safePos ); 03411 if ( FAILED(result) ) { 03412 sprintf(message, "RtAudio: Unable to get current DS position (%s): %s.", 03413 devices[stream->device[0]].name, getErrorString(result)); 03414 error(RtError::DRIVER_ERROR); 03415 } 03416 if ( currentPos < nextWritePos ) currentPos += dsBufferSize; // unwrap offset 03417 } 03418 03419 // Lock free space in the buffer 03420 result = dsBuffer->Lock (nextWritePos, buffer_bytes, &buffer1, 03421 &bufferSize1, &buffer2, &bufferSize2, 0); 03422 if ( FAILED(result) ) { 03423 sprintf(message, "RtAudio: Unable to lock DS buffer during playback (%s): %s.", 03424 devices[stream->device[0]].name, getErrorString(result)); 03425 error(RtError::DRIVER_ERROR); 03426 } 03427 03428 // Copy our buffer into the DS buffer 03429 CopyMemory(buffer1, buffer, bufferSize1); 03430 if (buffer2 != NULL) CopyMemory(buffer2, buffer+bufferSize1, bufferSize2); 03431 03432 // Update our buffer offset and unlock sound buffer 03433 dsBuffer->Unlock (buffer1, bufferSize1, buffer2, bufferSize2); 03434 if ( FAILED(result) ) { 03435 sprintf(message, "RtAudio: Unable to unlock DS buffer during playback (%s): %s.", 03436 devices[stream->device[0]].name, getErrorString(result)); 03437 error(RtError::DRIVER_ERROR); 03438 } 03439 nextWritePos = (nextWritePos + bufferSize1 + bufferSize2) % dsBufferSize; 03440 stream->handle[0].bufferPointer = nextWritePos; 03441 } 03442 03443 if (stream->mode == RECORD || stream->mode == DUPLEX) { 03444 03445 // Setup parameters. 03446 if (stream->doConvertBuffer[1]) { 03447 buffer = stream->deviceBuffer; 03448 buffer_bytes = stream->bufferSize * stream->nDeviceChannels[1]; 03449 buffer_bytes *= formatBytes(stream->deviceFormat[1]); 03450 } 03451 else { 03452 buffer = stream->userBuffer; 03453 buffer_bytes = stream->bufferSize * stream->nUserChannels[1]; 03454 buffer_bytes *= formatBytes(stream->userFormat); 03455 } 03456 03457 LPDIRECTSOUNDCAPTUREBUFFER dsBuffer = (LPDIRECTSOUNDCAPTUREBUFFER) stream->handle[1].buffer; 03458 UINT nextReadPos = stream->handle[1].bufferPointer; 03459 DWORD dsBufferSize = buffer_bytes * stream->nBuffers; 03460 03461 // Find out where the write and "safe read" pointers are. 03462 result = dsBuffer->GetCurrentPosition(¤tPos, &safePos); 03463 if ( FAILED(result) ) { 03464 sprintf(message, "RtAudio: Unable to get current DS capture position (%s): %s.", 03465 devices[stream->device[1]].name, getErrorString(result)); 03466 error(RtError::DRIVER_ERROR); 03467 } 03468 03469 if ( safePos < nextReadPos ) safePos += dsBufferSize; // unwrap offset 03470 DWORD endRead = nextReadPos + buffer_bytes; 03471 03472 // Check whether the entire write region is behind the play pointer. 03473 while ( safePos < endRead ) { 03474 // See comments for playback. 03475 float millis = (endRead - safePos) * 900.0; 03476 millis /= ( formatBytes(stream->deviceFormat[1]) * stream->sampleRate); 03477 if ( millis < 1.0 ) millis = 1.0; 03478 Sleep( (DWORD) millis ); 03479 03480 // Wake up, find out where we are now 03481 result = dsBuffer->GetCurrentPosition( ¤tPos, &safePos ); 03482 if ( FAILED(result) ) { 03483 sprintf(message, "RtAudio: Unable to get current DS capture position (%s): %s.", 03484 devices[stream->device[1]].name, getErrorString(result)); 03485 error(RtError::DRIVER_ERROR); 03486 } 03487 03488 if ( safePos < nextReadPos ) safePos += dsBufferSize; // unwrap offset 03489 } 03490 03491 // Lock free space in the buffer 03492 result = dsBuffer->Lock (nextReadPos, buffer_bytes, &buffer1, 03493 &bufferSize1, &buffer2, &bufferSize2, 0); 03494 if ( FAILED(result) ) { 03495 sprintf(message, "RtAudio: Unable to lock DS buffer during capture (%s): %s.", 03496 devices[stream->device[1]].name, getErrorString(result)); 03497 error(RtError::DRIVER_ERROR); 03498 } 03499 03500 // Copy our buffer into the DS buffer 03501 CopyMemory(buffer, buffer1, bufferSize1); 03502 if (buffer2 != NULL) CopyMemory(buffer+bufferSize1, buffer2, bufferSize2); 03503 03504 // Update our buffer offset and unlock sound buffer 03505 nextReadPos = (nextReadPos + bufferSize1 + bufferSize2) % dsBufferSize; 03506 dsBuffer->Unlock (buffer1, bufferSize1, buffer2, bufferSize2); 03507 if ( FAILED(result) ) { 03508 sprintf(message, "RtAudio: Unable to unlock DS buffer during capture (%s): %s.", 03509 devices[stream->device[1]].name, getErrorString(result)); 03510 error(RtError::DRIVER_ERROR); 03511 } 03512 stream->handle[1].bufferPointer = nextReadPos; 03513 03514 // No byte swapping necessary in DirectSound implementation. 03515 03516 // Do buffer conversion if necessary. 03517 if (stream->doConvertBuffer[1]) 03518 convertStreamBuffer(stream, RECORD); 03519 } 03520 03521 MUTEX_UNLOCK(&stream->mutex); 03522 03523 if (stream->usingCallback && stopStream) 03524 this->stopStream(streamId); 03525 } 03526 03527 // Definitions for utility functions and callbacks 03528 // specific to the DirectSound implementation. 03529 03530 extern "C" unsigned __stdcall callbackHandler(void *ptr) 03531 { 03532 RtAudio *object = thread_info.object; 03533 int stream = thread_info.streamId; 03534 bool *usingCallback = (bool *) ptr; 03535 03536 while ( *usingCallback ) { 03537 try { 03538 object->tickStream(stream); 03539 } 03540 catch (RtError &exception) { 03541 fprintf(stderr, "\nCallback thread error (%s) ... closing thread.\n\n", 03542 exception.getMessage()); 03543 break; 03544 } 03545 } 03546 03547 _endthreadex( 0 ); 03548 return 0; 03549 } 03550 03551 static bool CALLBACK deviceCountCallback(LPGUID lpguid, 03552 LPCSTR lpcstrDescription, 03553 LPCSTR lpcstrModule, 03554 LPVOID lpContext) 03555 { 03556 int *pointer = ((int *) lpContext); 03557 (*pointer)++; 03558 03559 return true; 03560 } 03561 03562 static bool CALLBACK deviceInfoCallback(LPGUID lpguid, 03563 LPCSTR lpcstrDescription, 03564 LPCSTR lpcstrModule, 03565 LPVOID lpContext) 03566 { 03567 enum_info *info = ((enum_info *) lpContext); 03568 while (strlen(info->name) > 0) info++; 03569 03570 strncpy(info->name, lpcstrDescription, 64); 03571 info->id = lpguid; 03572 03573 HRESULT hr; 03574 info->isValid = false; 03575 if (info->isInput == true) { 03576 DSCCAPS caps; 03577 LPDIRECTSOUNDCAPTURE object; 03578 03579 hr = DirectSoundCaptureCreate( lpguid, &object, NULL ); 03580 if( hr != DS_OK ) return true; 03581 03582 caps.dwSize = sizeof(caps); 03583 hr = object->GetCaps( &caps ); 03584 if( hr == DS_OK ) { 03585 if (caps.dwChannels > 0 && caps.dwFormats > 0) 03586 info->isValid = true; 03587 } 03588 object->Release(); 03589 } 03590 else { 03591 DSCAPS caps; 03592 LPDIRECTSOUND object; 03593 hr = DirectSoundCreate( lpguid, &object, NULL ); 03594 if( hr != DS_OK ) return true; 03595 03596 caps.dwSize = sizeof(caps); 03597 hr = object->GetCaps( &caps ); 03598 if( hr == DS_OK ) { 03599 if ( caps.dwFlags & DSCAPS_PRIMARYMONO || caps.dwFlags & DSCAPS_PRIMARYSTEREO ) 03600 info->isValid = true; 03601 } 03602 object->Release(); 03603 } 03604 03605 return true; 03606 } 03607 03608 static char* getErrorString(int code) 03609 { 03610 switch (code) { 03611 03612 case DSERR_ALLOCATED: 03613 return "Direct Sound already allocated"; 03614 03615 case DSERR_CONTROLUNAVAIL: 03616 return "Direct Sound control unavailable"; 03617 03618 case DSERR_INVALIDPARAM: 03619 return "Direct Sound invalid parameter"; 03620 03621 case DSERR_INVALIDCALL: 03622 return "Direct Sound invalid call"; 03623 03624 case DSERR_GENERIC: 03625 return "Direct Sound generic error"; 03626 03627 case DSERR_PRIOLEVELNEEDED: 03628 return "Direct Sound Priority level needed"; 03629 03630 case DSERR_OUTOFMEMORY: 03631 return "Direct Sound out of memory"; 03632 03633 case DSERR_BADFORMAT: 03634 return "Direct Sound bad format"; 03635 03636 case DSERR_UNSUPPORTED: 03637 return "Direct Sound unsupported error"; 03638 03639 case DSERR_NODRIVER: 03640 return "Direct Sound no driver error"; 03641 03642 case DSERR_ALREADYINITIALIZED: 03643 return "Direct Sound already initialized"; 03644 03645 case DSERR_NOAGGREGATION: 03646 return "Direct Sound no aggregation"; 03647 03648 case DSERR_BUFFERLOST: 03649 return "Direct Sound buffer lost"; 03650 03651 case DSERR_OTHERAPPHASPRIO: 03652 return "Direct Sound other app has priority"; 03653 03654 case DSERR_UNINITIALIZED: 03655 return "Direct Sound uninitialized"; 03656 03657 default: 03658 return "Direct Sound unknown error"; 03659 } 03660 } 03661 03662 //******************** End of __WINDOWS_DS__ *********************// 03663 03664 #elif defined(__IRIX_AL__) // SGI's AL API for IRIX 03665 03666 #include <unistd.h> 03667 #include <errno.h> 03668 03669 void RtAudio :: initialize(void) 03670 { 03671 03672 // Count cards and devices 03673 nDevices = 0; 03674 03675 // Determine the total number of input and output devices. 03676 nDevices = alQueryValues(AL_SYSTEM, AL_DEVICES, 0, 0, 0, 0); 03677 if (nDevices < 0) { 03678 sprintf(message, "RtAudio: AL error counting devices: %s.", 03679 alGetErrorString(oserror())); 03680 error(RtError::DRIVER_ERROR); 03681 } 03682 03683 if (nDevices <= 0) return; 03684 03685 ALvalue *vls = (ALvalue *) new ALvalue[nDevices]; 03686 03687 // Add one for our default input/output devices. 03688 nDevices++; 03689 03690 // Allocate the RTAUDIO_DEVICE structures. 03691 devices = (RTAUDIO_DEVICE *) calloc(nDevices, sizeof(RTAUDIO_DEVICE)); 03692 if (devices == NULL) { 03693 sprintf(message, "RtAudio: memory allocation error!"); 03694 error(RtError::MEMORY_ERROR); 03695 } 03696 03697 // Write device ascii identifiers to device info structure. 03698 char name[32]; 03699 int outs, ins, i; 03700 ALpv pvs[1]; 03701 pvs[0].param = AL_NAME; 03702 pvs[0].value.ptr = name; 03703 pvs[0].sizeIn = 32; 03704 03705 strcpy(devices[0].name, "Default Input/Output Devices"); 03706 03707 outs = alQueryValues(AL_SYSTEM, AL_DEFAULT_OUTPUT, vls, nDevices-1, 0, 0); 03708 if (outs < 0) { 03709 sprintf(message, "RtAudio: AL error getting output devices: %s.", 03710 alGetErrorString(oserror())); 03711 error(RtError::DRIVER_ERROR); 03712 } 03713 03714 for (i=0; i<outs; i++) { 03715 if (alGetParams(vls[i].i, pvs, 1) < 0) { 03716 sprintf(message, "RtAudio: AL error querying output devices: %s.", 03717 alGetErrorString(oserror())); 03718 error(RtError::DRIVER_ERROR); 03719 } 03720 strncpy(devices[i+1].name, name, 32); 03721 devices[i+1].id[0] = vls[i].i; 03722 } 03723 03724 ins = alQueryValues(AL_SYSTEM, AL_DEFAULT_INPUT, &vls[outs], nDevices-outs-1, 0, 0); 03725 if (ins < 0) { 03726 sprintf(message, "RtAudio: AL error getting input devices: %s.", 03727 alGetErrorString(oserror())); 03728 error(RtError::DRIVER_ERROR); 03729 } 03730 03731 for (i=outs; i<ins+outs; i++) { 03732 if (alGetParams(vls[i].i, pvs, 1) < 0) { 03733 sprintf(message, "RtAudio: AL error querying input devices: %s.", 03734 alGetErrorString(oserror())); 03735 error(RtError::DRIVER_ERROR); 03736 } 03737 strncpy(devices[i+1].name, name, 32); 03738 devices[i+1].id[1] = vls[i].i; 03739 } 03740 03741 delete [] vls; 03742 03743 return; 03744 } 03745 03746 void RtAudio :: probeDeviceInfo(RTAUDIO_DEVICE *info) 03747 { 03748 int resource, result, i; 03749 ALvalue value; 03750 ALparamInfo pinfo; 03751 03752 // Get output resource ID if it exists. 03753 if ( !strncmp(info->name, "Default Input/Output Devices", 28) ) { 03754 result = alQueryValues(AL_SYSTEM, AL_DEFAULT_OUTPUT, &value, 1, 0, 0); 03755 if (result < 0) { 03756 sprintf(message, "RtAudio: AL error getting default output device id: %s.", 03757 alGetErrorString(oserror())); 03758 error(RtError::WARNING); 03759 } 03760 else 03761 resource = value.i; 03762 } 03763 else 03764 resource = info->id[0]; 03765 03766 if (resource > 0) { 03767 03768 // Probe output device parameters. 03769 result = alQueryValues(resource, AL_CHANNELS, &value, 1, 0, 0); 03770 if (result < 0) { 03771 sprintf(message, "RtAudio: AL error getting device (%s) channels: %s.", 03772 info->name, alGetErrorString(oserror())); 03773 error(RtError::WARNING); 03774 } 03775 else { 03776 info->maxOutputChannels = value.i; 03777 info->minOutputChannels = 1; 03778 } 03779 03780 result = alGetParamInfo(resource, AL_RATE, &pinfo); 03781 if (result < 0) { 03782 sprintf(message, "RtAudio: AL error getting device (%s) rates: %s.", 03783 info->name, alGetErrorString(oserror())); 03784 error(RtError::WARNING); 03785 } 03786 else { 03787 info->nSampleRates = 0; 03788 for (i=0; i<MAX_SAMPLE_RATES; i++) { 03789 if ( SAMPLE_RATES[i] >= pinfo.min.i && SAMPLE_RATES[i] <= pinfo.max.i ) { 03790 info->sampleRates[info->nSampleRates] = SAMPLE_RATES[i]; 03791 info->nSampleRates++; 03792 } 03793 } 03794 } 03795 03796 // The AL library supports all our formats, except 24-bit and 32-bit ints. 03797 info->nativeFormats = (RTAUDIO_FORMAT) 51; 03798 } 03799 03800 // Now get input resource ID if it exists. 03801 if ( !strncmp(info->name, "Default Input/Output Devices", 28) ) { 03802 result = alQueryValues(AL_SYSTEM, AL_DEFAULT_INPUT, &value, 1, 0, 0); 03803 if (result < 0) { 03804 sprintf(message, "RtAudio: AL error getting default input device id: %s.", 03805 alGetErrorString(oserror())); 03806 error(RtError::WARNING); 03807 } 03808 else 03809 resource = value.i; 03810 } 03811 else 03812 resource = info->id[1]; 03813 03814 if (resource > 0) { 03815 03816 // Probe input device parameters. 03817 result = alQueryValues(resource, AL_CHANNELS, &value, 1, 0, 0); 03818 if (result < 0) { 03819 sprintf(message, "RtAudio: AL error getting device (%s) channels: %s.", 03820 info->name, alGetErrorString(oserror())); 03821 error(RtError::WARNING); 03822 } 03823 else { 03824 info->maxInputChannels = value.i; 03825 info->minInputChannels = 1; 03826 } 03827 03828 result = alGetParamInfo(resource, AL_RATE, &pinfo); 03829 if (result < 0) { 03830 sprintf(message, "RtAudio: AL error getting device (%s) rates: %s.", 03831 info->name, alGetErrorString(oserror())); 03832 error(RtError::WARNING); 03833 } 03834 else { 03835 // In the case of the default device, these values will 03836 // overwrite the rates determined for the output device. Since 03837 // the input device is most likely to be more limited than the 03838 // output device, this is ok. 03839 info->nSampleRates = 0; 03840 for (i=0; i<MAX_SAMPLE_RATES; i++) { 03841 if ( SAMPLE_RATES[i] >= pinfo.min.i && SAMPLE_RATES[i] <= pinfo.max.i ) { 03842 info->sampleRates[info->nSampleRates] = SAMPLE_RATES[i]; 03843 info->nSampleRates++; 03844 } 03845 } 03846 } 03847 03848 // The AL library supports all our formats, except 24-bit and 32-bit ints. 03849 info->nativeFormats = (RTAUDIO_FORMAT) 51; 03850 } 03851 03852 if ( info->maxInputChannels == 0 && info->maxOutputChannels == 0 ) 03853 return; 03854 if ( info->nSampleRates == 0 ) 03855 return; 03856 03857 // Determine duplex status. 03858 if (info->maxInputChannels < info->maxOutputChannels) 03859 info->maxDuplexChannels = info->maxInputChannels; 03860 else 03861 info->maxDuplexChannels = info->maxOutputChannels; 03862 if (info->minInputChannels < info->minOutputChannels) 03863 info->minDuplexChannels = info->minInputChannels; 03864 else 03865 info->minDuplexChannels = info->minOutputChannels; 03866 03867 if ( info->maxDuplexChannels > 0 ) info->hasDuplexSupport = true; 03868 else info->hasDuplexSupport = false; 03869 03870 info->probed = true; 03871 03872 return; 03873 } 03874 03875 bool RtAudio :: probeDeviceOpen(int device, RTAUDIO_STREAM *stream, 03876 STREAM_MODE mode, int channels, 03877 int sampleRate, RTAUDIO_FORMAT format, 03878 int *bufferSize, int numberOfBuffers) 03879 { 03880 int result, resource, nBuffers; 03881 ALconfig al_config; 03882 ALport port; 03883 ALpv pvs[2]; 03884 03885 // Get a new ALconfig structure. 03886 al_config = alNewConfig(); 03887 if ( !al_config ) { 03888 sprintf(message,"RtAudio: can't get AL config: %s.", 03889 alGetErrorString(oserror())); 03890 error(RtError::WARNING); 03891 return FAILURE; 03892 } 03893 03894 // Set the channels. 03895 result = alSetChannels(al_config, channels); 03896 if ( result < 0 ) { 03897 sprintf(message,"RtAudio: can't set %d channels in AL config: %s.", 03898 channels, alGetErrorString(oserror())); 03899 error(RtError::WARNING); 03900 return FAILURE; 03901 } 03902 03903 // Set the queue (buffer) size. 03904 if ( numberOfBuffers < 1 ) 03905 nBuffers = 1; 03906 else 03907 nBuffers = numberOfBuffers; 03908 long buffer_size = *bufferSize * nBuffers; 03909 result = alSetQueueSize(al_config, buffer_size); // in sample frames 03910 if ( result < 0 ) { 03911 sprintf(message,"RtAudio: can't set buffer size (%ld) in AL config: %s.", 03912 buffer_size, alGetErrorString(oserror())); 03913 error(RtError::WARNING); 03914 return FAILURE; 03915 } 03916 03917 // Set the data format. 03918 stream->userFormat = format; 03919 stream->deviceFormat[mode] = format; 03920 if (format == RTAUDIO_SINT8) { 03921 result = alSetSampFmt(al_config, AL_SAMPFMT_TWOSCOMP); 03922 result = alSetWidth(al_config, AL_SAMPLE_8); 03923 } 03924 else if (format == RTAUDIO_SINT16) { 03925 result = alSetSampFmt(al_config, AL_SAMPFMT_TWOSCOMP); 03926 result = alSetWidth(al_config, AL_SAMPLE_16); 03927 } 03928 else if (format == RTAUDIO_SINT24) { 03929 // Our 24-bit format assumes the upper 3 bytes of a 4 byte word. 03930 // The AL library uses the lower 3 bytes, so we'll need to do our 03931 // own conversion. 03932 result = alSetSampFmt(al_config, AL_SAMPFMT_FLOAT); 03933 stream->deviceFormat[mode] = RTAUDIO_FLOAT32; 03934 } 03935 else if (format == RTAUDIO_SINT32) { 03936 // The AL library doesn't seem to support the 32-bit integer 03937 // format, so we'll need to do our own conversion. 03938 result = alSetSampFmt(al_config, AL_SAMPFMT_FLOAT); 03939 stream->deviceFormat[mode] = RTAUDIO_FLOAT32; 03940 } 03941 else if (format == RTAUDIO_FLOAT32) 03942 result = alSetSampFmt(al_config, AL_SAMPFMT_FLOAT); 03943 else if (format == RTAUDIO_FLOAT64) 03944 result = alSetSampFmt(al_config, AL_SAMPFMT_DOUBLE); 03945 03946 if ( result == -1 ) { 03947 sprintf(message,"RtAudio: AL error setting sample format in AL config: %s.", 03948 alGetErrorString(oserror())); 03949 error(RtError::WARNING); 03950 return FAILURE; 03951 } 03952 03953 if (mode == PLAYBACK) { 03954 03955 // Set our device. 03956 if (device == 0) 03957 resource = AL_DEFAULT_OUTPUT; 03958 else 03959 resource = devices[device].id[0]; 03960 result = alSetDevice(al_config, resource); 03961 if ( result == -1 ) { 03962 sprintf(message,"RtAudio: AL error setting device (%s) in AL config: %s.", 03963 devices[device].name, alGetErrorString(oserror())); 03964 error(RtError::WARNING); 03965 return FAILURE; 03966 } 03967 03968 // Open the port. 03969 port = alOpenPort("RtAudio Output Port", "w", al_config); 03970 if( !port ) { 03971 sprintf(message,"RtAudio: AL error opening output port: %s.", 03972 alGetErrorString(oserror())); 03973 error(RtError::WARNING); 03974 return FAILURE; 03975 } 03976 03977 // Set the sample rate 03978 pvs[0].param = AL_MASTER_CLOCK; 03979 pvs[0].value.i = AL_CRYSTAL_MCLK_TYPE; 03980 pvs[1].param = AL_RATE; 03981 pvs[1].value.ll = alDoubleToFixed((double)sampleRate); 03982 result = alSetParams(resource, pvs, 2); 03983 if ( result < 0 ) { 03984 alClosePort(port); 03985 sprintf(message,"RtAudio: AL error setting sample rate (%d) for device (%s): %s.", 03986 sampleRate, devices[device].name, alGetErrorString(oserror())); 03987 error(RtError::WARNING); 03988 return FAILURE; 03989 } 03990 } 03991 else { // mode == RECORD 03992 03993 // Set our device. 03994 if (device == 0) 03995 resource = AL_DEFAULT_INPUT; 03996 else 03997 resource = devices[device].id[1]; 03998 result = alSetDevice(al_config, resource); 03999 if ( result == -1 ) { 04000 sprintf(message,"RtAudio: AL error setting device (%s) in AL config: %s.", 04001 devices[device].name, alGetErrorString(oserror())); 04002 error(RtError::WARNING); 04003 return FAILURE; 04004 } 04005 04006 // Open the port. 04007 port = alOpenPort("RtAudio Output Port", "r", al_config); 04008 if( !port ) { 04009 sprintf(message,"RtAudio: AL error opening input port: %s.", 04010 alGetErrorString(oserror())); 04011 error(RtError::WARNING); 04012 return FAILURE; 04013 } 04014 04015 // Set the sample rate 04016 pvs[0].param = AL_MASTER_CLOCK; 04017 pvs[0].value.i = AL_CRYSTAL_MCLK_TYPE; 04018 pvs[1].param = AL_RATE; 04019 pvs[1].value.ll = alDoubleToFixed((double)sampleRate); 04020 result = alSetParams(resource, pvs, 2); 04021 if ( result < 0 ) { 04022 alClosePort(port); 04023 sprintf(message,"RtAudio: AL error setting sample rate (%d) for device (%s): %s.", 04024 sampleRate, devices[device].name, alGetErrorString(oserror())); 04025 error(RtError::WARNING); 04026 return FAILURE; 04027 } 04028 } 04029 04030 alFreeConfig(al_config); 04031 04032 stream->nUserChannels[mode] = channels; 04033 stream->nDeviceChannels[mode] = channels; 04034 04035 // Set handle and flags for buffer conversion 04036 stream->handle[mode] = port; 04037 stream->doConvertBuffer[mode] = false; 04038 if (stream->userFormat != stream->deviceFormat[mode]) 04039 stream->doConvertBuffer[mode] = true; 04040 04041 // Allocate necessary internal buffers 04042 if ( stream->nUserChannels[0] != stream->nUserChannels[1] ) { 04043 04044 long buffer_bytes; 04045 if (stream->nUserChannels[0] >= stream->nUserChannels[1]) 04046 buffer_bytes = stream->nUserChannels[0]; 04047 else 04048 buffer_bytes = stream->nUserChannels[1]; 04049 04050 buffer_bytes *= *bufferSize * formatBytes(stream->userFormat); 04051 if (stream->userBuffer) free(stream->userBuffer); 04052 stream->userBuffer = (char *) calloc(buffer_bytes, 1); 04053 if (stream->userBuffer == NULL) 04054 goto memory_error; 04055 } 04056 04057 if ( stream->doConvertBuffer[mode] ) { 04058 04059 long buffer_bytes; 04060 bool makeBuffer = true; 04061 if ( mode == PLAYBACK ) 04062 buffer_bytes = stream->nDeviceChannels[0] * formatBytes(stream->deviceFormat[0]); 04063 else { // mode == RECORD 04064 buffer_bytes = stream->nDeviceChannels[1] * formatBytes(stream->deviceFormat[1]); 04065 if ( stream->mode == PLAYBACK ) { 04066 long bytes_out = stream->nDeviceChannels[0] * formatBytes(stream->deviceFormat[0]); 04067 if ( buffer_bytes > bytes_out ) 04068 buffer_bytes = (buffer_bytes > bytes_out) ? buffer_bytes : bytes_out; 04069 else 04070 makeBuffer = false; 04071 } 04072 } 04073 04074 if ( makeBuffer ) { 04075 buffer_bytes *= *bufferSize; 04076 if (stream->deviceBuffer) free(stream->deviceBuffer); 04077 stream->deviceBuffer = (char *) calloc(buffer_bytes, 1); 04078 if (stream->deviceBuffer == NULL) 04079 goto memory_error; 04080 } 04081 } 04082 04083 stream->device[mode] = device; 04084 stream->state = STREAM_STOPPED; 04085 if ( stream->mode == PLAYBACK && mode == RECORD ) 04086 // We had already set up an output stream. 04087 stream->mode = DUPLEX; 04088 else 04089 stream->mode = mode; 04090 stream->nBuffers = nBuffers; 04091 stream->bufferSize = *bufferSize; 04092 stream->sampleRate = sampleRate; 04093 04094 return SUCCESS; 04095 04096 memory_error: 04097 if (stream->handle[0]) { 04098 alClosePort(stream->handle[0]); 04099 stream->handle[0] = 0; 04100 } 04101 if (stream->handle[1]) { 04102 alClosePort(stream->handle[1]); 04103 stream->handle[1] = 0; 04104 } 04105 if (stream->userBuffer) { 04106 free(stream->userBuffer); 04107 stream->userBuffer = 0; 04108 } 04109 sprintf(message, "RtAudio: ALSA error allocating buffer memory for device (%s).", 04110 devices[device].name); 04111 error(RtError::WARNING); 04112 return FAILURE; 04113 } 04114 04115 void RtAudio :: cancelStreamCallback(int streamId) 04116 { 04117 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId); 04118 04119 if (stream->usingCallback) { 04120 stream->usingCallback = false; 04121 pthread_cancel(stream->thread); 04122 pthread_join(stream->thread, NULL); 04123 stream->thread = 0; 04124 stream->callback = NULL; 04125 stream->userData = NULL; 04126 } 04127 } 04128 04129 void RtAudio :: closeStream(int streamId) 04130 { 04131 // We don't want an exception to be thrown here because this 04132 // function is called by our class destructor. So, do our own 04133 // streamId check. 04134 if ( streams.find( streamId ) == streams.end() ) { 04135 sprintf(message, "RtAudio: invalid stream identifier!"); 04136 error(RtError::WARNING); 04137 return; 04138 } 04139 04140 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) streams[streamId]; 04141 04142 if (stream->usingCallback) { 04143 pthread_cancel(stream->thread); 04144 pthread_join(stream->thread, NULL); 04145 } 04146 04147 pthread_mutex_destroy(&stream->mutex); 04148 04149 if (stream->handle[0]) 04150 alClosePort(stream->handle[0]); 04151 04152 if (stream->handle[1]) 04153 alClosePort(stream->handle[1]); 04154 04155 if (stream->userBuffer) 04156 free(stream->userBuffer); 04157 04158 if (stream->deviceBuffer) 04159 free(stream->deviceBuffer); 04160 04161 free(stream); 04162 streams.erase(streamId); 04163 } 04164 04165 void RtAudio :: startStream(int streamId) 04166 { 04167 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId); 04168 04169 if (stream->state == STREAM_RUNNING) 04170 return; 04171 04172 // The AL port is ready as soon as it is opened. 04173 stream->state = STREAM_RUNNING; 04174 } 04175 04176 void RtAudio :: stopStream(int streamId) 04177 { 04178 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId); 04179 04180 MUTEX_LOCK(&stream->mutex); 04181 04182 if (stream->state == STREAM_STOPPED) 04183 goto unlock; 04184 04185 int result; 04186 int buffer_size = stream->bufferSize * stream->nBuffers; 04187 04188 if (stream->mode == PLAYBACK || stream->mode == DUPLEX) 04189 alZeroFrames(stream->handle[0], buffer_size); 04190 04191 if (stream->mode == RECORD || stream->mode == DUPLEX) { 04192 result = alDiscardFrames(stream->handle[1], buffer_size); 04193 if (result == -1) { 04194 sprintf(message, "RtAudio: AL error draining stream device (%s): %s.", 04195 devices[stream->device[1]].name, alGetErrorString(oserror())); 04196 error(RtError::DRIVER_ERROR); 04197 } 04198 } 04199 stream->state = STREAM_STOPPED; 04200 04201 unlock: 04202 MUTEX_UNLOCK(&stream->mutex); 04203 } 04204 04205 void RtAudio :: abortStream(int streamId) 04206 { 04207 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId); 04208 04209 MUTEX_LOCK(&stream->mutex); 04210 04211 if (stream->state == STREAM_STOPPED) 04212 goto unlock; 04213 04214 if (stream->mode == PLAYBACK || stream->mode == DUPLEX) { 04215 04216 int buffer_size = stream->bufferSize * stream->nBuffers; 04217 int result = alDiscardFrames(stream->handle[0], buffer_size); 04218 if (result == -1) { 04219 sprintf(message, "RtAudio: AL error aborting stream device (%s): %s.", 04220 devices[stream->device[0]].name, alGetErrorString(oserror())); 04221 error(RtError::DRIVER_ERROR); 04222 } 04223 } 04224 04225 // There is no clear action to take on the input stream, since the 04226 // port will continue to run in any event. 04227 stream->state = STREAM_STOPPED; 04228 04229 unlock: 04230 MUTEX_UNLOCK(&stream->mutex); 04231 } 04232 04233 int RtAudio :: streamWillBlock(int streamId) 04234 { 04235 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId); 04236 04237 MUTEX_LOCK(&stream->mutex); 04238 04239 int frames = 0; 04240 if (stream->state == STREAM_STOPPED) 04241 goto unlock; 04242 04243 int err = 0; 04244 if (stream->mode == PLAYBACK || stream->mode == DUPLEX) { 04245 err = alGetFillable(stream->handle[0]); 04246 if (err < 0) { 04247 sprintf(message, "RtAudio: AL error getting available frames for stream (%s): %s.", 04248 devices[stream->device[0]].name, alGetErrorString(oserror())); 04249 error(RtError::DRIVER_ERROR); 04250 } 04251 } 04252 04253 frames = err; 04254 04255 if (stream->mode == RECORD || stream->mode == DUPLEX) { 04256 err = alGetFilled(stream->handle[1]); 04257 if (err < 0) { 04258 sprintf(message, "RtAudio: AL error getting available frames for stream (%s): %s.", 04259 devices[stream->device[1]].name, alGetErrorString(oserror())); 04260 error(RtError::DRIVER_ERROR); 04261 } 04262 if (frames > err) frames = err; 04263 } 04264 04265 frames = stream->bufferSize - frames; 04266 if (frames < 0) frames = 0; 04267 04268 unlock: 04269 MUTEX_UNLOCK(&stream->mutex); 04270 return frames; 04271 } 04272 04273 void RtAudio :: tickStream(int streamId) 04274 { 04275 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId); 04276 04277 int stopStream = 0; 04278 if (stream->state == STREAM_STOPPED) { 04279 if (stream->usingCallback) usleep(50000); // sleep 50 milliseconds 04280 return; 04281 } 04282 else if (stream->usingCallback) { 04283 stopStream = stream->callback(stream->userBuffer, stream->bufferSize, stream->userData); 04284 } 04285 04286 MUTEX_LOCK(&stream->mutex); 04287 04288 // The state might change while waiting on a mutex. 04289 if (stream->state == STREAM_STOPPED) 04290 goto unlock; 04291 04292 char *buffer; 04293 int channels; 04294 RTAUDIO_FORMAT format; 04295 if (stream->mode == PLAYBACK || stream->mode == DUPLEX) { 04296 04297 // Setup parameters and do buffer conversion if necessary. 04298 if (stream->doConvertBuffer[0]) { 04299 convertStreamBuffer(stream, PLAYBACK); 04300 buffer = stream->deviceBuffer; 04301 channels = stream->nDeviceChannels[0]; 04302 format = stream->deviceFormat[0]; 04303 } 04304 else { 04305 buffer = stream->userBuffer; 04306 channels = stream->nUserChannels[0]; 04307 format = stream->userFormat; 04308 } 04309 04310 // Do byte swapping if necessary. 04311 if (stream->doByteSwap[0]) 04312 byteSwapBuffer(buffer, stream->bufferSize * channels, format); 04313 04314 // Write interleaved samples to device. 04315 alWriteFrames(stream->handle[0], buffer, stream->bufferSize); 04316 } 04317 04318 if (stream->mode == RECORD || stream->mode == DUPLEX) { 04319 04320 // Setup parameters. 04321 if (stream->doConvertBuffer[1]) { 04322 buffer = stream->deviceBuffer; 04323 channels = stream->nDeviceChannels[1]; 04324 format = stream->deviceFormat[1]; 04325 } 04326 else { 04327 buffer = stream->userBuffer; 04328 channels = stream->nUserChannels[1]; 04329 format = stream->userFormat; 04330 } 04331 04332 // Read interleaved samples from device. 04333 alReadFrames(stream->handle[1], buffer, stream->bufferSize); 04334 04335 // Do byte swapping if necessary. 04336 if (stream->doByteSwap[1]) 04337 byteSwapBuffer(buffer, stream->bufferSize * channels, format); 04338 04339 // Do buffer conversion if necessary. 04340 if (stream->doConvertBuffer[1]) 04341 convertStreamBuffer(stream, RECORD); 04342 } 04343 04344 unlock: 04345 MUTEX_UNLOCK(&stream->mutex); 04346 04347 if (stream->usingCallback && stopStream) 04348 this->stopStream(streamId); 04349 } 04350 04351 extern "C" void *callbackHandler(void *ptr) 04352 { 04353 RtAudio *object = thread_info.object; 04354 int stream = thread_info.streamId; 04355 bool *usingCallback = (bool *) ptr; 04356 04357 while ( *usingCallback ) { 04358 pthread_testcancel(); 04359 try { 04360 object->tickStream(stream); 04361 } 04362 catch (RtError &exception) { 04363 fprintf(stderr, "\nCallback thread error (%s) ... closing thread.\n\n", 04364 exception.getMessage()); 04365 break; 04366 } 04367 } 04368 04369 return 0; 04370 } 04371 04372 //******************** End of __IRIX_AL__ *********************// 04373 04374 #endif 04375 04376 04377 // *************************************************** // 04378 // 04379 // Private common (OS-independent) RtAudio methods. 04380 // 04381 // *************************************************** // 04382 04383 // This method can be modified to control the behavior of error 04384 // message reporting and throwing. 04385 void RtAudio :: error(RtError::TYPE type) 04386 { 04387 if (type == RtError::WARNING) { 04388 #if defined(RTAUDIO_DEBUG) 04389 fprintf(stderr, "\n%s\n\n", message); 04390 else if (type == RtError::DEBUG_WARNING) { 04391 fprintf(stderr, "\n%s\n\n", message); 04392 #endif 04393 } 04394 else { 04395 fprintf(stderr, "\n%s\n\n", message); 04396 throw RtError(message, type); 04397 } 04398 } 04399 04400 void *RtAudio :: verifyStream(int streamId) 04401 { 04402 // Verify the stream key. 04403 if ( streams.find( streamId ) == streams.end() ) { 04404 sprintf(message, "RtAudio: invalid stream identifier!"); 04405 error(RtError::INVALID_STREAM); 04406 } 04407 04408 return streams[streamId]; 04409 } 04410 04411 void RtAudio :: clearDeviceInfo(RTAUDIO_DEVICE *info) 04412 { 04413 // Don't clear the name or DEVICE_ID fields here ... they are 04414 // typically set prior to a call of this function. 04415 info->probed = false; 04416 info->maxOutputChannels = 0; 04417 info->maxInputChannels = 0; 04418 info->maxDuplexChannels = 0; 04419 info->minOutputChannels = 0; 04420 info->minInputChannels = 0; 04421 info->minDuplexChannels = 0; 04422 info->hasDuplexSupport = false; 04423 info->nSampleRates = 0; 04424 for (int i=0; i<MAX_SAMPLE_RATES; i++) 04425 info->sampleRates[i] = 0; 04426 info->nativeFormats = 0; 04427 } 04428 04429 int RtAudio :: formatBytes(RTAUDIO_FORMAT format) 04430 { 04431 if (format == RTAUDIO_SINT16) 04432 return 2; 04433 else if (format == RTAUDIO_SINT24 || format == RTAUDIO_SINT32 || 04434 format == RTAUDIO_FLOAT32) 04435 return 4; 04436 else if (format == RTAUDIO_FLOAT64) 04437 return 8; 04438 else if (format == RTAUDIO_SINT8) 04439 return 1; 04440 04441 sprintf(message,"RtAudio: undefined format in formatBytes()."); 04442 error(RtError::WARNING); 04443 04444 return 0; 04445 } 04446 04447 void RtAudio :: convertStreamBuffer(RTAUDIO_STREAM *stream, STREAM_MODE mode) 04448 { 04449 // This method does format conversion, input/output channel compensation, and 04450 // data interleaving/deinterleaving. 24-bit integers are assumed to occupy 04451 // the upper three bytes of a 32-bit integer. 04452 04453 int j, channels_in, channels_out, channels; 04454 RTAUDIO_FORMAT format_in, format_out; 04455 char *input, *output; 04456 04457 if (mode == RECORD) { // convert device to user buffer 04458 input = stream->deviceBuffer; 04459 output = stream->userBuffer; 04460 channels_in = stream->nDeviceChannels[1]; 04461 channels_out = stream->nUserChannels[1]; 04462 format_in = stream->deviceFormat[1]; 04463 format_out = stream->userFormat; 04464 } 04465 else { // convert user to device buffer 04466 input = stream->userBuffer; 04467 output = stream->deviceBuffer; 04468 channels_in = stream->nUserChannels[0]; 04469 channels_out = stream->nDeviceChannels[0]; 04470 format_in = stream->userFormat; 04471 format_out = stream->deviceFormat[0]; 04472 04473 // clear our device buffer when in/out duplex device channels are different 04474 if ( stream->mode == DUPLEX && 04475 stream->nDeviceChannels[0] != stream->nDeviceChannels[1] ) 04476 memset(output, 0, stream->bufferSize * channels_out * formatBytes(format_out)); 04477 } 04478 04479 channels = (channels_in < channels_out) ? channels_in : channels_out; 04480 04481 // Set up the interleave/deinterleave offsets 04482 std::vector<int> offset_in(channels); 04483 std::vector<int> offset_out(channels); 04484 if (mode == RECORD && stream->deInterleave[1]) { 04485 for (int k=0; k<channels; k++) { 04486 offset_in[k] = k * stream->bufferSize; 04487 offset_out[k] = k; 04488 } 04489 } 04490 else if (mode == PLAYBACK && stream->deInterleave[0]) { 04491 for (int k=0; k<channels; k++) { 04492 offset_in[k] = k; 04493 offset_out[k] = k * stream->bufferSize; 04494 } 04495 } 04496 else { 04497 for (int k=0; k<channels; k++) { 04498 offset_in[k] = k; 04499 offset_out[k] = k; 04500 } 04501 } 04502 04503 if (format_out == RTAUDIO_FLOAT64) { 04504 FLOAT64 scale; 04505 FLOAT64 *out = (FLOAT64 *)output; 04506 04507 if (format_in == RTAUDIO_SINT8) { 04508 signed char *in = (signed char *)input; 04509 scale = 1.0 / 128.0; 04510 for (int i=0; i<stream->bufferSize; i++) { 04511 for (j=0; j<channels; j++) { 04512 out[offset_out[j]] = (FLOAT64) in[offset_in[j]]; 04513 out[offset_out[j]] *= scale; 04514 } 04515 in += channels_in; 04516 out += channels_out; 04517 } 04518 } 04519 else if (format_in == RTAUDIO_SINT16) { 04520 INT16 *in = (INT16 *)input; 04521 scale = 1.0 / 32768.0; 04522 for (int i=0; i<stream->bufferSize; i++) { 04523 for (j=0; j<channels; j++) { 04524 out[offset_out[j]] = (FLOAT64) in[offset_in[j]]; 04525 out[offset_out[j]] *= scale; 04526 } 04527 in += channels_in; 04528 out += channels_out; 04529 } 04530 } 04531 else if (format_in == RTAUDIO_SINT24) { 04532 INT32 *in = (INT32 *)input; 04533 scale = 1.0 / 2147483648.0; 04534 for (int i=0; i<stream->bufferSize; i++) { 04535 for (j=0; j<channels; j++) { 04536 out[offset_out[j]] = (FLOAT64) (in[offset_in[j]] & 0xffffff00); 04537 out[offset_out[j]] *= scale; 04538 } 04539 in += channels_in; 04540 out += channels_out; 04541 } 04542 } 04543 else if (format_in == RTAUDIO_SINT32) { 04544 INT32 *in = (INT32 *)input; 04545 scale = 1.0 / 2147483648.0; 04546 for (int i=0; i<stream->bufferSize; i++) { 04547 for (j=0; j<channels; j++) { 04548 out[offset_out[j]] = (FLOAT64) in[offset_in[j]]; 04549 out[offset_out[j]] *= scale; 04550 } 04551 in += channels_in; 04552 out += channels_out; 04553 } 04554 } 04555 else if (format_in == RTAUDIO_FLOAT32) { 04556 FLOAT32 *in = (FLOAT32 *)input; 04557 for (int i=0; i<stream->bufferSize; i++) { 04558 for (j=0; j<channels; j++) { 04559 out[offset_out[j]] = (FLOAT64) in[offset_in[j]]; 04560 } 04561 in += channels_in; 04562 out += channels_out; 04563 } 04564 } 04565 else if (format_in == RTAUDIO_FLOAT64) { 04566 // Channel compensation and/or (de)interleaving only. 04567 FLOAT64 *in = (FLOAT64 *)input; 04568 for (int i=0; i<stream->bufferSize; i++) { 04569 for (j=0; j<channels; j++) { 04570 out[offset_out[j]] = in[offset_in[j]]; 04571 } 04572 in += channels_in; 04573 out += channels_out; 04574 } 04575 } 04576 } 04577 else if (format_out == RTAUDIO_FLOAT32) { 04578 FLOAT32 scale; 04579 FLOAT32 *out = (FLOAT32 *)output; 04580 04581 if (format_in == RTAUDIO_SINT8) { 04582 signed char *in = (signed char *)input; 04583 scale = 1.0 / 128.0; 04584 for (int i=0; i<stream->bufferSize; i++) { 04585 for (j=0; j<channels; j++) { 04586 out[offset_out[j]] = (FLOAT32) in[offset_in[j]]; 04587 out[offset_out[j]] *= scale; 04588 } 04589 in += channels_in; 04590 out += channels_out; 04591 } 04592 } 04593 else if (format_in == RTAUDIO_SINT16) { 04594 INT16 *in = (INT16 *)input; 04595 scale = 1.0 / 32768.0; 04596 for (int i=0; i<stream->bufferSize; i++) { 04597 for (j=0; j<channels; j++) { 04598 out[offset_out[j]] = (FLOAT32) in[offset_in[j]]; 04599 out[offset_out[j]] *= scale; 04600 } 04601 in += channels_in; 04602 out += channels_out; 04603 } 04604 } 04605 else if (format_in == RTAUDIO_SINT24) { 04606 INT32 *in = (INT32 *)input; 04607 scale = 1.0 / 2147483648.0; 04608 for (int i=0; i<stream->bufferSize; i++) { 04609 for (j=0; j<channels; j++) { 04610 out[offset_out[j]] = (FLOAT32) (in[offset_in[j]] & 0xffffff00); 04611 out[offset_out[j]] *= scale; 04612 } 04613 in += channels_in; 04614 out += channels_out; 04615 } 04616 } 04617 else if (format_in == RTAUDIO_SINT32) { 04618 INT32 *in = (INT32 *)input; 04619 scale = 1.0 / 2147483648.0; 04620 for (int i=0; i<stream->bufferSize; i++) { 04621 for (j=0; j<channels; j++) { 04622 out[offset_out[j]] = (FLOAT32) in[offset_in[j]]; 04623 out[offset_out[j]] *= scale; 04624 } 04625 in += channels_in; 04626 out += channels_out; 04627 } 04628 } 04629 else if (format_in == RTAUDIO_FLOAT32) { 04630 // Channel compensation and/or (de)interleaving only. 04631 FLOAT32 *in = (FLOAT32 *)input; 04632 for (int i=0; i<stream->bufferSize; i++) { 04633 for (j=0; j<channels; j++) { 04634 out[offset_out[j]] = in[offset_in[j]]; 04635 } 04636 in += channels_in; 04637 out += channels_out; 04638 } 04639 } 04640 else if (format_in == RTAUDIO_FLOAT64) { 04641 FLOAT64 *in = (FLOAT64 *)input; 04642 for (int i=0; i<stream->bufferSize; i++) { 04643 for (j=0; j<channels; j++) { 04644 out[offset_out[j]] = (FLOAT32) in[offset_in[j]]; 04645 } 04646 in += channels_in; 04647 out += channels_out; 04648 } 04649 } 04650 } 04651 else if (format_out == RTAUDIO_SINT32) { 04652 INT32 *out = (INT32 *)output; 04653 if (format_in == RTAUDIO_SINT8) { 04654 signed char *in = (signed char *)input; 04655 for (int i=0; i<stream->bufferSize; i++) { 04656 for (j=0; j<channels; j++) { 04657 out[offset_out[j]] = (INT32) in[offset_in[j]]; 04658 out[offset_out[j]] <<= 24; 04659 } 04660 in += channels_in; 04661 out += channels_out; 04662 } 04663 } 04664 else if (format_in == RTAUDIO_SINT16) { 04665 INT16 *in = (INT16 *)input; 04666 for (int i=0; i<stream->bufferSize; i++) { 04667 for (j=0; j<channels; j++) { 04668 out[offset_out[j]] = (INT32) in[offset_in[j]]; 04669 out[offset_out[j]] <<= 16; 04670 } 04671 in += channels_in; 04672 out += channels_out; 04673 } 04674 } 04675 else if (format_in == RTAUDIO_SINT24) { 04676 INT32 *in = (INT32 *)input; 04677 for (int i=0; i<stream->bufferSize; i++) { 04678 for (j=0; j<channels; j++) { 04679 out[offset_out[j]] = (INT32) in[offset_in[j]]; 04680 } 04681 in += channels_in; 04682 out += channels_out; 04683 } 04684 } 04685 else if (format_in == RTAUDIO_SINT32) { 04686 // Channel compensation and/or (de)interleaving only. 04687 INT32 *in = (INT32 *)input; 04688 for (int i=0; i<stream->bufferSize; i++) { 04689 for (j=0; j<channels; j++) { 04690 out[offset_out[j]] = in[offset_in[j]]; 04691 } 04692 in += channels_in; 04693 out += channels_out; 04694 } 04695 } 04696 else if (format_in == RTAUDIO_FLOAT32) { 04697 FLOAT32 *in = (FLOAT32 *)input; 04698 for (int i=0; i<stream->bufferSize; i++) { 04699 for (j=0; j<channels; j++) { 04700 out[offset_out[j]] = (INT32) (in[offset_in[j]] * 2147483647.0); 04701 } 04702 in += channels_in; 04703 out += channels_out; 04704 } 04705 } 04706 else if (format_in == RTAUDIO_FLOAT64) { 04707 FLOAT64 *in = (FLOAT64 *)input; 04708 for (int i=0; i<stream->bufferSize; i++) { 04709 for (j=0; j<channels; j++) { 04710 out[offset_out[j]] = (INT32) (in[offset_in[j]] * 2147483647.0); 04711 } 04712 in += channels_in; 04713 out += channels_out; 04714 } 04715 } 04716 } 04717 else if (format_out == RTAUDIO_SINT24) { 04718 INT32 *out = (INT32 *)output; 04719 if (format_in == RTAUDIO_SINT8) { 04720 signed char *in = (signed char *)input; 04721 for (int i=0; i<stream->bufferSize; i++) { 04722 for (j=0; j<channels; j++) { 04723 out[offset_out[j]] = (INT32) in[offset_in[j]]; 04724 out[offset_out[j]] <<= 24; 04725 } 04726 in += channels_in; 04727 out += channels_out; 04728 } 04729 } 04730 else if (format_in == RTAUDIO_SINT16) { 04731 INT16 *in = (INT16 *)input; 04732 for (int i=0; i<stream->bufferSize; i++) { 04733 for (j=0; j<channels; j++) { 04734 out[offset_out[j]] = (INT32) in[offset_in[j]]; 04735 out[offset_out[j]] <<= 16; 04736 } 04737 in += channels_in; 04738 out += channels_out; 04739 } 04740 } 04741 else if (format_in == RTAUDIO_SINT24) { 04742 // Channel compensation and/or (de)interleaving only. 04743 INT32 *in = (INT32 *)input; 04744 for (int i=0; i<stream->bufferSize; i++) { 04745 for (j=0; j<channels; j++) { 04746 out[offset_out[j]] = in[offset_in[j]]; 04747 } 04748 in += channels_in; 04749 out += channels_out; 04750 } 04751 } 04752 else if (format_in == RTAUDIO_SINT32) { 04753 INT32 *in = (INT32 *)input; 04754 for (int i=0; i<stream->bufferSize; i++) { 04755 for (j=0; j<channels; j++) { 04756 out[offset_out[j]] = (INT32) (in[offset_in[j]] & 0xffffff00); 04757 } 04758 in += channels_in; 04759 out += channels_out; 04760 } 04761 } 04762 else if (format_in == RTAUDIO_FLOAT32) { 04763 FLOAT32 *in = (FLOAT32 *)input; 04764 for (int i=0; i<stream->bufferSize; i++) { 04765 for (j=0; j<channels; j++) { 04766 out[offset_out[j]] = (INT32) (in[offset_in[j]] * 2147483647.0); 04767 } 04768 in += channels_in; 04769 out += channels_out; 04770 } 04771 } 04772 else if (format_in == RTAUDIO_FLOAT64) { 04773 FLOAT64 *in = (FLOAT64 *)input; 04774 for (int i=0; i<stream->bufferSize; i++) { 04775 for (j=0; j<channels; j++) { 04776 out[offset_out[j]] = (INT32) (in[offset_in[j]] * 2147483647.0); 04777 } 04778 in += channels_in; 04779 out += channels_out; 04780 } 04781 } 04782 } 04783 else if (format_out == RTAUDIO_SINT16) { 04784 INT16 *out = (INT16 *)output; 04785 if (format_in == RTAUDIO_SINT8) { 04786 signed char *in = (signed char *)input; 04787 for (int i=0; i<stream->bufferSize; i++) { 04788 for (j=0; j<channels; j++) { 04789 out[offset_out[j]] = (INT16) in[offset_in[j]]; 04790 out[offset_out[j]] <<= 8; 04791 } 04792 in += channels_in; 04793 out += channels_out; 04794 } 04795 } 04796 else if (format_in == RTAUDIO_SINT16) { 04797 // Channel compensation and/or (de)interleaving only. 04798 INT16 *in = (INT16 *)input; 04799 for (int i=0; i<stream->bufferSize; i++) { 04800 for (j=0; j<channels; j++) { 04801 out[offset_out[j]] = in[offset_in[j]]; 04802 } 04803 in += channels_in; 04804 out += channels_out; 04805 } 04806 } 04807 else if (format_in == RTAUDIO_SINT24) { 04808 INT32 *in = (INT32 *)input; 04809 for (int i=0; i<stream->bufferSize; i++) { 04810 for (j=0; j<channels; j++) { 04811 out[offset_out[j]] = (INT16) ((in[offset_in[j]] >> 16) & 0x0000ffff); 04812 } 04813 in += channels_in; 04814 out += channels_out; 04815 } 04816 } 04817 else if (format_in == RTAUDIO_SINT32) { 04818 INT32 *in = (INT32 *)input; 04819 for (int i=0; i<stream->bufferSize; i++) { 04820 for (j=0; j<channels; j++) { 04821 out[offset_out[j]] = (INT16) ((in[offset_in[j]] >> 16) & 0x0000ffff); 04822 } 04823 in += channels_in; 04824 out += channels_out; 04825 } 04826 } 04827 else if (format_in == RTAUDIO_FLOAT32) { 04828 FLOAT32 *in = (FLOAT32 *)input; 04829 for (int i=0; i<stream->bufferSize; i++) { 04830 for (j=0; j<channels; j++) { 04831 out[offset_out[j]] = (INT16) (in[offset_in[j]] * 32767.0); 04832 } 04833 in += channels_in; 04834 out += channels_out; 04835 } 04836 } 04837 else if (format_in == RTAUDIO_FLOAT64) { 04838 FLOAT64 *in = (FLOAT64 *)input; 04839 for (int i=0; i<stream->bufferSize; i++) { 04840 for (j=0; j<channels; j++) { 04841 out[offset_out[j]] = (INT16) (in[offset_in[j]] * 32767.0); 04842 } 04843 in += channels_in; 04844 out += channels_out; 04845 } 04846 } 04847 } 04848 else if (format_out == RTAUDIO_SINT8) { 04849 signed char *out = (signed char *)output; 04850 if (format_in == RTAUDIO_SINT8) { 04851 // Channel compensation and/or (de)interleaving only. 04852 signed char *in = (signed char *)input; 04853 for (int i=0; i<stream->bufferSize; i++) { 04854 for (j=0; j<channels; j++) { 04855 out[offset_out[j]] = in[offset_in[j]]; 04856 } 04857 in += channels_in; 04858 out += channels_out; 04859 } 04860 } 04861 if (format_in == RTAUDIO_SINT16) { 04862 INT16 *in = (INT16 *)input; 04863 for (int i=0; i<stream->bufferSize; i++) { 04864 for (j=0; j<channels; j++) { 04865 out[offset_out[j]] = (signed char) ((in[offset_in[j]] >> 8) & 0x00ff); 04866 } 04867 in += channels_in; 04868 out += channels_out; 04869 } 04870 } 04871 else if (format_in == RTAUDIO_SINT24) { 04872 INT32 *in = (INT32 *)input; 04873 for (int i=0; i<stream->bufferSize; i++) { 04874 for (j=0; j<channels; j++) { 04875 out[offset_out[j]] = (signed char) ((in[offset_in[j]] >> 24) & 0x000000ff); 04876 } 04877 in += channels_in; 04878 out += channels_out; 04879 } 04880 } 04881 else if (format_in == RTAUDIO_SINT32) { 04882 INT32 *in = (INT32 *)input; 04883 for (int i=0; i<stream->bufferSize; i++) { 04884 for (j=0; j<channels; j++) { 04885 out[offset_out[j]] = (signed char) ((in[offset_in[j]] >> 24) & 0x000000ff); 04886 } 04887 in += channels_in; 04888 out += channels_out; 04889 } 04890 } 04891 else if (format_in == RTAUDIO_FLOAT32) { 04892 FLOAT32 *in = (FLOAT32 *)input; 04893 for (int i=0; i<stream->bufferSize; i++) { 04894 for (j=0; j<channels; j++) { 04895 out[offset_out[j]] = (signed char) (in[offset_in[j]] * 127.0); 04896 } 04897 in += channels_in; 04898 out += channels_out; 04899 } 04900 } 04901 else if (format_in == RTAUDIO_FLOAT64) { 04902 FLOAT64 *in = (FLOAT64 *)input; 04903 for (int i=0; i<stream->bufferSize; i++) { 04904 for (j=0; j<channels; j++) { 04905 out[offset_out[j]] = (signed char) (in[offset_in[j]] * 127.0); 04906 } 04907 in += channels_in; 04908 out += channels_out; 04909 } 04910 } 04911 } 04912 } 04913 04914 void RtAudio :: byteSwapBuffer(char *buffer, int samples, RTAUDIO_FORMAT format) 04915 { 04916 register char val; 04917 register char *ptr; 04918 04919 ptr = buffer; 04920 if (format == RTAUDIO_SINT16) { 04921 for (int i=0; i<samples; i++) { 04922 // Swap 1st and 2nd bytes. 04923 val = *(ptr); 04924 *(ptr) = *(ptr+1); 04925 *(ptr+1) = val; 04926 04927 // Increment 2 bytes. 04928 ptr += 2; 04929 } 04930 } 04931 else if (format == RTAUDIO_SINT24 || 04932 format == RTAUDIO_SINT32 || 04933 format == RTAUDIO_FLOAT32) { 04934 for (int i=0; i<samples; i++) { 04935 // Swap 1st and 4th bytes. 04936 val = *(ptr); 04937 *(ptr) = *(ptr+3); 04938 *(ptr+3) = val; 04939 04940 // Swap 2nd and 3rd bytes. 04941 ptr += 1; 04942 val = *(ptr); 04943 *(ptr) = *(ptr+1); 04944 *(ptr+1) = val; 04945 04946 // Increment 4 bytes. 04947 ptr += 4; 04948 } 04949 } 04950 else if (format == RTAUDIO_FLOAT64) { 04951 for (int i=0; i<samples; i++) { 04952 // Swap 1st and 8th bytes 04953 val = *(ptr); 04954 *(ptr) = *(ptr+7); 04955 *(ptr+7) = val; 04956 04957 // Swap 2nd and 7th bytes 04958 ptr += 1; 04959 val = *(ptr); 04960 *(ptr) = *(ptr+5); 04961 *(ptr+5) = val; 04962 04963 // Swap 3rd and 6th bytes 04964 ptr += 1; 04965 val = *(ptr); 04966 *(ptr) = *(ptr+3); 04967 *(ptr+3) = val; 04968 04969 // Swap 4th and 5th bytes 04970 ptr += 1; 04971 val = *(ptr); 04972 *(ptr) = *(ptr+1); 04973 *(ptr+1) = val; 04974 04975 // Increment 8 bytes. 04976 ptr += 8; 04977 } 04978 } 04979 } 04980 04981 04982 // *************************************************** // 04983 // 04984 // RtError class definition. 04985 // 04986 // *************************************************** // 04987 04988 RtError :: RtError(const char *p, TYPE tipe) 04989 { 04990 type = tipe; 04991 strncpy(error_message, p, 256); 04992 } 04993 04994 RtError :: ~RtError() 04995 { 04996 } 04997 04998 void RtError :: printMessage() 04999 { 05000 printf("\n%s\n\n", error_message); 05001 }