1 /******************************************/
3 RtAudio - realtime sound I/O C++ class
4 Version 2.0 by Gary P. Scavone, 2001-2002.
6 /******************************************/
12 // Static variable definitions.
13 const unsigned int RtAudio :: SAMPLE_RATES[] = {
14 4000, 5512, 8000, 9600, 11025, 16000, 22050,
15 32000, 44100, 48000, 88200, 96000, 176400, 192000
17 const RtAudio::RTAUDIO_FORMAT RtAudio :: RTAUDIO_SINT8 = 1;
18 const RtAudio::RTAUDIO_FORMAT RtAudio :: RTAUDIO_SINT16 = 2;
19 const RtAudio::RTAUDIO_FORMAT RtAudio :: RTAUDIO_SINT24 = 4;
20 const RtAudio::RTAUDIO_FORMAT RtAudio :: RTAUDIO_SINT32 = 8;
21 const RtAudio::RTAUDIO_FORMAT RtAudio :: RTAUDIO_FLOAT32 = 16;
22 const RtAudio::RTAUDIO_FORMAT RtAudio :: RTAUDIO_FLOAT64 = 32;
24 #if defined(__WINDOWS_DS_)
25 #define MUTEX_INITIALIZE(A) InitializeCriticalSection(A)
26 #define MUTEX_LOCK(A) EnterCriticalSection(A)
27 #define MUTEX_UNLOCK(A) LeaveCriticalSection(A)
28 typedef unsigned THREAD_RETURN;
30 #define MUTEX_INITIALIZE(A) pthread_mutex_init(A, NULL)
31 #define MUTEX_LOCK(A) pthread_mutex_lock(A)
32 #define MUTEX_UNLOCK(A) pthread_mutex_unlock(A)
33 typedef void * THREAD_RETURN;
36 // *************************************************** //
38 // Public common (OS-independent) methods.
40 // *************************************************** //
47 sprintf(message, "RtAudio: no audio devices found!");
48 error(RtAudioError::NO_DEVICES_FOUND);
52 RtAudio :: RtAudio(int *streamID,
53 int outputDevice, int outputChannels,
54 int inputDevice, int inputChannels,
55 RTAUDIO_FORMAT format, int sampleRate,
56 int *bufferSize, int numberOfBuffers)
61 sprintf(message, "RtAudio: no audio devices found!");
62 error(RtAudioError::NO_DEVICES_FOUND);
66 *streamID = openStream(outputDevice, outputChannels, inputDevice, inputChannels,
67 format, sampleRate, bufferSize, numberOfBuffers);
69 catch (RtAudioError &exception) {
70 // deallocate the RTAUDIO_DEVICE structures
71 if (devices) free(devices);
72 error(exception.getType());
78 // close any existing streams
79 while ( streams.size() )
80 closeStream( streams.begin()->first );
82 // deallocate the RTAUDIO_DEVICE structures
83 if (devices) free(devices);
86 int RtAudio :: openStream(int outputDevice, int outputChannels,
87 int inputDevice, int inputChannels,
88 RTAUDIO_FORMAT format, int sampleRate,
89 int *bufferSize, int numberOfBuffers)
91 static int streamKey = 0; // Unique stream identifier ... OK for multiple instances.
93 if (outputChannels < 1 && inputChannels < 1) {
94 sprintf(message,"RtAudio: one or both 'channel' parameters must be greater than zero.");
95 error(RtAudioError::INVALID_PARAMETER);
98 if ( formatBytes(format) == 0 ) {
99 sprintf(message,"RtAudio: 'format' parameter value is undefined.");
100 error(RtAudioError::INVALID_PARAMETER);
103 if ( outputChannels > 0 ) {
104 if (outputDevice >= nDevices || outputDevice < 0) {
105 sprintf(message,"RtAudio: 'outputDevice' parameter value (%d) is invalid.", outputDevice);
106 error(RtAudioError::INVALID_PARAMETER);
110 if ( inputChannels > 0 ) {
111 if (inputDevice >= nDevices || inputDevice < 0) {
112 sprintf(message,"RtAudio: 'inputDevice' parameter value (%d) is invalid.", inputDevice);
113 error(RtAudioError::INVALID_PARAMETER);
117 // Allocate a new stream structure.
118 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) calloc(1, sizeof(RTAUDIO_STREAM));
119 if (stream == NULL) {
120 sprintf(message, "RtAudio: memory allocation error!");
121 error(RtAudioError::MEMORY_ERROR);
123 streams[++streamKey] = (void *) stream;
124 stream->mode = UNINITIALIZED;
126 bool result = SUCCESS;
130 if ( outputChannels > 0 ) {
132 device = outputDevice;
134 channels = outputChannels;
136 if (device == 0) { // Try default device first.
137 for (int i=0; i<nDevices; i++) {
138 if (devices[i].probed == false) {
139 // If the device wasn't successfully probed before, try it
141 clearDeviceInfo(&devices[i]);
142 probeDeviceInfo(&devices[i]);
143 if (devices[i].probed == false)
146 result = probeDeviceOpen(i, stream, mode, channels, sampleRate,
147 format, bufferSize, numberOfBuffers);
148 if (result == SUCCESS)
153 result = probeDeviceOpen(device, stream, mode, channels, sampleRate,
154 format, bufferSize, numberOfBuffers);
158 if ( inputChannels > 0 && result == SUCCESS ) {
160 device = inputDevice;
162 channels = inputChannels;
164 if (device == 0) { // Try default device first.
165 for (int i=0; i<nDevices; i++) {
166 if (devices[i].probed == false) {
167 // If the device wasn't successfully probed before, try it
169 clearDeviceInfo(&devices[i]);
170 probeDeviceInfo(&devices[i]);
171 if (devices[i].probed == false)
174 result = probeDeviceOpen(i, stream, mode, channels, sampleRate,
175 format, bufferSize, numberOfBuffers);
176 if (result == SUCCESS)
181 result = probeDeviceOpen(device, stream, mode, channels, sampleRate,
182 format, bufferSize, numberOfBuffers);
186 if ( result == SUCCESS ) {
187 MUTEX_INITIALIZE(&stream->mutex);
191 // If we get here, all attempted probes failed. Close any opened
192 // devices and delete the allocated stream.
193 closeStream(streamKey);
194 sprintf(message,"RtAudio: no devices found for given parameters.");
195 error(RtAudioError::INVALID_PARAMETER);
200 int RtAudio :: getDeviceCount(void)
205 void RtAudio :: getDeviceInfo(int device, RTAUDIO_DEVICE *info)
207 if (device >= nDevices || device < 0) {
208 sprintf(message, "RtAudio: invalid device specifier (%d)!", device);
209 error(RtAudioError::INVALID_DEVICE);
212 // If the device wasn't successfully probed before, try it again.
213 if (devices[device].probed == false) {
214 clearDeviceInfo(&devices[device]);
215 probeDeviceInfo(&devices[device]);
218 // Clear the info structure.
219 memset(info, 0, sizeof(RTAUDIO_DEVICE));
221 strncpy(info->name, devices[device].name, 128);
222 info->probed = devices[device].probed;
223 if ( info->probed == true ) {
224 info->maxOutputChannels = devices[device].maxOutputChannels;
225 info->maxInputChannels = devices[device].maxInputChannels;
226 info->maxDuplexChannels = devices[device].maxDuplexChannels;
227 info->minOutputChannels = devices[device].minOutputChannels;
228 info->minInputChannels = devices[device].minInputChannels;
229 info->minDuplexChannels = devices[device].minDuplexChannels;
230 info->hasDuplexSupport = devices[device].hasDuplexSupport;
231 info->nSampleRates = devices[device].nSampleRates;
232 if (info->nSampleRates == -1) {
233 info->sampleRates[0] = devices[device].sampleRates[0];
234 info->sampleRates[1] = devices[device].sampleRates[1];
237 for (int i=0; i<info->nSampleRates; i++)
238 info->sampleRates[i] = devices[device].sampleRates[i];
240 info->nativeFormats = devices[device].nativeFormats;
246 char * const RtAudio :: getStreamBuffer(int streamID)
248 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamID);
250 return stream->userBuffer;
253 // This global structure is used to pass information to the thread
254 // function. I tried other methods but had intermittent errors due to
255 // variable persistence during thread startup.
261 #if defined(__WINDOWS_DS_)
262 extern "C" unsigned __stdcall callbackHandler(void *ptr);
264 extern "C" void *callbackHandler(void *ptr);
267 void RtAudio :: setStreamCallback(int streamID, RTAUDIO_CALLBACK callback, void *userData)
269 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamID);
271 stream->callback = callback;
272 stream->userData = userData;
273 stream->usingCallback = true;
274 thread_info.object = this;
275 thread_info.streamID = streamID;
278 #if defined(__WINDOWS_DS_)
280 stream->thread = _beginthreadex(NULL, 0, &callbackHandler,
281 &stream->usingCallback, 0, &thread_id);
282 if (stream->thread == 0) err = -1;
283 // When spawning multiple threads in quick succession, it appears to be
284 // necessary to wait a bit for each to initialize ... another windism!
287 err = pthread_create(&stream->thread, NULL, callbackHandler, &stream->usingCallback);
291 stream->usingCallback = false;
292 sprintf(message, "RtAudio: error starting callback thread!");
293 error(RtAudioError::THREAD_ERROR);
297 // *************************************************** //
299 // OS/API-specific methods.
301 // *************************************************** //
303 #if defined(__LINUX_ALSA_)
305 void RtAudio :: initialize(void)
307 int card, err, device;
308 int devices_per_card[32] = {0};
311 snd_ctl_card_info_t *info;
312 snd_ctl_card_info_alloca(&info);
314 // Count cards and devices
317 snd_card_next(&card);
319 sprintf(name, "hw:%d", card);
320 err = snd_ctl_open(&handle, name, 0);
322 sprintf(message, "RtAudio: ALSA control open (%i): %s.", card, snd_strerror(err));
323 error(RtAudioError::WARNING);
326 err = snd_ctl_card_info(handle, info);
328 sprintf(message, "RtAudio: ALSA control hardware info (%i): %s.", card, snd_strerror(err));
329 error(RtAudioError::WARNING);
334 err = snd_ctl_pcm_next_device(handle, &device);
336 sprintf(message, "RtAudio: ALSA control next device (%i): %s.", card, snd_strerror(err));
337 error(RtAudioError::WARNING);
343 devices_per_card[card]++;
347 snd_ctl_close(handle);
348 snd_card_next(&card);
351 if (nDevices == 0) return;
353 // Allocate the RTAUDIO_DEVICE structures.
354 devices = (RTAUDIO_DEVICE *) calloc(nDevices, sizeof(RTAUDIO_DEVICE));
355 if (devices == NULL) {
356 sprintf(message, "RtAudio: memory allocation error!");
357 error(RtAudioError::MEMORY_ERROR);
360 // Write device ascii identifiers to device structures and then
361 // probe the device capabilities.
364 for (int i=0; i<nDevices; i++) {
365 if (devices_per_card[card])
366 sprintf(devices[i].name, "hw:%d,%d", card, device);
367 if (devices_per_card[card] <= device+1) {
373 probeDeviceInfo(&devices[i]);
379 void RtAudio :: probeDeviceInfo(RTAUDIO_DEVICE *info)
382 int open_mode = SND_PCM_ASYNC;
384 snd_pcm_stream_t stream;
386 // First try for playback
387 stream = SND_PCM_STREAM_PLAYBACK;
388 err = snd_pcm_open(&handle, info->name, stream, open_mode);
390 sprintf(message, "RtAudio: ALSA pcm playback open (%s): %s.",
391 info->name, snd_strerror(err));
392 error(RtAudioError::WARNING);
396 snd_pcm_hw_params_t *params;
397 snd_pcm_hw_params_alloca(¶ms);
399 // We have an open device ... allocate the parameter structure.
400 err = snd_pcm_hw_params_any(handle, params);
402 snd_pcm_close(handle);
403 sprintf(message, "RtAudio: ALSA hardware probe error (%s): %s.",
404 info->name, snd_strerror(err));
405 error(RtAudioError::WARNING);
409 // Get output channel information.
410 info->minOutputChannels = snd_pcm_hw_params_get_channels_min(params);
411 info->maxOutputChannels = snd_pcm_hw_params_get_channels_max(params);
413 snd_pcm_close(handle);
416 // Now try for capture
417 stream = SND_PCM_STREAM_CAPTURE;
418 err = snd_pcm_open(&handle, info->name, stream, open_mode);
420 sprintf(message, "RtAudio: ALSA pcm capture open (%s): %s.",
421 info->name, snd_strerror(err));
422 error(RtAudioError::WARNING);
423 if (info->maxOutputChannels == 0)
424 // didn't open for playback either ... device invalid
426 goto probe_parameters;
429 // We have an open capture device ... allocate the parameter structure.
430 err = snd_pcm_hw_params_any(handle, params);
432 snd_pcm_close(handle);
433 sprintf(message, "RtAudio: ALSA hardware probe error (%s): %s.",
434 info->name, snd_strerror(err));
435 error(RtAudioError::WARNING);
436 if (info->maxOutputChannels > 0)
437 goto probe_parameters;
442 // Get input channel information.
443 info->minInputChannels = snd_pcm_hw_params_get_channels_min(params);
444 info->maxInputChannels = snd_pcm_hw_params_get_channels_max(params);
446 // If device opens for both playback and capture, we determine the channels.
447 if (info->maxOutputChannels == 0 || info->maxInputChannels == 0)
448 goto probe_parameters;
450 info->hasDuplexSupport = true;
451 info->maxDuplexChannels = (info->maxOutputChannels > info->maxInputChannels) ?
452 info->maxInputChannels : info->maxOutputChannels;
453 info->minDuplexChannels = (info->minOutputChannels > info->minInputChannels) ?
454 info->minInputChannels : info->minOutputChannels;
456 snd_pcm_close(handle);
459 // At this point, we just need to figure out the supported data formats and sample rates.
460 // We'll proceed by openning the device in the direction with the maximum number of channels,
461 // or playback if they are equal. This might limit our sample rate options, but so be it.
463 if (info->maxOutputChannels >= info->maxInputChannels)
464 stream = SND_PCM_STREAM_PLAYBACK;
466 stream = SND_PCM_STREAM_CAPTURE;
468 err = snd_pcm_open(&handle, info->name, stream, open_mode);
470 sprintf(message, "RtAudio: ALSA pcm (%s) won't reopen during probe: %s.",
471 info->name, snd_strerror(err));
472 error(RtAudioError::WARNING);
476 // We have an open device ... allocate the parameter structure.
477 err = snd_pcm_hw_params_any(handle, params);
479 snd_pcm_close(handle);
480 sprintf(message, "RtAudio: ALSA hardware reopen probe error (%s): %s.",
481 info->name, snd_strerror(err));
482 error(RtAudioError::WARNING);
486 // Test a non-standard sample rate to see if continuous rate is supported.
488 if (snd_pcm_hw_params_test_rate(handle, params, 35500, dir) == 0) {
489 // It appears that continuous sample rate support is available.
490 info->nSampleRates = -1;
491 info->sampleRates[0] = snd_pcm_hw_params_get_rate_min(params, &dir);
492 info->sampleRates[1] = snd_pcm_hw_params_get_rate_max(params, &dir);
495 // No continuous rate support ... test our discrete set of sample rate values.
496 info->nSampleRates = 0;
497 for (int i=0; i<MAX_SAMPLE_RATES; i++) {
498 if (snd_pcm_hw_params_test_rate(handle, params, SAMPLE_RATES[i], dir) == 0) {
499 info->sampleRates[info->nSampleRates] = SAMPLE_RATES[i];
500 info->nSampleRates++;
503 if (info->nSampleRates == 0) {
504 snd_pcm_close(handle);
509 // Probe the supported data formats ... we don't care about endian-ness just yet
510 snd_pcm_format_t format;
511 info->nativeFormats = 0;
512 format = SND_PCM_FORMAT_S8;
513 if (snd_pcm_hw_params_test_format(handle, params, format) == 0)
514 info->nativeFormats |= RTAUDIO_SINT8;
515 format = SND_PCM_FORMAT_S16;
516 if (snd_pcm_hw_params_test_format(handle, params, format) == 0)
517 info->nativeFormats |= RTAUDIO_SINT16;
518 format = SND_PCM_FORMAT_S24;
519 if (snd_pcm_hw_params_test_format(handle, params, format) == 0)
520 info->nativeFormats |= RTAUDIO_SINT24;
521 format = SND_PCM_FORMAT_S32;
522 if (snd_pcm_hw_params_test_format(handle, params, format) == 0)
523 info->nativeFormats |= RTAUDIO_SINT32;
524 format = SND_PCM_FORMAT_FLOAT;
525 if (snd_pcm_hw_params_test_format(handle, params, format) == 0)
526 info->nativeFormats |= RTAUDIO_FLOAT32;
527 format = SND_PCM_FORMAT_FLOAT64;
528 if (snd_pcm_hw_params_test_format(handle, params, format) == 0)
529 info->nativeFormats |= RTAUDIO_FLOAT64;
531 // Check that we have at least one supported format
532 if (info->nativeFormats == 0) {
533 snd_pcm_close(handle);
534 sprintf(message, "RtAudio: ALSA PCM device (%s) data format not supported by RtAudio.",
536 error(RtAudioError::WARNING);
540 // That's all ... close the device and return
541 snd_pcm_close(handle);
546 bool RtAudio :: probeDeviceOpen(int device, RTAUDIO_STREAM *stream,
547 STREAM_MODE mode, int channels,
548 int sampleRate, RTAUDIO_FORMAT format,
549 int *bufferSize, int numberOfBuffers)
551 #if defined(RTAUDIO_DEBUG)
553 snd_output_stdio_attach(&out, stderr, 0);
556 // I'm not using the "plug" interface ... too much inconsistent behavior.
557 const char *name = devices[device].name;
559 snd_pcm_stream_t alsa_stream;
560 if (mode == PLAYBACK)
561 alsa_stream = SND_PCM_STREAM_PLAYBACK;
563 alsa_stream = SND_PCM_STREAM_CAPTURE;
567 int alsa_open_mode = SND_PCM_ASYNC;
568 err = snd_pcm_open(&handle, name, alsa_stream, alsa_open_mode);
570 sprintf(message,"RtAudio: ALSA pcm device (%s) won't open: %s.",
571 name, snd_strerror(err));
572 error(RtAudioError::WARNING);
576 // Fill the parameter structure.
577 snd_pcm_hw_params_t *hw_params;
578 snd_pcm_hw_params_alloca(&hw_params);
579 err = snd_pcm_hw_params_any(handle, hw_params);
581 snd_pcm_close(handle);
582 sprintf(message, "RtAudio: ALSA error getting parameter handle (%s): %s.",
583 name, snd_strerror(err));
584 error(RtAudioError::WARNING);
588 #if defined(RTAUDIO_DEBUG)
589 fprintf(stderr, "\nRtAudio: ALSA dump hardware params just after device open:\n\n");
590 snd_pcm_hw_params_dump(hw_params, out);
593 // Set access ... try interleaved access first, then non-interleaved
594 err = snd_pcm_hw_params_set_access(handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED);
596 // No interleave support ... try non-interleave.
597 err = snd_pcm_hw_params_set_access(handle, hw_params, SND_PCM_ACCESS_RW_NONINTERLEAVED);
599 snd_pcm_close(handle);
600 sprintf(message, "RtAudio: ALSA error setting access ( (%s): %s.",
601 name, snd_strerror(err));
602 error(RtAudioError::WARNING);
605 stream->deInterleave[mode] = true;
608 // Determine how to set the device format.
609 stream->userFormat = format;
610 snd_pcm_format_t device_format;
612 if (format == RTAUDIO_SINT8)
613 device_format = SND_PCM_FORMAT_S8;
614 else if (format == RTAUDIO_SINT16)
615 device_format = SND_PCM_FORMAT_S16;
616 else if (format == RTAUDIO_SINT24)
617 device_format = SND_PCM_FORMAT_S24;
618 else if (format == RTAUDIO_SINT32)
619 device_format = SND_PCM_FORMAT_S32;
620 else if (format == RTAUDIO_FLOAT32)
621 device_format = SND_PCM_FORMAT_FLOAT;
622 else if (format == RTAUDIO_FLOAT64)
623 device_format = SND_PCM_FORMAT_FLOAT64;
625 if (snd_pcm_hw_params_test_format(handle, hw_params, device_format) == 0) {
626 stream->deviceFormat[mode] = format;
630 // The user requested format is not natively supported by the device.
631 device_format = SND_PCM_FORMAT_FLOAT64;
632 if (snd_pcm_hw_params_test_format(handle, hw_params, device_format) == 0) {
633 stream->deviceFormat[mode] = RTAUDIO_FLOAT64;
637 device_format = SND_PCM_FORMAT_FLOAT;
638 if (snd_pcm_hw_params_test_format(handle, hw_params, device_format) == 0) {
639 stream->deviceFormat[mode] = RTAUDIO_FLOAT32;
643 device_format = SND_PCM_FORMAT_S32;
644 if (snd_pcm_hw_params_test_format(handle, hw_params, device_format) == 0) {
645 stream->deviceFormat[mode] = RTAUDIO_SINT32;
649 device_format = SND_PCM_FORMAT_S24;
650 if (snd_pcm_hw_params_test_format(handle, hw_params, device_format) == 0) {
651 stream->deviceFormat[mode] = RTAUDIO_SINT24;
655 device_format = SND_PCM_FORMAT_S16;
656 if (snd_pcm_hw_params_test_format(handle, hw_params, device_format) == 0) {
657 stream->deviceFormat[mode] = RTAUDIO_SINT16;
661 device_format = SND_PCM_FORMAT_S8;
662 if (snd_pcm_hw_params_test_format(handle, hw_params, device_format) == 0) {
663 stream->deviceFormat[mode] = RTAUDIO_SINT8;
667 // If we get here, no supported format was found.
668 sprintf(message,"RtAudio: ALSA pcm device (%s) data format not supported by RtAudio.", name);
669 snd_pcm_close(handle);
670 error(RtAudioError::WARNING);
674 err = snd_pcm_hw_params_set_format(handle, hw_params, device_format);
676 snd_pcm_close(handle);
677 sprintf(message, "RtAudio: ALSA error setting format (%s): %s.",
678 name, snd_strerror(err));
679 error(RtAudioError::WARNING);
683 // Determine whether byte-swaping is necessary.
684 stream->doByteSwap[mode] = false;
685 if (device_format != SND_PCM_FORMAT_S8) {
686 err = snd_pcm_format_cpu_endian(device_format);
688 stream->doByteSwap[mode] = true;
690 snd_pcm_close(handle);
691 sprintf(message, "RtAudio: ALSA error getting format endian-ness (%s): %s.",
692 name, snd_strerror(err));
693 error(RtAudioError::WARNING);
698 // Determine the number of channels for this device. We support a possible
699 // minimum device channel number > than the value requested by the user.
700 stream->nUserChannels[mode] = channels;
701 int device_channels = snd_pcm_hw_params_get_channels_max(hw_params);
702 if (device_channels < channels) {
703 snd_pcm_close(handle);
704 sprintf(message, "RtAudio: channels (%d) not supported by device (%s).",
706 error(RtAudioError::WARNING);
710 device_channels = snd_pcm_hw_params_get_channels_min(hw_params);
711 if (device_channels < channels) device_channels = channels;
712 stream->nDeviceChannels[mode] = device_channels;
714 // Set the device channels.
715 err = snd_pcm_hw_params_set_channels(handle, hw_params, device_channels);
717 snd_pcm_close(handle);
718 sprintf(message, "RtAudio: ALSA error setting channels (%d) on device (%s): %s.",
719 device_channels, name, snd_strerror(err));
720 error(RtAudioError::WARNING);
724 // Set the sample rate.
725 err = snd_pcm_hw_params_set_rate(handle, hw_params, (unsigned int)sampleRate, 0);
727 snd_pcm_close(handle);
728 sprintf(message, "RtAudio: ALSA error setting sample rate (%d) on device (%s): %s.",
729 sampleRate, name, snd_strerror(err));
730 error(RtAudioError::WARNING);
734 // Set the buffer number, which in ALSA is referred to as the "period".
736 int periods = numberOfBuffers;
737 // Even though the hardware might allow 1 buffer, it won't work reliably.
738 if (periods < 2) periods = 2;
739 err = snd_pcm_hw_params_get_periods_min(hw_params, &dir);
740 if (err > periods) periods = err;
742 err = snd_pcm_hw_params_set_periods(handle, hw_params, periods, 0);
744 snd_pcm_close(handle);
745 sprintf(message, "RtAudio: ALSA error setting periods (%s): %s.",
746 name, snd_strerror(err));
747 error(RtAudioError::WARNING);
751 // Set the buffer (or period) size.
752 err = snd_pcm_hw_params_get_period_size_min(hw_params, &dir);
753 if (err > *bufferSize) *bufferSize = err;
755 err = snd_pcm_hw_params_set_period_size(handle, hw_params, *bufferSize, 0);
757 snd_pcm_close(handle);
758 sprintf(message, "RtAudio: ALSA error setting period size (%s): %s.",
759 name, snd_strerror(err));
760 error(RtAudioError::WARNING);
764 stream->bufferSize = *bufferSize;
766 // Install the hardware configuration
767 err = snd_pcm_hw_params(handle, hw_params);
769 snd_pcm_close(handle);
770 sprintf(message, "RtAudio: ALSA error installing hardware configuration (%s): %s.",
771 name, snd_strerror(err));
772 error(RtAudioError::WARNING);
776 #if defined(RTAUDIO_DEBUG)
777 fprintf(stderr, "\nRtAudio: ALSA dump hardware params after installation:\n\n");
778 snd_pcm_hw_params_dump(hw_params, out);
782 // Install the software configuration
783 snd_pcm_sw_params_t *sw_params = NULL;
784 snd_pcm_sw_params_alloca(&sw_params);
785 snd_pcm_sw_params_current(handle, sw_params);
786 err = snd_pcm_sw_params(handle, sw_params);
788 snd_pcm_close(handle);
789 sprintf(message, "RtAudio: ALSA error installing software configuration (%s): %s.",
790 name, snd_strerror(err));
791 error(RtAudioError::WARNING);
796 // Set handle and flags for buffer conversion
797 stream->handle[mode] = handle;
798 stream->doConvertBuffer[mode] = false;
799 if (stream->userFormat != stream->deviceFormat[mode])
800 stream->doConvertBuffer[mode] = true;
801 if (stream->nUserChannels[mode] < stream->nDeviceChannels[mode])
802 stream->doConvertBuffer[mode] = true;
803 if (stream->nUserChannels[mode] > 1 && stream->deInterleave[mode])
804 stream->doConvertBuffer[mode] = true;
806 // Allocate necessary internal buffers
807 if ( stream->nUserChannels[0] != stream->nUserChannels[1] ) {
810 if (stream->nUserChannels[0] >= stream->nUserChannels[1])
811 buffer_bytes = stream->nUserChannels[0];
813 buffer_bytes = stream->nUserChannels[1];
815 buffer_bytes *= *bufferSize * formatBytes(stream->userFormat);
816 if (stream->userBuffer) free(stream->userBuffer);
817 stream->userBuffer = (char *) calloc(buffer_bytes, 1);
818 if (stream->userBuffer == NULL)
822 if ( stream->doConvertBuffer[mode] ) {
825 bool makeBuffer = true;
826 if ( mode == PLAYBACK )
827 buffer_bytes = stream->nDeviceChannels[0] * formatBytes(stream->deviceFormat[0]);
828 else { // mode == RECORD
829 buffer_bytes = stream->nDeviceChannels[1] * formatBytes(stream->deviceFormat[1]);
830 if ( stream->mode == PLAYBACK ) {
831 long bytes_out = stream->nDeviceChannels[0] * formatBytes(stream->deviceFormat[0]);
832 if ( buffer_bytes > bytes_out )
833 buffer_bytes = (buffer_bytes > bytes_out) ? buffer_bytes : bytes_out;
840 buffer_bytes *= *bufferSize;
841 if (stream->deviceBuffer) free(stream->deviceBuffer);
842 stream->deviceBuffer = (char *) calloc(buffer_bytes, 1);
843 if (stream->deviceBuffer == NULL)
848 stream->device[mode] = device;
849 stream->state = STREAM_STOPPED;
850 if ( stream->mode == PLAYBACK && mode == RECORD )
851 // We had already set up an output stream.
852 stream->mode = DUPLEX;
855 stream->nBuffers = periods;
856 stream->sampleRate = sampleRate;
861 if (stream->handle[0]) {
862 snd_pcm_close(stream->handle[0]);
863 stream->handle[0] = 0;
865 if (stream->handle[1]) {
866 snd_pcm_close(stream->handle[1]);
867 stream->handle[1] = 0;
869 if (stream->userBuffer) {
870 free(stream->userBuffer);
871 stream->userBuffer = 0;
873 sprintf(message, "RtAudio: ALSA error allocating buffer memory (%s).", name);
874 error(RtAudioError::WARNING);
878 void RtAudio :: cancelStreamCallback(int streamID)
880 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamID);
882 if (stream->usingCallback) {
883 stream->usingCallback = false;
884 pthread_cancel(stream->thread);
885 pthread_join(stream->thread, NULL);
887 stream->callback = NULL;
888 stream->userData = NULL;
892 void RtAudio :: closeStream(int streamID)
894 // We don't want an exception to be thrown here because this
895 // function is called by our class destructor. So, do our own
897 if ( streams.find( streamID ) == streams.end() ) {
898 sprintf(message, "RtAudio: invalid stream identifier!");
899 error(RtAudioError::WARNING);
903 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) streams[streamID];
905 if (stream->usingCallback) {
906 pthread_cancel(stream->thread);
907 pthread_join(stream->thread, NULL);
910 if (stream->state == STREAM_RUNNING) {
911 if (stream->mode == PLAYBACK || stream->mode == DUPLEX)
912 snd_pcm_drop(stream->handle[0]);
913 if (stream->mode == RECORD || stream->mode == DUPLEX)
914 snd_pcm_drop(stream->handle[1]);
917 pthread_mutex_destroy(&stream->mutex);
919 if (stream->handle[0])
920 snd_pcm_close(stream->handle[0]);
922 if (stream->handle[1])
923 snd_pcm_close(stream->handle[1]);
925 if (stream->userBuffer)
926 free(stream->userBuffer);
928 if (stream->deviceBuffer)
929 free(stream->deviceBuffer);
932 streams.erase(streamID);
935 void RtAudio :: startStream(int streamID)
937 // This method calls snd_pcm_prepare if the device isn't already in that state.
939 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamID);
941 MUTEX_LOCK(&stream->mutex);
943 if (stream->state == STREAM_RUNNING)
947 snd_pcm_state_t state;
948 if (stream->mode == PLAYBACK || stream->mode == DUPLEX) {
949 state = snd_pcm_state(stream->handle[0]);
950 if (state != SND_PCM_STATE_PREPARED) {
951 err = snd_pcm_prepare(stream->handle[0]);
953 sprintf(message, "RtAudio: ALSA error preparing pcm device (%s): %s.",
954 devices[stream->device[0]].name, snd_strerror(err));
955 MUTEX_UNLOCK(&stream->mutex);
956 error(RtAudioError::DRIVER_ERROR);
961 if (stream->mode == RECORD || stream->mode == DUPLEX) {
962 state = snd_pcm_state(stream->handle[1]);
963 if (state != SND_PCM_STATE_PREPARED) {
964 err = snd_pcm_prepare(stream->handle[1]);
966 sprintf(message, "RtAudio: ALSA error preparing pcm device (%s): %s.",
967 devices[stream->device[1]].name, snd_strerror(err));
968 MUTEX_UNLOCK(&stream->mutex);
969 error(RtAudioError::DRIVER_ERROR);
973 stream->state = STREAM_RUNNING;
976 MUTEX_UNLOCK(&stream->mutex);
979 void RtAudio :: stopStream(int streamID)
981 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamID);
983 MUTEX_LOCK(&stream->mutex);
985 if (stream->state == STREAM_STOPPED)
989 if (stream->mode == PLAYBACK || stream->mode == DUPLEX) {
990 err = snd_pcm_drain(stream->handle[0]);
992 sprintf(message, "RtAudio: ALSA error draining pcm device (%s): %s.",
993 devices[stream->device[0]].name, snd_strerror(err));
994 MUTEX_UNLOCK(&stream->mutex);
995 error(RtAudioError::DRIVER_ERROR);
999 if (stream->mode == RECORD || stream->mode == DUPLEX) {
1000 err = snd_pcm_drain(stream->handle[1]);
1002 sprintf(message, "RtAudio: ALSA error draining pcm device (%s): %s.",
1003 devices[stream->device[1]].name, snd_strerror(err));
1004 MUTEX_UNLOCK(&stream->mutex);
1005 error(RtAudioError::DRIVER_ERROR);
1008 stream->state = STREAM_STOPPED;
1011 MUTEX_UNLOCK(&stream->mutex);
1014 void RtAudio :: abortStream(int streamID)
1016 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamID);
1018 MUTEX_LOCK(&stream->mutex);
1020 if (stream->state == STREAM_STOPPED)
1024 if (stream->mode == PLAYBACK || stream->mode == DUPLEX) {
1025 err = snd_pcm_drop(stream->handle[0]);
1027 sprintf(message, "RtAudio: ALSA error draining pcm device (%s): %s.",
1028 devices[stream->device[0]].name, snd_strerror(err));
1029 MUTEX_UNLOCK(&stream->mutex);
1030 error(RtAudioError::DRIVER_ERROR);
1034 if (stream->mode == RECORD || stream->mode == DUPLEX) {
1035 err = snd_pcm_drop(stream->handle[1]);
1037 sprintf(message, "RtAudio: ALSA error draining pcm device (%s): %s.",
1038 devices[stream->device[1]].name, snd_strerror(err));
1039 MUTEX_UNLOCK(&stream->mutex);
1040 error(RtAudioError::DRIVER_ERROR);
1043 stream->state = STREAM_STOPPED;
1046 MUTEX_UNLOCK(&stream->mutex);
1049 int RtAudio :: streamWillBlock(int streamID)
1051 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamID);
1053 MUTEX_LOCK(&stream->mutex);
1055 int err = 0, frames = 0;
1056 if (stream->state == STREAM_STOPPED)
1059 if (stream->mode == PLAYBACK || stream->mode == DUPLEX) {
1060 err = snd_pcm_avail_update(stream->handle[0]);
1062 sprintf(message, "RtAudio: ALSA error getting available frames for device (%s): %s.",
1063 devices[stream->device[0]].name, snd_strerror(err));
1064 MUTEX_UNLOCK(&stream->mutex);
1065 error(RtAudioError::DRIVER_ERROR);
1071 if (stream->mode == RECORD || stream->mode == DUPLEX) {
1072 err = snd_pcm_avail_update(stream->handle[1]);
1074 sprintf(message, "RtAudio: ALSA error getting available frames for device (%s): %s.",
1075 devices[stream->device[1]].name, snd_strerror(err));
1076 MUTEX_UNLOCK(&stream->mutex);
1077 error(RtAudioError::DRIVER_ERROR);
1079 if (frames > err) frames = err;
1082 frames = stream->bufferSize - frames;
1083 if (frames < 0) frames = 0;
1086 MUTEX_UNLOCK(&stream->mutex);
1090 void RtAudio :: tickStream(int streamID)
1092 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamID);
1095 if (stream->state == STREAM_STOPPED) {
1096 if (stream->usingCallback) usleep(50000); // sleep 50 milliseconds
1099 else if (stream->usingCallback) {
1100 stopStream = stream->callback(stream->userBuffer, stream->bufferSize, stream->userData);
1103 MUTEX_LOCK(&stream->mutex);
1105 // The state might change while waiting on a mutex.
1106 if (stream->state == STREAM_STOPPED)
1112 RTAUDIO_FORMAT format;
1113 if (stream->mode == PLAYBACK || stream->mode == DUPLEX) {
1115 // Setup parameters and do buffer conversion if necessary.
1116 if (stream->doConvertBuffer[0]) {
1117 convertStreamBuffer(stream, PLAYBACK);
1118 buffer = stream->deviceBuffer;
1119 channels = stream->nDeviceChannels[0];
1120 format = stream->deviceFormat[0];
1123 buffer = stream->userBuffer;
1124 channels = stream->nUserChannels[0];
1125 format = stream->userFormat;
1128 // Do byte swapping if necessary.
1129 if (stream->doByteSwap[0])
1130 byteSwapBuffer(buffer, stream->bufferSize * channels, format);
1132 // Write samples to device in interleaved/non-interleaved format.
1133 if (stream->deInterleave[0]) {
1134 void *bufs[channels];
1135 size_t offset = stream->bufferSize * formatBytes(format);
1136 for (int i=0; i<channels; i++)
1137 bufs[i] = (void *) (buffer + (i * offset));
1138 err = snd_pcm_writen(stream->handle[0], bufs, stream->bufferSize);
1141 err = snd_pcm_writei(stream->handle[0], buffer, stream->bufferSize);
1143 if (err < stream->bufferSize) {
1144 // Either an error or underrun occured.
1145 if (err == -EPIPE) {
1146 snd_pcm_state_t state = snd_pcm_state(stream->handle[0]);
1147 if (state == SND_PCM_STATE_XRUN) {
1148 sprintf(message, "RtAudio: ALSA underrun detected.");
1149 error(RtAudioError::WARNING);
1150 err = snd_pcm_prepare(stream->handle[0]);
1152 sprintf(message, "RtAudio: ALSA error preparing handle after underrun: %s.",
1154 MUTEX_UNLOCK(&stream->mutex);
1155 error(RtAudioError::DRIVER_ERROR);
1159 sprintf(message, "RtAudio: ALSA error, current state is %s.",
1160 snd_pcm_state_name(state));
1161 MUTEX_UNLOCK(&stream->mutex);
1162 error(RtAudioError::DRIVER_ERROR);
1167 sprintf(message, "RtAudio: ALSA audio write error for device (%s): %s.",
1168 devices[stream->device[0]].name, snd_strerror(err));
1169 MUTEX_UNLOCK(&stream->mutex);
1170 error(RtAudioError::DRIVER_ERROR);
1175 if (stream->mode == RECORD || stream->mode == DUPLEX) {
1177 // Setup parameters.
1178 if (stream->doConvertBuffer[1]) {
1179 buffer = stream->deviceBuffer;
1180 channels = stream->nDeviceChannels[1];
1181 format = stream->deviceFormat[1];
1184 buffer = stream->userBuffer;
1185 channels = stream->nUserChannels[1];
1186 format = stream->userFormat;
1189 // Read samples from device in interleaved/non-interleaved format.
1190 if (stream->deInterleave[1]) {
1191 void *bufs[channels];
1192 size_t offset = stream->bufferSize * formatBytes(format);
1193 for (int i=0; i<channels; i++)
1194 bufs[i] = (void *) (buffer + (i * offset));
1195 err = snd_pcm_readn(stream->handle[1], bufs, stream->bufferSize);
1198 err = snd_pcm_readi(stream->handle[1], buffer, stream->bufferSize);
1200 if (err < stream->bufferSize) {
1201 // Either an error or underrun occured.
1202 if (err == -EPIPE) {
1203 snd_pcm_state_t state = snd_pcm_state(stream->handle[1]);
1204 if (state == SND_PCM_STATE_XRUN) {
1205 sprintf(message, "RtAudio: ALSA overrun detected.");
1206 error(RtAudioError::WARNING);
1207 err = snd_pcm_prepare(stream->handle[1]);
1209 sprintf(message, "RtAudio: ALSA error preparing handle after overrun: %s.",
1211 MUTEX_UNLOCK(&stream->mutex);
1212 error(RtAudioError::DRIVER_ERROR);
1216 sprintf(message, "RtAudio: ALSA error, current state is %s.",
1217 snd_pcm_state_name(state));
1218 MUTEX_UNLOCK(&stream->mutex);
1219 error(RtAudioError::DRIVER_ERROR);
1224 sprintf(message, "RtAudio: ALSA audio read error for device (%s): %s.",
1225 devices[stream->device[1]].name, snd_strerror(err));
1226 MUTEX_UNLOCK(&stream->mutex);
1227 error(RtAudioError::DRIVER_ERROR);
1231 // Do byte swapping if necessary.
1232 if (stream->doByteSwap[1])
1233 byteSwapBuffer(buffer, stream->bufferSize * channels, format);
1235 // Do buffer conversion if necessary.
1236 if (stream->doConvertBuffer[1])
1237 convertStreamBuffer(stream, RECORD);
1241 MUTEX_UNLOCK(&stream->mutex);
1243 if (stream->usingCallback && stopStream)
1244 this->stopStream(streamID);
1247 extern "C" void *callbackHandler(void *ptr)
1249 RtAudio *object = thread_info.object;
1250 int stream = thread_info.streamID;
1251 bool *usingCallback = (bool *) ptr;
1253 while ( *usingCallback ) {
1254 pthread_testcancel();
1256 object->tickStream(stream);
1258 catch (RtAudioError &exception) {
1259 fprintf(stderr, "\nCallback thread error (%s) ... closing thread.\n\n",
1260 exception.getMessage());
1268 //******************** End of __LINUX_ALSA_ *********************//
1270 #elif defined(__LINUX_OSS_)
1272 #include <sys/stat.h>
1273 #include <sys/types.h>
1274 #include <sys/ioctl.h>
1277 #include <sys/soundcard.h>
1281 #define DAC_NAME "/dev/dsp"
1282 #define MAX_DEVICES 16
1283 #define MAX_CHANNELS 16
1285 void RtAudio :: initialize(void)
1287 // Count cards and devices
1290 // We check /dev/dsp before probing devices. /dev/dsp is supposed to
1291 // be a link to the "default" audio device, of the form /dev/dsp0,
1292 // /dev/dsp1, etc... However, I've seen one case where /dev/dsp was a
1293 // real device, so we need to check for that. Also, sometimes the
1294 // link is to /dev/dspx and other times just dspx. I'm not sure how
1295 // the latter works, but it does.
1296 char device_name[16];
1297 struct stat dspstat;
1300 if (lstat(DAC_NAME, &dspstat) == 0) {
1301 if (S_ISLNK(dspstat.st_mode)) {
1302 i = readlink(DAC_NAME, device_name, sizeof(device_name));
1304 device_name[i] = '\0';
1305 if (i > 8) { // check for "/dev/dspx"
1306 if (!strncmp(DAC_NAME, device_name, 8))
1307 dsplink = atoi(&device_name[8]);
1309 else if (i > 3) { // check for "dspx"
1310 if (!strncmp("dsp", device_name, 3))
1311 dsplink = atoi(&device_name[3]);
1315 sprintf(message, "RtAudio: cannot read value of symbolic link %s.", DAC_NAME);
1316 error(RtAudioError::SYSTEM_ERROR);
1321 sprintf(message, "RtAudio: cannot stat %s.", DAC_NAME);
1322 error(RtAudioError::SYSTEM_ERROR);
1325 // The OSS API doesn't provide a routine for determining the number
1326 // of devices. Thus, we'll just pursue a brute force method. The
1327 // idea is to start with /dev/dsp(0) and continue with higher device
1328 // numbers until we reach MAX_DSP_DEVICES. This should tell us how
1329 // many devices we have ... it is not a fullproof scheme, but hopefully
1330 // it will work most of the time.
1333 char names[MAX_DEVICES][16];
1334 for (i=-1; i<MAX_DEVICES; i++) {
1336 // Probe /dev/dsp first, since it is supposed to be the default device.
1338 sprintf(device_name, "%s", DAC_NAME);
1339 else if (i == dsplink)
1340 continue; // We've aready probed this device via /dev/dsp link ... try next device.
1342 sprintf(device_name, "%s%d", DAC_NAME, i);
1344 // First try to open the device for playback, then record mode.
1345 fd = open(device_name, O_WRONLY | O_NONBLOCK);
1347 // Open device for playback failed ... either busy or doesn't exist.
1348 if (errno != EBUSY && errno != EAGAIN) {
1349 // Try to open for capture
1350 fd = open(device_name, O_RDONLY | O_NONBLOCK);
1352 // Open device for record failed.
1353 if (errno != EBUSY && errno != EAGAIN)
1356 sprintf(message, "RtAudio: OSS record device (%s) is busy.", device_name);
1357 error(RtAudioError::WARNING);
1358 // still count it for now
1363 sprintf(message, "RtAudio: OSS playback device (%s) is busy.", device_name);
1364 error(RtAudioError::WARNING);
1365 // still count it for now
1369 if (fd >= 0) close(fd);
1370 strncpy(names[nDevices], device_name, 16);
1374 if (nDevices == 0) return;
1376 // Allocate the DEVICE_CONTROL structures.
1377 devices = (RTAUDIO_DEVICE *) calloc(nDevices, sizeof(RTAUDIO_DEVICE));
1378 if (devices == NULL) {
1379 sprintf(message, "RtAudio: memory allocation error!");
1380 error(RtAudioError::MEMORY_ERROR);
1383 // Write device ascii identifiers to device control structure and then probe capabilities.
1384 for (i=0; i<nDevices; i++) {
1385 strncpy(devices[i].name, names[i], 16);
1386 probeDeviceInfo(&devices[i]);
1392 void RtAudio :: probeDeviceInfo(RTAUDIO_DEVICE *info)
1394 int i, fd, channels, mask;
1396 // The OSS API doesn't provide a means for probing the capabilities
1397 // of devices. Thus, we'll just pursue a brute force method.
1399 // First try for playback
1400 fd = open(info->name, O_WRONLY | O_NONBLOCK);
1402 // Open device failed ... either busy or doesn't exist
1403 if (errno == EBUSY || errno == EAGAIN)
1404 sprintf(message, "RtAudio: OSS playback device (%s) is busy and cannot be probed.",
1407 sprintf(message, "RtAudio: OSS playback device (%s) open error.", info->name);
1408 error(RtAudioError::WARNING);
1412 // We have an open device ... see how many channels it can handle
1413 for (i=MAX_CHANNELS; i>0; i--) {
1415 if (ioctl(fd, SNDCTL_DSP_CHANNELS, &channels) == -1) {
1416 // This would normally indicate some sort of hardware error, but under ALSA's
1417 // OSS emulation, it sometimes indicates an invalid channel value. Further,
1418 // the returned channel value is not changed. So, we'll ignore the possible
1420 continue; // try next channel number
1422 // Check to see whether the device supports the requested number of channels
1423 if (channels != i ) continue; // try next channel number
1424 // If here, we found the largest working channel value
1427 info->maxOutputChannels = channels;
1429 // Now find the minimum number of channels it can handle
1430 for (i=1; i<=info->maxOutputChannels; i++) {
1432 if (ioctl(fd, SNDCTL_DSP_CHANNELS, &channels) == -1 || channels != i)
1433 continue; // try next channel number
1434 // If here, we found the smallest working channel value
1437 info->minOutputChannels = channels;
1441 // Now try for capture
1442 fd = open(info->name, O_RDONLY | O_NONBLOCK);
1444 // Open device for capture failed ... either busy or doesn't exist
1445 if (errno == EBUSY || errno == EAGAIN)
1446 sprintf(message, "RtAudio: OSS capture device (%s) is busy and cannot be probed.",
1449 sprintf(message, "RtAudio: OSS capture device (%s) open error.", info->name);
1450 error(RtAudioError::WARNING);
1451 if (info->maxOutputChannels == 0)
1452 // didn't open for playback either ... device invalid
1454 goto probe_parameters;
1457 // We have the device open for capture ... see how many channels it can handle
1458 for (i=MAX_CHANNELS; i>0; i--) {
1460 if (ioctl(fd, SNDCTL_DSP_CHANNELS, &channels) == -1 || channels != i) {
1461 continue; // as above
1463 // If here, we found a working channel value
1466 info->maxInputChannels = channels;
1468 // Now find the minimum number of channels it can handle
1469 for (i=1; i<=info->maxInputChannels; i++) {
1471 if (ioctl(fd, SNDCTL_DSP_CHANNELS, &channels) == -1 || channels != i)
1472 continue; // try next channel number
1473 // If here, we found the smallest working channel value
1476 info->minInputChannels = channels;
1479 // If device opens for both playback and capture, we determine the channels.
1480 if (info->maxOutputChannels == 0 || info->maxInputChannels == 0)
1481 goto probe_parameters;
1483 fd = open(info->name, O_RDWR | O_NONBLOCK);
1485 goto probe_parameters;
1487 ioctl(fd, SNDCTL_DSP_SETDUPLEX, 0);
1488 ioctl(fd, SNDCTL_DSP_GETCAPS, &mask);
1489 if (mask & DSP_CAP_DUPLEX) {
1490 info->hasDuplexSupport = true;
1491 // We have the device open for duplex ... see how many channels it can handle
1492 for (i=MAX_CHANNELS; i>0; i--) {
1494 if (ioctl(fd, SNDCTL_DSP_CHANNELS, &channels) == -1 || channels != i)
1495 continue; // as above
1496 // If here, we found a working channel value
1499 info->maxDuplexChannels = channels;
1501 // Now find the minimum number of channels it can handle
1502 for (i=1; i<=info->maxDuplexChannels; i++) {
1504 if (ioctl(fd, SNDCTL_DSP_CHANNELS, &channels) == -1 || channels != i)
1505 continue; // try next channel number
1506 // If here, we found the smallest working channel value
1509 info->minDuplexChannels = channels;
1514 // At this point, we need to figure out the supported data formats
1515 // and sample rates. We'll proceed by openning the device in the
1516 // direction with the maximum number of channels, or playback if
1517 // they are equal. This might limit our sample rate options, but so
1520 if (info->maxOutputChannels >= info->maxInputChannels) {
1521 fd = open(info->name, O_WRONLY | O_NONBLOCK);
1522 channels = info->maxOutputChannels;
1525 fd = open(info->name, O_RDONLY | O_NONBLOCK);
1526 channels = info->maxInputChannels;
1530 // We've got some sort of conflict ... abort
1531 sprintf(message, "RtAudio: OSS device (%s) won't reopen during probe.",
1533 error(RtAudioError::WARNING);
1537 // We have an open device ... set to maximum channels.
1539 if (ioctl(fd, SNDCTL_DSP_CHANNELS, &channels) == -1 || channels != i) {
1540 // We've got some sort of conflict ... abort
1542 sprintf(message, "RtAudio: OSS device (%s) won't revert to previous channel setting.",
1544 error(RtAudioError::WARNING);
1548 if (ioctl(fd, SNDCTL_DSP_GETFMTS, &mask) == -1) {
1550 sprintf(message, "RtAudio: OSS device (%s) can't get supported audio formats.",
1552 error(RtAudioError::WARNING);
1556 // Probe the supported data formats ... we don't care about endian-ness just yet.
1558 info->nativeFormats = 0;
1559 #if defined (AFMT_S32_BE)
1560 // This format does not seem to be in the 2.4 kernel version of OSS soundcard.h
1561 if (mask & AFMT_S32_BE) {
1562 format = AFMT_S32_BE;
1563 info->nativeFormats |= RTAUDIO_SINT32;
1566 #if defined (AFMT_S32_LE)
1567 /* This format is not in the 2.4.4 kernel version of OSS soundcard.h */
1568 if (mask & AFMT_S32_LE) {
1569 format = AFMT_S32_LE;
1570 info->nativeFormats |= RTAUDIO_SINT32;
1573 if (mask & AFMT_S8) {
1575 info->nativeFormats |= RTAUDIO_SINT8;
1577 if (mask & AFMT_S16_BE) {
1578 format = AFMT_S16_BE;
1579 info->nativeFormats |= RTAUDIO_SINT16;
1581 if (mask & AFMT_S16_LE) {
1582 format = AFMT_S16_LE;
1583 info->nativeFormats |= RTAUDIO_SINT16;
1586 // Check that we have at least one supported format
1587 if (info->nativeFormats == 0) {
1589 sprintf(message, "RtAudio: OSS device (%s) data format not supported by RtAudio.",
1591 error(RtAudioError::WARNING);
1597 if (ioctl(fd, SNDCTL_DSP_SETFMT, &format) == -1 || format != i) {
1599 sprintf(message, "RtAudio: OSS device (%s) error setting data format.",
1601 error(RtAudioError::WARNING);
1605 // Probe the supported sample rates ... first get lower limit
1607 if (ioctl(fd, SNDCTL_DSP_SPEED, &speed) == -1) {
1608 // If we get here, we're probably using an ALSA driver with OSS-emulation,
1609 // which doesn't conform to the OSS specification. In this case,
1610 // we'll probe our predefined list of sample rates for working values.
1611 info->nSampleRates = 0;
1612 for (i=0; i<MAX_SAMPLE_RATES; i++) {
1613 speed = SAMPLE_RATES[i];
1614 if (ioctl(fd, SNDCTL_DSP_SPEED, &speed) != -1) {
1615 info->sampleRates[info->nSampleRates] = SAMPLE_RATES[i];
1616 info->nSampleRates++;
1619 if (info->nSampleRates == 0) {
1625 info->sampleRates[0] = speed;
1627 // Now get upper limit
1629 if (ioctl(fd, SNDCTL_DSP_SPEED, &speed) == -1) {
1631 sprintf(message, "RtAudio: OSS device (%s) error setting sample rate.",
1633 error(RtAudioError::WARNING);
1636 info->sampleRates[1] = speed;
1637 info->nSampleRates = -1;
1639 finished: // That's all ... close the device and return
1641 info->probed = true;
1645 bool RtAudio :: probeDeviceOpen(int device, RTAUDIO_STREAM *stream,
1646 STREAM_MODE mode, int channels,
1647 int sampleRate, RTAUDIO_FORMAT format,
1648 int *bufferSize, int numberOfBuffers)
1650 int buffers, buffer_bytes, device_channels, device_format;
1651 int srate, temp, fd;
1653 const char *name = devices[device].name;
1655 if (mode == PLAYBACK)
1656 fd = open(name, O_WRONLY | O_NONBLOCK);
1657 else { // mode == RECORD
1658 if (stream->mode == PLAYBACK && stream->device[0] == device) {
1659 // We just set the same device for playback ... close and reopen for duplex (OSS only).
1660 close(stream->handle[0]);
1661 stream->handle[0] = 0;
1662 // First check that the number previously set channels is the same.
1663 if (stream->nUserChannels[0] != channels) {
1664 sprintf(message, "RtAudio: input/output channels must be equal for OSS duplex device (%s).", name);
1667 fd = open(name, O_RDWR | O_NONBLOCK);
1670 fd = open(name, O_RDONLY | O_NONBLOCK);
1674 if (errno == EBUSY || errno == EAGAIN)
1675 sprintf(message, "RtAudio: OSS device (%s) is busy and cannot be opened.",
1678 sprintf(message, "RtAudio: OSS device (%s) cannot be opened.", name);
1682 // Now reopen in blocking mode.
1684 if (mode == PLAYBACK)
1685 fd = open(name, O_WRONLY | O_SYNC);
1686 else { // mode == RECORD
1687 if (stream->mode == PLAYBACK && stream->device[0] == device)
1688 fd = open(name, O_RDWR | O_SYNC);
1690 fd = open(name, O_RDONLY | O_SYNC);
1694 sprintf(message, "RtAudio: OSS device (%s) cannot be opened.", name);
1698 // Get the sample format mask
1700 if (ioctl(fd, SNDCTL_DSP_GETFMTS, &mask) == -1) {
1702 sprintf(message, "RtAudio: OSS device (%s) can't get supported audio formats.",
1707 // Determine how to set the device format.
1708 stream->userFormat = format;
1710 stream->doByteSwap[mode] = false;
1711 if (format == RTAUDIO_SINT8) {
1712 if (mask & AFMT_S8) {
1713 device_format = AFMT_S8;
1714 stream->deviceFormat[mode] = RTAUDIO_SINT8;
1717 else if (format == RTAUDIO_SINT16) {
1718 if (mask & AFMT_S16_NE) {
1719 device_format = AFMT_S16_NE;
1720 stream->deviceFormat[mode] = RTAUDIO_SINT16;
1722 #if BYTE_ORDER == LITTLE_ENDIAN
1723 else if (mask & AFMT_S16_BE) {
1724 device_format = AFMT_S16_BE;
1725 stream->deviceFormat[mode] = RTAUDIO_SINT16;
1726 stream->doByteSwap[mode] = true;
1729 else if (mask & AFMT_S16_LE) {
1730 device_format = AFMT_S16_LE;
1731 stream->deviceFormat[mode] = RTAUDIO_SINT16;
1732 stream->doByteSwap[mode] = true;
1736 #if defined (AFMT_S32_NE) && defined (AFMT_S32_LE) && defined (AFMT_S32_BE)
1737 else if (format == RTAUDIO_SINT32) {
1738 if (mask & AFMT_S32_NE) {
1739 device_format = AFMT_S32_NE;
1740 stream->deviceFormat[mode] = RTAUDIO_SINT32;
1742 #if BYTE_ORDER == LITTLE_ENDIAN
1743 else if (mask & AFMT_S32_BE) {
1744 device_format = AFMT_S32_BE;
1745 stream->deviceFormat[mode] = RTAUDIO_SINT32;
1746 stream->doByteSwap[mode] = true;
1749 else if (mask & AFMT_S32_LE) {
1750 device_format = AFMT_S32_LE;
1751 stream->deviceFormat[mode] = RTAUDIO_SINT32;
1752 stream->doByteSwap[mode] = true;
1758 if (device_format == -1) {
1759 // The user requested format is not natively supported by the device.
1760 if (mask & AFMT_S16_NE) {
1761 device_format = AFMT_S16_NE;
1762 stream->deviceFormat[mode] = RTAUDIO_SINT16;
1764 #if BYTE_ORDER == LITTLE_ENDIAN
1765 else if (mask & AFMT_S16_BE) {
1766 device_format = AFMT_S16_BE;
1767 stream->deviceFormat[mode] = RTAUDIO_SINT16;
1768 stream->doByteSwap[mode] = true;
1771 else if (mask & AFMT_S16_LE) {
1772 device_format = AFMT_S16_LE;
1773 stream->deviceFormat[mode] = RTAUDIO_SINT16;
1774 stream->doByteSwap[mode] = true;
1777 #if defined (AFMT_S32_NE) && defined (AFMT_S32_LE) && defined (AFMT_S32_BE)
1778 else if (mask & AFMT_S32_NE) {
1779 device_format = AFMT_S32_NE;
1780 stream->deviceFormat[mode] = RTAUDIO_SINT32;
1782 #if BYTE_ORDER == LITTLE_ENDIAN
1783 else if (mask & AFMT_S32_BE) {
1784 device_format = AFMT_S32_BE;
1785 stream->deviceFormat[mode] = RTAUDIO_SINT32;
1786 stream->doByteSwap[mode] = true;
1789 else if (mask & AFMT_S32_LE) {
1790 device_format = AFMT_S32_LE;
1791 stream->deviceFormat[mode] = RTAUDIO_SINT32;
1792 stream->doByteSwap[mode] = true;
1796 else if (mask & AFMT_S8) {
1797 device_format = AFMT_S8;
1798 stream->deviceFormat[mode] = RTAUDIO_SINT8;
1802 if (stream->deviceFormat[mode] == 0) {
1803 // This really shouldn't happen ...
1805 sprintf(message, "RtAudio: OSS device (%s) data format not supported by RtAudio.",
1810 // Determine the number of channels for this device. Note that the
1811 // channel value requested by the user might be < min_X_Channels.
1812 stream->nUserChannels[mode] = channels;
1813 device_channels = channels;
1814 if (mode == PLAYBACK) {
1815 if (channels < devices[device].minOutputChannels)
1816 device_channels = devices[device].minOutputChannels;
1818 else { // mode == RECORD
1819 if (stream->mode == PLAYBACK && stream->device[0] == device) {
1820 // We're doing duplex setup here.
1821 if (channels < devices[device].minDuplexChannels)
1822 device_channels = devices[device].minDuplexChannels;
1825 if (channels < devices[device].minInputChannels)
1826 device_channels = devices[device].minInputChannels;
1829 stream->nDeviceChannels[mode] = device_channels;
1831 // Attempt to set the buffer size. According to OSS, the minimum
1832 // number of buffers is two. The supposed minimum buffer size is 16
1833 // bytes, so that will be our lower bound. The argument to this
1834 // call is in the form 0xMMMMSSSS (hex), where the buffer size (in
1835 // bytes) is given as 2^SSSS and the number of buffers as 2^MMMM.
1836 // We'll check the actual value used near the end of the setup
1838 buffer_bytes = *bufferSize * formatBytes(stream->deviceFormat[mode]) * device_channels;
1839 if (buffer_bytes < 16) buffer_bytes = 16;
1840 buffers = numberOfBuffers;
1841 if (buffers < 2) buffers = 2;
1842 temp = ((int) buffers << 16) + (int)(log10((double)buffer_bytes)/log10(2.0));
1843 if (ioctl(fd, SNDCTL_DSP_SETFRAGMENT, &temp)) {
1845 sprintf(message, "RtAudio: OSS error setting fragment size for device (%s).",
1849 stream->nBuffers = buffers;
1851 // Set the data format.
1852 temp = device_format;
1853 if (ioctl(fd, SNDCTL_DSP_SETFMT, &device_format) == -1 || device_format != temp) {
1855 sprintf(message, "RtAudio: OSS error setting data format for device (%s).",
1860 // Set the number of channels.
1861 temp = device_channels;
1862 if (ioctl(fd, SNDCTL_DSP_CHANNELS, &device_channels) == -1 || device_channels != temp) {
1864 sprintf(message, "RtAudio: OSS error setting %d channels on device (%s).",
1869 // Set the sample rate.
1872 if (ioctl(fd, SNDCTL_DSP_SPEED, &srate) == -1) {
1874 sprintf(message, "RtAudio: OSS error setting sample rate = %d on device (%s).",
1879 // Verify the sample rate setup worked.
1880 if (abs(srate - temp) > 100) {
1882 sprintf(message, "RtAudio: OSS error ... audio device (%s) doesn't support sample rate of %d.",
1886 stream->sampleRate = sampleRate;
1888 if (ioctl(fd, SNDCTL_DSP_GETBLKSIZE, &buffer_bytes) == -1) {
1890 sprintf(message, "RtAudio: OSS error getting buffer size for device (%s).",
1895 // Save buffer size (in sample frames).
1896 *bufferSize = buffer_bytes / (formatBytes(stream->deviceFormat[mode]) * device_channels);
1897 stream->bufferSize = *bufferSize;
1899 if (mode == RECORD && stream->mode == PLAYBACK &&
1900 stream->device[0] == device) {
1901 // We're doing duplex setup here.
1902 stream->deviceFormat[0] = stream->deviceFormat[1];
1903 stream->nDeviceChannels[0] = device_channels;
1906 // Set flags for buffer conversion
1907 stream->doConvertBuffer[mode] = false;
1908 if (stream->userFormat != stream->deviceFormat[mode])
1909 stream->doConvertBuffer[mode] = true;
1910 if (stream->nUserChannels[mode] < stream->nDeviceChannels[mode])
1911 stream->doConvertBuffer[mode] = true;
1913 // Allocate necessary internal buffers
1914 if ( stream->nUserChannels[0] != stream->nUserChannels[1] ) {
1917 if (stream->nUserChannels[0] >= stream->nUserChannels[1])
1918 buffer_bytes = stream->nUserChannels[0];
1920 buffer_bytes = stream->nUserChannels[1];
1922 buffer_bytes *= *bufferSize * formatBytes(stream->userFormat);
1923 if (stream->userBuffer) free(stream->userBuffer);
1924 stream->userBuffer = (char *) calloc(buffer_bytes, 1);
1925 if (stream->userBuffer == NULL) {
1927 sprintf(message, "RtAudio: OSS error allocating user buffer memory (%s).",
1933 if ( stream->doConvertBuffer[mode] ) {
1936 bool makeBuffer = true;
1937 if ( mode == PLAYBACK )
1938 buffer_bytes = stream->nDeviceChannels[0] * formatBytes(stream->deviceFormat[0]);
1939 else { // mode == RECORD
1940 buffer_bytes = stream->nDeviceChannels[1] * formatBytes(stream->deviceFormat[1]);
1941 if ( stream->mode == PLAYBACK ) {
1942 long bytes_out = stream->nDeviceChannels[0] * formatBytes(stream->deviceFormat[0]);
1943 if ( buffer_bytes > bytes_out )
1944 buffer_bytes = (buffer_bytes > bytes_out) ? buffer_bytes : bytes_out;
1951 buffer_bytes *= *bufferSize;
1952 if (stream->deviceBuffer) free(stream->deviceBuffer);
1953 stream->deviceBuffer = (char *) calloc(buffer_bytes, 1);
1954 if (stream->deviceBuffer == NULL) {
1956 free(stream->userBuffer);
1957 sprintf(message, "RtAudio: OSS error allocating device buffer memory (%s).",
1964 stream->device[mode] = device;
1965 stream->handle[mode] = fd;
1966 stream->state = STREAM_STOPPED;
1967 if ( stream->mode == PLAYBACK && mode == RECORD ) {
1968 stream->mode = DUPLEX;
1969 if (stream->device[0] == device)
1970 stream->handle[0] = fd;
1973 stream->mode = mode;
1978 if (stream->handle[0]) {
1979 close(stream->handle[0]);
1980 stream->handle[0] = 0;
1982 error(RtAudioError::WARNING);
1986 void RtAudio :: cancelStreamCallback(int streamID)
1988 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamID);
1990 if (stream->usingCallback) {
1991 stream->usingCallback = false;
1992 pthread_cancel(stream->thread);
1993 pthread_join(stream->thread, NULL);
1995 stream->callback = NULL;
1996 stream->userData = NULL;
2000 void RtAudio :: closeStream(int streamID)
2002 // We don't want an exception to be thrown here because this
2003 // function is called by our class destructor. So, do our own
2005 if ( streams.find( streamID ) == streams.end() ) {
2006 sprintf(message, "RtAudio: invalid stream identifier!");
2007 error(RtAudioError::WARNING);
2011 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) streams[streamID];
2013 if (stream->usingCallback) {
2014 pthread_cancel(stream->thread);
2015 pthread_join(stream->thread, NULL);
2018 if (stream->state == STREAM_RUNNING) {
2019 if (stream->mode == PLAYBACK || stream->mode == DUPLEX)
2020 ioctl(stream->handle[0], SNDCTL_DSP_RESET, 0);
2021 if (stream->mode == RECORD || stream->mode == DUPLEX)
2022 ioctl(stream->handle[1], SNDCTL_DSP_RESET, 0);
2025 pthread_mutex_destroy(&stream->mutex);
2027 if (stream->handle[0])
2028 close(stream->handle[0]);
2030 if (stream->handle[1])
2031 close(stream->handle[1]);
2033 if (stream->userBuffer)
2034 free(stream->userBuffer);
2036 if (stream->deviceBuffer)
2037 free(stream->deviceBuffer);
2040 streams.erase(streamID);
2043 void RtAudio :: startStream(int streamID)
2045 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamID);
2047 stream->state = STREAM_RUNNING;
2049 // No need to do anything else here ... OSS automatically starts when fed samples.
2052 void RtAudio :: stopStream(int streamID)
2054 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamID);
2056 MUTEX_LOCK(&stream->mutex);
2058 if (stream->state == STREAM_STOPPED)
2062 if (stream->mode == PLAYBACK || stream->mode == DUPLEX) {
2063 err = ioctl(stream->handle[0], SNDCTL_DSP_SYNC, 0);
2065 sprintf(message, "RtAudio: OSS error stopping device (%s).",
2066 devices[stream->device[0]].name);
2067 error(RtAudioError::DRIVER_ERROR);
2071 err = ioctl(stream->handle[1], SNDCTL_DSP_SYNC, 0);
2073 sprintf(message, "RtAudio: OSS error stopping device (%s).",
2074 devices[stream->device[1]].name);
2075 error(RtAudioError::DRIVER_ERROR);
2078 stream->state = STREAM_STOPPED;
2081 MUTEX_UNLOCK(&stream->mutex);
2084 void RtAudio :: abortStream(int streamID)
2086 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamID);
2088 MUTEX_LOCK(&stream->mutex);
2090 if (stream->state == STREAM_STOPPED)
2094 if (stream->mode == PLAYBACK || stream->mode == DUPLEX) {
2095 err = ioctl(stream->handle[0], SNDCTL_DSP_RESET, 0);
2097 sprintf(message, "RtAudio: OSS error aborting device (%s).",
2098 devices[stream->device[0]].name);
2099 error(RtAudioError::DRIVER_ERROR);
2103 err = ioctl(stream->handle[1], SNDCTL_DSP_RESET, 0);
2105 sprintf(message, "RtAudio: OSS error aborting device (%s).",
2106 devices[stream->device[1]].name);
2107 error(RtAudioError::DRIVER_ERROR);
2110 stream->state = STREAM_STOPPED;
2113 MUTEX_UNLOCK(&stream->mutex);
2116 int RtAudio :: streamWillBlock(int streamID)
2118 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamID);
2120 MUTEX_LOCK(&stream->mutex);
2122 int bytes, channels = 0, frames = 0;
2123 if (stream->state == STREAM_STOPPED)
2126 audio_buf_info info;
2127 if (stream->mode == PLAYBACK || stream->mode == DUPLEX) {
2128 ioctl(stream->handle[0], SNDCTL_DSP_GETOSPACE, &info);
2130 channels = stream->nDeviceChannels[0];
2133 if (stream->mode == RECORD || stream->mode == DUPLEX) {
2134 ioctl(stream->handle[1], SNDCTL_DSP_GETISPACE, &info);
2135 if (stream->mode == DUPLEX ) {
2136 bytes = (bytes < info.bytes) ? bytes : info.bytes;
2137 channels = stream->nDeviceChannels[0];
2141 channels = stream->nDeviceChannels[1];
2145 frames = (int) (bytes / (channels * formatBytes(stream->deviceFormat[0])));
2146 frames -= stream->bufferSize;
2147 if (frames < 0) frames = 0;
2150 MUTEX_UNLOCK(&stream->mutex);
2154 void RtAudio :: tickStream(int streamID)
2156 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamID);
2159 if (stream->state == STREAM_STOPPED) {
2160 if (stream->usingCallback) usleep(50000); // sleep 50 milliseconds
2163 else if (stream->usingCallback) {
2164 stopStream = stream->callback(stream->userBuffer, stream->bufferSize, stream->userData);
2167 MUTEX_LOCK(&stream->mutex);
2169 // The state might change while waiting on a mutex.
2170 if (stream->state == STREAM_STOPPED)
2176 RTAUDIO_FORMAT format;
2177 if (stream->mode == PLAYBACK || stream->mode == DUPLEX) {
2179 // Setup parameters and do buffer conversion if necessary.
2180 if (stream->doConvertBuffer[0]) {
2181 convertStreamBuffer(stream, PLAYBACK);
2182 buffer = stream->deviceBuffer;
2183 samples = stream->bufferSize * stream->nDeviceChannels[0];
2184 format = stream->deviceFormat[0];
2187 buffer = stream->userBuffer;
2188 samples = stream->bufferSize * stream->nUserChannels[0];
2189 format = stream->userFormat;
2192 // Do byte swapping if necessary.
2193 if (stream->doByteSwap[0])
2194 byteSwapBuffer(buffer, samples, format);
2196 // Write samples to device.
2197 result = write(stream->handle[0], buffer, samples * formatBytes(format));
2200 // This could be an underrun, but the basic OSS API doesn't provide a means for determining that.
2201 sprintf(message, "RtAudio: OSS audio write error for device (%s).",
2202 devices[stream->device[0]].name);
2203 error(RtAudioError::DRIVER_ERROR);
2207 if (stream->mode == RECORD || stream->mode == DUPLEX) {
2209 // Setup parameters.
2210 if (stream->doConvertBuffer[1]) {
2211 buffer = stream->deviceBuffer;
2212 samples = stream->bufferSize * stream->nDeviceChannels[1];
2213 format = stream->deviceFormat[1];
2216 buffer = stream->userBuffer;
2217 samples = stream->bufferSize * stream->nUserChannels[1];
2218 format = stream->userFormat;
2221 // Read samples from device.
2222 result = read(stream->handle[1], buffer, samples * formatBytes(format));
2225 // This could be an overrun, but the basic OSS API doesn't provide a means for determining that.
2226 sprintf(message, "RtAudio: OSS audio read error for device (%s).",
2227 devices[stream->device[1]].name);
2228 error(RtAudioError::DRIVER_ERROR);
2231 // Do byte swapping if necessary.
2232 if (stream->doByteSwap[1])
2233 byteSwapBuffer(buffer, samples, format);
2235 // Do buffer conversion if necessary.
2236 if (stream->doConvertBuffer[1])
2237 convertStreamBuffer(stream, RECORD);
2241 MUTEX_UNLOCK(&stream->mutex);
2243 if (stream->usingCallback && stopStream)
2244 this->stopStream(streamID);
2247 extern "C" void *callbackHandler(void *ptr)
2249 RtAudio *object = thread_info.object;
2250 int stream = thread_info.streamID;
2251 bool *usingCallback = (bool *) ptr;
2253 while ( *usingCallback ) {
2254 pthread_testcancel();
2256 object->tickStream(stream);
2258 catch (RtAudioError &exception) {
2259 fprintf(stderr, "\nCallback thread error (%s) ... closing thread.\n\n",
2260 exception.getMessage());
2268 //******************** End of __LINUX_OSS_ *********************//
2270 #elif defined(__WINDOWS_DS_) // Windows DirectSound API
2274 // Declarations for utility functions, callbacks, and structures
2275 // specific to the DirectSound implementation.
2276 static bool CALLBACK deviceCountCallback(LPGUID lpguid,
2277 LPCSTR lpcstrDescription,
2278 LPCSTR lpcstrModule,
2281 static bool CALLBACK deviceInfoCallback(LPGUID lpguid,
2282 LPCSTR lpcstrDescription,
2283 LPCSTR lpcstrModule,
2286 static char* getErrorString(int code);
2295 // RtAudio methods for DirectSound implementation.
2296 void RtAudio :: initialize(void)
2298 int i, ins = 0, outs = 0, count = 0;
2303 // Count DirectSound devices.
2304 result = DirectSoundEnumerate((LPDSENUMCALLBACK)deviceCountCallback, &outs);
2305 if ( FAILED(result) ) {
2306 sprintf(message, "RtAudio: Unable to enumerate through sound playback devices: %s.",
2307 getErrorString(result));
2308 error(RtAudioError::DRIVER_ERROR);
2311 // Count DirectSoundCapture devices.
2312 result = DirectSoundCaptureEnumerate((LPDSENUMCALLBACK)deviceCountCallback, &ins);
2313 if ( FAILED(result) ) {
2314 sprintf(message, "RtAudio: Unable to enumerate through sound capture devices: %s.",
2315 getErrorString(result));
2316 error(RtAudioError::DRIVER_ERROR);
2320 if (count == 0) return;
2322 std::vector<enum_info> info(count);
2323 for (i=0; i<count; i++) {
2324 info[i].name[0] = '\0';
2325 if (i < outs) info[i].isInput = false;
2326 else info[i].isInput = true;
2329 // Get playback device info and check capabilities.
2330 result = DirectSoundEnumerate((LPDSENUMCALLBACK)deviceInfoCallback, &info[0]);
2331 if ( FAILED(result) ) {
2332 sprintf(message, "RtAudio: Unable to enumerate through sound playback devices: %s.",
2333 getErrorString(result));
2334 error(RtAudioError::DRIVER_ERROR);
2337 // Get capture device info and check capabilities.
2338 result = DirectSoundCaptureEnumerate((LPDSENUMCALLBACK)deviceInfoCallback, &info[0]);
2339 if ( FAILED(result) ) {
2340 sprintf(message, "RtAudio: Unable to enumerate through sound capture devices: %s.",
2341 getErrorString(result));
2342 error(RtAudioError::DRIVER_ERROR);
2345 // Parse the devices and check validity. Devices are considered
2346 // invalid if they cannot be opened, they report no supported data
2347 // formats, or they report < 1 supported channels.
2348 for (i=0; i<count; i++) {
2349 if (info[i].isValid && info[i].id == NULL ) // default device
2353 // We group the default input and output devices together (as one
2360 // Non-default devices are listed separately.
2361 for (i=0; i<count; i++) {
2362 if (info[i].isValid && info[i].id != NULL )
2366 if (nDevices == 0) return;
2368 // Allocate the RTAUDIO_DEVICE structures.
2369 devices = (RTAUDIO_DEVICE *) calloc(nDevices, sizeof(RTAUDIO_DEVICE));
2370 if (devices == NULL) {
2371 sprintf(message, "RtAudio: memory allocation error!");
2372 error(RtAudioError::MEMORY_ERROR);
2375 // Initialize the GUIDs to NULL for later validation.
2376 for (i=0; i<nDevices; i++) {
2377 devices[i].id[0] = NULL;
2378 devices[i].id[1] = NULL;
2381 // Rename the default device(s).
2383 strcpy(devices[0].name, "Default Input/Output Devices");
2385 // Copy the names and GUIDs to our devices structures.
2386 for (i=0; i<count; i++) {
2387 if (info[i].isValid && info[i].id != NULL ) {
2388 strncpy(devices[index].name, info[i].name, 64);
2389 if (info[i].isInput)
2390 devices[index].id[1] = info[i].id;
2392 devices[index].id[0] = info[i].id;
2397 for (i=0;i<nDevices; i++)
2398 probeDeviceInfo(&devices[i]);
2403 void RtAudio :: probeDeviceInfo(RTAUDIO_DEVICE *info)
2407 // Get the device index so that we can check the device handle.
2409 for (index=0; index<nDevices; index++)
2410 if ( info == &devices[index] ) break;
2412 if ( index >= nDevices ) {
2413 sprintf(message, "RtAudio: device (%s) indexing error in DirectSound probeDeviceInfo().",
2415 error(RtAudioError::WARNING);
2419 // Do capture probe first. If this is not the default device (index
2420 // = 0) _and_ GUID = NULL, then the capture handle is invalid.
2421 if ( index != 0 && info->id[1] == NULL )
2422 goto playback_probe;
2424 LPDIRECTSOUNDCAPTURE input;
2425 result = DirectSoundCaptureCreate( info->id[0], &input, NULL );
2426 if ( FAILED(result) ) {
2427 sprintf(message, "RtAudio: Could not create DirectSound capture object (%s): %s.",
2428 info->name, getErrorString(result));
2429 error(RtAudioError::WARNING);
2430 goto playback_probe;
2434 in_caps.dwSize = sizeof(in_caps);
2435 result = input->GetCaps( &in_caps );
2436 if ( FAILED(result) ) {
2438 sprintf(message, "RtAudio: Could not get DirectSound capture capabilities (%s): %s.",
2439 info->name, getErrorString(result));
2440 error(RtAudioError::WARNING);
2441 goto playback_probe;
2444 // Get input channel information.
2445 info->minInputChannels = 1;
2446 info->maxInputChannels = in_caps.dwChannels;
2448 // Get sample rate and format information.
2449 if( in_caps.dwChannels == 2 ) {
2450 if( in_caps.dwFormats & WAVE_FORMAT_1S16 ) info->nativeFormats |= RTAUDIO_SINT16;
2451 if( in_caps.dwFormats & WAVE_FORMAT_2S16 ) info->nativeFormats |= RTAUDIO_SINT16;
2452 if( in_caps.dwFormats & WAVE_FORMAT_4S16 ) info->nativeFormats |= RTAUDIO_SINT16;
2453 if( in_caps.dwFormats & WAVE_FORMAT_1S08 ) info->nativeFormats |= RTAUDIO_SINT8;
2454 if( in_caps.dwFormats & WAVE_FORMAT_2S08 ) info->nativeFormats |= RTAUDIO_SINT8;
2455 if( in_caps.dwFormats & WAVE_FORMAT_4S08 ) info->nativeFormats |= RTAUDIO_SINT8;
2457 if ( info->nativeFormats & RTAUDIO_SINT16 ) {
2458 if( in_caps.dwFormats & WAVE_FORMAT_1S16 ) info->sampleRates[info->nSampleRates++] = 11025;
2459 if( in_caps.dwFormats & WAVE_FORMAT_2S16 ) info->sampleRates[info->nSampleRates++] = 22050;
2460 if( in_caps.dwFormats & WAVE_FORMAT_4S16 ) info->sampleRates[info->nSampleRates++] = 44100;
2462 else if ( info->nativeFormats & RTAUDIO_SINT8 ) {
2463 if( in_caps.dwFormats & WAVE_FORMAT_1S08 ) info->sampleRates[info->nSampleRates++] = 11025;
2464 if( in_caps.dwFormats & WAVE_FORMAT_2S08 ) info->sampleRates[info->nSampleRates++] = 22050;
2465 if( in_caps.dwFormats & WAVE_FORMAT_4S08 ) info->sampleRates[info->nSampleRates++] = 44100;
2468 else if ( in_caps.dwChannels == 1 ) {
2469 if( in_caps.dwFormats & WAVE_FORMAT_1M16 ) info->nativeFormats |= RTAUDIO_SINT16;
2470 if( in_caps.dwFormats & WAVE_FORMAT_2M16 ) info->nativeFormats |= RTAUDIO_SINT16;
2471 if( in_caps.dwFormats & WAVE_FORMAT_4M16 ) info->nativeFormats |= RTAUDIO_SINT16;
2472 if( in_caps.dwFormats & WAVE_FORMAT_1M08 ) info->nativeFormats |= RTAUDIO_SINT8;
2473 if( in_caps.dwFormats & WAVE_FORMAT_2M08 ) info->nativeFormats |= RTAUDIO_SINT8;
2474 if( in_caps.dwFormats & WAVE_FORMAT_4M08 ) info->nativeFormats |= RTAUDIO_SINT8;
2476 if ( info->nativeFormats & RTAUDIO_SINT16 ) {
2477 if( in_caps.dwFormats & WAVE_FORMAT_1M16 ) info->sampleRates[info->nSampleRates++] = 11025;
2478 if( in_caps.dwFormats & WAVE_FORMAT_2M16 ) info->sampleRates[info->nSampleRates++] = 22050;
2479 if( in_caps.dwFormats & WAVE_FORMAT_4M16 ) info->sampleRates[info->nSampleRates++] = 44100;
2481 else if ( info->nativeFormats & RTAUDIO_SINT8 ) {
2482 if( in_caps.dwFormats & WAVE_FORMAT_1M08 ) info->sampleRates[info->nSampleRates++] = 11025;
2483 if( in_caps.dwFormats & WAVE_FORMAT_2M08 ) info->sampleRates[info->nSampleRates++] = 22050;
2484 if( in_caps.dwFormats & WAVE_FORMAT_4M08 ) info->sampleRates[info->nSampleRates++] = 44100;
2487 else info->minInputChannels = 0; // technically, this would be an error
2492 LPDIRECTSOUND output;
2495 // Now do playback probe. If this is not the default device (index
2496 // = 0) _and_ GUID = NULL, then the playback handle is invalid.
2497 if ( index != 0 && info->id[0] == NULL )
2498 goto check_parameters;
2500 result = DirectSoundCreate( info->id[0], &output, NULL );
2501 if ( FAILED(result) ) {
2502 sprintf(message, "RtAudio: Could not create DirectSound playback object (%s): %s.",
2503 info->name, getErrorString(result));
2504 error(RtAudioError::WARNING);
2505 goto check_parameters;
2508 out_caps.dwSize = sizeof(out_caps);
2509 result = output->GetCaps( &out_caps );
2510 if ( FAILED(result) ) {
2512 sprintf(message, "RtAudio: Could not get DirectSound playback capabilities (%s): %s.",
2513 info->name, getErrorString(result));
2514 error(RtAudioError::WARNING);
2515 goto check_parameters;
2518 // Get output channel information.
2519 info->minOutputChannels = 1;
2520 info->maxOutputChannels = ( out_caps.dwFlags & DSCAPS_PRIMARYSTEREO ) ? 2 : 1;
2522 // Get sample rate information. Use capture device rate information
2524 if ( info->nSampleRates == 0 ) {
2525 info->sampleRates[0] = (int) out_caps.dwMinSecondarySampleRate;
2526 info->sampleRates[1] = (int) out_caps.dwMaxSecondarySampleRate;
2527 if ( out_caps.dwFlags & DSCAPS_CONTINUOUSRATE )
2528 info->nSampleRates = -1;
2529 else if ( out_caps.dwMinSecondarySampleRate == out_caps.dwMaxSecondarySampleRate ) {
2530 if ( out_caps.dwMinSecondarySampleRate == 0 ) {
2531 // This is a bogus driver report ... fake the range and cross
2533 info->sampleRates[0] = 11025;
2534 info->sampleRates[1] = 48000;
2535 info->nSampleRates = -1; /* continuous range */
2536 sprintf(message, "RtAudio: bogus sample rates reported by DirectSound driver ... using defaults (%s).",
2538 error(RtAudioError::WARNING);
2541 info->nSampleRates = 1;
2544 else if ( (out_caps.dwMinSecondarySampleRate < 1000.0) &&
2545 (out_caps.dwMaxSecondarySampleRate > 50000.0) ) {
2546 // This is a bogus driver report ... support for only two
2547 // distant rates. We'll assume this is a range.
2548 info->nSampleRates = -1;
2549 sprintf(message, "RtAudio: bogus sample rates reported by DirectSound driver ... using range (%s).",
2551 error(RtAudioError::WARNING);
2553 else info->nSampleRates = 2;
2556 // Check input rates against output rate range
2557 for ( int i=info->nSampleRates-1; i>=0; i-- ) {
2558 if ( info->sampleRates[i] <= out_caps.dwMaxSecondarySampleRate )
2560 info->nSampleRates--;
2562 while ( info->sampleRates[0] < out_caps.dwMinSecondarySampleRate ) {
2563 info->nSampleRates--;
2564 for ( int i=0; i<info->nSampleRates; i++)
2565 info->sampleRates[i] = info->sampleRates[i+1];
2566 if ( info->nSampleRates <= 0 ) break;
2570 // Get format information.
2571 if ( out_caps.dwFlags & DSCAPS_PRIMARY16BIT ) info->nativeFormats |= RTAUDIO_SINT16;
2572 if ( out_caps.dwFlags & DSCAPS_PRIMARY8BIT ) info->nativeFormats |= RTAUDIO_SINT8;
2577 if ( info->maxInputChannels == 0 && info->maxOutputChannels == 0 )
2579 if ( info->nSampleRates == 0 || info->nativeFormats == 0 )
2582 // Determine duplex status.
2583 if (info->maxInputChannels < info->maxOutputChannels)
2584 info->maxDuplexChannels = info->maxInputChannels;
2586 info->maxDuplexChannels = info->maxOutputChannels;
2587 if (info->minInputChannels < info->minOutputChannels)
2588 info->minDuplexChannels = info->minInputChannels;
2590 info->minDuplexChannels = info->minOutputChannels;
2592 if ( info->maxDuplexChannels > 0 ) info->hasDuplexSupport = true;
2593 else info->hasDuplexSupport = false;
2595 info->probed = true;
2600 bool RtAudio :: probeDeviceOpen(int device, RTAUDIO_STREAM *stream,
2601 STREAM_MODE mode, int channels,
2602 int sampleRate, RTAUDIO_FORMAT format,
2603 int *bufferSize, int numberOfBuffers)
2606 HWND hWnd = GetForegroundWindow();
2607 // According to a note in PortAudio, using GetDesktopWindow()
2608 // instead of GetForegroundWindow() is supposed to avoid problems
2609 // that occur when the application's window is not the foreground
2610 // window. Also, if the application window closes before the
2611 // DirectSound buffer, DirectSound can crash. However, for console
2612 // applications, no sound was produced when using GetDesktopWindow().
2618 // Check the numberOfBuffers parameter and limit the lowest value to
2619 // two. This is a judgement call and a value of two is probably too
2620 // low for capture, but it should work for playback.
2621 if (numberOfBuffers < 2)
2624 nBuffers = numberOfBuffers;
2626 // Define the wave format structure (16-bit PCM, srate, channels)
2627 WAVEFORMATEX waveFormat;
2628 ZeroMemory(&waveFormat, sizeof(WAVEFORMATEX));
2629 waveFormat.wFormatTag = WAVE_FORMAT_PCM;
2630 waveFormat.nChannels = channels;
2631 waveFormat.nSamplesPerSec = (unsigned long) sampleRate;
2633 // Determine the data format.
2634 if ( devices[device].nativeFormats ) { // 8-bit and/or 16-bit support
2635 if ( format == RTAUDIO_SINT8 ) {
2636 if ( devices[device].nativeFormats & RTAUDIO_SINT8 )
2637 waveFormat.wBitsPerSample = 8;
2639 waveFormat.wBitsPerSample = 16;
2642 if ( devices[device].nativeFormats & RTAUDIO_SINT16 )
2643 waveFormat.wBitsPerSample = 16;
2645 waveFormat.wBitsPerSample = 8;
2649 sprintf(message, "RtAudio: no reported data formats for DirectSound device (%s).",
2650 devices[device].name);
2651 error(RtAudioError::WARNING);
2655 waveFormat.nBlockAlign = waveFormat.nChannels * waveFormat.wBitsPerSample / 8;
2656 waveFormat.nAvgBytesPerSec = waveFormat.nSamplesPerSec * waveFormat.nBlockAlign;
2658 if ( mode == PLAYBACK ) {
2660 LPGUID id = devices[device].id[0];
2661 LPDIRECTSOUND object;
2662 LPDIRECTSOUNDBUFFER buffer;
2663 DSBUFFERDESC bufferDescription;
2665 result = DirectSoundCreate( id, &object, NULL );
2666 if ( FAILED(result) ) {
2667 sprintf(message, "RtAudio: Could not create DirectSound playback object (%s): %s.",
2668 devices[device].name, getErrorString(result));
2669 error(RtAudioError::WARNING);
2673 // Set cooperative level to DSSCL_EXCLUSIVE
2674 result = object->SetCooperativeLevel(hWnd, DSSCL_EXCLUSIVE);
2675 if ( FAILED(result) ) {
2677 sprintf(message, "RtAudio: Unable to set DirectSound cooperative level (%s): %s.",
2678 devices[device].name, getErrorString(result));
2679 error(RtAudioError::WARNING);
2683 // Even though we will write to the secondary buffer, we need to
2684 // access the primary buffer to set the correct output format.
2685 // The default is 8-bit, 22 kHz!
2686 // Setup the DS primary buffer description.
2687 ZeroMemory(&bufferDescription, sizeof(DSBUFFERDESC));
2688 bufferDescription.dwSize = sizeof(DSBUFFERDESC);
2689 bufferDescription.dwFlags = DSBCAPS_PRIMARYBUFFER;
2690 // Obtain the primary buffer
2691 result = object->CreateSoundBuffer(&bufferDescription, &buffer, NULL);
2692 if ( FAILED(result) ) {
2694 sprintf(message, "RtAudio: Unable to access DS primary buffer (%s): %s.",
2695 devices[device].name, getErrorString(result));
2696 error(RtAudioError::WARNING);
2700 // Set the primary DS buffer sound format.
2701 result = buffer->SetFormat(&waveFormat);
2702 if ( FAILED(result) ) {
2704 sprintf(message, "RtAudio: Unable to set DS primary buffer format (%s): %s.",
2705 devices[device].name, getErrorString(result));
2706 error(RtAudioError::WARNING);
2710 // Setup the secondary DS buffer description.
2711 buffer_size = channels * *bufferSize * nBuffers * waveFormat.wBitsPerSample / 8;
2712 ZeroMemory(&bufferDescription, sizeof(DSBUFFERDESC));
2713 bufferDescription.dwSize = sizeof(DSBUFFERDESC);
2714 bufferDescription.dwFlags = ( DSBCAPS_STICKYFOCUS |
2715 DSBCAPS_GETCURRENTPOSITION2 |
2716 DSBCAPS_LOCHARDWARE ); // Force hardware mixing
2717 bufferDescription.dwBufferBytes = buffer_size;
2718 bufferDescription.lpwfxFormat = &waveFormat;
2720 // Try to create the secondary DS buffer. If that doesn't work,
2721 // try to use software mixing. Otherwise, there's a problem.
2722 result = object->CreateSoundBuffer(&bufferDescription, &buffer, NULL);
2723 if ( FAILED(result) ) {
2724 bufferDescription.dwFlags = ( DSBCAPS_STICKYFOCUS |
2725 DSBCAPS_GETCURRENTPOSITION2 |
2726 DSBCAPS_LOCSOFTWARE ); // Force software mixing
2727 result = object->CreateSoundBuffer(&bufferDescription, &buffer, NULL);
2728 if ( FAILED(result) ) {
2730 sprintf(message, "RtAudio: Unable to create secondary DS buffer (%s): %s.",
2731 devices[device].name, getErrorString(result));
2732 error(RtAudioError::WARNING);
2737 // Get the buffer size ... might be different from what we specified.
2739 dsbcaps.dwSize = sizeof(DSBCAPS);
2740 buffer->GetCaps(&dsbcaps);
2741 buffer_size = dsbcaps.dwBufferBytes;
2743 // Lock the DS buffer
2744 result = buffer->Lock(0, buffer_size, &audioPtr, &dataLen, NULL, NULL, 0);
2745 if ( FAILED(result) ) {
2747 sprintf(message, "RtAudio: Unable to lock DS buffer (%s): %s.",
2748 devices[device].name, getErrorString(result));
2749 error(RtAudioError::WARNING);
2753 // Zero the DS buffer
2754 ZeroMemory(audioPtr, dataLen);
2756 // Unlock the DS buffer
2757 result = buffer->Unlock(audioPtr, dataLen, NULL, 0);
2758 if ( FAILED(result) ) {
2760 sprintf(message, "RtAudio: Unable to unlock DS buffer(%s): %s.",
2761 devices[device].name, getErrorString(result));
2762 error(RtAudioError::WARNING);
2766 stream->handle[0].object = (void *) object;
2767 stream->handle[0].buffer = (void *) buffer;
2768 stream->nDeviceChannels[0] = channels;
2771 if ( mode == RECORD ) {
2773 LPGUID id = devices[device].id[1];
2774 LPDIRECTSOUNDCAPTURE object;
2775 LPDIRECTSOUNDCAPTUREBUFFER buffer;
2776 DSCBUFFERDESC bufferDescription;
2778 result = DirectSoundCaptureCreate( id, &object, NULL );
2779 if ( FAILED(result) ) {
2780 sprintf(message, "RtAudio: Could not create DirectSound capture object (%s): %s.",
2781 devices[device].name, getErrorString(result));
2782 error(RtAudioError::WARNING);
2786 // Setup the secondary DS buffer description.
2787 buffer_size = channels * *bufferSize * nBuffers * waveFormat.wBitsPerSample / 8;
2788 ZeroMemory(&bufferDescription, sizeof(DSCBUFFERDESC));
2789 bufferDescription.dwSize = sizeof(DSCBUFFERDESC);
2790 bufferDescription.dwFlags = 0;
2791 bufferDescription.dwReserved = 0;
2792 bufferDescription.dwBufferBytes = buffer_size;
2793 bufferDescription.lpwfxFormat = &waveFormat;
2795 // Create the capture buffer.
2796 result = object->CreateCaptureBuffer(&bufferDescription, &buffer, NULL);
2797 if ( FAILED(result) ) {
2799 sprintf(message, "RtAudio: Unable to create DS capture buffer (%s): %s.",
2800 devices[device].name, getErrorString(result));
2801 error(RtAudioError::WARNING);
2805 // Lock the capture buffer
2806 result = buffer->Lock(0, buffer_size, &audioPtr, &dataLen, NULL, NULL, 0);
2807 if ( FAILED(result) ) {
2809 sprintf(message, "RtAudio: Unable to lock DS capture buffer (%s): %s.",
2810 devices[device].name, getErrorString(result));
2811 error(RtAudioError::WARNING);
2816 ZeroMemory(audioPtr, dataLen);
2818 // Unlock the buffer
2819 result = buffer->Unlock(audioPtr, dataLen, NULL, 0);
2820 if ( FAILED(result) ) {
2822 sprintf(message, "RtAudio: Unable to unlock DS capture buffer (%s): %s.",
2823 devices[device].name, getErrorString(result));
2824 error(RtAudioError::WARNING);
2828 stream->handle[1].object = (void *) object;
2829 stream->handle[1].buffer = (void *) buffer;
2830 stream->nDeviceChannels[1] = channels;
2833 stream->userFormat = format;
2834 if ( waveFormat.wBitsPerSample == 8 )
2835 stream->deviceFormat[mode] = RTAUDIO_SINT8;
2837 stream->deviceFormat[mode] = RTAUDIO_SINT16;
2838 stream->nUserChannels[mode] = channels;
2839 *bufferSize = buffer_size / (channels * nBuffers * waveFormat.wBitsPerSample / 8);
2840 stream->bufferSize = *bufferSize;
2842 // Set flags for buffer conversion
2843 stream->doConvertBuffer[mode] = false;
2844 if (stream->userFormat != stream->deviceFormat[mode])
2845 stream->doConvertBuffer[mode] = true;
2846 if (stream->nUserChannels[mode] < stream->nDeviceChannels[mode])
2847 stream->doConvertBuffer[mode] = true;
2849 // Allocate necessary internal buffers
2850 if ( stream->nUserChannels[0] != stream->nUserChannels[1] ) {
2853 if (stream->nUserChannels[0] >= stream->nUserChannels[1])
2854 buffer_bytes = stream->nUserChannels[0];
2856 buffer_bytes = stream->nUserChannels[1];
2858 buffer_bytes *= *bufferSize * formatBytes(stream->userFormat);
2859 if (stream->userBuffer) free(stream->userBuffer);
2860 stream->userBuffer = (char *) calloc(buffer_bytes, 1);
2861 if (stream->userBuffer == NULL)
2865 if ( stream->doConvertBuffer[mode] ) {
2868 bool makeBuffer = true;
2869 if ( mode == PLAYBACK )
2870 buffer_bytes = stream->nDeviceChannels[0] * formatBytes(stream->deviceFormat[0]);
2871 else { // mode == RECORD
2872 buffer_bytes = stream->nDeviceChannels[1] * formatBytes(stream->deviceFormat[1]);
2873 if ( stream->mode == PLAYBACK ) {
2874 long bytes_out = stream->nDeviceChannels[0] * formatBytes(stream->deviceFormat[0]);
2875 if ( buffer_bytes > bytes_out )
2876 buffer_bytes = (buffer_bytes > bytes_out) ? buffer_bytes : bytes_out;
2883 buffer_bytes *= *bufferSize;
2884 if (stream->deviceBuffer) free(stream->deviceBuffer);
2885 stream->deviceBuffer = (char *) calloc(buffer_bytes, 1);
2886 if (stream->deviceBuffer == NULL)
2891 stream->device[mode] = device;
2892 stream->state = STREAM_STOPPED;
2893 if ( stream->mode == PLAYBACK && mode == RECORD )
2894 // We had already set up an output stream.
2895 stream->mode = DUPLEX;
2897 stream->mode = mode;
2898 stream->nBuffers = nBuffers;
2899 stream->sampleRate = sampleRate;
2904 if (stream->handle[0].object) {
2905 LPDIRECTSOUND object = (LPDIRECTSOUND) stream->handle[0].object;
2906 LPDIRECTSOUNDBUFFER buffer = (LPDIRECTSOUNDBUFFER) stream->handle[0].buffer;
2909 stream->handle[0].buffer = NULL;
2912 stream->handle[0].object = NULL;
2914 if (stream->handle[1].object) {
2915 LPDIRECTSOUNDCAPTURE object = (LPDIRECTSOUNDCAPTURE) stream->handle[1].object;
2916 LPDIRECTSOUNDCAPTUREBUFFER buffer = (LPDIRECTSOUNDCAPTUREBUFFER) stream->handle[1].buffer;
2919 stream->handle[1].buffer = NULL;
2922 stream->handle[1].object = NULL;
2924 if (stream->userBuffer) {
2925 free(stream->userBuffer);
2926 stream->userBuffer = 0;
2928 sprintf(message, "RtAudio: error allocating buffer memory (%s).",
2929 devices[device].name);
2930 error(RtAudioError::WARNING);
2934 void RtAudio :: cancelStreamCallback(int streamID)
2936 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamID);
2938 if (stream->usingCallback) {
2939 stream->usingCallback = false;
2940 WaitForSingleObject( (HANDLE)stream->thread, INFINITE );
2941 CloseHandle( (HANDLE)stream->thread );
2943 stream->callback = NULL;
2944 stream->userData = NULL;
2948 void RtAudio :: closeStream(int streamID)
2950 // We don't want an exception to be thrown here because this
2951 // function is called by our class destructor. So, do our own
2953 if ( streams.find( streamID ) == streams.end() ) {
2954 sprintf(message, "RtAudio: invalid stream identifier!");
2955 error(RtAudioError::WARNING);
2959 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) streams[streamID];
2961 if (stream->usingCallback) {
2962 stream->usingCallback = false;
2963 WaitForSingleObject( (HANDLE)stream->thread, INFINITE );
2964 CloseHandle( (HANDLE)stream->thread );
2967 DeleteCriticalSection(&stream->mutex);
2969 if (stream->handle[0].object) {
2970 LPDIRECTSOUND object = (LPDIRECTSOUND) stream->handle[0].object;
2971 LPDIRECTSOUNDBUFFER buffer = (LPDIRECTSOUNDBUFFER) stream->handle[0].buffer;
2979 if (stream->handle[1].object) {
2980 LPDIRECTSOUNDCAPTURE object = (LPDIRECTSOUNDCAPTURE) stream->handle[1].object;
2981 LPDIRECTSOUNDCAPTUREBUFFER buffer = (LPDIRECTSOUNDCAPTUREBUFFER) stream->handle[1].buffer;
2989 if (stream->userBuffer)
2990 free(stream->userBuffer);
2992 if (stream->deviceBuffer)
2993 free(stream->deviceBuffer);
2996 streams.erase(streamID);
2999 void RtAudio :: startStream(int streamID)
3001 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamID);
3003 MUTEX_LOCK(&stream->mutex);
3005 if (stream->state == STREAM_RUNNING)
3009 if (stream->mode == PLAYBACK || stream->mode == DUPLEX) {
3010 LPDIRECTSOUNDBUFFER buffer = (LPDIRECTSOUNDBUFFER) stream->handle[0].buffer;
3011 result = buffer->Play(0, 0, DSBPLAY_LOOPING );
3012 if ( FAILED(result) ) {
3013 sprintf(message, "RtAudio: Unable to start DS buffer (%s): %s.",
3014 devices[stream->device[0]].name, getErrorString(result));
3015 error(RtAudioError::DRIVER_ERROR);
3019 if (stream->mode == RECORD || stream->mode == DUPLEX) {
3020 LPDIRECTSOUNDCAPTUREBUFFER buffer = (LPDIRECTSOUNDCAPTUREBUFFER) stream->handle[1].buffer;
3021 result = buffer->Start(DSCBSTART_LOOPING );
3022 if ( FAILED(result) ) {
3023 sprintf(message, "RtAudio: Unable to start DS capture buffer (%s): %s.",
3024 devices[stream->device[1]].name, getErrorString(result));
3025 error(RtAudioError::DRIVER_ERROR);
3028 stream->state = STREAM_RUNNING;
3031 MUTEX_UNLOCK(&stream->mutex);
3034 void RtAudio :: stopStream(int streamID)
3036 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamID);
3038 MUTEX_LOCK(&stream->mutex);
3040 if (stream->state == STREAM_STOPPED) {
3041 MUTEX_UNLOCK(&stream->mutex);
3045 // There is no specific DirectSound API call to "drain" a buffer
3046 // before stopping. We can hack this for playback by writing zeroes
3047 // for another bufferSize * nBuffers frames. For capture, the
3048 // concept is less clear so we'll repeat what we do in the
3049 // abortStream() case.
3052 LPVOID buffer1 = NULL;
3053 LPVOID buffer2 = NULL;
3054 DWORD bufferSize1 = 0;
3055 DWORD bufferSize2 = 0;
3056 if (stream->mode == PLAYBACK || stream->mode == DUPLEX) {
3058 DWORD currentPos, safePos;
3059 long buffer_bytes = stream->bufferSize * stream->nDeviceChannels[0];
3060 buffer_bytes *= formatBytes(stream->deviceFormat[0]);
3062 LPDIRECTSOUNDBUFFER dsBuffer = (LPDIRECTSOUNDBUFFER) stream->handle[0].buffer;
3063 UINT nextWritePos = stream->handle[0].bufferPointer;
3064 dsBufferSize = buffer_bytes * stream->nBuffers;
3066 // Write zeroes for nBuffer counts.
3067 for (int i=0; i<stream->nBuffers; i++) {
3069 // Find out where the read and "safe write" pointers are.
3070 result = dsBuffer->GetCurrentPosition(¤tPos, &safePos);
3071 if ( FAILED(result) ) {
3072 sprintf(message, "RtAudio: Unable to get current DS position (%s): %s.",
3073 devices[stream->device[0]].name, getErrorString(result));
3074 error(RtAudioError::DRIVER_ERROR);
3077 if ( currentPos < nextWritePos ) currentPos += dsBufferSize; // unwrap offset
3078 DWORD endWrite = nextWritePos + buffer_bytes;
3080 // Check whether the entire write region is behind the play pointer.
3081 while ( currentPos < endWrite ) {
3082 float millis = (endWrite - currentPos) * 900.0;
3083 millis /= ( formatBytes(stream->deviceFormat[0]) * stream->sampleRate);
3084 if ( millis < 1.0 ) millis = 1.0;
3085 Sleep( (DWORD) millis );
3087 // Wake up, find out where we are now
3088 result = dsBuffer->GetCurrentPosition( ¤tPos, &safePos );
3089 if ( FAILED(result) ) {
3090 sprintf(message, "RtAudio: Unable to get current DS position (%s): %s.",
3091 devices[stream->device[0]].name, getErrorString(result));
3092 error(RtAudioError::DRIVER_ERROR);
3094 if ( currentPos < nextWritePos ) currentPos += dsBufferSize; // unwrap offset
3097 // Lock free space in the buffer
3098 result = dsBuffer->Lock (nextWritePos, buffer_bytes, &buffer1,
3099 &bufferSize1, &buffer2, &bufferSize2, 0);
3100 if ( FAILED(result) ) {
3101 sprintf(message, "RtAudio: Unable to lock DS buffer during playback (%s): %s.",
3102 devices[stream->device[0]].name, getErrorString(result));
3103 error(RtAudioError::DRIVER_ERROR);
3106 // Zero the free space
3107 ZeroMemory(buffer1, bufferSize1);
3108 if (buffer2 != NULL) ZeroMemory(buffer2, bufferSize2);
3110 // Update our buffer offset and unlock sound buffer
3111 dsBuffer->Unlock (buffer1, bufferSize1, buffer2, bufferSize2);
3112 if ( FAILED(result) ) {
3113 sprintf(message, "RtAudio: Unable to unlock DS buffer during playback (%s): %s.",
3114 devices[stream->device[0]].name, getErrorString(result));
3115 error(RtAudioError::DRIVER_ERROR);
3117 nextWritePos = (nextWritePos + bufferSize1 + bufferSize2) % dsBufferSize;
3118 stream->handle[0].bufferPointer = nextWritePos;
3121 // If we play again, start at the beginning of the buffer.
3122 stream->handle[0].bufferPointer = 0;
3125 if (stream->mode == RECORD || stream->mode == DUPLEX) {
3126 LPDIRECTSOUNDCAPTUREBUFFER buffer = (LPDIRECTSOUNDCAPTUREBUFFER) stream->handle[1].buffer;
3130 result = buffer->Stop();
3131 if ( FAILED(result) ) {
3132 sprintf(message, "RtAudio: Unable to stop DS capture buffer (%s): %s",
3133 devices[stream->device[1]].name, getErrorString(result));
3134 error(RtAudioError::DRIVER_ERROR);
3137 dsBufferSize = stream->bufferSize * stream->nDeviceChannels[1];
3138 dsBufferSize *= formatBytes(stream->deviceFormat[1]) * stream->nBuffers;
3140 // Lock the buffer and clear it so that if we start to play again,
3141 // we won't have old data playing.
3142 result = buffer->Lock(0, dsBufferSize, &buffer1, &bufferSize1, NULL, NULL, 0);
3143 if ( FAILED(result) ) {
3144 sprintf(message, "RtAudio: Unable to lock DS capture buffer (%s): %s.",
3145 devices[stream->device[1]].name, getErrorString(result));
3146 error(RtAudioError::DRIVER_ERROR);
3149 // Zero the DS buffer
3150 ZeroMemory(buffer1, bufferSize1);
3152 // Unlock the DS buffer
3153 result = buffer->Unlock(buffer1, bufferSize1, NULL, 0);
3154 if ( FAILED(result) ) {
3155 sprintf(message, "RtAudio: Unable to unlock DS capture buffer (%s): %s.",
3156 devices[stream->device[1]].name, getErrorString(result));
3157 error(RtAudioError::DRIVER_ERROR);
3160 // If we start recording again, we must begin at beginning of buffer.
3161 stream->handle[1].bufferPointer = 0;
3163 stream->state = STREAM_STOPPED;
3165 MUTEX_UNLOCK(&stream->mutex);
3168 void RtAudio :: abortStream(int streamID)
3170 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamID);
3172 MUTEX_LOCK(&stream->mutex);
3174 if (stream->state == STREAM_STOPPED)
3181 if (stream->mode == PLAYBACK || stream->mode == DUPLEX) {
3182 LPDIRECTSOUNDBUFFER buffer = (LPDIRECTSOUNDBUFFER) stream->handle[0].buffer;
3183 result = buffer->Stop();
3184 if ( FAILED(result) ) {
3185 sprintf(message, "RtAudio: Unable to stop DS buffer (%s): %s",
3186 devices[stream->device[0]].name, getErrorString(result));
3187 error(RtAudioError::DRIVER_ERROR);
3190 dsBufferSize = stream->bufferSize * stream->nDeviceChannels[0];
3191 dsBufferSize *= formatBytes(stream->deviceFormat[0]) * stream->nBuffers;
3193 // Lock the buffer and clear it so that if we start to play again,
3194 // we won't have old data playing.
3195 result = buffer->Lock(0, dsBufferSize, &audioPtr, &dataLen, NULL, NULL, 0);
3196 if ( FAILED(result) ) {
3197 sprintf(message, "RtAudio: Unable to lock DS buffer (%s): %s.",
3198 devices[stream->device[0]].name, getErrorString(result));
3199 error(RtAudioError::DRIVER_ERROR);
3202 // Zero the DS buffer
3203 ZeroMemory(audioPtr, dataLen);
3205 // Unlock the DS buffer
3206 result = buffer->Unlock(audioPtr, dataLen, NULL, 0);
3207 if ( FAILED(result) ) {
3208 sprintf(message, "RtAudio: Unable to unlock DS buffer (%s): %s.",
3209 devices[stream->device[0]].name, getErrorString(result));
3210 error(RtAudioError::DRIVER_ERROR);
3213 // If we start playing again, we must begin at beginning of buffer.
3214 stream->handle[0].bufferPointer = 0;
3217 if (stream->mode == RECORD || stream->mode == DUPLEX) {
3218 LPDIRECTSOUNDCAPTUREBUFFER buffer = (LPDIRECTSOUNDCAPTUREBUFFER) stream->handle[1].buffer;
3222 result = buffer->Stop();
3223 if ( FAILED(result) ) {
3224 sprintf(message, "RtAudio: Unable to stop DS capture buffer (%s): %s",
3225 devices[stream->device[1]].name, getErrorString(result));
3226 error(RtAudioError::DRIVER_ERROR);
3229 dsBufferSize = stream->bufferSize * stream->nDeviceChannels[1];
3230 dsBufferSize *= formatBytes(stream->deviceFormat[1]) * stream->nBuffers;
3232 // Lock the buffer and clear it so that if we start to play again,
3233 // we won't have old data playing.
3234 result = buffer->Lock(0, dsBufferSize, &audioPtr, &dataLen, NULL, NULL, 0);
3235 if ( FAILED(result) ) {
3236 sprintf(message, "RtAudio: Unable to lock DS capture buffer (%s): %s.",
3237 devices[stream->device[1]].name, getErrorString(result));
3238 error(RtAudioError::DRIVER_ERROR);
3241 // Zero the DS buffer
3242 ZeroMemory(audioPtr, dataLen);
3244 // Unlock the DS buffer
3245 result = buffer->Unlock(audioPtr, dataLen, NULL, 0);
3246 if ( FAILED(result) ) {
3247 sprintf(message, "RtAudio: Unable to unlock DS capture buffer (%s): %s.",
3248 devices[stream->device[1]].name, getErrorString(result));
3249 error(RtAudioError::DRIVER_ERROR);
3252 // If we start recording again, we must begin at beginning of buffer.
3253 stream->handle[1].bufferPointer = 0;
3255 stream->state = STREAM_STOPPED;
3258 MUTEX_UNLOCK(&stream->mutex);
3261 int RtAudio :: streamWillBlock(int streamID)
3263 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamID);
3265 MUTEX_LOCK(&stream->mutex);
3269 if (stream->state == STREAM_STOPPED)
3273 DWORD currentPos, safePos;
3274 if (stream->mode == PLAYBACK || stream->mode == DUPLEX) {
3276 LPDIRECTSOUNDBUFFER dsBuffer = (LPDIRECTSOUNDBUFFER) stream->handle[0].buffer;
3277 UINT nextWritePos = stream->handle[0].bufferPointer;
3278 channels = stream->nDeviceChannels[0];
3279 DWORD dsBufferSize = stream->bufferSize * channels;
3280 dsBufferSize *= formatBytes(stream->deviceFormat[0]) * stream->nBuffers;
3282 // Find out where the read and "safe write" pointers are.
3283 result = dsBuffer->GetCurrentPosition(¤tPos, &safePos);
3284 if ( FAILED(result) ) {
3285 sprintf(message, "RtAudio: Unable to get current DS position (%s): %s.",
3286 devices[stream->device[0]].name, getErrorString(result));
3287 error(RtAudioError::DRIVER_ERROR);
3290 if ( currentPos < nextWritePos ) currentPos += dsBufferSize; // unwrap offset
3291 frames = currentPos - nextWritePos;
3292 frames /= channels * formatBytes(stream->deviceFormat[0]);
3295 if (stream->mode == RECORD || stream->mode == DUPLEX) {
3297 LPDIRECTSOUNDCAPTUREBUFFER dsBuffer = (LPDIRECTSOUNDCAPTUREBUFFER) stream->handle[1].buffer;
3298 UINT nextReadPos = stream->handle[1].bufferPointer;
3299 channels = stream->nDeviceChannels[1];
3300 DWORD dsBufferSize = stream->bufferSize * channels;
3301 dsBufferSize *= formatBytes(stream->deviceFormat[1]) * stream->nBuffers;
3303 // Find out where the write and "safe read" pointers are.
3304 result = dsBuffer->GetCurrentPosition(¤tPos, &safePos);
3305 if ( FAILED(result) ) {
3306 sprintf(message, "RtAudio: Unable to get current DS capture position (%s): %s.",
3307 devices[stream->device[1]].name, getErrorString(result));
3308 error(RtAudioError::DRIVER_ERROR);
3311 if ( safePos < nextReadPos ) safePos += dsBufferSize; // unwrap offset
3313 if (stream->mode == DUPLEX ) {
3314 // Take largest value of the two.
3315 int temp = safePos - nextReadPos;
3316 temp /= channels * formatBytes(stream->deviceFormat[1]);
3317 frames = ( temp > frames ) ? temp : frames;
3320 frames = safePos - nextReadPos;
3321 frames /= channels * formatBytes(stream->deviceFormat[1]);
3325 frames = stream->bufferSize - frames;
3326 if (frames < 0) frames = 0;
3329 MUTEX_UNLOCK(&stream->mutex);
3333 void RtAudio :: tickStream(int streamID)
3335 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamID);
3338 if (stream->state == STREAM_STOPPED) {
3339 if (stream->usingCallback) Sleep(50); // sleep 50 milliseconds
3342 else if (stream->usingCallback) {
3343 stopStream = stream->callback(stream->userBuffer, stream->bufferSize, stream->userData);
3346 MUTEX_LOCK(&stream->mutex);
3348 // The state might change while waiting on a mutex.
3349 if (stream->state == STREAM_STOPPED)
3353 DWORD currentPos, safePos;
3354 LPVOID buffer1, buffer2;
3355 DWORD bufferSize1, bufferSize2;
3358 if (stream->mode == PLAYBACK || stream->mode == DUPLEX) {
3360 // Setup parameters and do buffer conversion if necessary.
3361 if (stream->doConvertBuffer[0]) {
3362 convertStreamBuffer(stream, PLAYBACK);
3363 buffer = stream->deviceBuffer;
3364 buffer_bytes = stream->bufferSize * stream->nDeviceChannels[0];
3365 buffer_bytes *= formatBytes(stream->deviceFormat[0]);
3368 buffer = stream->userBuffer;
3369 buffer_bytes = stream->bufferSize * stream->nUserChannels[0];
3370 buffer_bytes *= formatBytes(stream->userFormat);
3373 // No byte swapping necessary in DirectSound implementation.
3375 LPDIRECTSOUNDBUFFER dsBuffer = (LPDIRECTSOUNDBUFFER) stream->handle[0].buffer;
3376 UINT nextWritePos = stream->handle[0].bufferPointer;
3377 DWORD dsBufferSize = buffer_bytes * stream->nBuffers;
3379 // Find out where the read and "safe write" pointers are.
3380 result = dsBuffer->GetCurrentPosition(¤tPos, &safePos);
3381 if ( FAILED(result) ) {
3382 sprintf(message, "RtAudio: Unable to get current DS position (%s): %s.",
3383 devices[stream->device[0]].name, getErrorString(result));
3384 error(RtAudioError::DRIVER_ERROR);
3387 if ( currentPos < nextWritePos ) currentPos += dsBufferSize; // unwrap offset
3388 DWORD endWrite = nextWritePos + buffer_bytes;
3390 // Check whether the entire write region is behind the play pointer.
3391 while ( currentPos < endWrite ) {
3392 // If we are here, then we must wait until the play pointer gets
3393 // beyond the write region. The approach here is to use the
3394 // Sleep() function to suspend operation until safePos catches
3395 // up. Calculate number of milliseconds to wait as:
3396 // time = distance * (milliseconds/second) * fudgefactor /
3397 // ((bytes/sample) * (samples/second))
3398 // A "fudgefactor" less than 1 is used because it was found
3399 // that sleeping too long was MUCH worse than sleeping for
3400 // several shorter periods.
3401 float millis = (endWrite - currentPos) * 900.0;
3402 millis /= ( formatBytes(stream->deviceFormat[0]) * stream->sampleRate);
3403 if ( millis < 1.0 ) millis = 1.0;
3404 Sleep( (DWORD) millis );
3406 // Wake up, find out where we are now
3407 result = dsBuffer->GetCurrentPosition( ¤tPos, &safePos );
3408 if ( FAILED(result) ) {
3409 sprintf(message, "RtAudio: Unable to get current DS position (%s): %s.",
3410 devices[stream->device[0]].name, getErrorString(result));
3411 error(RtAudioError::DRIVER_ERROR);
3413 if ( currentPos < nextWritePos ) currentPos += dsBufferSize; // unwrap offset
3416 // Lock free space in the buffer
3417 result = dsBuffer->Lock (nextWritePos, buffer_bytes, &buffer1,
3418 &bufferSize1, &buffer2, &bufferSize2, 0);
3419 if ( FAILED(result) ) {
3420 sprintf(message, "RtAudio: Unable to lock DS buffer during playback (%s): %s.",
3421 devices[stream->device[0]].name, getErrorString(result));
3422 error(RtAudioError::DRIVER_ERROR);
3425 // Copy our buffer into the DS buffer
3426 CopyMemory(buffer1, buffer, bufferSize1);
3427 if (buffer2 != NULL) CopyMemory(buffer2, buffer+bufferSize1, bufferSize2);
3429 // Update our buffer offset and unlock sound buffer
3430 dsBuffer->Unlock (buffer1, bufferSize1, buffer2, bufferSize2);
3431 if ( FAILED(result) ) {
3432 sprintf(message, "RtAudio: Unable to unlock DS buffer during playback (%s): %s.",
3433 devices[stream->device[0]].name, getErrorString(result));
3434 error(RtAudioError::DRIVER_ERROR);
3436 nextWritePos = (nextWritePos + bufferSize1 + bufferSize2) % dsBufferSize;
3437 stream->handle[0].bufferPointer = nextWritePos;
3440 if (stream->mode == RECORD || stream->mode == DUPLEX) {
3442 // Setup parameters.
3443 if (stream->doConvertBuffer[1]) {
3444 buffer = stream->deviceBuffer;
3445 buffer_bytes = stream->bufferSize * stream->nDeviceChannels[1];
3446 buffer_bytes *= formatBytes(stream->deviceFormat[1]);
3449 buffer = stream->userBuffer;
3450 buffer_bytes = stream->bufferSize * stream->nUserChannels[1];
3451 buffer_bytes *= formatBytes(stream->userFormat);
3454 LPDIRECTSOUNDCAPTUREBUFFER dsBuffer = (LPDIRECTSOUNDCAPTUREBUFFER) stream->handle[1].buffer;
3455 UINT nextReadPos = stream->handle[1].bufferPointer;
3456 DWORD dsBufferSize = buffer_bytes * stream->nBuffers;
3458 // Find out where the write and "safe read" pointers are.
3459 result = dsBuffer->GetCurrentPosition(¤tPos, &safePos);
3460 if ( FAILED(result) ) {
3461 sprintf(message, "RtAudio: Unable to get current DS capture position (%s): %s.",
3462 devices[stream->device[1]].name, getErrorString(result));
3463 error(RtAudioError::DRIVER_ERROR);
3466 if ( safePos < nextReadPos ) safePos += dsBufferSize; // unwrap offset
3467 DWORD endRead = nextReadPos + buffer_bytes;
3469 // Check whether the entire write region is behind the play pointer.
3470 while ( safePos < endRead ) {
3471 // See comments for playback.
3472 float millis = (endRead - safePos) * 900.0;
3473 millis /= ( formatBytes(stream->deviceFormat[1]) * stream->sampleRate);
3474 if ( millis < 1.0 ) millis = 1.0;
3475 Sleep( (DWORD) millis );
3477 // Wake up, find out where we are now
3478 result = dsBuffer->GetCurrentPosition( ¤tPos, &safePos );
3479 if ( FAILED(result) ) {
3480 sprintf(message, "RtAudio: Unable to get current DS capture position (%s): %s.",
3481 devices[stream->device[1]].name, getErrorString(result));
3482 error(RtAudioError::DRIVER_ERROR);
3485 if ( safePos < nextReadPos ) safePos += dsBufferSize; // unwrap offset
3488 // Lock free space in the buffer
3489 result = dsBuffer->Lock (nextReadPos, buffer_bytes, &buffer1,
3490 &bufferSize1, &buffer2, &bufferSize2, 0);
3491 if ( FAILED(result) ) {
3492 sprintf(message, "RtAudio: Unable to lock DS buffer during capture (%s): %s.",
3493 devices[stream->device[1]].name, getErrorString(result));
3494 error(RtAudioError::DRIVER_ERROR);
3497 // Copy our buffer into the DS buffer
3498 CopyMemory(buffer, buffer1, bufferSize1);
3499 if (buffer2 != NULL) CopyMemory(buffer+bufferSize1, buffer2, bufferSize2);
3501 // Update our buffer offset and unlock sound buffer
3502 nextReadPos = (nextReadPos + bufferSize1 + bufferSize2) % dsBufferSize;
3503 dsBuffer->Unlock (buffer1, bufferSize1, buffer2, bufferSize2);
3504 if ( FAILED(result) ) {
3505 sprintf(message, "RtAudio: Unable to unlock DS buffer during capture (%s): %s.",
3506 devices[stream->device[1]].name, getErrorString(result));
3507 error(RtAudioError::DRIVER_ERROR);
3509 stream->handle[1].bufferPointer = nextReadPos;
3511 // No byte swapping necessary in DirectSound implementation.
3513 // Do buffer conversion if necessary.
3514 if (stream->doConvertBuffer[1])
3515 convertStreamBuffer(stream, RECORD);
3519 MUTEX_UNLOCK(&stream->mutex);
3521 if (stream->usingCallback && stopStream)
3522 this->stopStream(streamID);
3525 // Definitions for utility functions and callbacks
3526 // specific to the DirectSound implementation.
3528 extern "C" unsigned __stdcall callbackHandler(void *ptr)
3530 RtAudio *object = thread_info.object;
3531 int stream = thread_info.streamID;
3532 bool *usingCallback = (bool *) ptr;
3534 while ( *usingCallback ) {
3536 object->tickStream(stream);
3538 catch (RtAudioError &exception) {
3539 fprintf(stderr, "\nCallback thread error (%s) ... closing thread.\n\n",
3540 exception.getMessage());
3549 static bool CALLBACK deviceCountCallback(LPGUID lpguid,
3550 LPCSTR lpcstrDescription,
3551 LPCSTR lpcstrModule,
3554 int *pointer = ((int *) lpContext);
3560 static bool CALLBACK deviceInfoCallback(LPGUID lpguid,
3561 LPCSTR lpcstrDescription,
3562 LPCSTR lpcstrModule,
3565 enum_info *info = ((enum_info *) lpContext);
3566 while (strlen(info->name) > 0) info++;
3568 strncpy(info->name, lpcstrDescription, 64);
3572 info->isValid = false;
3573 if (info->isInput == true) {
3575 LPDIRECTSOUNDCAPTURE object;
3577 hr = DirectSoundCaptureCreate( lpguid, &object, NULL );
3578 if( hr != DS_OK ) return true;
3580 caps.dwSize = sizeof(caps);
3581 hr = object->GetCaps( &caps );
3583 if (caps.dwChannels > 0 && caps.dwFormats > 0)
3584 info->isValid = true;
3590 LPDIRECTSOUND object;
3591 hr = DirectSoundCreate( lpguid, &object, NULL );
3592 if( hr != DS_OK ) return true;
3594 caps.dwSize = sizeof(caps);
3595 hr = object->GetCaps( &caps );
3597 if ( caps.dwFlags & DSCAPS_PRIMARYMONO || caps.dwFlags & DSCAPS_PRIMARYSTEREO )
3598 info->isValid = true;
3606 static char* getErrorString(int code)
3610 case DSERR_ALLOCATED:
3611 return "Direct Sound already allocated";
3613 case DSERR_CONTROLUNAVAIL:
3614 return "Direct Sound control unavailable";
3616 case DSERR_INVALIDPARAM:
3617 return "Direct Sound invalid parameter";
3619 case DSERR_INVALIDCALL:
3620 return "Direct Sound invalid call";
3623 return "Direct Sound generic error";
3625 case DSERR_PRIOLEVELNEEDED:
3626 return "Direct Sound Priority level needed";
3628 case DSERR_OUTOFMEMORY:
3629 return "Direct Sound out of memory";
3631 case DSERR_BADFORMAT:
3632 return "Direct Sound bad format";
3634 case DSERR_UNSUPPORTED:
3635 return "Direct Sound unsupported error";
3637 case DSERR_NODRIVER:
3638 return "Direct Sound no driver error";
3640 case DSERR_ALREADYINITIALIZED:
3641 return "Direct Sound already initialized";
3643 case DSERR_NOAGGREGATION:
3644 return "Direct Sound no aggregation";
3646 case DSERR_BUFFERLOST:
3647 return "Direct Sound buffer lost";
3649 case DSERR_OTHERAPPHASPRIO:
3650 return "Direct Sound other app has priority";
3652 case DSERR_UNINITIALIZED:
3653 return "Direct Sound uninitialized";
3656 return "Direct Sound unknown error";
3660 //******************** End of __WINDOWS_DS_ *********************//
3662 #elif defined(__IRIX_AL_) // SGI's AL API for IRIX
3667 void RtAudio :: initialize(void)
3670 // Count cards and devices
3673 // Determine the total number of input and output devices.
3674 nDevices = alQueryValues(AL_SYSTEM, AL_DEVICES, 0, 0, 0, 0);
3676 sprintf(message, "RtAudio: AL error counting devices: %s.",
3677 alGetErrorString(oserror()));
3678 error(RtAudioError::DRIVER_ERROR);
3681 if (nDevices <= 0) return;
3683 ALvalue *vls = (ALvalue *) new ALvalue[nDevices];
3685 // Add one for our default input/output devices.
3688 // Allocate the DEVICE_CONTROL structures.
3689 devices = (RTAUDIO_DEVICE *) calloc(nDevices, sizeof(RTAUDIO_DEVICE));
3690 if (devices == NULL) {
3691 sprintf(message, "RtAudio: memory allocation error!");
3692 error(RtAudioError::MEMORY_ERROR);
3695 // Write device ascii identifiers to device info structure.
3699 pvs[0].param = AL_NAME;
3700 pvs[0].value.ptr = name;
3703 strcpy(devices[0].name, "Default Input/Output Devices");
3705 outs = alQueryValues(AL_SYSTEM, AL_DEFAULT_OUTPUT, vls, nDevices-1, 0, 0);
3707 sprintf(message, "RtAudio: AL error getting output devices: %s.",
3708 alGetErrorString(oserror()));
3709 error(RtAudioError::DRIVER_ERROR);
3712 for (i=0; i<outs; i++) {
3713 if (alGetParams(vls[i].i, pvs, 1) < 0) {
3714 sprintf(message, "RtAudio: AL error querying output devices: %s.",
3715 alGetErrorString(oserror()));
3716 error(RtAudioError::DRIVER_ERROR);
3718 strncpy(devices[i+1].name, name, 32);
3719 devices[i+1].id[0] = vls[i].i;
3722 ins = alQueryValues(AL_SYSTEM, AL_DEFAULT_INPUT, &vls[outs], nDevices-outs-1, 0, 0);
3724 sprintf(message, "RtAudio: AL error getting input devices: %s.",
3725 alGetErrorString(oserror()));
3726 error(RtAudioError::DRIVER_ERROR);
3729 for (i=outs; i<ins+outs; i++) {
3730 if (alGetParams(vls[i].i, pvs, 1) < 0) {
3731 sprintf(message, "RtAudio: AL error querying input devices: %s.",
3732 alGetErrorString(oserror()));
3733 error(RtAudioError::DRIVER_ERROR);
3735 strncpy(devices[i+1].name, name, 32);
3736 devices[i+1].id[1] = vls[i].i;
3744 void RtAudio :: probeDeviceInfo(RTAUDIO_DEVICE *info)
3746 int resource, result, i;
3750 // Get output resource ID if it exists.
3751 if ( !strncmp(info->name, "Default Input/Output Devices", 28) ) {
3752 result = alQueryValues(AL_SYSTEM, AL_DEFAULT_OUTPUT, &value, 1, 0, 0);
3754 sprintf(message, "RtAudio: AL error getting default output device id: %s.",
3755 alGetErrorString(oserror()));
3756 error(RtAudioError::WARNING);
3762 resource = info->id[0];
3766 // Probe output device parameters.
3767 result = alQueryValues(resource, AL_CHANNELS, &value, 1, 0, 0);
3769 sprintf(message, "RtAudio: AL error getting device (%s) channels: %s.",
3770 info->name, alGetErrorString(oserror()));
3771 error(RtAudioError::WARNING);
3774 info->maxOutputChannels = value.i;
3775 info->minOutputChannels = 1;
3778 result = alGetParamInfo(resource, AL_RATE, &pinfo);
3780 sprintf(message, "RtAudio: AL error getting device (%s) rates: %s.",
3781 info->name, alGetErrorString(oserror()));
3782 error(RtAudioError::WARNING);
3785 info->nSampleRates = 0;
3786 for (i=0; i<MAX_SAMPLE_RATES; i++) {
3787 if ( SAMPLE_RATES[i] >= pinfo.min.i && SAMPLE_RATES[i] <= pinfo.max.i ) {
3788 info->sampleRates[info->nSampleRates] = SAMPLE_RATES[i];
3789 info->nSampleRates++;
3794 // The AL library supports all our formats, except 24-bit and 32-bit ints.
3795 info->nativeFormats = (RTAUDIO_FORMAT) 51;
3798 // Now get input resource ID if it exists.
3799 if ( !strncmp(info->name, "Default Input/Output Devices", 28) ) {
3800 result = alQueryValues(AL_SYSTEM, AL_DEFAULT_INPUT, &value, 1, 0, 0);
3802 sprintf(message, "RtAudio: AL error getting default input device id: %s.",
3803 alGetErrorString(oserror()));
3804 error(RtAudioError::WARNING);
3810 resource = info->id[1];
3814 // Probe input device parameters.
3815 result = alQueryValues(resource, AL_CHANNELS, &value, 1, 0, 0);
3817 sprintf(message, "RtAudio: AL error getting device (%s) channels: %s.",
3818 info->name, alGetErrorString(oserror()));
3819 error(RtAudioError::WARNING);
3822 info->maxInputChannels = value.i;
3823 info->minInputChannels = 1;
3826 result = alGetParamInfo(resource, AL_RATE, &pinfo);
3828 sprintf(message, "RtAudio: AL error getting device (%s) rates: %s.",
3829 info->name, alGetErrorString(oserror()));
3830 error(RtAudioError::WARNING);
3833 // In the case of the default device, these values will
3834 // overwrite the rates determined for the output device. Since
3835 // the input device is most likely to be more limited than the
3836 // output device, this is ok.
3837 info->nSampleRates = 0;
3838 for (i=0; i<MAX_SAMPLE_RATES; i++) {
3839 if ( SAMPLE_RATES[i] >= pinfo.min.i && SAMPLE_RATES[i] <= pinfo.max.i ) {
3840 info->sampleRates[info->nSampleRates] = SAMPLE_RATES[i];
3841 info->nSampleRates++;
3846 // The AL library supports all our formats, except 24-bit and 32-bit ints.
3847 info->nativeFormats = (RTAUDIO_FORMAT) 51;
3850 if ( info->maxInputChannels == 0 && info->maxOutputChannels == 0 )
3852 if ( info->nSampleRates == 0 )
3855 // Determine duplex status.
3856 if (info->maxInputChannels < info->maxOutputChannels)
3857 info->maxDuplexChannels = info->maxInputChannels;
3859 info->maxDuplexChannels = info->maxOutputChannels;
3860 if (info->minInputChannels < info->minOutputChannels)
3861 info->minDuplexChannels = info->minInputChannels;
3863 info->minDuplexChannels = info->minOutputChannels;
3865 if ( info->maxDuplexChannels > 0 ) info->hasDuplexSupport = true;
3866 else info->hasDuplexSupport = false;
3868 info->probed = true;
3873 bool RtAudio :: probeDeviceOpen(int device, RTAUDIO_STREAM *stream,
3874 STREAM_MODE mode, int channels,
3875 int sampleRate, RTAUDIO_FORMAT format,
3876 int *bufferSize, int numberOfBuffers)
3878 int result, resource, nBuffers;
3883 // Get a new ALconfig structure.
3884 al_config = alNewConfig();
3886 sprintf(message,"RtAudio: can't get AL config: %s.",
3887 alGetErrorString(oserror()));
3888 error(RtAudioError::WARNING);
3892 // Set the channels.
3893 result = alSetChannels(al_config, channels);
3895 sprintf(message,"RtAudio: can't set %d channels in AL config: %s.",
3896 channels, alGetErrorString(oserror()));
3897 error(RtAudioError::WARNING);
3901 // Set the queue (buffer) size.
3902 if ( numberOfBuffers < 1 )
3905 nBuffers = numberOfBuffers;
3906 long buffer_size = *bufferSize * nBuffers;
3907 result = alSetQueueSize(al_config, buffer_size); // in sample frames
3909 sprintf(message,"RtAudio: can't set buffer size (%ld) in AL config: %s.",
3910 buffer_size, alGetErrorString(oserror()));
3911 error(RtAudioError::WARNING);
3915 // Set the data format.
3916 stream->userFormat = format;
3917 stream->deviceFormat[mode] = format;
3918 if (format == RTAUDIO_SINT8) {
3919 result = alSetSampFmt(al_config, AL_SAMPFMT_TWOSCOMP);
3920 result = alSetWidth(al_config, AL_SAMPLE_8);
3922 else if (format == RTAUDIO_SINT16) {
3923 result = alSetSampFmt(al_config, AL_SAMPFMT_TWOSCOMP);
3924 result = alSetWidth(al_config, AL_SAMPLE_16);
3926 else if (format == RTAUDIO_SINT24) {
3927 // Our 24-bit format assumes the upper 3 bytes of a 4 byte word.
3928 // The AL library uses the lower 3 bytes, so we'll need to do our
3930 result = alSetSampFmt(al_config, AL_SAMPFMT_FLOAT);
3931 stream->deviceFormat[mode] = RTAUDIO_FLOAT32;
3933 else if (format == RTAUDIO_SINT32) {
3934 // The AL library doesn't seem to support the 32-bit integer
3935 // format, so we'll need to do our own conversion.
3936 result = alSetSampFmt(al_config, AL_SAMPFMT_FLOAT);
3937 stream->deviceFormat[mode] = RTAUDIO_FLOAT32;
3939 else if (format == RTAUDIO_FLOAT32)
3940 result = alSetSampFmt(al_config, AL_SAMPFMT_FLOAT);
3941 else if (format == RTAUDIO_FLOAT64)
3942 result = alSetSampFmt(al_config, AL_SAMPFMT_DOUBLE);
3944 if ( result == -1 ) {
3945 sprintf(message,"RtAudio: AL error setting sample format in AL config: %s.",
3946 alGetErrorString(oserror()));
3947 error(RtAudioError::WARNING);
3951 if (mode == PLAYBACK) {
3955 resource = AL_DEFAULT_OUTPUT;
3957 resource = devices[device].id[0];
3958 result = alSetDevice(al_config, resource);
3959 if ( result == -1 ) {
3960 sprintf(message,"RtAudio: AL error setting device (%s) in AL config: %s.",
3961 devices[device].name, alGetErrorString(oserror()));
3962 error(RtAudioError::WARNING);
3967 port = alOpenPort("RtAudio Output Port", "w", al_config);
3969 sprintf(message,"RtAudio: AL error opening output port: %s.",
3970 alGetErrorString(oserror()));
3971 error(RtAudioError::WARNING);
3975 // Set the sample rate
3976 pvs[0].param = AL_MASTER_CLOCK;
3977 pvs[0].value.i = AL_CRYSTAL_MCLK_TYPE;
3978 pvs[1].param = AL_RATE;
3979 pvs[1].value.ll = alDoubleToFixed((double)sampleRate);
3980 result = alSetParams(resource, pvs, 2);
3983 sprintf(message,"RtAudio: AL error setting sample rate (%d) for device (%s): %s.",
3984 sampleRate, devices[device].name, alGetErrorString(oserror()));
3985 error(RtAudioError::WARNING);
3989 else { // mode == RECORD
3993 resource = AL_DEFAULT_INPUT;
3995 resource = devices[device].id[1];
3996 result = alSetDevice(al_config, resource);
3997 if ( result == -1 ) {
3998 sprintf(message,"RtAudio: AL error setting device (%s) in AL config: %s.",
3999 devices[device].name, alGetErrorString(oserror()));
4000 error(RtAudioError::WARNING);
4005 port = alOpenPort("RtAudio Output Port", "r", al_config);
4007 sprintf(message,"RtAudio: AL error opening input port: %s.",
4008 alGetErrorString(oserror()));
4009 error(RtAudioError::WARNING);
4013 // Set the sample rate
4014 pvs[0].param = AL_MASTER_CLOCK;
4015 pvs[0].value.i = AL_CRYSTAL_MCLK_TYPE;
4016 pvs[1].param = AL_RATE;
4017 pvs[1].value.ll = alDoubleToFixed((double)sampleRate);
4018 result = alSetParams(resource, pvs, 2);
4021 sprintf(message,"RtAudio: AL error setting sample rate (%d) for device (%s): %s.",
4022 sampleRate, devices[device].name, alGetErrorString(oserror()));
4023 error(RtAudioError::WARNING);
4028 alFreeConfig(al_config);
4030 stream->nUserChannels[mode] = channels;
4031 stream->nDeviceChannels[mode] = channels;
4033 // Set handle and flags for buffer conversion
4034 stream->handle[mode] = port;
4035 stream->doConvertBuffer[mode] = false;
4036 if (stream->userFormat != stream->deviceFormat[mode])
4037 stream->doConvertBuffer[mode] = true;
4039 // Allocate necessary internal buffers
4040 if ( stream->nUserChannels[0] != stream->nUserChannels[1] ) {
4043 if (stream->nUserChannels[0] >= stream->nUserChannels[1])
4044 buffer_bytes = stream->nUserChannels[0];
4046 buffer_bytes = stream->nUserChannels[1];
4048 buffer_bytes *= *bufferSize * formatBytes(stream->userFormat);
4049 if (stream->userBuffer) free(stream->userBuffer);
4050 stream->userBuffer = (char *) calloc(buffer_bytes, 1);
4051 if (stream->userBuffer == NULL)
4055 if ( stream->doConvertBuffer[mode] ) {
4058 bool makeBuffer = true;
4059 if ( mode == PLAYBACK )
4060 buffer_bytes = stream->nDeviceChannels[0] * formatBytes(stream->deviceFormat[0]);
4061 else { // mode == RECORD
4062 buffer_bytes = stream->nDeviceChannels[1] * formatBytes(stream->deviceFormat[1]);
4063 if ( stream->mode == PLAYBACK ) {
4064 long bytes_out = stream->nDeviceChannels[0] * formatBytes(stream->deviceFormat[0]);
4065 if ( buffer_bytes > bytes_out )
4066 buffer_bytes = (buffer_bytes > bytes_out) ? buffer_bytes : bytes_out;
4073 buffer_bytes *= *bufferSize;
4074 if (stream->deviceBuffer) free(stream->deviceBuffer);
4075 stream->deviceBuffer = (char *) calloc(buffer_bytes, 1);
4076 if (stream->deviceBuffer == NULL)
4081 stream->device[mode] = device;
4082 stream->state = STREAM_STOPPED;
4083 if ( stream->mode == PLAYBACK && mode == RECORD )
4084 // We had already set up an output stream.
4085 stream->mode = DUPLEX;
4087 stream->mode = mode;
4088 stream->nBuffers = nBuffers;
4089 stream->bufferSize = *bufferSize;
4090 stream->sampleRate = sampleRate;
4095 if (stream->handle[0]) {
4096 alClosePort(stream->handle[0]);
4097 stream->handle[0] = 0;
4099 if (stream->handle[1]) {
4100 alClosePort(stream->handle[1]);
4101 stream->handle[1] = 0;
4103 if (stream->userBuffer) {
4104 free(stream->userBuffer);
4105 stream->userBuffer = 0;
4107 sprintf(message, "RtAudio: ALSA error allocating buffer memory for device (%s).",
4108 devices[device].name);
4109 error(RtAudioError::WARNING);
4113 void RtAudio :: cancelStreamCallback(int streamID)
4115 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamID);
4117 if (stream->usingCallback) {
4118 stream->usingCallback = false;
4119 pthread_cancel(stream->thread);
4120 pthread_join(stream->thread, NULL);
4122 stream->callback = NULL;
4123 stream->userData = NULL;
4127 void RtAudio :: closeStream(int streamID)
4129 // We don't want an exception to be thrown here because this
4130 // function is called by our class destructor. So, do our own
4132 if ( streams.find( streamID ) == streams.end() ) {
4133 sprintf(message, "RtAudio: invalid stream identifier!");
4134 error(RtAudioError::WARNING);
4138 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) streams[streamID];
4140 if (stream->usingCallback) {
4141 pthread_cancel(stream->thread);
4142 pthread_join(stream->thread, NULL);
4145 pthread_mutex_destroy(&stream->mutex);
4147 if (stream->handle[0])
4148 alClosePort(stream->handle[0]);
4150 if (stream->handle[1])
4151 alClosePort(stream->handle[1]);
4153 if (stream->userBuffer)
4154 free(stream->userBuffer);
4156 if (stream->deviceBuffer)
4157 free(stream->deviceBuffer);
4160 streams.erase(streamID);
4163 void RtAudio :: startStream(int streamID)
4165 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamID);
4167 if (stream->state == STREAM_RUNNING)
4170 // The AL port is ready as soon as it is opened.
4171 stream->state = STREAM_RUNNING;
4174 void RtAudio :: stopStream(int streamID)
4176 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamID);
4178 MUTEX_LOCK(&stream->mutex);
4180 if (stream->state == STREAM_STOPPED)
4184 int buffer_size = stream->bufferSize * stream->nBuffers;
4186 if (stream->mode == PLAYBACK || stream->mode == DUPLEX)
4187 alZeroFrames(stream->handle[0], buffer_size);
4189 if (stream->mode == RECORD || stream->mode == DUPLEX) {
4190 result = alDiscardFrames(stream->handle[1], buffer_size);
4192 sprintf(message, "RtAudio: AL error draining stream device (%s): %s.",
4193 devices[stream->device[1]].name, alGetErrorString(oserror()));
4194 error(RtAudioError::DRIVER_ERROR);
4197 stream->state = STREAM_STOPPED;
4200 MUTEX_UNLOCK(&stream->mutex);
4203 void RtAudio :: abortStream(int streamID)
4205 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamID);
4207 MUTEX_LOCK(&stream->mutex);
4209 if (stream->state == STREAM_STOPPED)
4212 if (stream->mode == PLAYBACK || stream->mode == DUPLEX) {
4214 int buffer_size = stream->bufferSize * stream->nBuffers;
4215 int result = alDiscardFrames(stream->handle[0], buffer_size);
4217 sprintf(message, "RtAudio: AL error aborting stream device (%s): %s.",
4218 devices[stream->device[0]].name, alGetErrorString(oserror()));
4219 error(RtAudioError::DRIVER_ERROR);
4223 // There is no clear action to take on the input stream, since the
4224 // port will continue to run in any event.
4225 stream->state = STREAM_STOPPED;
4228 MUTEX_UNLOCK(&stream->mutex);
4231 int RtAudio :: streamWillBlock(int streamID)
4233 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamID);
4235 MUTEX_LOCK(&stream->mutex);
4238 if (stream->state == STREAM_STOPPED)
4242 if (stream->mode == PLAYBACK || stream->mode == DUPLEX) {
4243 err = alGetFillable(stream->handle[0]);
4245 sprintf(message, "RtAudio: AL error getting available frames for stream (%s): %s.",
4246 devices[stream->device[0]].name, alGetErrorString(oserror()));
4247 error(RtAudioError::DRIVER_ERROR);
4253 if (stream->mode == RECORD || stream->mode == DUPLEX) {
4254 err = alGetFilled(stream->handle[1]);
4256 sprintf(message, "RtAudio: AL error getting available frames for stream (%s): %s.",
4257 devices[stream->device[1]].name, alGetErrorString(oserror()));
4258 error(RtAudioError::DRIVER_ERROR);
4260 if (frames > err) frames = err;
4263 frames = stream->bufferSize - frames;
4264 if (frames < 0) frames = 0;
4267 MUTEX_UNLOCK(&stream->mutex);
4271 void RtAudio :: tickStream(int streamID)
4273 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamID);
4276 if (stream->state == STREAM_STOPPED) {
4277 if (stream->usingCallback) usleep(50000); // sleep 50 milliseconds
4280 else if (stream->usingCallback) {
4281 stopStream = stream->callback(stream->userBuffer, stream->bufferSize, stream->userData);
4284 MUTEX_LOCK(&stream->mutex);
4286 // The state might change while waiting on a mutex.
4287 if (stream->state == STREAM_STOPPED)
4292 RTAUDIO_FORMAT format;
4293 if (stream->mode == PLAYBACK || stream->mode == DUPLEX) {
4295 // Setup parameters and do buffer conversion if necessary.
4296 if (stream->doConvertBuffer[0]) {
4297 convertStreamBuffer(stream, PLAYBACK);
4298 buffer = stream->deviceBuffer;
4299 channels = stream->nDeviceChannels[0];
4300 format = stream->deviceFormat[0];
4303 buffer = stream->userBuffer;
4304 channels = stream->nUserChannels[0];
4305 format = stream->userFormat;
4308 // Do byte swapping if necessary.
4309 if (stream->doByteSwap[0])
4310 byteSwapBuffer(buffer, stream->bufferSize * channels, format);
4312 // Write interleaved samples to device.
4313 alWriteFrames(stream->handle[0], buffer, stream->bufferSize);
4316 if (stream->mode == RECORD || stream->mode == DUPLEX) {
4318 // Setup parameters.
4319 if (stream->doConvertBuffer[1]) {
4320 buffer = stream->deviceBuffer;
4321 channels = stream->nDeviceChannels[1];
4322 format = stream->deviceFormat[1];
4325 buffer = stream->userBuffer;
4326 channels = stream->nUserChannels[1];
4327 format = stream->userFormat;
4330 // Read interleaved samples from device.
4331 alReadFrames(stream->handle[1], buffer, stream->bufferSize);
4333 // Do byte swapping if necessary.
4334 if (stream->doByteSwap[1])
4335 byteSwapBuffer(buffer, stream->bufferSize * channels, format);
4337 // Do buffer conversion if necessary.
4338 if (stream->doConvertBuffer[1])
4339 convertStreamBuffer(stream, RECORD);
4343 MUTEX_UNLOCK(&stream->mutex);
4345 if (stream->usingCallback && stopStream)
4346 this->stopStream(streamID);
4349 extern "C" void *callbackHandler(void *ptr)
4351 RtAudio *object = thread_info.object;
4352 int stream = thread_info.streamID;
4353 bool *usingCallback = (bool *) ptr;
4355 while ( *usingCallback ) {
4356 pthread_testcancel();
4358 object->tickStream(stream);
4360 catch (RtAudioError &exception) {
4361 fprintf(stderr, "\nCallback thread error (%s) ... closing thread.\n\n",
4362 exception.getMessage());
4370 //******************** End of __IRIX_AL_ *********************//
4375 // *************************************************** //
4377 // Private common (OS-independent) RtAudio methods.
4379 // *************************************************** //
4381 // This method can be modified to control the behavior of error
4382 // message reporting and throwing.
4383 void RtAudio :: error(RtAudioError::TYPE type)
4385 if (type == RtAudioError::WARNING)
4386 fprintf(stderr, "\n%s\n\n", message);
4387 else if (type == RtAudioError::DEBUG_WARNING) {
4388 #if defined(RTAUDIO_DEBUG)
4389 fprintf(stderr, "\n%s\n\n", message);
4393 throw RtAudioError(message, type);
4396 void *RtAudio :: verifyStream(int streamID)
4398 // Verify the stream key.
4399 if ( streams.find( streamID ) == streams.end() ) {
4400 sprintf(message, "RtAudio: invalid stream identifier!");
4401 error(RtAudioError::INVALID_STREAM);
4404 return streams[streamID];
4407 void RtAudio :: clearDeviceInfo(RTAUDIO_DEVICE *info)
4409 // Don't clear the name or DEVICE_ID fields here ... they are
4410 // typically set prior to a call of this function.
4411 info->probed = false;
4412 info->maxOutputChannels = 0;
4413 info->maxInputChannels = 0;
4414 info->maxDuplexChannels = 0;
4415 info->minOutputChannels = 0;
4416 info->minInputChannels = 0;
4417 info->minDuplexChannels = 0;
4418 info->hasDuplexSupport = false;
4419 info->nSampleRates = 0;
4420 for (int i=0; i<MAX_SAMPLE_RATES; i++)
4421 info->sampleRates[i] = 0;
4422 info->nativeFormats = 0;
4425 int RtAudio :: formatBytes(RTAUDIO_FORMAT format)
4427 if (format == RTAUDIO_SINT16)
4429 else if (format == RTAUDIO_SINT24 || format == RTAUDIO_SINT32 ||
4430 format == RTAUDIO_FLOAT32)
4432 else if (format == RTAUDIO_FLOAT64)
4434 else if (format == RTAUDIO_SINT8)
4437 sprintf(message,"RtAudio: undefined format in formatBytes().");
4438 error(RtAudioError::WARNING);
4443 void RtAudio :: convertStreamBuffer(RTAUDIO_STREAM *stream, STREAM_MODE mode)
4445 // This method does format conversion, input/output channel compensation, and
4446 // data interleaving/deinterleaving. 24-bit integers are assumed to occupy
4447 // the upper three bytes of a 32-bit integer.
4449 int j, channels_in, channels_out, channels;
4450 RTAUDIO_FORMAT format_in, format_out;
4451 char *input, *output;
4453 if (mode == RECORD) { // convert device to user buffer
4454 input = stream->deviceBuffer;
4455 output = stream->userBuffer;
4456 channels_in = stream->nDeviceChannels[1];
4457 channels_out = stream->nUserChannels[1];
4458 format_in = stream->deviceFormat[1];
4459 format_out = stream->userFormat;
4461 else { // convert user to device buffer
4462 input = stream->userBuffer;
4463 output = stream->deviceBuffer;
4464 channels_in = stream->nUserChannels[0];
4465 channels_out = stream->nDeviceChannels[0];
4466 format_in = stream->userFormat;
4467 format_out = stream->deviceFormat[0];
4469 // clear our device buffer when in/out duplex device channels are different
4470 if ( stream->mode == DUPLEX &&
4471 stream->nDeviceChannels[0] != stream->nDeviceChannels[1] )
4472 memset(output, 0, stream->bufferSize * channels_out * formatBytes(format_out));
4475 channels = (channels_in < channels_out) ? channels_in : channels_out;
4477 // Set up the interleave/deinterleave offsets
4478 std::vector<int> offset_in(channels);
4479 std::vector<int> offset_out(channels);
4480 if (mode == RECORD && stream->deInterleave[1]) {
4481 for (int k=0; k<channels; k++) {
4482 offset_in[k] = k * stream->bufferSize;
4486 else if (mode == PLAYBACK && stream->deInterleave[0]) {
4487 for (int k=0; k<channels; k++) {
4489 offset_out[k] = k * stream->bufferSize;
4493 for (int k=0; k<channels; k++) {
4499 if (format_out == RTAUDIO_FLOAT64) {
4501 FLOAT64 *out = (FLOAT64 *)output;
4503 if (format_in == RTAUDIO_SINT8) {
4504 signed char *in = (signed char *)input;
4505 scale = 1.0 / 128.0;
4506 for (int i=0; i<stream->bufferSize; i++) {
4507 for (j=0; j<channels; j++) {
4508 out[offset_out[j]] = (FLOAT64) in[offset_in[j]];
4509 out[offset_out[j]] *= scale;
4512 out += channels_out;
4515 else if (format_in == RTAUDIO_SINT16) {
4516 INT16 *in = (INT16 *)input;
4517 scale = 1.0 / 32768.0;
4518 for (int i=0; i<stream->bufferSize; i++) {
4519 for (j=0; j<channels; j++) {
4520 out[offset_out[j]] = (FLOAT64) in[offset_in[j]];
4521 out[offset_out[j]] *= scale;
4524 out += channels_out;
4527 else if (format_in == RTAUDIO_SINT24) {
4528 INT32 *in = (INT32 *)input;
4529 scale = 1.0 / 2147483648.0;
4530 for (int i=0; i<stream->bufferSize; i++) {
4531 for (j=0; j<channels; j++) {
4532 out[offset_out[j]] = (FLOAT64) (in[offset_in[j]] & 0xffffff00);
4533 out[offset_out[j]] *= scale;
4536 out += channels_out;
4539 else if (format_in == RTAUDIO_SINT32) {
4540 INT32 *in = (INT32 *)input;
4541 scale = 1.0 / 2147483648.0;
4542 for (int i=0; i<stream->bufferSize; i++) {
4543 for (j=0; j<channels; j++) {
4544 out[offset_out[j]] = (FLOAT64) in[offset_in[j]];
4545 out[offset_out[j]] *= scale;
4548 out += channels_out;
4551 else if (format_in == RTAUDIO_FLOAT32) {
4552 FLOAT32 *in = (FLOAT32 *)input;
4553 for (int i=0; i<stream->bufferSize; i++) {
4554 for (j=0; j<channels; j++) {
4555 out[offset_out[j]] = (FLOAT64) in[offset_in[j]];
4558 out += channels_out;
4561 else if (format_in == RTAUDIO_FLOAT64) {
4562 // Channel compensation and/or (de)interleaving only.
4563 FLOAT64 *in = (FLOAT64 *)input;
4564 for (int i=0; i<stream->bufferSize; i++) {
4565 for (j=0; j<channels; j++) {
4566 out[offset_out[j]] = in[offset_in[j]];
4569 out += channels_out;
4573 else if (format_out == RTAUDIO_FLOAT32) {
4575 FLOAT32 *out = (FLOAT32 *)output;
4577 if (format_in == RTAUDIO_SINT8) {
4578 signed char *in = (signed char *)input;
4579 scale = 1.0 / 128.0;
4580 for (int i=0; i<stream->bufferSize; i++) {
4581 for (j=0; j<channels; j++) {
4582 out[offset_out[j]] = (FLOAT32) in[offset_in[j]];
4583 out[offset_out[j]] *= scale;
4586 out += channels_out;
4589 else if (format_in == RTAUDIO_SINT16) {
4590 INT16 *in = (INT16 *)input;
4591 scale = 1.0 / 32768.0;
4592 for (int i=0; i<stream->bufferSize; i++) {
4593 for (j=0; j<channels; j++) {
4594 out[offset_out[j]] = (FLOAT32) in[offset_in[j]];
4595 out[offset_out[j]] *= scale;
4598 out += channels_out;
4601 else if (format_in == RTAUDIO_SINT24) {
4602 INT32 *in = (INT32 *)input;
4603 scale = 1.0 / 2147483648.0;
4604 for (int i=0; i<stream->bufferSize; i++) {
4605 for (j=0; j<channels; j++) {
4606 out[offset_out[j]] = (FLOAT32) (in[offset_in[j]] & 0xffffff00);
4607 out[offset_out[j]] *= scale;
4610 out += channels_out;
4613 else if (format_in == RTAUDIO_SINT32) {
4614 INT32 *in = (INT32 *)input;
4615 scale = 1.0 / 2147483648.0;
4616 for (int i=0; i<stream->bufferSize; i++) {
4617 for (j=0; j<channels; j++) {
4618 out[offset_out[j]] = (FLOAT32) in[offset_in[j]];
4619 out[offset_out[j]] *= scale;
4622 out += channels_out;
4625 else if (format_in == RTAUDIO_FLOAT32) {
4626 // Channel compensation and/or (de)interleaving only.
4627 FLOAT32 *in = (FLOAT32 *)input;
4628 for (int i=0; i<stream->bufferSize; i++) {
4629 for (j=0; j<channels; j++) {
4630 out[offset_out[j]] = in[offset_in[j]];
4633 out += channels_out;
4636 else if (format_in == RTAUDIO_FLOAT64) {
4637 FLOAT64 *in = (FLOAT64 *)input;
4638 for (int i=0; i<stream->bufferSize; i++) {
4639 for (j=0; j<channels; j++) {
4640 out[offset_out[j]] = (FLOAT32) in[offset_in[j]];
4643 out += channels_out;
4647 else if (format_out == RTAUDIO_SINT32) {
4648 INT32 *out = (INT32 *)output;
4649 if (format_in == RTAUDIO_SINT8) {
4650 signed char *in = (signed char *)input;
4651 for (int i=0; i<stream->bufferSize; i++) {
4652 for (j=0; j<channels; j++) {
4653 out[offset_out[j]] = (INT32) in[offset_in[j]];
4654 out[offset_out[j]] <<= 24;
4657 out += channels_out;
4660 else if (format_in == RTAUDIO_SINT16) {
4661 INT16 *in = (INT16 *)input;
4662 for (int i=0; i<stream->bufferSize; i++) {
4663 for (j=0; j<channels; j++) {
4664 out[offset_out[j]] = (INT32) in[offset_in[j]];
4665 out[offset_out[j]] <<= 16;
4668 out += channels_out;
4671 else if (format_in == RTAUDIO_SINT24) {
4672 INT32 *in = (INT32 *)input;
4673 for (int i=0; i<stream->bufferSize; i++) {
4674 for (j=0; j<channels; j++) {
4675 out[offset_out[j]] = (INT32) in[offset_in[j]];
4678 out += channels_out;
4681 else if (format_in == RTAUDIO_SINT32) {
4682 // Channel compensation and/or (de)interleaving only.
4683 INT32 *in = (INT32 *)input;
4684 for (int i=0; i<stream->bufferSize; i++) {
4685 for (j=0; j<channels; j++) {
4686 out[offset_out[j]] = in[offset_in[j]];
4689 out += channels_out;
4692 else if (format_in == RTAUDIO_FLOAT32) {
4693 FLOAT32 *in = (FLOAT32 *)input;
4694 for (int i=0; i<stream->bufferSize; i++) {
4695 for (j=0; j<channels; j++) {
4696 out[offset_out[j]] = (INT32) (in[offset_in[j]] * 2147483647.0);
4699 out += channels_out;
4702 else if (format_in == RTAUDIO_FLOAT64) {
4703 FLOAT64 *in = (FLOAT64 *)input;
4704 for (int i=0; i<stream->bufferSize; i++) {
4705 for (j=0; j<channels; j++) {
4706 out[offset_out[j]] = (INT32) (in[offset_in[j]] * 2147483647.0);
4709 out += channels_out;
4713 else if (format_out == RTAUDIO_SINT24) {
4714 INT32 *out = (INT32 *)output;
4715 if (format_in == RTAUDIO_SINT8) {
4716 signed char *in = (signed char *)input;
4717 for (int i=0; i<stream->bufferSize; i++) {
4718 for (j=0; j<channels; j++) {
4719 out[offset_out[j]] = (INT32) in[offset_in[j]];
4720 out[offset_out[j]] <<= 24;
4723 out += channels_out;
4726 else if (format_in == RTAUDIO_SINT16) {
4727 INT16 *in = (INT16 *)input;
4728 for (int i=0; i<stream->bufferSize; i++) {
4729 for (j=0; j<channels; j++) {
4730 out[offset_out[j]] = (INT32) in[offset_in[j]];
4731 out[offset_out[j]] <<= 16;
4734 out += channels_out;
4737 else if (format_in == RTAUDIO_SINT24) {
4738 // Channel compensation and/or (de)interleaving only.
4739 INT32 *in = (INT32 *)input;
4740 for (int i=0; i<stream->bufferSize; i++) {
4741 for (j=0; j<channels; j++) {
4742 out[offset_out[j]] = in[offset_in[j]];
4745 out += channels_out;
4748 else if (format_in == RTAUDIO_SINT32) {
4749 INT32 *in = (INT32 *)input;
4750 for (int i=0; i<stream->bufferSize; i++) {
4751 for (j=0; j<channels; j++) {
4752 out[offset_out[j]] = (INT32) (in[offset_in[j]] & 0xffffff00);
4755 out += channels_out;
4758 else if (format_in == RTAUDIO_FLOAT32) {
4759 FLOAT32 *in = (FLOAT32 *)input;
4760 for (int i=0; i<stream->bufferSize; i++) {
4761 for (j=0; j<channels; j++) {
4762 out[offset_out[j]] = (INT32) (in[offset_in[j]] * 2147483647.0);
4765 out += channels_out;
4768 else if (format_in == RTAUDIO_FLOAT64) {
4769 FLOAT64 *in = (FLOAT64 *)input;
4770 for (int i=0; i<stream->bufferSize; i++) {
4771 for (j=0; j<channels; j++) {
4772 out[offset_out[j]] = (INT32) (in[offset_in[j]] * 2147483647.0);
4775 out += channels_out;
4779 else if (format_out == RTAUDIO_SINT16) {
4780 INT16 *out = (INT16 *)output;
4781 if (format_in == RTAUDIO_SINT8) {
4782 signed char *in = (signed char *)input;
4783 for (int i=0; i<stream->bufferSize; i++) {
4784 for (j=0; j<channels; j++) {
4785 out[offset_out[j]] = (INT16) in[offset_in[j]];
4786 out[offset_out[j]] <<= 8;
4789 out += channels_out;
4792 else if (format_in == RTAUDIO_SINT16) {
4793 // Channel compensation and/or (de)interleaving only.
4794 INT16 *in = (INT16 *)input;
4795 for (int i=0; i<stream->bufferSize; i++) {
4796 for (j=0; j<channels; j++) {
4797 out[offset_out[j]] = in[offset_in[j]];
4800 out += channels_out;
4803 else if (format_in == RTAUDIO_SINT24) {
4804 INT32 *in = (INT32 *)input;
4805 for (int i=0; i<stream->bufferSize; i++) {
4806 for (j=0; j<channels; j++) {
4807 out[offset_out[j]] = (INT16) ((in[offset_in[j]] >> 16) & 0x0000ffff);
4810 out += channels_out;
4813 else if (format_in == RTAUDIO_SINT32) {
4814 INT32 *in = (INT32 *)input;
4815 for (int i=0; i<stream->bufferSize; i++) {
4816 for (j=0; j<channels; j++) {
4817 out[offset_out[j]] = (INT16) ((in[offset_in[j]] >> 16) & 0x0000ffff);
4820 out += channels_out;
4823 else if (format_in == RTAUDIO_FLOAT32) {
4824 FLOAT32 *in = (FLOAT32 *)input;
4825 for (int i=0; i<stream->bufferSize; i++) {
4826 for (j=0; j<channels; j++) {
4827 out[offset_out[j]] = (INT16) (in[offset_in[j]] * 32767.0);
4830 out += channels_out;
4833 else if (format_in == RTAUDIO_FLOAT64) {
4834 FLOAT64 *in = (FLOAT64 *)input;
4835 for (int i=0; i<stream->bufferSize; i++) {
4836 for (j=0; j<channels; j++) {
4837 out[offset_out[j]] = (INT16) (in[offset_in[j]] * 32767.0);
4840 out += channels_out;
4844 else if (format_out == RTAUDIO_SINT8) {
4845 signed char *out = (signed char *)output;
4846 if (format_in == RTAUDIO_SINT8) {
4847 // Channel compensation and/or (de)interleaving only.
4848 signed char *in = (signed char *)input;
4849 for (int i=0; i<stream->bufferSize; i++) {
4850 for (j=0; j<channels; j++) {
4851 out[offset_out[j]] = in[offset_in[j]];
4854 out += channels_out;
4857 if (format_in == RTAUDIO_SINT16) {
4858 INT16 *in = (INT16 *)input;
4859 for (int i=0; i<stream->bufferSize; i++) {
4860 for (j=0; j<channels; j++) {
4861 out[offset_out[j]] = (signed char) ((in[offset_in[j]] >> 8) & 0x00ff);
4864 out += channels_out;
4867 else if (format_in == RTAUDIO_SINT24) {
4868 INT32 *in = (INT32 *)input;
4869 for (int i=0; i<stream->bufferSize; i++) {
4870 for (j=0; j<channels; j++) {
4871 out[offset_out[j]] = (signed char) ((in[offset_in[j]] >> 24) & 0x000000ff);
4874 out += channels_out;
4877 else if (format_in == RTAUDIO_SINT32) {
4878 INT32 *in = (INT32 *)input;
4879 for (int i=0; i<stream->bufferSize; i++) {
4880 for (j=0; j<channels; j++) {
4881 out[offset_out[j]] = (signed char) ((in[offset_in[j]] >> 24) & 0x000000ff);
4884 out += channels_out;
4887 else if (format_in == RTAUDIO_FLOAT32) {
4888 FLOAT32 *in = (FLOAT32 *)input;
4889 for (int i=0; i<stream->bufferSize; i++) {
4890 for (j=0; j<channels; j++) {
4891 out[offset_out[j]] = (signed char) (in[offset_in[j]] * 127.0);
4894 out += channels_out;
4897 else if (format_in == RTAUDIO_FLOAT64) {
4898 FLOAT64 *in = (FLOAT64 *)input;
4899 for (int i=0; i<stream->bufferSize; i++) {
4900 for (j=0; j<channels; j++) {
4901 out[offset_out[j]] = (signed char) (in[offset_in[j]] * 127.0);
4904 out += channels_out;
4910 void RtAudio :: byteSwapBuffer(char *buffer, int samples, RTAUDIO_FORMAT format)
4916 if (format == RTAUDIO_SINT16) {
4917 for (int i=0; i<samples; i++) {
4918 // Swap 1st and 2nd bytes.
4923 // Increment 2 bytes.
4927 else if (format == RTAUDIO_SINT24 ||
4928 format == RTAUDIO_SINT32 ||
4929 format == RTAUDIO_FLOAT32) {
4930 for (int i=0; i<samples; i++) {
4931 // Swap 1st and 4th bytes.
4936 // Swap 2nd and 3rd bytes.
4942 // Increment 4 bytes.
4946 else if (format == RTAUDIO_FLOAT64) {
4947 for (int i=0; i<samples; i++) {
4948 // Swap 1st and 8th bytes
4953 // Swap 2nd and 7th bytes
4959 // Swap 3rd and 6th bytes
4965 // Swap 4th and 5th bytes
4971 // Increment 8 bytes.
4978 // *************************************************** //
4980 // RtAudioError class definition.
4982 // *************************************************** //
4984 RtAudioError :: RtAudioError(const char *p, TYPE tipe)
4987 strncpy(error_message, p, 256);
4990 RtAudioError :: ~RtAudioError()
4994 void RtAudioError :: printMessage()
4996 printf("\n%s\n\n", error_message);