00001
00002
00003
00004
00005
00006
00007
00008 #include "RtAudio.h"
00009 #include <vector>
00010 #include <stdio.h>
00011
00012
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
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
00072 if (devices) free(devices);
00073 error(exception.getType());
00074 }
00075 }
00076
00077 RtAudio :: ~RtAudio()
00078 {
00079
00080 while ( streams.size() )
00081 closeStream( streams.begin()->first );
00082
00083
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;
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
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) {
00139 for (int i=0; i<nDevices; i++) {
00140 if (devices[i].probed == false) {
00141
00142
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) {
00167 for (int i=0; i<nDevices; i++) {
00168 if (devices[i].probed == false) {
00169
00170
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
00192
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
00213 if (devices[device].probed == false) {
00214 clearDeviceInfo(&devices[device]);
00215 probeDeviceInfo(&devices[device]);
00216 }
00217
00218
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
00254
00255
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
00280
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
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
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
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
00359
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
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
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
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
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
00414 return;
00415 goto probe_parameters;
00416 }
00417
00418
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
00432 info->minInputChannels = snd_pcm_hw_params_get_channels_min(params);
00433 info->maxInputChannels = snd_pcm_hw_params_get_channels_max(params);
00434
00435
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
00449
00450
00451
00452
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
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
00478 int dir = 0;
00479 if (snd_pcm_hw_params_test_rate(handle, params, 35500, dir) == 0) {
00480
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
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
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
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
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
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
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
00585 err = snd_pcm_hw_params_set_access(handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED);
00586 if (err < 0) {
00587
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
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
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
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
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
00690
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
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
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
00726 int dir;
00727 int periods = numberOfBuffers;
00728
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
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
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
00774
00775
00776
00777
00778
00779
00780
00781
00782
00783
00784
00785
00786
00787
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
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 {
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
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
00886
00887
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
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);
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
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
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
01120 if (stream->doByteSwap[0])
01121 byteSwapBuffer(buffer, stream->bufferSize * channels, format);
01122
01123
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
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
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
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
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
01223 if (stream->doByteSwap[1])
01224 byteSwapBuffer(buffer, stream->bufferSize * channels, format);
01225
01226
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
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
01279 nDevices = 0;
01280
01281
01282
01283
01284
01285
01286
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) {
01297 if (!strncmp(DAC_NAME, device_name, 8))
01298 dsplink = atoi(&device_name[8]);
01299 }
01300 else if (i > 3) {
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
01317
01318
01319
01320
01321
01322
01323 int fd = 0;
01324 char names[MAX_DEVICES][16];
01325 for (i=-1; i<MAX_DEVICES; i++) {
01326
01327
01328 if (i == -1)
01329 sprintf(device_name, "%s", DAC_NAME);
01330 else if (i == dsplink)
01331 continue;
01332 else
01333 sprintf(device_name, "%s%d", DAC_NAME, i);
01334
01335
01336 fd = open(device_name, O_WRONLY | O_NONBLOCK);
01337 if (fd == -1) {
01338
01339 if (errno != EBUSY && errno != EAGAIN) {
01340
01341 fd = open(device_name, O_RDONLY | O_NONBLOCK);
01342 if (fd == -1) {
01343
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
01350 }
01351 }
01352 }
01353 else {
01354 sprintf(message, "RtAudio: OSS playback device (%s) is busy.", device_name);
01355 error(RtError::WARNING);
01356
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
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
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
01388
01389
01390
01391 fd = open(info->name, O_WRONLY | O_NONBLOCK);
01392 if (fd == -1) {
01393
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
01404 for (i=MAX_CHANNELS; i>0; i--) {
01405 channels = i;
01406 if (ioctl(fd, SNDCTL_DSP_CHANNELS, &channels) == -1) {
01407
01408
01409
01410
01411 continue;
01412 }
01413
01414 if (channels != i ) continue;
01415
01416 break;
01417 }
01418 info->maxOutputChannels = channels;
01419
01420
01421 for (i=1; i<=info->maxOutputChannels; i++) {
01422 channels = i;
01423 if (ioctl(fd, SNDCTL_DSP_CHANNELS, &channels) == -1 || channels != i)
01424 continue;
01425
01426 break;
01427 }
01428 info->minOutputChannels = channels;
01429 close(fd);
01430
01431 capture_probe:
01432
01433 fd = open(info->name, O_RDONLY | O_NONBLOCK);
01434 if (fd == -1) {
01435
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
01444 return;
01445 goto probe_parameters;
01446 }
01447
01448
01449 for (i=MAX_CHANNELS; i>0; i--) {
01450 channels = i;
01451 if (ioctl(fd, SNDCTL_DSP_CHANNELS, &channels) == -1 || channels != i) {
01452 continue;
01453 }
01454
01455 break;
01456 }
01457 info->maxInputChannels = channels;
01458
01459
01460 for (i=1; i<=info->maxInputChannels; i++) {
01461 channels = i;
01462 if (ioctl(fd, SNDCTL_DSP_CHANNELS, &channels) == -1 || channels != i)
01463 continue;
01464
01465 break;
01466 }
01467 info->minInputChannels = channels;
01468 close(fd);
01469
01470
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
01483 for (i=MAX_CHANNELS; i>0; i--) {
01484 channels = i;
01485 if (ioctl(fd, SNDCTL_DSP_CHANNELS, &channels) == -1 || channels != i)
01486 continue;
01487
01488 break;
01489 }
01490 info->maxDuplexChannels = channels;
01491
01492
01493 for (i=1; i<=info->maxDuplexChannels; i++) {
01494 channels = i;
01495 if (ioctl(fd, SNDCTL_DSP_CHANNELS, &channels) == -1 || channels != i)
01496 continue;
01497
01498 break;
01499 }
01500 info->minDuplexChannels = channels;
01501 }
01502 close(fd);
01503
01504 probe_parameters:
01505
01506
01507
01508
01509
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
01522 sprintf(message, "RtAudio: OSS device (%s) won't reopen during probe.",
01523 info->name);
01524 error(RtError::WARNING);
01525 return;
01526 }
01527
01528
01529 i = channels;
01530 if (ioctl(fd, SNDCTL_DSP_CHANNELS, &channels) == -1 || channels != i) {
01531
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
01548 int format;
01549 info->nativeFormats = 0;
01550 #if defined (AFMT_S32_BE)
01551
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
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
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
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
01597 int speed = 1;
01598 if (ioctl(fd, SNDCTL_DSP_SPEED, &speed) == -1) {
01599
01600
01601
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
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:
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 {
01649 if (stream->mode == PLAYBACK && stream->device[0] == device) {
01650
01651 close(stream->handle[0]);
01652 stream->handle[0] = 0;
01653
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
01674 close(fd);
01675 if (mode == PLAYBACK)
01676 fd = open(name, O_WRONLY | O_SYNC);
01677 else {
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
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
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
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
01795 close(fd);
01796 sprintf(message, "RtAudio: OSS device (%s) data format not supported by RtAudio.",
01797 name);
01798 goto error;
01799 }
01800
01801
01802
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 {
01810 if (stream->mode == PLAYBACK && stream->device[0] == device) {
01811
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
01823
01824
01825
01826
01827
01828
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
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
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
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
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
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
01893 stream->deviceFormat[0] = stream->deviceFormat[1];
01894 stream->nDeviceChannels[0] = device_channels;
01895 }
01896
01897
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
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 {
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
01994
01995
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
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);
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
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
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
02184 if (stream->doByteSwap[0])
02185 byteSwapBuffer(buffer, samples, format);
02186
02187
02188 result = write(stream->handle[0], buffer, samples * formatBytes(format));
02189
02190 if (result == -1) {
02191
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
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
02213 result = read(stream->handle[1], buffer, samples * formatBytes(format));
02214
02215 if (result == -1) {
02216
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
02223 if (stream->doByteSwap[1])
02224 byteSwapBuffer(buffer, samples, format);
02225
02226
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
02260
02261 #elif defined(__WINDOWS_DS__) // Windows DirectSound API
02262
02263 #include <dsound.h>
02264
02265
02266
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
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
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
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
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
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
02337
02338
02339 for (i=0; i<count; i++) {
02340 if (info[i].isValid && info[i].id == NULL )
02341 nDevices++;
02342 }
02343
02344
02345
02346 if (nDevices > 0) {
02347 nDevices = 1;
02348 index = 1;
02349 }
02350
02351
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
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
02367 for (i=0; i<nDevices; i++) {
02368 devices[i].id[0] = NULL;
02369 devices[i].id[1] = NULL;
02370 }
02371
02372
02373 if (index)
02374 strcpy(devices[0].name, "Default Input/Output Devices");
02375
02376
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
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
02411
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
02436 info->minInputChannels = 1;
02437 info->maxInputChannels = in_caps.dwChannels;
02438
02439
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;
02479
02480 input->Release();
02481
02482 playback_probe:
02483 LPDIRECTSOUND output;
02484 DSCAPS out_caps;
02485
02486
02487
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
02510 info->minOutputChannels = 1;
02511 info->maxOutputChannels = ( out_caps.dwFlags & DSCAPS_PRIMARYSTEREO ) ? 2 : 1;
02512
02513
02514
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
02523
02524 info->sampleRates[0] = 11025;
02525 info->sampleRates[1] = 48000;
02526 info->nSampleRates = -1;
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
02538
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
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
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
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
02599
02600
02601
02602
02603
02604 long buffer_size;
02605 LPVOID audioPtr;
02606 DWORD dataLen;
02607 int nBuffers;
02608
02609
02610
02611
02612 if (numberOfBuffers < 2)
02613 nBuffers = 2;
02614 else
02615 nBuffers = numberOfBuffers;
02616
02617
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
02625 if ( devices[device].nativeFormats ) {
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
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
02678
02679
02680
02681 ZeroMemory(&bufferDescription, sizeof(DSBUFFERDESC));
02682 bufferDescription.dwSize = sizeof(DSBUFFERDESC);
02683 bufferDescription.dwFlags = DSBCAPS_PRIMARYBUFFER;
02684
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
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
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 );
02711 bufferDescription.dwBufferBytes = buffer_size;
02712 bufferDescription.lpwfxFormat = &waveFormat;
02713
02714
02715
02716 result = object->CreateSoundBuffer(&bufferDescription, &buffer, NULL);
02717 if ( FAILED(result) ) {
02718 bufferDescription.dwFlags = ( DSBCAPS_STICKYFOCUS |
02719 DSBCAPS_GETCURRENTPOSITION2 |
02720 DSBCAPS_LOCSOFTWARE );
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
02732 DSBCAPS dsbcaps;
02733 dsbcaps.dwSize = sizeof(DSBCAPS);
02734 buffer->GetCaps(&dsbcaps);
02735 buffer_size = dsbcaps.dwBufferBytes;
02736
02737
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
02748 ZeroMemory(audioPtr, dataLen);
02749
02750
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
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
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
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
02813 ZeroMemory(audioPtr, dataLen);
02814
02815
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
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
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 {
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
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
02948
02949
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
03043
03044
03045
03046
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
03064 for (int i=0; i<stream->nBuffers; i++) {
03065
03066
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;
03075 DWORD endWrite = nextWritePos + buffer_bytes;
03076
03077
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
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;
03092 }
03093
03094
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
03104 ZeroMemory(buffer1, bufferSize1);
03105 if (buffer2 != NULL) ZeroMemory(buffer2, bufferSize2);
03106
03107
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
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
03138
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
03147 ZeroMemory(buffer1, bufferSize1);
03148
03149
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
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
03191
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
03200 ZeroMemory(audioPtr, dataLen);
03201
03202
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
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
03230
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
03239 ZeroMemory(audioPtr, dataLen);
03240
03241
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
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
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;
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
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;
03310
03311 if (stream->mode == DUPLEX ) {
03312
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);
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
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
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
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
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;
03391 DWORD endWrite = nextWritePos + buffer_bytes;
03392
03393
03394 while ( currentPos < endWrite ) {
03395
03396
03397
03398
03399
03400
03401
03402
03403
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
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;
03417 }
03418
03419
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
03429 CopyMemory(buffer1, buffer, bufferSize1);
03430 if (buffer2 != NULL) CopyMemory(buffer2, buffer+bufferSize1, bufferSize2);
03431
03432
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
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
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;
03470 DWORD endRead = nextReadPos + buffer_bytes;
03471
03472
03473 while ( safePos < endRead ) {
03474
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
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;
03489 }
03490
03491
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
03501 CopyMemory(buffer, buffer1, bufferSize1);
03502 if (buffer2 != NULL) CopyMemory(buffer+bufferSize1, buffer2, bufferSize2);
03503
03504
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
03515
03516
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
03528
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
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
03673 nDevices = 0;
03674
03675
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
03688 nDevices++;
03689
03690
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
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
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
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
03797 info->nativeFormats = (RTAUDIO_FORMAT) 51;
03798 }
03799
03800
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
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
03836
03837
03838
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
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
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
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
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
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);
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
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
03930
03931
03932 result = alSetSampFmt(al_config, AL_SAMPFMT_FLOAT);
03933 stream->deviceFormat[mode] = RTAUDIO_FLOAT32;
03934 }
03935 else if (format == RTAUDIO_SINT32) {
03936
03937
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
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
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
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 {
03992
03993
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
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
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
04036 stream->handle[mode] = port;
04037 stream->doConvertBuffer[mode] = false;
04038 if (stream->userFormat != stream->deviceFormat[mode])
04039 stream->doConvertBuffer[mode] = true;
04040
04041
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 {
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
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
04132
04133
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
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
04226
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);
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
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
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
04311 if (stream->doByteSwap[0])
04312 byteSwapBuffer(buffer, stream->bufferSize * channels, format);
04313
04314
04315 alWriteFrames(stream->handle[0], buffer, stream->bufferSize);
04316 }
04317
04318 if (stream->mode == RECORD || stream->mode == DUPLEX) {
04319
04320
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
04333 alReadFrames(stream->handle[1], buffer, stream->bufferSize);
04334
04335
04336 if (stream->doByteSwap[1])
04337 byteSwapBuffer(buffer, stream->bufferSize * channels, format);
04338
04339
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
04373
04374 #endif
04375
04376
04377
04378
04379
04380
04381
04382
04383
04384
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
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
04414
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
04450
04451
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) {
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 {
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
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
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
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
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
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
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
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
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
04923 val = *(ptr);
04924 *(ptr) = *(ptr+1);
04925 *(ptr+1) = val;
04926
04927
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
04936 val = *(ptr);
04937 *(ptr) = *(ptr+3);
04938 *(ptr+3) = val;
04939
04940
04941 ptr += 1;
04942 val = *(ptr);
04943 *(ptr) = *(ptr+1);
04944 *(ptr+1) = val;
04945
04946
04947 ptr += 4;
04948 }
04949 }
04950 else if (format == RTAUDIO_FLOAT64) {
04951 for (int i=0; i<samples; i++) {
04952
04953 val = *(ptr);
04954 *(ptr) = *(ptr+7);
04955 *(ptr+7) = val;
04956
04957
04958 ptr += 1;
04959 val = *(ptr);
04960 *(ptr) = *(ptr+5);
04961 *(ptr+5) = val;
04962
04963
04964 ptr += 1;
04965 val = *(ptr);
04966 *(ptr) = *(ptr+3);
04967 *(ptr+3) = val;
04968
04969
04970 ptr += 1;
04971 val = *(ptr);
04972 *(ptr) = *(ptr+1);
04973 *(ptr+1) = val;
04974
04975
04976 ptr += 8;
04977 }
04978 }
04979 }
04980
04981
04982
04983
04984
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 }