1 /************************************************************************/
3 \brief Realtime audio i/o C++ class.
5 RtAudio provides a common API (Application Programming Interface)
6 for realtime audio input/output across Linux (native ALSA and
7 OSS), SGI, Macintosh OS X (CoreAudio), and Windows (DirectSound
8 and ASIO) operating systems.
10 RtAudio WWW site: http://www-ccrma.stanford.edu/~gary/rtaudio/
12 RtAudio: a realtime audio i/o C++ class
13 Copyright (c) 2001-2002 Gary P. Scavone
15 Permission is hereby granted, free of charge, to any person
16 obtaining a copy of this software and associated documentation files
17 (the "Software"), to deal in the Software without restriction,
18 including without limitation the rights to use, copy, modify, merge,
19 publish, distribute, sublicense, and/or sell copies of the Software,
20 and to permit persons to whom the Software is furnished to do so,
21 subject to the following conditions:
23 The above copyright notice and this permission notice shall be
24 included in all copies or substantial portions of the Software.
26 Any person wishing to distribute modifications to the Software is
27 requested to send the modifications to the original developer so that
28 they can be incorporated into the canonical version.
30 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
31 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
32 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
33 IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
34 ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
35 CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
36 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
38 /************************************************************************/
40 // RtAudio: Version 2.1.1, 24 October 2002
47 // Static variable definitions.
48 const unsigned int RtAudio :: SAMPLE_RATES[] = {
49 4000, 5512, 8000, 9600, 11025, 16000, 22050,
50 32000, 44100, 48000, 88200, 96000, 176400, 192000
52 const RtAudio::RTAUDIO_FORMAT RtAudio :: RTAUDIO_SINT8 = 1;
53 const RtAudio::RTAUDIO_FORMAT RtAudio :: RTAUDIO_SINT16 = 2;
54 const RtAudio::RTAUDIO_FORMAT RtAudio :: RTAUDIO_SINT24 = 4;
55 const RtAudio::RTAUDIO_FORMAT RtAudio :: RTAUDIO_SINT32 = 8;
56 const RtAudio::RTAUDIO_FORMAT RtAudio :: RTAUDIO_FLOAT32 = 16;
57 const RtAudio::RTAUDIO_FORMAT RtAudio :: RTAUDIO_FLOAT64 = 32;
59 #if defined(__WINDOWS_DS__) || defined(__WINDOWS_ASIO__)
60 #define MUTEX_INITIALIZE(A) InitializeCriticalSection(A)
61 #define MUTEX_LOCK(A) EnterCriticalSection(A)
62 #define MUTEX_UNLOCK(A) LeaveCriticalSection(A)
64 #define MUTEX_INITIALIZE(A) pthread_mutex_init(A, NULL)
65 #define MUTEX_LOCK(A) pthread_mutex_lock(A)
66 #define MUTEX_UNLOCK(A) pthread_mutex_unlock(A)
69 // *************************************************** //
71 // Public common (OS-independent) methods.
73 // *************************************************** //
80 sprintf(message, "RtAudio: no audio devices found!");
81 error(RtError::NO_DEVICES_FOUND);
85 RtAudio :: RtAudio(int *streamId,
86 int outputDevice, int outputChannels,
87 int inputDevice, int inputChannels,
88 RTAUDIO_FORMAT format, int sampleRate,
89 int *bufferSize, int numberOfBuffers)
94 sprintf(message, "RtAudio: no audio devices found!");
95 error(RtError::NO_DEVICES_FOUND);
99 *streamId = openStream(outputDevice, outputChannels, inputDevice, inputChannels,
100 format, sampleRate, bufferSize, numberOfBuffers);
102 catch (RtError &exception) {
103 // deallocate the RTAUDIO_DEVICE structures
104 if (devices) free(devices);
109 RtAudio :: ~RtAudio()
111 // close any existing streams
112 while ( streams.size() )
113 closeStream( streams.begin()->first );
115 // deallocate the RTAUDIO_DEVICE structures
116 if (devices) free(devices);
119 int RtAudio :: openStream(int outputDevice, int outputChannels,
120 int inputDevice, int inputChannels,
121 RTAUDIO_FORMAT format, int sampleRate,
122 int *bufferSize, int numberOfBuffers)
124 static int streamKey = 0; // Unique stream identifier ... OK for multiple instances.
126 if (outputChannels < 1 && inputChannels < 1) {
127 sprintf(message,"RtAudio: one or both 'channel' parameters must be greater than zero.");
128 error(RtError::INVALID_PARAMETER);
131 if ( formatBytes(format) == 0 ) {
132 sprintf(message,"RtAudio: 'format' parameter value is undefined.");
133 error(RtError::INVALID_PARAMETER);
136 if ( outputChannels > 0 ) {
137 if (outputDevice > nDevices || outputDevice < 0) {
138 sprintf(message,"RtAudio: 'outputDevice' parameter value (%d) is invalid.", outputDevice);
139 error(RtError::INVALID_PARAMETER);
143 if ( inputChannels > 0 ) {
144 if (inputDevice > nDevices || inputDevice < 0) {
145 sprintf(message,"RtAudio: 'inputDevice' parameter value (%d) is invalid.", inputDevice);
146 error(RtError::INVALID_PARAMETER);
150 // Allocate a new stream structure.
151 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) calloc(1, sizeof(RTAUDIO_STREAM));
152 if (stream == NULL) {
153 sprintf(message, "RtAudio: memory allocation error!");
154 error(RtError::MEMORY_ERROR);
156 stream->mode = UNINITIALIZED;
157 MUTEX_INITIALIZE(&stream->mutex);
159 bool result = FAILURE;
160 int device, defaultDevice = 0;
163 if ( outputChannels > 0 ) {
166 channels = outputChannels;
168 if ( outputDevice == 0 ) { // Try default device first.
169 defaultDevice = getDefaultOutputDevice();
170 device = defaultDevice;
173 device = outputDevice - 1;
175 for (int i=-1; i<nDevices; i++) {
177 if ( i == defaultDevice ) continue;
180 if (devices[device].probed == false) {
181 // If the device wasn't successfully probed before, try it
183 clearDeviceInfo(&devices[device]);
184 probeDeviceInfo(&devices[device]);
186 if ( devices[device].probed )
187 result = probeDeviceOpen(device, stream, mode, channels, sampleRate,
188 format, bufferSize, numberOfBuffers);
189 if (result == SUCCESS) break;
190 if ( outputDevice > 0 ) break;
194 if ( inputChannels > 0 && ( result == SUCCESS || outputChannels <= 0 ) ) {
197 channels = inputChannels;
199 if ( inputDevice == 0 ) { // Try default device first.
200 defaultDevice = getDefaultInputDevice();
201 device = defaultDevice;
204 device = inputDevice - 1;
206 for (int i=-1; i<nDevices; i++) {
208 if ( i == defaultDevice ) continue;
211 if (devices[device].probed == false) {
212 // If the device wasn't successfully probed before, try it
214 clearDeviceInfo(&devices[device]);
215 probeDeviceInfo(&devices[device]);
217 if ( devices[device].probed )
218 result = probeDeviceOpen(device, stream, mode, channels, sampleRate,
219 format, bufferSize, numberOfBuffers);
220 if (result == SUCCESS) break;
221 if ( outputDevice > 0 ) break;
225 streams[++streamKey] = (void *) stream;
226 if ( result == SUCCESS )
229 // If we get here, all attempted probes failed. Close any opened
230 // devices and delete the allocated stream.
231 closeStream(streamKey);
232 if ( ( outputDevice == 0 && outputChannels > 0 )
233 || ( inputDevice == 0 && inputChannels > 0 ) )
234 sprintf(message,"RtAudio: no devices found for given parameters.");
236 sprintf(message,"RtAudio: unable to open specified device(s) with given stream parameters.");
237 error(RtError::INVALID_PARAMETER);
242 int RtAudio :: getDeviceCount(void)
247 void RtAudio :: getDeviceInfo(int device, RTAUDIO_DEVICE *info)
249 if (device > nDevices || device < 1) {
250 sprintf(message, "RtAudio: invalid device specifier (%d)!", device);
251 error(RtError::INVALID_DEVICE);
254 int deviceIndex = device - 1;
256 // If the device wasn't successfully probed before, try it now (or again).
257 if (devices[deviceIndex].probed == false) {
258 clearDeviceInfo(&devices[deviceIndex]);
259 probeDeviceInfo(&devices[deviceIndex]);
262 // Clear the info structure.
263 memset(info, 0, sizeof(RTAUDIO_DEVICE));
265 strncpy(info->name, devices[deviceIndex].name, 128);
266 info->probed = devices[deviceIndex].probed;
267 if ( info->probed == true ) {
268 info->maxOutputChannels = devices[deviceIndex].maxOutputChannels;
269 info->maxInputChannels = devices[deviceIndex].maxInputChannels;
270 info->maxDuplexChannels = devices[deviceIndex].maxDuplexChannels;
271 info->minOutputChannels = devices[deviceIndex].minOutputChannels;
272 info->minInputChannels = devices[deviceIndex].minInputChannels;
273 info->minDuplexChannels = devices[deviceIndex].minDuplexChannels;
274 info->hasDuplexSupport = devices[deviceIndex].hasDuplexSupport;
275 info->nSampleRates = devices[deviceIndex].nSampleRates;
276 if (info->nSampleRates == -1) {
277 info->sampleRates[0] = devices[deviceIndex].sampleRates[0];
278 info->sampleRates[1] = devices[deviceIndex].sampleRates[1];
281 for (int i=0; i<info->nSampleRates; i++)
282 info->sampleRates[i] = devices[deviceIndex].sampleRates[i];
284 info->nativeFormats = devices[deviceIndex].nativeFormats;
285 if ( deviceIndex == getDefaultOutputDevice() ||
286 deviceIndex == getDefaultInputDevice() )
287 info->isDefault = true;
293 char * const RtAudio :: getStreamBuffer(int streamId)
295 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
297 return stream->userBuffer;
300 #if defined(__LINUX_ALSA__) || defined(__LINUX_OSS__) || defined(__IRIX_AL__)
302 extern "C" void *callbackHandler(void * ptr);
304 void RtAudio :: setStreamCallback(int streamId, RTAUDIO_CALLBACK callback, void *userData)
306 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
308 CALLBACK_INFO *info = (CALLBACK_INFO *) &stream->callbackInfo;
309 if ( info->usingCallback ) {
310 sprintf(message, "RtAudio: A callback is already set for this stream!");
311 error(RtError::WARNING);
315 info->callback = (void *) callback;
316 info->userData = userData;
317 info->usingCallback = true;
318 info->object = (void *) this;
319 info->streamId = streamId;
321 int err = pthread_create(&info->thread, NULL, callbackHandler, &stream->callbackInfo);
324 info->usingCallback = false;
325 sprintf(message, "RtAudio: error starting callback thread!");
326 error(RtError::THREAD_ERROR);
330 void RtAudio :: cancelStreamCallback(int streamId)
332 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
334 if (stream->callbackInfo.usingCallback) {
336 if (stream->state == STREAM_RUNNING)
337 stopStream( streamId );
339 MUTEX_LOCK(&stream->mutex);
341 stream->callbackInfo.usingCallback = false;
342 pthread_cancel(stream->callbackInfo.thread);
343 pthread_join(stream->callbackInfo.thread, NULL);
344 stream->callbackInfo.thread = 0;
345 stream->callbackInfo.callback = NULL;
346 stream->callbackInfo.userData = NULL;
348 MUTEX_UNLOCK(&stream->mutex);
354 // *************************************************** //
356 // OS/API-specific methods.
358 // *************************************************** //
360 #if defined(__MACOSX_CORE__)
362 // The OS X CoreAudio API is designed to use a separate callback
363 // procedure for each of its audio devices. A single RtAudio duplex
364 // stream using two different devices is supported here, though it
365 // cannot be guaranteed to always behave correctly because we cannot
366 // synchronize these two callbacks. This same functionality can be
367 // achieved with better synchrony by opening two separate streams for
368 // the devices and using RtAudio blocking calls (i.e. tickStream()).
370 // The possibility of having multiple RtAudio streams accessing the
371 // same CoreAudio device is not currently supported. The problem
372 // involves the inability to install our callbackHandler function for
373 // the same device more than once. I experimented with a workaround
374 // for this, but it requires an additional buffer for mixing output
375 // data before filling the CoreAudio device buffer. In the end, I
376 // decided it wasn't worth supporting.
378 // Property listeners are currently not used. The issue is what could
379 // be done if a critical stream parameter (buffer size, sample rate,
380 // device disconnect) notification arrived. The listeners entail
381 // quite a bit of extra code and most likely, a user program wouldn't
382 // be prepared for the result anyway. Some initial listener code is
385 void RtAudio :: initialize(void)
387 OSStatus err = noErr;
389 AudioDeviceID *deviceList = NULL;
392 // Find out how many audio devices there are, if any.
393 err = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDevices, &dataSize, NULL);
395 sprintf(message, "RtAudio: OSX error getting device info!");
396 error(RtError::SYSTEM_ERROR);
399 nDevices = dataSize / sizeof(AudioDeviceID);
400 if (nDevices == 0) return;
402 // Allocate the RTAUDIO_DEVICE structures.
403 devices = (RTAUDIO_DEVICE *) calloc(nDevices, sizeof(RTAUDIO_DEVICE));
404 if (devices == NULL) {
405 sprintf(message, "RtAudio: memory allocation error!");
406 error(RtError::MEMORY_ERROR);
409 // Make space for the devices we are about to get.
410 deviceList = (AudioDeviceID *) malloc( dataSize );
411 if (deviceList == NULL) {
412 sprintf(message, "RtAudio: memory allocation error!");
413 error(RtError::MEMORY_ERROR);
416 // Get the array of AudioDeviceIDs.
417 err = AudioHardwareGetProperty(kAudioHardwarePropertyDevices, &dataSize, (void *) deviceList);
420 sprintf(message, "RtAudio: OSX error getting device properties!");
421 error(RtError::SYSTEM_ERROR);
424 // Write device identifiers to device structures and then
425 // probe the device capabilities.
426 for (int i=0; i<nDevices; i++) {
427 devices[i].id[0] = deviceList[i];
428 //probeDeviceInfo(&devices[i]);
434 int RtAudio :: getDefaultInputDevice(void)
437 UInt32 dataSize = sizeof( AudioDeviceID );
439 OSStatus result = AudioHardwareGetProperty( kAudioHardwarePropertyDefaultInputDevice,
442 if (result != noErr) {
443 sprintf( message, "RtAudio: OSX error getting default input device." );
444 error(RtError::WARNING);
448 for ( int i=0; i<nDevices; i++ ) {
449 if ( id == devices[i].id[0] ) return i;
455 int RtAudio :: getDefaultOutputDevice(void)
458 UInt32 dataSize = sizeof( AudioDeviceID );
460 OSStatus result = AudioHardwareGetProperty( kAudioHardwarePropertyDefaultOutputDevice,
463 if (result != noErr) {
464 sprintf( message, "RtAudio: OSX error getting default output device." );
465 error(RtError::WARNING);
469 for ( int i=0; i<nDevices; i++ ) {
470 if ( id == devices[i].id[0] ) return i;
476 static bool deviceSupportsFormat( AudioDeviceID id, bool isInput,
477 AudioStreamBasicDescription *desc, bool isDuplex )
479 OSStatus result = noErr;
480 UInt32 dataSize = sizeof( AudioStreamBasicDescription );
482 result = AudioDeviceGetProperty( id, 0, isInput,
483 kAudioDevicePropertyStreamFormatSupported,
486 if (result == kAudioHardwareNoError) {
488 result = AudioDeviceGetProperty( id, 0, true,
489 kAudioDevicePropertyStreamFormatSupported,
493 if (result != kAudioHardwareNoError)
502 void RtAudio :: probeDeviceInfo(RTAUDIO_DEVICE *info)
504 OSStatus err = noErr;
506 // Get the device manufacturer and name.
509 UInt32 dataSize = 256;
510 err = AudioDeviceGetProperty( info->id[0], 0, false,
511 kAudioDevicePropertyDeviceManufacturer,
514 sprintf( message, "RtAudio: OSX error getting device manufacturer." );
515 error(RtError::DEBUG_WARNING);
518 strncpy(fullname, name, 256);
519 strcat(fullname, ": " );
522 err = AudioDeviceGetProperty( info->id[0], 0, false,
523 kAudioDevicePropertyDeviceName,
526 sprintf( message, "RtAudio: OSX error getting device name." );
527 error(RtError::DEBUG_WARNING);
530 strncat(fullname, name, 254);
531 strncat(info->name, fullname, 128);
533 // Get output channel information.
534 unsigned int i, minChannels, maxChannels, nStreams = 0;
535 AudioBufferList *bufferList = nil;
536 err = AudioDeviceGetPropertyInfo( info->id[0], 0, false,
537 kAudioDevicePropertyStreamConfiguration,
539 if (err == noErr && dataSize > 0) {
540 bufferList = (AudioBufferList *) malloc( dataSize );
541 if (bufferList == NULL) {
542 sprintf(message, "RtAudio: memory allocation error!");
543 error(RtError::DEBUG_WARNING);
547 err = AudioDeviceGetProperty( info->id[0], 0, false,
548 kAudioDevicePropertyStreamConfiguration,
549 &dataSize, bufferList );
553 nStreams = bufferList->mNumberBuffers;
554 for ( i=0; i<nStreams; i++ ) {
555 maxChannels += bufferList->mBuffers[i].mNumberChannels;
556 if ( bufferList->mBuffers[i].mNumberChannels < minChannels )
557 minChannels = bufferList->mBuffers[i].mNumberChannels;
561 if (err != noErr || dataSize <= 0) {
562 sprintf( message, "RtAudio: OSX error getting output channels for device (%s).", info->name );
563 error(RtError::DEBUG_WARNING);
569 if ( maxChannels > 0 )
570 info->maxOutputChannels = maxChannels;
571 if ( minChannels > 0 )
572 info->minOutputChannels = minChannels;
575 // Get input channel information.
577 err = AudioDeviceGetPropertyInfo( info->id[0], 0, true,
578 kAudioDevicePropertyStreamConfiguration,
580 if (err == noErr && dataSize > 0) {
581 bufferList = (AudioBufferList *) malloc( dataSize );
582 if (bufferList == NULL) {
583 sprintf(message, "RtAudio: memory allocation error!");
584 error(RtError::DEBUG_WARNING);
587 err = AudioDeviceGetProperty( info->id[0], 0, true,
588 kAudioDevicePropertyStreamConfiguration,
589 &dataSize, bufferList );
593 nStreams = bufferList->mNumberBuffers;
594 for ( i=0; i<nStreams; i++ ) {
595 if ( bufferList->mBuffers[i].mNumberChannels < minChannels )
596 minChannels = bufferList->mBuffers[i].mNumberChannels;
597 maxChannels += bufferList->mBuffers[i].mNumberChannels;
601 if (err != noErr || dataSize <= 0) {
602 sprintf( message, "RtAudio: OSX error getting input channels for device (%s).", info->name );
603 error(RtError::DEBUG_WARNING);
609 if ( maxChannels > 0 )
610 info->maxInputChannels = maxChannels;
611 if ( minChannels > 0 )
612 info->minInputChannels = minChannels;
615 // If device opens for both playback and capture, we determine the channels.
616 if (info->maxOutputChannels > 0 && info->maxInputChannels > 0) {
617 info->hasDuplexSupport = true;
618 info->maxDuplexChannels = (info->maxOutputChannels > info->maxInputChannels) ?
619 info->maxInputChannels : info->maxOutputChannels;
620 info->minDuplexChannels = (info->minOutputChannels > info->minInputChannels) ?
621 info->minInputChannels : info->minOutputChannels;
624 // Probe the device sample rate and data format parameters. The
625 // core audio query mechanism is performed on a "stream"
626 // description, which can have a variable number of channels and
627 // apply to input or output only.
629 // Create a stream description structure.
630 AudioStreamBasicDescription description;
631 dataSize = sizeof( AudioStreamBasicDescription );
632 memset(&description, 0, sizeof(AudioStreamBasicDescription));
633 bool isInput = false;
634 if ( info->maxOutputChannels == 0 ) isInput = true;
635 bool isDuplex = false;
636 if ( info->maxDuplexChannels > 0 ) isDuplex = true;
638 // Determine the supported sample rates.
639 info->nSampleRates = 0;
640 for (i=0; i<MAX_SAMPLE_RATES; i++) {
641 description.mSampleRate = (double) SAMPLE_RATES[i];
642 if ( deviceSupportsFormat( info->id[0], isInput, &description, isDuplex ) )
643 info->sampleRates[info->nSampleRates++] = SAMPLE_RATES[i];
646 if (info->nSampleRates == 0) {
647 sprintf( message, "RtAudio: No supported sample rates found for OSX device (%s).", info->name );
648 error(RtError::DEBUG_WARNING);
652 // Check for continuous sample rate support.
653 description.mSampleRate = kAudioStreamAnyRate;
654 if ( deviceSupportsFormat( info->id[0], isInput, &description, isDuplex ) ) {
655 info->sampleRates[1] = info->sampleRates[info->nSampleRates-1];
656 info->nSampleRates = -1;
659 // Determine the supported data formats.
660 info->nativeFormats = 0;
661 description.mFormatID = kAudioFormatLinearPCM;
662 description.mBitsPerChannel = 8;
663 description.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsPacked | kLinearPCMFormatFlagIsBigEndian;
664 if ( deviceSupportsFormat( info->id[0], isInput, &description, isDuplex ) )
665 info->nativeFormats |= RTAUDIO_SINT8;
667 description.mFormatFlags &= ~kLinearPCMFormatFlagIsBigEndian;
668 if ( deviceSupportsFormat( info->id[0], isInput, &description, isDuplex ) )
669 info->nativeFormats |= RTAUDIO_SINT8;
672 description.mBitsPerChannel = 16;
673 description.mFormatFlags |= kLinearPCMFormatFlagIsBigEndian;
674 if ( deviceSupportsFormat( info->id[0], isInput, &description, isDuplex ) )
675 info->nativeFormats |= RTAUDIO_SINT16;
677 description.mFormatFlags &= ~kLinearPCMFormatFlagIsBigEndian;
678 if ( deviceSupportsFormat( info->id[0], isInput, &description, isDuplex ) )
679 info->nativeFormats |= RTAUDIO_SINT16;
682 description.mBitsPerChannel = 32;
683 description.mFormatFlags |= kLinearPCMFormatFlagIsBigEndian;
684 if ( deviceSupportsFormat( info->id[0], isInput, &description, isDuplex ) )
685 info->nativeFormats |= RTAUDIO_SINT32;
687 description.mFormatFlags &= ~kLinearPCMFormatFlagIsBigEndian;
688 if ( deviceSupportsFormat( info->id[0], isInput, &description, isDuplex ) )
689 info->nativeFormats |= RTAUDIO_SINT32;
692 description.mBitsPerChannel = 24;
693 description.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsAlignedHigh | kLinearPCMFormatFlagIsBigEndian;
694 if ( deviceSupportsFormat( info->id[0], isInput, &description, isDuplex ) )
695 info->nativeFormats |= RTAUDIO_SINT24;
697 description.mFormatFlags &= ~kLinearPCMFormatFlagIsBigEndian;
698 if ( deviceSupportsFormat( info->id[0], isInput, &description, isDuplex ) )
699 info->nativeFormats |= RTAUDIO_SINT24;
702 description.mBitsPerChannel = 32;
703 description.mFormatFlags = kLinearPCMFormatFlagIsFloat | kLinearPCMFormatFlagIsPacked | kLinearPCMFormatFlagIsBigEndian;
704 if ( deviceSupportsFormat( info->id[0], isInput, &description, isDuplex ) )
705 info->nativeFormats |= RTAUDIO_FLOAT32;
707 description.mFormatFlags &= ~kLinearPCMFormatFlagIsBigEndian;
708 if ( deviceSupportsFormat( info->id[0], isInput, &description, isDuplex ) )
709 info->nativeFormats |= RTAUDIO_FLOAT32;
712 description.mBitsPerChannel = 64;
713 description.mFormatFlags |= kLinearPCMFormatFlagIsBigEndian;
714 if ( deviceSupportsFormat( info->id[0], isInput, &description, isDuplex ) )
715 info->nativeFormats |= RTAUDIO_FLOAT64;
717 description.mFormatFlags &= ~kLinearPCMFormatFlagIsBigEndian;
718 if ( deviceSupportsFormat( info->id[0], isInput, &description, isDuplex ) )
719 info->nativeFormats |= RTAUDIO_FLOAT64;
722 // Check that we have at least one supported format.
723 if (info->nativeFormats == 0) {
724 sprintf(message, "RtAudio: OSX PCM device (%s) data format not supported by RtAudio.",
726 error(RtError::DEBUG_WARNING);
733 OSStatus callbackHandler(AudioDeviceID inDevice,
734 const AudioTimeStamp* inNow,
735 const AudioBufferList* inInputData,
736 const AudioTimeStamp* inInputTime,
737 AudioBufferList* outOutputData,
738 const AudioTimeStamp* inOutputTime,
741 CALLBACK_INFO *info = (CALLBACK_INFO *) infoPointer;
743 RtAudio *object = (RtAudio *) info->object;
745 object->callbackEvent( info->streamId, inDevice, (void *)inInputData, (void *)outOutputData );
747 catch (RtError &exception) {
748 fprintf(stderr, "\nCallback handler error (%s)!\n\n", exception.getMessage());
749 return kAudioHardwareUnspecifiedError;
752 return kAudioHardwareNoError;
756 OSStatus deviceListener(AudioDeviceID inDevice,
759 AudioDevicePropertyID propertyID,
762 CALLBACK_INFO *info = (CALLBACK_INFO *) infoPointer;
764 RtAudio *object = (RtAudio *) info->object;
766 object->settingChange( info->streamId );
768 catch (RtError &exception) {
769 fprintf(stderr, "\nDevice listener error (%s)!\n\n", exception.getMessage());
770 return kAudioHardwareUnspecifiedError;
773 return kAudioHardwareNoError;
777 bool RtAudio :: probeDeviceOpen(int device, RTAUDIO_STREAM *stream,
778 STREAM_MODE mode, int channels,
779 int sampleRate, RTAUDIO_FORMAT format,
780 int *bufferSize, int numberOfBuffers)
782 // Check to make sure we don't already have a stream accessing this device.
783 RTAUDIO_STREAM *streamPtr;
784 std::map<int, void *>::const_iterator i;
785 for ( i=streams.begin(); i!=streams.end(); ++i ) {
786 streamPtr = (RTAUDIO_STREAM *) i->second;
787 if ( streamPtr->device[0] == device || streamPtr->device[1] == device ) {
788 sprintf(message, "RtAudio: no current OS X support for multiple streams accessing the same device!");
789 error(RtError::WARNING);
794 // Setup for stream mode.
795 bool isInput = false;
796 AudioDeviceID id = devices[device].id[0];
797 if ( mode == INPUT ) isInput = true;
799 // Search for a stream which contains the desired number of channels.
800 OSStatus err = noErr;
802 unsigned int deviceChannels, nStreams;
803 UInt32 iChannel = 0, iStream = 0;
804 AudioBufferList *bufferList = nil;
805 err = AudioDeviceGetPropertyInfo( id, 0, isInput,
806 kAudioDevicePropertyStreamConfiguration,
809 if (err == noErr && dataSize > 0) {
810 bufferList = (AudioBufferList *) malloc( dataSize );
811 if (bufferList == NULL) {
812 sprintf(message, "RtAudio: memory allocation error!");
813 error(RtError::DEBUG_WARNING);
816 err = AudioDeviceGetProperty( id, 0, isInput,
817 kAudioDevicePropertyStreamConfiguration,
818 &dataSize, bufferList );
821 stream->deInterleave[mode] = false;
822 nStreams = bufferList->mNumberBuffers;
823 for ( iStream=0; iStream<nStreams; iStream++ ) {
824 if ( bufferList->mBuffers[iStream].mNumberChannels >= (unsigned int) channels ) break;
825 iChannel += bufferList->mBuffers[iStream].mNumberChannels;
827 // If we didn't find a single stream above, see if we can meet
828 // the channel specification in mono mode (i.e. using separate
829 // non-interleaved buffers). This can only work if there are N
830 // consecutive one-channel streams, where N is the number of
833 if ( iStream >= nStreams && nStreams >= (unsigned int) channels ) {
835 for ( iStream=0; iStream<nStreams; iStream++ ) {
836 if ( bufferList->mBuffers[iStream].mNumberChannels == 1 )
840 if ( counter == channels ) {
841 iStream -= channels - 1;
842 iChannel -= channels - 1;
843 stream->deInterleave[mode] = true;
846 iChannel += bufferList->mBuffers[iStream].mNumberChannels;
851 if (err != noErr || dataSize <= 0) {
852 if ( bufferList ) free( bufferList );
853 sprintf( message, "RtAudio: OSX error getting channels for device (%s).", devices[device].name );
854 error(RtError::DEBUG_WARNING);
858 if (iStream >= nStreams) {
860 sprintf( message, "RtAudio: unable to find OSX audio stream on device (%s) for requested channels (%d).",
861 devices[device].name, channels );
862 error(RtError::DEBUG_WARNING);
866 // This is ok even for mono mode ... it gets updated later.
867 deviceChannels = bufferList->mBuffers[iStream].mNumberChannels;
870 // Determine the buffer size.
871 AudioValueRange bufferRange;
872 dataSize = sizeof(AudioValueRange);
873 err = AudioDeviceGetProperty( id, 0, isInput,
874 kAudioDevicePropertyBufferSizeRange,
875 &dataSize, &bufferRange);
877 sprintf( message, "RtAudio: OSX error getting buffer size range for device (%s).",
878 devices[device].name );
879 error(RtError::DEBUG_WARNING);
883 long bufferBytes = *bufferSize * deviceChannels * formatBytes(RTAUDIO_FLOAT32);
884 if (bufferRange.mMinimum > bufferBytes) bufferBytes = (int) bufferRange.mMinimum;
885 else if (bufferRange.mMaximum < bufferBytes) bufferBytes = (int) bufferRange.mMaximum;
887 // Set the buffer size. For mono mode, I'm assuming we only need to
888 // make this setting for the first channel.
889 UInt32 theSize = (UInt32) bufferBytes;
890 dataSize = sizeof( UInt32);
891 err = AudioDeviceSetProperty(id, NULL, 0, isInput,
892 kAudioDevicePropertyBufferSize,
895 sprintf( message, "RtAudio: OSX error setting the buffer size for device (%s).",
896 devices[device].name );
897 error(RtError::DEBUG_WARNING);
901 // If attempting to setup a duplex stream, the bufferSize parameter
902 // MUST be the same in both directions!
903 *bufferSize = bufferBytes / ( deviceChannels * formatBytes(RTAUDIO_FLOAT32) );
904 if ( stream->mode == OUTPUT && mode == INPUT && *bufferSize != stream->bufferSize ) {
905 sprintf( message, "RtAudio: OSX error setting buffer size for duplex stream on device (%s).",
906 devices[device].name );
907 error(RtError::DEBUG_WARNING);
911 stream->bufferSize = *bufferSize;
912 stream->nBuffers = 1;
914 // Set the stream format description. Do for each channel in mono mode.
915 AudioStreamBasicDescription description;
916 dataSize = sizeof( AudioStreamBasicDescription );
917 if ( stream->deInterleave[mode] ) nStreams = channels;
919 for ( unsigned int i=0; i<nStreams; i++, iChannel++ ) {
921 err = AudioDeviceGetProperty( id, iChannel, isInput,
922 kAudioDevicePropertyStreamFormat,
923 &dataSize, &description );
925 sprintf( message, "RtAudio: OSX error getting stream format for device (%s).", devices[device].name );
926 error(RtError::DEBUG_WARNING);
930 // Set the sample rate and data format id.
931 description.mSampleRate = (double) sampleRate;
932 description.mFormatID = kAudioFormatLinearPCM;
933 err = AudioDeviceSetProperty( id, NULL, iChannel, isInput,
934 kAudioDevicePropertyStreamFormat,
935 dataSize, &description );
937 sprintf( message, "RtAudio: OSX error setting sample rate or data format for device (%s).", devices[device].name );
938 error(RtError::DEBUG_WARNING);
943 // Check whether we need byte-swapping (assuming OS X host is big-endian).
944 iChannel -= nStreams;
945 err = AudioDeviceGetProperty( id, iChannel, isInput,
946 kAudioDevicePropertyStreamFormat,
947 &dataSize, &description );
949 sprintf( message, "RtAudio: OSX error getting stream format for device (%s).", devices[device].name );
950 error(RtError::DEBUG_WARNING);
954 stream->doByteSwap[mode] = false;
955 if ( !description.mFormatFlags & kLinearPCMFormatFlagIsBigEndian )
956 stream->doByteSwap[mode] = true;
958 // From the CoreAudio documentation, PCM data must be supplied as
960 stream->userFormat = format;
961 stream->deviceFormat[mode] = RTAUDIO_FLOAT32;
963 if ( stream->deInterleave[mode] )
964 stream->nDeviceChannels[mode] = channels;
966 stream->nDeviceChannels[mode] = description.mChannelsPerFrame;
967 stream->nUserChannels[mode] = channels;
969 // Set handle and flags for buffer conversion.
970 stream->handle[mode] = iStream;
971 stream->doConvertBuffer[mode] = false;
972 if (stream->userFormat != stream->deviceFormat[mode])
973 stream->doConvertBuffer[mode] = true;
974 if (stream->nUserChannels[mode] < stream->nDeviceChannels[mode])
975 stream->doConvertBuffer[mode] = true;
976 if (stream->nUserChannels[mode] > 1 && stream->deInterleave[mode])
977 stream->doConvertBuffer[mode] = true;
979 // Allocate necessary internal buffers.
980 if ( stream->nUserChannels[0] != stream->nUserChannels[1] ) {
983 if (stream->nUserChannels[0] >= stream->nUserChannels[1])
984 buffer_bytes = stream->nUserChannels[0];
986 buffer_bytes = stream->nUserChannels[1];
988 buffer_bytes *= *bufferSize * formatBytes(stream->userFormat);
989 if (stream->userBuffer) free(stream->userBuffer);
990 stream->userBuffer = (char *) calloc(buffer_bytes, 1);
991 if (stream->userBuffer == NULL)
995 if ( stream->deInterleave[mode] ) {
998 bool makeBuffer = true;
999 if ( mode == OUTPUT )
1000 buffer_bytes = stream->nDeviceChannels[0] * formatBytes(stream->deviceFormat[0]);
1001 else { // mode == INPUT
1002 buffer_bytes = stream->nDeviceChannels[1] * formatBytes(stream->deviceFormat[1]);
1003 if ( stream->mode == OUTPUT && stream->deviceBuffer ) {
1004 long bytes_out = stream->nDeviceChannels[0] * formatBytes(stream->deviceFormat[0]);
1005 if ( buffer_bytes < bytes_out ) makeBuffer = false;
1010 buffer_bytes *= *bufferSize;
1011 if (stream->deviceBuffer) free(stream->deviceBuffer);
1012 stream->deviceBuffer = (char *) calloc(buffer_bytes, 1);
1013 if (stream->deviceBuffer == NULL)
1016 // If not de-interleaving, we point stream->deviceBuffer to the
1017 // OS X supplied device buffer before doing any necessary data
1018 // conversions. This presents a problem if we have a duplex
1019 // stream using one device which needs de-interleaving and
1020 // another device which doesn't. So, save a pointer to our own
1021 // device buffer in the CALLBACK_INFO structure.
1022 stream->callbackInfo.buffers = stream->deviceBuffer;
1026 stream->sampleRate = sampleRate;
1027 stream->device[mode] = device;
1028 stream->state = STREAM_STOPPED;
1029 stream->callbackInfo.object = (void *) this;
1030 stream->callbackInfo.waitTime = (unsigned long) (200000.0 * stream->bufferSize / stream->sampleRate);
1031 stream->callbackInfo.device[mode] = id;
1032 if ( stream->mode == OUTPUT && mode == INPUT && stream->device[0] == device )
1033 // Only one callback procedure per device.
1034 stream->mode = DUPLEX;
1036 err = AudioDeviceAddIOProc( id, callbackHandler, (void *) &stream->callbackInfo );
1038 sprintf( message, "RtAudio: OSX error setting callback for device (%s).", devices[device].name );
1039 error(RtError::DEBUG_WARNING);
1042 if ( stream->mode == OUTPUT && mode == INPUT )
1043 stream->mode = DUPLEX;
1045 stream->mode = mode;
1048 // If we wanted to use property listeners, they would be setup here.
1053 if (stream->userBuffer) {
1054 free(stream->userBuffer);
1055 stream->userBuffer = 0;
1057 sprintf(message, "RtAudio: OSX error allocating buffer memory (%s).", devices[device].name);
1058 error(RtError::WARNING);
1062 void RtAudio :: cancelStreamCallback(int streamId)
1064 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
1066 if (stream->callbackInfo.usingCallback) {
1068 if (stream->state == STREAM_RUNNING)
1069 stopStream( streamId );
1071 MUTEX_LOCK(&stream->mutex);
1073 stream->callbackInfo.usingCallback = false;
1074 stream->callbackInfo.userData = NULL;
1075 stream->state = STREAM_STOPPED;
1076 stream->callbackInfo.callback = NULL;
1078 MUTEX_UNLOCK(&stream->mutex);
1082 void RtAudio :: closeStream(int streamId)
1084 // We don't want an exception to be thrown here because this
1085 // function is called by our class destructor. So, do our own
1087 if ( streams.find( streamId ) == streams.end() ) {
1088 sprintf(message, "RtAudio: invalid stream identifier!");
1089 error(RtError::WARNING);
1093 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) streams[streamId];
1096 if (stream->mode == OUTPUT || stream->mode == DUPLEX) {
1097 id = devices[stream->device[0]].id[0];
1098 if (stream->state == STREAM_RUNNING)
1099 AudioDeviceStop( id, callbackHandler );
1100 AudioDeviceRemoveIOProc( id, callbackHandler );
1103 if (stream->mode == INPUT || ( stream->mode == DUPLEX && stream->device[0] != stream->device[1]) ) {
1104 id = devices[stream->device[1]].id[0];
1105 if (stream->state == STREAM_RUNNING)
1106 AudioDeviceStop( id, callbackHandler );
1107 AudioDeviceRemoveIOProc( id, callbackHandler );
1110 pthread_mutex_destroy(&stream->mutex);
1112 if (stream->userBuffer)
1113 free(stream->userBuffer);
1115 if ( stream->deInterleave[0] || stream->deInterleave[1] )
1116 free(stream->callbackInfo.buffers);
1119 streams.erase(streamId);
1122 void RtAudio :: startStream(int streamId)
1124 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
1126 MUTEX_LOCK(&stream->mutex);
1128 if (stream->state == STREAM_RUNNING)
1132 if (stream->mode == OUTPUT || stream->mode == DUPLEX) {
1134 err = AudioDeviceStart(devices[stream->device[0]].id[0], callbackHandler);
1136 sprintf(message, "RtAudio: OSX error starting callback procedure on device (%s).",
1137 devices[stream->device[0]].name);
1138 MUTEX_UNLOCK(&stream->mutex);
1139 error(RtError::DRIVER_ERROR);
1143 if (stream->mode == INPUT || ( stream->mode == DUPLEX && stream->device[0] != stream->device[1]) ) {
1145 err = AudioDeviceStart(devices[stream->device[1]].id[0], callbackHandler);
1147 sprintf(message, "RtAudio: OSX error starting input callback procedure on device (%s).",
1148 devices[stream->device[0]].name);
1149 MUTEX_UNLOCK(&stream->mutex);
1150 error(RtError::DRIVER_ERROR);
1154 stream->callbackInfo.streamId = streamId;
1155 stream->state = STREAM_RUNNING;
1156 stream->callbackInfo.blockTick = true;
1157 stream->callbackInfo.stopStream = false;
1160 MUTEX_UNLOCK(&stream->mutex);
1163 void RtAudio :: stopStream(int streamId)
1165 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
1167 MUTEX_LOCK(&stream->mutex);
1169 if (stream->state == STREAM_STOPPED)
1173 if (stream->mode == OUTPUT || stream->mode == DUPLEX) {
1175 err = AudioDeviceStop(devices[stream->device[0]].id[0], callbackHandler);
1177 sprintf(message, "RtAudio: OSX error stopping callback procedure on device (%s).",
1178 devices[stream->device[0]].name);
1179 MUTEX_UNLOCK(&stream->mutex);
1180 error(RtError::DRIVER_ERROR);
1184 if (stream->mode == INPUT || ( stream->mode == DUPLEX && stream->device[0] != stream->device[1]) ) {
1186 err = AudioDeviceStop(devices[stream->device[1]].id[0], callbackHandler);
1188 sprintf(message, "RtAudio: OSX error stopping input callback procedure on device (%s).",
1189 devices[stream->device[0]].name);
1190 MUTEX_UNLOCK(&stream->mutex);
1191 error(RtError::DRIVER_ERROR);
1195 stream->state = STREAM_STOPPED;
1198 MUTEX_UNLOCK(&stream->mutex);
1201 void RtAudio :: abortStream(int streamId)
1203 stopStream( streamId );
1206 // I don't know how this function can be implemented.
1207 int RtAudio :: streamWillBlock(int streamId)
1209 sprintf(message, "RtAudio: streamWillBlock() cannot be implemented for OS X.");
1210 error(RtError::WARNING);
1214 void RtAudio :: tickStream(int streamId)
1216 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
1218 if (stream->state == STREAM_STOPPED)
1221 if (stream->callbackInfo.usingCallback) {
1222 sprintf(message, "RtAudio: tickStream() should not be used when a callback function is set!");
1223 error(RtError::WARNING);
1227 // Block waiting here until the user data is processed in callbackEvent().
1228 while ( stream->callbackInfo.blockTick )
1229 usleep(stream->callbackInfo.waitTime);
1231 MUTEX_LOCK(&stream->mutex);
1233 stream->callbackInfo.blockTick = true;
1235 MUTEX_UNLOCK(&stream->mutex);
1238 void RtAudio :: callbackEvent( int streamId, DEVICE_ID deviceId, void *inData, void *outData )
1240 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
1242 CALLBACK_INFO *info;
1243 AudioBufferList *inBufferList = (AudioBufferList *) inData;
1244 AudioBufferList *outBufferList = (AudioBufferList *) outData;
1246 if (stream->state == STREAM_STOPPED) return;
1248 info = (CALLBACK_INFO *) &stream->callbackInfo;
1249 if ( !info->usingCallback ) {
1250 // Block waiting here until we get new user data in tickStream().
1251 while ( !info->blockTick )
1252 usleep(info->waitTime);
1254 else if ( info->stopStream ) {
1255 // Check if the stream should be stopped (via the previous user
1256 // callback return value). We stop the stream here, rather than
1257 // after the function call, so that output data can first be
1259 this->stopStream(info->streamId);
1263 MUTEX_LOCK(&stream->mutex);
1265 // Invoke user callback first, to get fresh output data. Don't
1266 // invoke the user callback if duplex mode, the input/output devices
1267 // are different, and this function is called for the input device.
1268 if ( info->usingCallback && (stream->mode != DUPLEX || deviceId == info->device[0] ) ) {
1269 RTAUDIO_CALLBACK callback = (RTAUDIO_CALLBACK) info->callback;
1270 info->stopStream = callback(stream->userBuffer, stream->bufferSize, info->userData);
1273 if ( stream->mode == OUTPUT || ( stream->mode == DUPLEX && deviceId == info->device[0] ) ) {
1275 if (stream->doConvertBuffer[0]) {
1277 if ( !stream->deInterleave[0] )
1278 stream->deviceBuffer = (char *) outBufferList->mBuffers[stream->handle[0]].mData;
1280 stream->deviceBuffer = (char *) stream->callbackInfo.buffers;
1282 convertStreamBuffer(stream, OUTPUT);
1283 if ( stream->doByteSwap[0] )
1284 byteSwapBuffer(stream->deviceBuffer,
1285 stream->bufferSize * stream->nDeviceChannels[0],
1286 stream->deviceFormat[0]);
1288 if ( stream->deInterleave[0] ) {
1289 int bufferBytes = outBufferList->mBuffers[stream->handle[0]].mDataByteSize;
1290 for ( int i=0; i<stream->nDeviceChannels[0]; i++ ) {
1291 memcpy(outBufferList->mBuffers[stream->handle[0]+i].mData,
1292 &stream->deviceBuffer[i*bufferBytes], bufferBytes );
1298 if (stream->doByteSwap[0])
1299 byteSwapBuffer(stream->userBuffer,
1300 stream->bufferSize * stream->nUserChannels[0],
1301 stream->userFormat);
1303 memcpy(outBufferList->mBuffers[stream->handle[0]].mData,
1305 outBufferList->mBuffers[stream->handle[0]].mDataByteSize );
1309 if ( stream->mode == INPUT || ( stream->mode == DUPLEX && deviceId == info->device[1] ) ) {
1311 if (stream->doConvertBuffer[1]) {
1313 if ( stream->deInterleave[1] ) {
1314 stream->deviceBuffer = (char *) stream->callbackInfo.buffers;
1315 int bufferBytes = inBufferList->mBuffers[stream->handle[1]].mDataByteSize;
1316 for ( int i=0; i<stream->nDeviceChannels[1]; i++ ) {
1317 memcpy(&stream->deviceBuffer[i*bufferBytes],
1318 inBufferList->mBuffers[stream->handle[1]+i].mData, bufferBytes );
1322 stream->deviceBuffer = (char *) inBufferList->mBuffers[stream->handle[1]].mData;
1324 if ( stream->doByteSwap[1] )
1325 byteSwapBuffer(stream->deviceBuffer,
1326 stream->bufferSize * stream->nDeviceChannels[1],
1327 stream->deviceFormat[1]);
1328 convertStreamBuffer(stream, INPUT);
1332 memcpy(stream->userBuffer,
1333 inBufferList->mBuffers[stream->handle[1]].mData,
1334 inBufferList->mBuffers[stream->handle[1]].mDataByteSize );
1336 if (stream->doByteSwap[1])
1337 byteSwapBuffer(stream->userBuffer,
1338 stream->bufferSize * stream->nUserChannels[1],
1339 stream->userFormat);
1343 if ( !info->usingCallback && (stream->mode != DUPLEX || deviceId == info->device[1] ) )
1344 info->blockTick = false;
1346 MUTEX_UNLOCK(&stream->mutex);
1350 void RtAudio :: setStreamCallback(int streamId, RTAUDIO_CALLBACK callback, void *userData)
1352 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
1354 stream->callbackInfo.callback = (void *) callback;
1355 stream->callbackInfo.userData = userData;
1356 stream->callbackInfo.usingCallback = true;
1359 //******************** End of __MACOSX_CORE__ *********************//
1361 #elif defined(__LINUX_ALSA__)
1363 #define MAX_DEVICES 16
1365 void RtAudio :: initialize(void)
1367 int card, result, device;
1370 char deviceNames[MAX_DEVICES][32];
1372 snd_ctl_card_info_t *info;
1373 snd_ctl_card_info_alloca(&info);
1375 // Count cards and devices
1378 snd_card_next(&card);
1379 while ( card >= 0 ) {
1380 sprintf(name, "hw:%d", card);
1381 result = snd_ctl_open(&handle, name, 0);
1383 sprintf(message, "RtAudio: ALSA control open (%i): %s.", card, snd_strerror(result));
1384 error(RtError::DEBUG_WARNING);
1387 result = snd_ctl_card_info(handle, info);
1389 sprintf(message, "RtAudio: ALSA control hardware info (%i): %s.", card, snd_strerror(result));
1390 error(RtError::DEBUG_WARNING);
1393 cardId = snd_ctl_card_info_get_id(info);
1396 result = snd_ctl_pcm_next_device(handle, &device);
1398 sprintf(message, "RtAudio: ALSA control next device (%i): %s.", card, snd_strerror(result));
1399 error(RtError::DEBUG_WARNING);
1404 if ( strlen(cardId) )
1405 sprintf( deviceNames[nDevices++], "hw:%s,%d", cardId, device );
1407 sprintf( deviceNames[nDevices++], "hw:%d,%d", card, device );
1408 if ( nDevices > MAX_DEVICES ) break;
1410 if ( nDevices > MAX_DEVICES ) break;
1412 snd_ctl_close(handle);
1413 snd_card_next(&card);
1416 if (nDevices == 0) return;
1418 // Allocate the RTAUDIO_DEVICE structures.
1419 devices = (RTAUDIO_DEVICE *) calloc(nDevices, sizeof(RTAUDIO_DEVICE));
1420 if (devices == NULL) {
1421 sprintf(message, "RtAudio: memory allocation error!");
1422 error(RtError::MEMORY_ERROR);
1425 // Write device ascii identifiers to device structures and then
1426 // probe the device capabilities.
1427 for (int i=0; i<nDevices; i++) {
1428 strncpy(devices[i].name, deviceNames[i], 32);
1429 //probeDeviceInfo(&devices[i]);
1433 int RtAudio :: getDefaultInputDevice(void)
1435 // No ALSA API functions for default devices.
1439 int RtAudio :: getDefaultOutputDevice(void)
1441 // No ALSA API functions for default devices.
1445 void RtAudio :: probeDeviceInfo(RTAUDIO_DEVICE *info)
1448 int open_mode = SND_PCM_ASYNC;
1451 snd_pcm_stream_t stream;
1452 snd_pcm_info_t *pcminfo;
1453 snd_pcm_info_alloca(&pcminfo);
1454 snd_pcm_hw_params_t *params;
1455 snd_pcm_hw_params_alloca(¶ms);
1459 // Open the control interface for this card.
1460 strncpy( name, info->name, 32 );
1461 card = strtok(name, ",");
1462 err = snd_ctl_open(&chandle, card, 0);
1464 sprintf(message, "RtAudio: ALSA control open (%s): %s.", card, snd_strerror(err));
1465 error(RtError::DEBUG_WARNING);
1468 unsigned int dev = (unsigned int) atoi( strtok(NULL, ",") );
1470 // First try for playback
1471 stream = SND_PCM_STREAM_PLAYBACK;
1472 snd_pcm_info_set_device(pcminfo, dev);
1473 snd_pcm_info_set_subdevice(pcminfo, 0);
1474 snd_pcm_info_set_stream(pcminfo, stream);
1476 if ((err = snd_ctl_pcm_info(chandle, pcminfo)) < 0) {
1477 if (err == -ENOENT) {
1478 sprintf(message, "RtAudio: ALSA pcm device (%s) doesn't handle output!", info->name);
1479 error(RtError::DEBUG_WARNING);
1482 sprintf(message, "RtAudio: ALSA snd_ctl_pcm_info error for device (%s) output: %s",
1483 info->name, snd_strerror(err));
1484 error(RtError::DEBUG_WARNING);
1489 err = snd_pcm_open(&handle, info->name, stream, open_mode | SND_PCM_NONBLOCK );
1492 sprintf(message, "RtAudio: ALSA pcm playback device (%s) is busy: %s.",
1493 info->name, snd_strerror(err));
1495 sprintf(message, "RtAudio: ALSA pcm playback open (%s) error: %s.",
1496 info->name, snd_strerror(err));
1497 error(RtError::DEBUG_WARNING);
1501 // We have an open device ... allocate the parameter structure.
1502 err = snd_pcm_hw_params_any(handle, params);
1504 snd_pcm_close(handle);
1505 sprintf(message, "RtAudio: ALSA hardware probe error (%s): %s.",
1506 info->name, snd_strerror(err));
1507 error(RtError::WARNING);
1511 // Get output channel information.
1512 info->minOutputChannels = snd_pcm_hw_params_get_channels_min(params);
1513 info->maxOutputChannels = snd_pcm_hw_params_get_channels_max(params);
1515 snd_pcm_close(handle);
1518 // Now try for capture
1519 stream = SND_PCM_STREAM_CAPTURE;
1520 snd_pcm_info_set_stream(pcminfo, stream);
1522 err = snd_ctl_pcm_info(chandle, pcminfo);
1523 snd_ctl_close(chandle);
1525 if (err == -ENOENT) {
1526 sprintf(message, "RtAudio: ALSA pcm device (%s) doesn't handle input!", info->name);
1527 error(RtError::DEBUG_WARNING);
1530 sprintf(message, "RtAudio: ALSA snd_ctl_pcm_info error for device (%s) input: %s",
1531 info->name, snd_strerror(err));
1532 error(RtError::DEBUG_WARNING);
1534 if (info->maxOutputChannels == 0)
1535 // didn't open for playback either ... device invalid
1537 goto probe_parameters;
1540 err = snd_pcm_open(&handle, info->name, stream, open_mode | SND_PCM_NONBLOCK);
1543 sprintf(message, "RtAudio: ALSA pcm capture device (%s) is busy: %s.",
1544 info->name, snd_strerror(err));
1546 sprintf(message, "RtAudio: ALSA pcm capture open (%s) error: %s.",
1547 info->name, snd_strerror(err));
1548 error(RtError::DEBUG_WARNING);
1549 if (info->maxOutputChannels == 0)
1550 // didn't open for playback either ... device invalid
1552 goto probe_parameters;
1555 // We have an open capture device ... allocate the parameter structure.
1556 err = snd_pcm_hw_params_any(handle, params);
1558 snd_pcm_close(handle);
1559 sprintf(message, "RtAudio: ALSA hardware probe error (%s): %s.",
1560 info->name, snd_strerror(err));
1561 error(RtError::WARNING);
1562 if (info->maxOutputChannels > 0)
1563 goto probe_parameters;
1568 // Get input channel information.
1569 info->minInputChannels = snd_pcm_hw_params_get_channels_min(params);
1570 info->maxInputChannels = snd_pcm_hw_params_get_channels_max(params);
1572 snd_pcm_close(handle);
1574 // If device opens for both playback and capture, we determine the channels.
1575 if (info->maxOutputChannels == 0 || info->maxInputChannels == 0)
1576 goto probe_parameters;
1578 info->hasDuplexSupport = true;
1579 info->maxDuplexChannels = (info->maxOutputChannels > info->maxInputChannels) ?
1580 info->maxInputChannels : info->maxOutputChannels;
1581 info->minDuplexChannels = (info->minOutputChannels > info->minInputChannels) ?
1582 info->minInputChannels : info->minOutputChannels;
1585 // At this point, we just need to figure out the supported data
1586 // formats and sample rates. We'll proceed by opening the device in
1587 // the direction with the maximum number of channels, or playback if
1588 // they are equal. This might limit our sample rate options, but so
1591 if (info->maxOutputChannels >= info->maxInputChannels)
1592 stream = SND_PCM_STREAM_PLAYBACK;
1594 stream = SND_PCM_STREAM_CAPTURE;
1596 err = snd_pcm_open(&handle, info->name, stream, open_mode);
1598 sprintf(message, "RtAudio: ALSA pcm (%s) won't reopen during probe: %s.",
1599 info->name, snd_strerror(err));
1600 error(RtError::WARNING);
1604 // We have an open device ... allocate the parameter structure.
1605 err = snd_pcm_hw_params_any(handle, params);
1607 snd_pcm_close(handle);
1608 sprintf(message, "RtAudio: ALSA hardware reopen probe error (%s): %s.",
1609 info->name, snd_strerror(err));
1610 error(RtError::WARNING);
1614 // Test a non-standard sample rate to see if continuous rate is supported.
1616 if (snd_pcm_hw_params_test_rate(handle, params, 35500, dir) == 0) {
1617 // It appears that continuous sample rate support is available.
1618 info->nSampleRates = -1;
1619 info->sampleRates[0] = snd_pcm_hw_params_get_rate_min(params, &dir);
1620 info->sampleRates[1] = snd_pcm_hw_params_get_rate_max(params, &dir);
1623 // No continuous rate support ... test our discrete set of sample rate values.
1624 info->nSampleRates = 0;
1625 for (int i=0; i<MAX_SAMPLE_RATES; i++) {
1626 if (snd_pcm_hw_params_test_rate(handle, params, SAMPLE_RATES[i], dir) == 0) {
1627 info->sampleRates[info->nSampleRates] = SAMPLE_RATES[i];
1628 info->nSampleRates++;
1631 if (info->nSampleRates == 0) {
1632 snd_pcm_close(handle);
1637 // Probe the supported data formats ... we don't care about endian-ness just yet
1638 snd_pcm_format_t format;
1639 info->nativeFormats = 0;
1640 format = SND_PCM_FORMAT_S8;
1641 if (snd_pcm_hw_params_test_format(handle, params, format) == 0)
1642 info->nativeFormats |= RTAUDIO_SINT8;
1643 format = SND_PCM_FORMAT_S16;
1644 if (snd_pcm_hw_params_test_format(handle, params, format) == 0)
1645 info->nativeFormats |= RTAUDIO_SINT16;
1646 format = SND_PCM_FORMAT_S24;
1647 if (snd_pcm_hw_params_test_format(handle, params, format) == 0)
1648 info->nativeFormats |= RTAUDIO_SINT24;
1649 format = SND_PCM_FORMAT_S32;
1650 if (snd_pcm_hw_params_test_format(handle, params, format) == 0)
1651 info->nativeFormats |= RTAUDIO_SINT32;
1652 format = SND_PCM_FORMAT_FLOAT;
1653 if (snd_pcm_hw_params_test_format(handle, params, format) == 0)
1654 info->nativeFormats |= RTAUDIO_FLOAT32;
1655 format = SND_PCM_FORMAT_FLOAT64;
1656 if (snd_pcm_hw_params_test_format(handle, params, format) == 0)
1657 info->nativeFormats |= RTAUDIO_FLOAT64;
1659 // Check that we have at least one supported format
1660 if (info->nativeFormats == 0) {
1661 snd_pcm_close(handle);
1662 sprintf(message, "RtAudio: ALSA PCM device (%s) data format not supported by RtAudio.",
1664 error(RtError::WARNING);
1668 // That's all ... close the device and return
1669 snd_pcm_close(handle);
1670 info->probed = true;
1674 bool RtAudio :: probeDeviceOpen(int device, RTAUDIO_STREAM *stream,
1675 STREAM_MODE mode, int channels,
1676 int sampleRate, RTAUDIO_FORMAT format,
1677 int *bufferSize, int numberOfBuffers)
1679 #if defined(__RTAUDIO_DEBUG__)
1681 snd_output_stdio_attach(&out, stderr, 0);
1684 // I'm not using the "plug" interface ... too much inconsistent behavior.
1685 const char *name = devices[device].name;
1687 snd_pcm_stream_t alsa_stream;
1689 alsa_stream = SND_PCM_STREAM_PLAYBACK;
1691 alsa_stream = SND_PCM_STREAM_CAPTURE;
1695 int alsa_open_mode = SND_PCM_ASYNC;
1696 err = snd_pcm_open(&handle, name, alsa_stream, alsa_open_mode);
1698 sprintf(message,"RtAudio: ALSA pcm device (%s) won't open: %s.",
1699 name, snd_strerror(err));
1700 error(RtError::WARNING);
1704 // Fill the parameter structure.
1705 snd_pcm_hw_params_t *hw_params;
1706 snd_pcm_hw_params_alloca(&hw_params);
1707 err = snd_pcm_hw_params_any(handle, hw_params);
1709 snd_pcm_close(handle);
1710 sprintf(message, "RtAudio: ALSA error getting parameter handle (%s): %s.",
1711 name, snd_strerror(err));
1712 error(RtError::WARNING);
1716 #if defined(__RTAUDIO_DEBUG__)
1717 fprintf(stderr, "\nRtAudio: ALSA dump hardware params just after device open:\n\n");
1718 snd_pcm_hw_params_dump(hw_params, out);
1722 // Set access ... try interleaved access first, then non-interleaved
1723 if ( !snd_pcm_hw_params_test_access( handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED) ) {
1724 err = snd_pcm_hw_params_set_access(handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED);
1726 else if ( !snd_pcm_hw_params_test_access( handle, hw_params, SND_PCM_ACCESS_RW_NONINTERLEAVED) ) {
1727 err = snd_pcm_hw_params_set_access(handle, hw_params, SND_PCM_ACCESS_RW_NONINTERLEAVED);
1728 stream->deInterleave[mode] = true;
1731 snd_pcm_close(handle);
1732 sprintf(message, "RtAudio: ALSA device (%s) access not supported by RtAudio.", name);
1733 error(RtError::WARNING);
1738 snd_pcm_close(handle);
1739 sprintf(message, "RtAudio: ALSA error setting access ( (%s): %s.", name, snd_strerror(err));
1740 error(RtError::WARNING);
1744 // Determine how to set the device format.
1745 stream->userFormat = format;
1746 snd_pcm_format_t device_format;
1748 if (format == RTAUDIO_SINT8)
1749 device_format = SND_PCM_FORMAT_S8;
1750 else if (format == RTAUDIO_SINT16)
1751 device_format = SND_PCM_FORMAT_S16;
1752 else if (format == RTAUDIO_SINT24)
1753 device_format = SND_PCM_FORMAT_S24;
1754 else if (format == RTAUDIO_SINT32)
1755 device_format = SND_PCM_FORMAT_S32;
1756 else if (format == RTAUDIO_FLOAT32)
1757 device_format = SND_PCM_FORMAT_FLOAT;
1758 else if (format == RTAUDIO_FLOAT64)
1759 device_format = SND_PCM_FORMAT_FLOAT64;
1761 if (snd_pcm_hw_params_test_format(handle, hw_params, device_format) == 0) {
1762 stream->deviceFormat[mode] = format;
1766 // The user requested format is not natively supported by the device.
1767 device_format = SND_PCM_FORMAT_FLOAT64;
1768 if (snd_pcm_hw_params_test_format(handle, hw_params, device_format) == 0) {
1769 stream->deviceFormat[mode] = RTAUDIO_FLOAT64;
1773 device_format = SND_PCM_FORMAT_FLOAT;
1774 if (snd_pcm_hw_params_test_format(handle, hw_params, device_format) == 0) {
1775 stream->deviceFormat[mode] = RTAUDIO_FLOAT32;
1779 device_format = SND_PCM_FORMAT_S32;
1780 if (snd_pcm_hw_params_test_format(handle, hw_params, device_format) == 0) {
1781 stream->deviceFormat[mode] = RTAUDIO_SINT32;
1785 device_format = SND_PCM_FORMAT_S24;
1786 if (snd_pcm_hw_params_test_format(handle, hw_params, device_format) == 0) {
1787 stream->deviceFormat[mode] = RTAUDIO_SINT24;
1791 device_format = SND_PCM_FORMAT_S16;
1792 if (snd_pcm_hw_params_test_format(handle, hw_params, device_format) == 0) {
1793 stream->deviceFormat[mode] = RTAUDIO_SINT16;
1797 device_format = SND_PCM_FORMAT_S8;
1798 if (snd_pcm_hw_params_test_format(handle, hw_params, device_format) == 0) {
1799 stream->deviceFormat[mode] = RTAUDIO_SINT8;
1803 // If we get here, no supported format was found.
1804 sprintf(message,"RtAudio: ALSA pcm device (%s) data format not supported by RtAudio.", name);
1805 snd_pcm_close(handle);
1806 error(RtError::WARNING);
1810 err = snd_pcm_hw_params_set_format(handle, hw_params, device_format);
1812 snd_pcm_close(handle);
1813 sprintf(message, "RtAudio: ALSA error setting format (%s): %s.",
1814 name, snd_strerror(err));
1815 error(RtError::WARNING);
1819 // Determine whether byte-swaping is necessary.
1820 stream->doByteSwap[mode] = false;
1821 if (device_format != SND_PCM_FORMAT_S8) {
1822 err = snd_pcm_format_cpu_endian(device_format);
1824 stream->doByteSwap[mode] = true;
1826 snd_pcm_close(handle);
1827 sprintf(message, "RtAudio: ALSA error getting format endian-ness (%s): %s.",
1828 name, snd_strerror(err));
1829 error(RtError::WARNING);
1834 // Set the sample rate.
1835 err = snd_pcm_hw_params_set_rate(handle, hw_params, (unsigned int)sampleRate, 0);
1837 snd_pcm_close(handle);
1838 sprintf(message, "RtAudio: ALSA error setting sample rate (%d) on device (%s): %s.",
1839 sampleRate, name, snd_strerror(err));
1840 error(RtError::WARNING);
1844 // Determine the number of channels for this device. We support a possible
1845 // minimum device channel number > than the value requested by the user.
1846 stream->nUserChannels[mode] = channels;
1847 int device_channels = snd_pcm_hw_params_get_channels_max(hw_params);
1848 if (device_channels < channels) {
1849 snd_pcm_close(handle);
1850 sprintf(message, "RtAudio: channels (%d) not supported by device (%s).",
1852 error(RtError::WARNING);
1856 device_channels = snd_pcm_hw_params_get_channels_min(hw_params);
1857 if (device_channels < channels) device_channels = channels;
1858 stream->nDeviceChannels[mode] = device_channels;
1860 // Set the device channels.
1861 err = snd_pcm_hw_params_set_channels(handle, hw_params, device_channels);
1863 snd_pcm_close(handle);
1864 sprintf(message, "RtAudio: ALSA error setting channels (%d) on device (%s): %s.",
1865 device_channels, name, snd_strerror(err));
1866 error(RtError::WARNING);
1870 // Set the buffer number, which in ALSA is referred to as the "period".
1872 int periods = numberOfBuffers;
1873 // Even though the hardware might allow 1 buffer, it won't work reliably.
1874 if (periods < 2) periods = 2;
1875 err = snd_pcm_hw_params_get_periods_min(hw_params, &dir);
1876 if (err > periods) periods = err;
1877 err = snd_pcm_hw_params_get_periods_max(hw_params, &dir);
1878 if (err < periods) periods = err;
1880 err = snd_pcm_hw_params_set_periods(handle, hw_params, periods, 0);
1882 snd_pcm_close(handle);
1883 sprintf(message, "RtAudio: ALSA error setting periods (%s): %s.",
1884 name, snd_strerror(err));
1885 error(RtError::WARNING);
1889 // Set the buffer (or period) size.
1890 err = snd_pcm_hw_params_get_period_size_min(hw_params, &dir);
1891 if (err > *bufferSize) *bufferSize = err;
1893 err = snd_pcm_hw_params_set_period_size(handle, hw_params, *bufferSize, 0);
1895 snd_pcm_close(handle);
1896 sprintf(message, "RtAudio: ALSA error setting period size (%s): %s.",
1897 name, snd_strerror(err));
1898 error(RtError::WARNING);
1902 // If attempting to setup a duplex stream, the bufferSize parameter
1903 // MUST be the same in both directions!
1904 if ( stream->mode == OUTPUT && mode == INPUT && *bufferSize != stream->bufferSize ) {
1905 sprintf( message, "RtAudio: ALSA error setting buffer size for duplex stream on device (%s).",
1907 error(RtError::DEBUG_WARNING);
1911 stream->bufferSize = *bufferSize;
1913 // Install the hardware configuration
1914 err = snd_pcm_hw_params(handle, hw_params);
1916 snd_pcm_close(handle);
1917 sprintf(message, "RtAudio: ALSA error installing hardware configuration (%s): %s.",
1918 name, snd_strerror(err));
1919 error(RtError::WARNING);
1923 #if defined(__RTAUDIO_DEBUG__)
1924 fprintf(stderr, "\nRtAudio: ALSA dump hardware params after installation:\n\n");
1925 snd_pcm_hw_params_dump(hw_params, out);
1929 // Install the software configuration
1930 snd_pcm_sw_params_t *sw_params = NULL;
1931 snd_pcm_sw_params_alloca(&sw_params);
1932 snd_pcm_sw_params_current(handle, sw_params);
1933 err = snd_pcm_sw_params(handle, sw_params);
1935 snd_pcm_close(handle);
1936 sprintf(message, "RtAudio: ALSA error installing software configuration (%s): %s.",
1937 name, snd_strerror(err));
1938 error(RtError::WARNING);
1943 // Set handle and flags for buffer conversion
1944 stream->handle[mode] = handle;
1945 stream->doConvertBuffer[mode] = false;
1946 if (stream->userFormat != stream->deviceFormat[mode])
1947 stream->doConvertBuffer[mode] = true;
1948 if (stream->nUserChannels[mode] < stream->nDeviceChannels[mode])
1949 stream->doConvertBuffer[mode] = true;
1950 if (stream->nUserChannels[mode] > 1 && stream->deInterleave[mode])
1951 stream->doConvertBuffer[mode] = true;
1953 // Allocate necessary internal buffers
1954 if ( stream->nUserChannels[0] != stream->nUserChannels[1] ) {
1957 if (stream->nUserChannels[0] >= stream->nUserChannels[1])
1958 buffer_bytes = stream->nUserChannels[0];
1960 buffer_bytes = stream->nUserChannels[1];
1962 buffer_bytes *= *bufferSize * formatBytes(stream->userFormat);
1963 if (stream->userBuffer) free(stream->userBuffer);
1964 stream->userBuffer = (char *) calloc(buffer_bytes, 1);
1965 if (stream->userBuffer == NULL)
1969 if ( stream->doConvertBuffer[mode] ) {
1972 bool makeBuffer = true;
1973 if ( mode == OUTPUT )
1974 buffer_bytes = stream->nDeviceChannels[0] * formatBytes(stream->deviceFormat[0]);
1975 else { // mode == INPUT
1976 buffer_bytes = stream->nDeviceChannels[1] * formatBytes(stream->deviceFormat[1]);
1977 if ( stream->mode == OUTPUT && stream->deviceBuffer ) {
1978 long bytes_out = stream->nDeviceChannels[0] * formatBytes(stream->deviceFormat[0]);
1979 if ( buffer_bytes < bytes_out ) makeBuffer = false;
1984 buffer_bytes *= *bufferSize;
1985 if (stream->deviceBuffer) free(stream->deviceBuffer);
1986 stream->deviceBuffer = (char *) calloc(buffer_bytes, 1);
1987 if (stream->deviceBuffer == NULL)
1992 stream->device[mode] = device;
1993 stream->state = STREAM_STOPPED;
1994 if ( stream->mode == OUTPUT && mode == INPUT )
1995 // We had already set up an output stream.
1996 stream->mode = DUPLEX;
1998 stream->mode = mode;
1999 stream->nBuffers = periods;
2000 stream->sampleRate = sampleRate;
2005 if (stream->handle[0]) {
2006 snd_pcm_close(stream->handle[0]);
2007 stream->handle[0] = 0;
2009 if (stream->handle[1]) {
2010 snd_pcm_close(stream->handle[1]);
2011 stream->handle[1] = 0;
2013 if (stream->userBuffer) {
2014 free(stream->userBuffer);
2015 stream->userBuffer = 0;
2017 sprintf(message, "RtAudio: ALSA error allocating buffer memory (%s).", name);
2018 error(RtError::WARNING);
2022 void RtAudio :: closeStream(int streamId)
2024 // We don't want an exception to be thrown here because this
2025 // function is called by our class destructor. So, do our own
2027 if ( streams.find( streamId ) == streams.end() ) {
2028 sprintf(message, "RtAudio: invalid stream identifier!");
2029 error(RtError::WARNING);
2033 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) streams[streamId];
2035 if (stream->callbackInfo.usingCallback) {
2036 pthread_cancel(stream->callbackInfo.thread);
2037 pthread_join(stream->callbackInfo.thread, NULL);
2040 if (stream->state == STREAM_RUNNING) {
2041 if (stream->mode == OUTPUT || stream->mode == DUPLEX)
2042 snd_pcm_drop(stream->handle[0]);
2043 if (stream->mode == INPUT || stream->mode == DUPLEX)
2044 snd_pcm_drop(stream->handle[1]);
2047 pthread_mutex_destroy(&stream->mutex);
2049 if (stream->handle[0])
2050 snd_pcm_close(stream->handle[0]);
2052 if (stream->handle[1])
2053 snd_pcm_close(stream->handle[1]);
2055 if (stream->userBuffer)
2056 free(stream->userBuffer);
2058 if (stream->deviceBuffer)
2059 free(stream->deviceBuffer);
2062 streams.erase(streamId);
2065 void RtAudio :: startStream(int streamId)
2067 // This method calls snd_pcm_prepare if the device isn't already in that state.
2069 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
2071 MUTEX_LOCK(&stream->mutex);
2073 if (stream->state == STREAM_RUNNING)
2077 snd_pcm_state_t state;
2078 if (stream->mode == OUTPUT || stream->mode == DUPLEX) {
2079 state = snd_pcm_state(stream->handle[0]);
2080 if (state != SND_PCM_STATE_PREPARED) {
2081 err = snd_pcm_prepare(stream->handle[0]);
2083 sprintf(message, "RtAudio: ALSA error preparing pcm device (%s): %s.",
2084 devices[stream->device[0]].name, snd_strerror(err));
2085 MUTEX_UNLOCK(&stream->mutex);
2086 error(RtError::DRIVER_ERROR);
2091 if (stream->mode == INPUT || stream->mode == DUPLEX) {
2092 state = snd_pcm_state(stream->handle[1]);
2093 if (state != SND_PCM_STATE_PREPARED) {
2094 err = snd_pcm_prepare(stream->handle[1]);
2096 sprintf(message, "RtAudio: ALSA error preparing pcm device (%s): %s.",
2097 devices[stream->device[1]].name, snd_strerror(err));
2098 MUTEX_UNLOCK(&stream->mutex);
2099 error(RtError::DRIVER_ERROR);
2103 stream->state = STREAM_RUNNING;
2106 MUTEX_UNLOCK(&stream->mutex);
2109 void RtAudio :: stopStream(int streamId)
2111 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
2113 MUTEX_LOCK(&stream->mutex);
2115 if (stream->state == STREAM_STOPPED)
2119 if (stream->mode == OUTPUT || stream->mode == DUPLEX) {
2120 err = snd_pcm_drain(stream->handle[0]);
2122 sprintf(message, "RtAudio: ALSA error draining pcm device (%s): %s.",
2123 devices[stream->device[0]].name, snd_strerror(err));
2124 MUTEX_UNLOCK(&stream->mutex);
2125 error(RtError::DRIVER_ERROR);
2129 if (stream->mode == INPUT || stream->mode == DUPLEX) {
2130 err = snd_pcm_drain(stream->handle[1]);
2132 sprintf(message, "RtAudio: ALSA error draining pcm device (%s): %s.",
2133 devices[stream->device[1]].name, snd_strerror(err));
2134 MUTEX_UNLOCK(&stream->mutex);
2135 error(RtError::DRIVER_ERROR);
2138 stream->state = STREAM_STOPPED;
2141 MUTEX_UNLOCK(&stream->mutex);
2144 void RtAudio :: abortStream(int streamId)
2146 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
2148 MUTEX_LOCK(&stream->mutex);
2150 if (stream->state == STREAM_STOPPED)
2154 if (stream->mode == OUTPUT || stream->mode == DUPLEX) {
2155 err = snd_pcm_drop(stream->handle[0]);
2157 sprintf(message, "RtAudio: ALSA error draining pcm device (%s): %s.",
2158 devices[stream->device[0]].name, snd_strerror(err));
2159 MUTEX_UNLOCK(&stream->mutex);
2160 error(RtError::DRIVER_ERROR);
2164 if (stream->mode == INPUT || stream->mode == DUPLEX) {
2165 err = snd_pcm_drop(stream->handle[1]);
2167 sprintf(message, "RtAudio: ALSA error draining pcm device (%s): %s.",
2168 devices[stream->device[1]].name, snd_strerror(err));
2169 MUTEX_UNLOCK(&stream->mutex);
2170 error(RtError::DRIVER_ERROR);
2173 stream->state = STREAM_STOPPED;
2176 MUTEX_UNLOCK(&stream->mutex);
2179 int RtAudio :: streamWillBlock(int streamId)
2181 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
2183 MUTEX_LOCK(&stream->mutex);
2185 int err = 0, frames = 0;
2186 if (stream->state == STREAM_STOPPED)
2189 if (stream->mode == OUTPUT || stream->mode == DUPLEX) {
2190 err = snd_pcm_avail_update(stream->handle[0]);
2192 sprintf(message, "RtAudio: ALSA error getting available frames for device (%s): %s.",
2193 devices[stream->device[0]].name, snd_strerror(err));
2194 MUTEX_UNLOCK(&stream->mutex);
2195 error(RtError::DRIVER_ERROR);
2201 if (stream->mode == INPUT || stream->mode == DUPLEX) {
2202 err = snd_pcm_avail_update(stream->handle[1]);
2204 sprintf(message, "RtAudio: ALSA error getting available frames for device (%s): %s.",
2205 devices[stream->device[1]].name, snd_strerror(err));
2206 MUTEX_UNLOCK(&stream->mutex);
2207 error(RtError::DRIVER_ERROR);
2209 if (frames > err) frames = err;
2212 frames = stream->bufferSize - frames;
2213 if (frames < 0) frames = 0;
2216 MUTEX_UNLOCK(&stream->mutex);
2220 void RtAudio :: tickStream(int streamId)
2222 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
2225 if (stream->state == STREAM_STOPPED) {
2226 if (stream->callbackInfo.usingCallback) usleep(50000); // sleep 50 milliseconds
2229 else if (stream->callbackInfo.usingCallback) {
2230 RTAUDIO_CALLBACK callback = (RTAUDIO_CALLBACK) stream->callbackInfo.callback;
2231 stopStream = callback(stream->userBuffer, stream->bufferSize, stream->callbackInfo.userData);
2234 MUTEX_LOCK(&stream->mutex);
2236 // The state might change while waiting on a mutex.
2237 if (stream->state == STREAM_STOPPED)
2243 RTAUDIO_FORMAT format;
2244 if (stream->mode == OUTPUT || stream->mode == DUPLEX) {
2246 // Setup parameters and do buffer conversion if necessary.
2247 if (stream->doConvertBuffer[0]) {
2248 convertStreamBuffer(stream, OUTPUT);
2249 buffer = stream->deviceBuffer;
2250 channels = stream->nDeviceChannels[0];
2251 format = stream->deviceFormat[0];
2254 buffer = stream->userBuffer;
2255 channels = stream->nUserChannels[0];
2256 format = stream->userFormat;
2259 // Do byte swapping if necessary.
2260 if (stream->doByteSwap[0])
2261 byteSwapBuffer(buffer, stream->bufferSize * channels, format);
2263 // Write samples to device in interleaved/non-interleaved format.
2264 if (stream->deInterleave[0]) {
2265 void *bufs[channels];
2266 size_t offset = stream->bufferSize * formatBytes(format);
2267 for (int i=0; i<channels; i++)
2268 bufs[i] = (void *) (buffer + (i * offset));
2269 err = snd_pcm_writen(stream->handle[0], bufs, stream->bufferSize);
2272 err = snd_pcm_writei(stream->handle[0], buffer, stream->bufferSize);
2274 if (err < stream->bufferSize) {
2275 // Either an error or underrun occured.
2276 if (err == -EPIPE) {
2277 snd_pcm_state_t state = snd_pcm_state(stream->handle[0]);
2278 if (state == SND_PCM_STATE_XRUN) {
2279 sprintf(message, "RtAudio: ALSA underrun detected.");
2280 error(RtError::WARNING);
2281 err = snd_pcm_prepare(stream->handle[0]);
2283 sprintf(message, "RtAudio: ALSA error preparing handle after underrun: %s.",
2285 MUTEX_UNLOCK(&stream->mutex);
2286 error(RtError::DRIVER_ERROR);
2290 sprintf(message, "RtAudio: ALSA error, current state is %s.",
2291 snd_pcm_state_name(state));
2292 MUTEX_UNLOCK(&stream->mutex);
2293 error(RtError::DRIVER_ERROR);
2298 sprintf(message, "RtAudio: ALSA audio write error for device (%s): %s.",
2299 devices[stream->device[0]].name, snd_strerror(err));
2300 MUTEX_UNLOCK(&stream->mutex);
2301 error(RtError::DRIVER_ERROR);
2306 if (stream->mode == INPUT || stream->mode == DUPLEX) {
2308 // Setup parameters.
2309 if (stream->doConvertBuffer[1]) {
2310 buffer = stream->deviceBuffer;
2311 channels = stream->nDeviceChannels[1];
2312 format = stream->deviceFormat[1];
2315 buffer = stream->userBuffer;
2316 channels = stream->nUserChannels[1];
2317 format = stream->userFormat;
2320 // Read samples from device in interleaved/non-interleaved format.
2321 if (stream->deInterleave[1]) {
2322 void *bufs[channels];
2323 size_t offset = stream->bufferSize * formatBytes(format);
2324 for (int i=0; i<channels; i++)
2325 bufs[i] = (void *) (buffer + (i * offset));
2326 err = snd_pcm_readn(stream->handle[1], bufs, stream->bufferSize);
2329 err = snd_pcm_readi(stream->handle[1], buffer, stream->bufferSize);
2331 if (err < stream->bufferSize) {
2332 // Either an error or underrun occured.
2333 if (err == -EPIPE) {
2334 snd_pcm_state_t state = snd_pcm_state(stream->handle[1]);
2335 if (state == SND_PCM_STATE_XRUN) {
2336 sprintf(message, "RtAudio: ALSA overrun detected.");
2337 error(RtError::WARNING);
2338 err = snd_pcm_prepare(stream->handle[1]);
2340 sprintf(message, "RtAudio: ALSA error preparing handle after overrun: %s.",
2342 MUTEX_UNLOCK(&stream->mutex);
2343 error(RtError::DRIVER_ERROR);
2347 sprintf(message, "RtAudio: ALSA error, current state is %s.",
2348 snd_pcm_state_name(state));
2349 MUTEX_UNLOCK(&stream->mutex);
2350 error(RtError::DRIVER_ERROR);
2355 sprintf(message, "RtAudio: ALSA audio read error for device (%s): %s.",
2356 devices[stream->device[1]].name, snd_strerror(err));
2357 MUTEX_UNLOCK(&stream->mutex);
2358 error(RtError::DRIVER_ERROR);
2362 // Do byte swapping if necessary.
2363 if (stream->doByteSwap[1])
2364 byteSwapBuffer(buffer, stream->bufferSize * channels, format);
2366 // Do buffer conversion if necessary.
2367 if (stream->doConvertBuffer[1])
2368 convertStreamBuffer(stream, INPUT);
2372 MUTEX_UNLOCK(&stream->mutex);
2374 if (stream->callbackInfo.usingCallback && stopStream)
2375 this->stopStream(streamId);
2378 extern "C" void *callbackHandler(void *ptr)
2380 CALLBACK_INFO *info = (CALLBACK_INFO *) ptr;
2381 RtAudio *object = (RtAudio *) info->object;
2382 int stream = info->streamId;
2383 bool *usingCallback = &info->usingCallback;
2385 while ( *usingCallback ) {
2386 pthread_testcancel();
2388 object->tickStream(stream);
2390 catch (RtError &exception) {
2391 fprintf(stderr, "\nRtAudio: Callback thread error (%s) ... closing thread.\n\n",
2392 exception.getMessage());
2400 //******************** End of __LINUX_ALSA__ *********************//
2402 #elif defined(__LINUX_OSS__)
2404 #include <sys/stat.h>
2405 #include <sys/types.h>
2406 #include <sys/ioctl.h>
2409 #include <sys/soundcard.h>
2413 #define DAC_NAME "/dev/dsp"
2414 #define MAX_DEVICES 16
2415 #define MAX_CHANNELS 16
2417 void RtAudio :: initialize(void)
2419 // Count cards and devices
2422 // We check /dev/dsp before probing devices. /dev/dsp is supposed to
2423 // be a link to the "default" audio device, of the form /dev/dsp0,
2424 // /dev/dsp1, etc... However, I've seen many cases where /dev/dsp was a
2425 // real device, so we need to check for that. Also, sometimes the
2426 // link is to /dev/dspx and other times just dspx. I'm not sure how
2427 // the latter works, but it does.
2428 char device_name[16];
2429 struct stat dspstat;
2432 if (lstat(DAC_NAME, &dspstat) == 0) {
2433 if (S_ISLNK(dspstat.st_mode)) {
2434 i = readlink(DAC_NAME, device_name, sizeof(device_name));
2436 device_name[i] = '\0';
2437 if (i > 8) { // check for "/dev/dspx"
2438 if (!strncmp(DAC_NAME, device_name, 8))
2439 dsplink = atoi(&device_name[8]);
2441 else if (i > 3) { // check for "dspx"
2442 if (!strncmp("dsp", device_name, 3))
2443 dsplink = atoi(&device_name[3]);
2447 sprintf(message, "RtAudio: cannot read value of symbolic link %s.", DAC_NAME);
2448 error(RtError::SYSTEM_ERROR);
2453 sprintf(message, "RtAudio: cannot stat %s.", DAC_NAME);
2454 error(RtError::SYSTEM_ERROR);
2457 // The OSS API doesn't provide a routine for determining the number
2458 // of devices. Thus, we'll just pursue a brute force method. The
2459 // idea is to start with /dev/dsp(0) and continue with higher device
2460 // numbers until we reach MAX_DSP_DEVICES. This should tell us how
2461 // many devices we have ... it is not a fullproof scheme, but hopefully
2462 // it will work most of the time.
2465 char names[MAX_DEVICES][16];
2466 for (i=-1; i<MAX_DEVICES; i++) {
2468 // Probe /dev/dsp first, since it is supposed to be the default device.
2470 sprintf(device_name, "%s", DAC_NAME);
2471 else if (i == dsplink)
2472 continue; // We've aready probed this device via /dev/dsp link ... try next device.
2474 sprintf(device_name, "%s%d", DAC_NAME, i);
2476 // First try to open the device for playback, then record mode.
2477 fd = open(device_name, O_WRONLY | O_NONBLOCK);
2479 // Open device for playback failed ... either busy or doesn't exist.
2480 if (errno != EBUSY && errno != EAGAIN) {
2481 // Try to open for capture
2482 fd = open(device_name, O_RDONLY | O_NONBLOCK);
2484 // Open device for record failed.
2485 if (errno != EBUSY && errno != EAGAIN)
2488 sprintf(message, "RtAudio: OSS record device (%s) is busy.", device_name);
2489 error(RtError::WARNING);
2490 // still count it for now
2495 sprintf(message, "RtAudio: OSS playback device (%s) is busy.", device_name);
2496 error(RtError::WARNING);
2497 // still count it for now
2501 if (fd >= 0) close(fd);
2502 strncpy(names[nDevices], device_name, 16);
2506 if (nDevices == 0) return;
2508 // Allocate the RTAUDIO_DEVICE structures.
2509 devices = (RTAUDIO_DEVICE *) calloc(nDevices, sizeof(RTAUDIO_DEVICE));
2510 if (devices == NULL) {
2511 sprintf(message, "RtAudio: memory allocation error!");
2512 error(RtError::MEMORY_ERROR);
2515 // Write device ascii identifiers to device control structure and then probe capabilities.
2516 for (i=0; i<nDevices; i++) {
2517 strncpy(devices[i].name, names[i], 16);
2518 //probeDeviceInfo(&devices[i]);
2524 int RtAudio :: getDefaultInputDevice(void)
2526 // No OSS API functions for default devices.
2530 int RtAudio :: getDefaultOutputDevice(void)
2532 // No OSS API functions for default devices.
2536 void RtAudio :: probeDeviceInfo(RTAUDIO_DEVICE *info)
2538 int i, fd, channels, mask;
2540 // The OSS API doesn't provide a means for probing the capabilities
2541 // of devices. Thus, we'll just pursue a brute force method.
2543 // First try for playback
2544 fd = open(info->name, O_WRONLY | O_NONBLOCK);
2546 // Open device failed ... either busy or doesn't exist
2547 if (errno == EBUSY || errno == EAGAIN)
2548 sprintf(message, "RtAudio: OSS playback device (%s) is busy and cannot be probed.",
2551 sprintf(message, "RtAudio: OSS playback device (%s) open error.", info->name);
2552 error(RtError::DEBUG_WARNING);
2556 // We have an open device ... see how many channels it can handle
2557 for (i=MAX_CHANNELS; i>0; i--) {
2559 if (ioctl(fd, SNDCTL_DSP_CHANNELS, &channels) == -1) {
2560 // This would normally indicate some sort of hardware error, but under ALSA's
2561 // OSS emulation, it sometimes indicates an invalid channel value. Further,
2562 // the returned channel value is not changed. So, we'll ignore the possible
2564 continue; // try next channel number
2566 // Check to see whether the device supports the requested number of channels
2567 if (channels != i ) continue; // try next channel number
2568 // If here, we found the largest working channel value
2571 info->maxOutputChannels = i;
2573 // Now find the minimum number of channels it can handle
2574 for (i=1; i<=info->maxOutputChannels; i++) {
2576 if (ioctl(fd, SNDCTL_DSP_CHANNELS, &channels) == -1 || channels != i)
2577 continue; // try next channel number
2578 // If here, we found the smallest working channel value
2581 info->minOutputChannels = i;
2585 // Now try for capture
2586 fd = open(info->name, O_RDONLY | O_NONBLOCK);
2588 // Open device for capture failed ... either busy or doesn't exist
2589 if (errno == EBUSY || errno == EAGAIN)
2590 sprintf(message, "RtAudio: OSS capture device (%s) is busy and cannot be probed.",
2593 sprintf(message, "RtAudio: OSS capture device (%s) open error.", info->name);
2594 error(RtError::DEBUG_WARNING);
2595 if (info->maxOutputChannels == 0)
2596 // didn't open for playback either ... device invalid
2598 goto probe_parameters;
2601 // We have the device open for capture ... see how many channels it can handle
2602 for (i=MAX_CHANNELS; i>0; i--) {
2604 if (ioctl(fd, SNDCTL_DSP_CHANNELS, &channels) == -1 || channels != i) {
2605 continue; // as above
2607 // If here, we found a working channel value
2610 info->maxInputChannels = i;
2612 // Now find the minimum number of channels it can handle
2613 for (i=1; i<=info->maxInputChannels; i++) {
2615 if (ioctl(fd, SNDCTL_DSP_CHANNELS, &channels) == -1 || channels != i)
2616 continue; // try next channel number
2617 // If here, we found the smallest working channel value
2620 info->minInputChannels = i;
2623 if (info->maxOutputChannels == 0 && info->maxInputChannels == 0) {
2624 sprintf(message, "RtAudio: OSS device (%s) reports zero channels for input and output.",
2626 error(RtError::DEBUG_WARNING);
2630 // If device opens for both playback and capture, we determine the channels.
2631 if (info->maxOutputChannels == 0 || info->maxInputChannels == 0)
2632 goto probe_parameters;
2634 fd = open(info->name, O_RDWR | O_NONBLOCK);
2636 goto probe_parameters;
2638 ioctl(fd, SNDCTL_DSP_SETDUPLEX, 0);
2639 ioctl(fd, SNDCTL_DSP_GETCAPS, &mask);
2640 if (mask & DSP_CAP_DUPLEX) {
2641 info->hasDuplexSupport = true;
2642 // We have the device open for duplex ... see how many channels it can handle
2643 for (i=MAX_CHANNELS; i>0; i--) {
2645 if (ioctl(fd, SNDCTL_DSP_CHANNELS, &channels) == -1 || channels != i)
2646 continue; // as above
2647 // If here, we found a working channel value
2650 info->maxDuplexChannels = i;
2652 // Now find the minimum number of channels it can handle
2653 for (i=1; i<=info->maxDuplexChannels; i++) {
2655 if (ioctl(fd, SNDCTL_DSP_CHANNELS, &channels) == -1 || channels != i)
2656 continue; // try next channel number
2657 // If here, we found the smallest working channel value
2660 info->minDuplexChannels = i;
2665 // At this point, we need to figure out the supported data formats
2666 // and sample rates. We'll proceed by openning the device in the
2667 // direction with the maximum number of channels, or playback if
2668 // they are equal. This might limit our sample rate options, but so
2671 if (info->maxOutputChannels >= info->maxInputChannels) {
2672 fd = open(info->name, O_WRONLY | O_NONBLOCK);
2673 channels = info->maxOutputChannels;
2676 fd = open(info->name, O_RDONLY | O_NONBLOCK);
2677 channels = info->maxInputChannels;
2681 // We've got some sort of conflict ... abort
2682 sprintf(message, "RtAudio: OSS device (%s) won't reopen during probe.",
2684 error(RtError::DEBUG_WARNING);
2688 // We have an open device ... set to maximum channels.
2690 if (ioctl(fd, SNDCTL_DSP_CHANNELS, &channels) == -1 || channels != i) {
2691 // We've got some sort of conflict ... abort
2693 sprintf(message, "RtAudio: OSS device (%s) won't revert to previous channel setting.",
2695 error(RtError::DEBUG_WARNING);
2699 if (ioctl(fd, SNDCTL_DSP_GETFMTS, &mask) == -1) {
2701 sprintf(message, "RtAudio: OSS device (%s) can't get supported audio formats.",
2703 error(RtError::DEBUG_WARNING);
2707 // Probe the supported data formats ... we don't care about endian-ness just yet.
2709 info->nativeFormats = 0;
2710 #if defined (AFMT_S32_BE)
2711 // This format does not seem to be in the 2.4 kernel version of OSS soundcard.h
2712 if (mask & AFMT_S32_BE) {
2713 format = AFMT_S32_BE;
2714 info->nativeFormats |= RTAUDIO_SINT32;
2717 #if defined (AFMT_S32_LE)
2718 /* This format is not in the 2.4.4 kernel version of OSS soundcard.h */
2719 if (mask & AFMT_S32_LE) {
2720 format = AFMT_S32_LE;
2721 info->nativeFormats |= RTAUDIO_SINT32;
2724 if (mask & AFMT_S8) {
2726 info->nativeFormats |= RTAUDIO_SINT8;
2728 if (mask & AFMT_S16_BE) {
2729 format = AFMT_S16_BE;
2730 info->nativeFormats |= RTAUDIO_SINT16;
2732 if (mask & AFMT_S16_LE) {
2733 format = AFMT_S16_LE;
2734 info->nativeFormats |= RTAUDIO_SINT16;
2737 // Check that we have at least one supported format
2738 if (info->nativeFormats == 0) {
2740 sprintf(message, "RtAudio: OSS device (%s) data format not supported by RtAudio.",
2742 error(RtError::DEBUG_WARNING);
2748 if (ioctl(fd, SNDCTL_DSP_SETFMT, &format) == -1 || format != i) {
2750 sprintf(message, "RtAudio: OSS device (%s) error setting data format.",
2752 error(RtError::DEBUG_WARNING);
2756 // Probe the supported sample rates ... first get lower limit
2758 if (ioctl(fd, SNDCTL_DSP_SPEED, &speed) == -1) {
2759 // If we get here, we're probably using an ALSA driver with OSS-emulation,
2760 // which doesn't conform to the OSS specification. In this case,
2761 // we'll probe our predefined list of sample rates for working values.
2762 info->nSampleRates = 0;
2763 for (i=0; i<MAX_SAMPLE_RATES; i++) {
2764 speed = SAMPLE_RATES[i];
2765 if (ioctl(fd, SNDCTL_DSP_SPEED, &speed) != -1) {
2766 info->sampleRates[info->nSampleRates] = SAMPLE_RATES[i];
2767 info->nSampleRates++;
2770 if (info->nSampleRates == 0) {
2776 info->sampleRates[0] = speed;
2778 // Now get upper limit
2780 if (ioctl(fd, SNDCTL_DSP_SPEED, &speed) == -1) {
2782 sprintf(message, "RtAudio: OSS device (%s) error setting sample rate.",
2784 error(RtError::DEBUG_WARNING);
2787 info->sampleRates[1] = speed;
2788 info->nSampleRates = -1;
2790 finished: // That's all ... close the device and return
2792 info->probed = true;
2796 bool RtAudio :: probeDeviceOpen(int device, RTAUDIO_STREAM *stream,
2797 STREAM_MODE mode, int channels,
2798 int sampleRate, RTAUDIO_FORMAT format,
2799 int *bufferSize, int numberOfBuffers)
2801 int buffers, buffer_bytes, device_channels, device_format;
2802 int srate, temp, fd;
2804 const char *name = devices[device].name;
2807 fd = open(name, O_WRONLY | O_NONBLOCK);
2808 else { // mode == INPUT
2809 if (stream->mode == OUTPUT && stream->device[0] == device) {
2810 // We just set the same device for playback ... close and reopen for duplex (OSS only).
2811 close(stream->handle[0]);
2812 stream->handle[0] = 0;
2813 // First check that the number previously set channels is the same.
2814 if (stream->nUserChannels[0] != channels) {
2815 sprintf(message, "RtAudio: input/output channels must be equal for OSS duplex device (%s).", name);
2818 fd = open(name, O_RDWR | O_NONBLOCK);
2821 fd = open(name, O_RDONLY | O_NONBLOCK);
2825 if (errno == EBUSY || errno == EAGAIN)
2826 sprintf(message, "RtAudio: OSS device (%s) is busy and cannot be opened.",
2829 sprintf(message, "RtAudio: OSS device (%s) cannot be opened.", name);
2833 // Now reopen in blocking mode.
2836 fd = open(name, O_WRONLY | O_SYNC);
2837 else { // mode == INPUT
2838 if (stream->mode == OUTPUT && stream->device[0] == device)
2839 fd = open(name, O_RDWR | O_SYNC);
2841 fd = open(name, O_RDONLY | O_SYNC);
2845 sprintf(message, "RtAudio: OSS device (%s) cannot be opened.", name);
2849 // Get the sample format mask
2851 if (ioctl(fd, SNDCTL_DSP_GETFMTS, &mask) == -1) {
2853 sprintf(message, "RtAudio: OSS device (%s) can't get supported audio formats.",
2858 // Determine how to set the device format.
2859 stream->userFormat = format;
2861 stream->doByteSwap[mode] = false;
2862 if (format == RTAUDIO_SINT8) {
2863 if (mask & AFMT_S8) {
2864 device_format = AFMT_S8;
2865 stream->deviceFormat[mode] = RTAUDIO_SINT8;
2868 else if (format == RTAUDIO_SINT16) {
2869 if (mask & AFMT_S16_NE) {
2870 device_format = AFMT_S16_NE;
2871 stream->deviceFormat[mode] = RTAUDIO_SINT16;
2873 #if BYTE_ORDER == LITTLE_ENDIAN
2874 else if (mask & AFMT_S16_BE) {
2875 device_format = AFMT_S16_BE;
2876 stream->deviceFormat[mode] = RTAUDIO_SINT16;
2877 stream->doByteSwap[mode] = true;
2880 else if (mask & AFMT_S16_LE) {
2881 device_format = AFMT_S16_LE;
2882 stream->deviceFormat[mode] = RTAUDIO_SINT16;
2883 stream->doByteSwap[mode] = true;
2887 #if defined (AFMT_S32_NE) && defined (AFMT_S32_LE) && defined (AFMT_S32_BE)
2888 else if (format == RTAUDIO_SINT32) {
2889 if (mask & AFMT_S32_NE) {
2890 device_format = AFMT_S32_NE;
2891 stream->deviceFormat[mode] = RTAUDIO_SINT32;
2893 #if BYTE_ORDER == LITTLE_ENDIAN
2894 else if (mask & AFMT_S32_BE) {
2895 device_format = AFMT_S32_BE;
2896 stream->deviceFormat[mode] = RTAUDIO_SINT32;
2897 stream->doByteSwap[mode] = true;
2900 else if (mask & AFMT_S32_LE) {
2901 device_format = AFMT_S32_LE;
2902 stream->deviceFormat[mode] = RTAUDIO_SINT32;
2903 stream->doByteSwap[mode] = true;
2909 if (device_format == -1) {
2910 // The user requested format is not natively supported by the device.
2911 if (mask & AFMT_S16_NE) {
2912 device_format = AFMT_S16_NE;
2913 stream->deviceFormat[mode] = RTAUDIO_SINT16;
2915 #if BYTE_ORDER == LITTLE_ENDIAN
2916 else if (mask & AFMT_S16_BE) {
2917 device_format = AFMT_S16_BE;
2918 stream->deviceFormat[mode] = RTAUDIO_SINT16;
2919 stream->doByteSwap[mode] = true;
2922 else if (mask & AFMT_S16_LE) {
2923 device_format = AFMT_S16_LE;
2924 stream->deviceFormat[mode] = RTAUDIO_SINT16;
2925 stream->doByteSwap[mode] = true;
2928 #if defined (AFMT_S32_NE) && defined (AFMT_S32_LE) && defined (AFMT_S32_BE)
2929 else if (mask & AFMT_S32_NE) {
2930 device_format = AFMT_S32_NE;
2931 stream->deviceFormat[mode] = RTAUDIO_SINT32;
2933 #if BYTE_ORDER == LITTLE_ENDIAN
2934 else if (mask & AFMT_S32_BE) {
2935 device_format = AFMT_S32_BE;
2936 stream->deviceFormat[mode] = RTAUDIO_SINT32;
2937 stream->doByteSwap[mode] = true;
2940 else if (mask & AFMT_S32_LE) {
2941 device_format = AFMT_S32_LE;
2942 stream->deviceFormat[mode] = RTAUDIO_SINT32;
2943 stream->doByteSwap[mode] = true;
2947 else if (mask & AFMT_S8) {
2948 device_format = AFMT_S8;
2949 stream->deviceFormat[mode] = RTAUDIO_SINT8;
2953 if (stream->deviceFormat[mode] == 0) {
2954 // This really shouldn't happen ...
2956 sprintf(message, "RtAudio: OSS device (%s) data format not supported by RtAudio.",
2961 // Determine the number of channels for this device. Note that the
2962 // channel value requested by the user might be < min_X_Channels.
2963 stream->nUserChannels[mode] = channels;
2964 device_channels = channels;
2965 if (mode == OUTPUT) {
2966 if (channels < devices[device].minOutputChannels)
2967 device_channels = devices[device].minOutputChannels;
2969 else { // mode == INPUT
2970 if (stream->mode == OUTPUT && stream->device[0] == device) {
2971 // We're doing duplex setup here.
2972 if (channels < devices[device].minDuplexChannels)
2973 device_channels = devices[device].minDuplexChannels;
2976 if (channels < devices[device].minInputChannels)
2977 device_channels = devices[device].minInputChannels;
2980 stream->nDeviceChannels[mode] = device_channels;
2982 // Attempt to set the buffer size. According to OSS, the minimum
2983 // number of buffers is two. The supposed minimum buffer size is 16
2984 // bytes, so that will be our lower bound. The argument to this
2985 // call is in the form 0xMMMMSSSS (hex), where the buffer size (in
2986 // bytes) is given as 2^SSSS and the number of buffers as 2^MMMM.
2987 // We'll check the actual value used near the end of the setup
2989 buffer_bytes = *bufferSize * formatBytes(stream->deviceFormat[mode]) * device_channels;
2990 if (buffer_bytes < 16) buffer_bytes = 16;
2991 buffers = numberOfBuffers;
2992 if (buffers < 2) buffers = 2;
2993 temp = ((int) buffers << 16) + (int)(log10((double)buffer_bytes)/log10(2.0));
2994 if (ioctl(fd, SNDCTL_DSP_SETFRAGMENT, &temp)) {
2996 sprintf(message, "RtAudio: OSS error setting fragment size for device (%s).",
3000 stream->nBuffers = buffers;
3002 // Set the data format.
3003 temp = device_format;
3004 if (ioctl(fd, SNDCTL_DSP_SETFMT, &device_format) == -1 || device_format != temp) {
3006 sprintf(message, "RtAudio: OSS error setting data format for device (%s).",
3011 // Set the number of channels.
3012 temp = device_channels;
3013 if (ioctl(fd, SNDCTL_DSP_CHANNELS, &device_channels) == -1 || device_channels != temp) {
3015 sprintf(message, "RtAudio: OSS error setting %d channels on device (%s).",
3020 // Set the sample rate.
3023 if (ioctl(fd, SNDCTL_DSP_SPEED, &srate) == -1) {
3025 sprintf(message, "RtAudio: OSS error setting sample rate = %d on device (%s).",
3030 // Verify the sample rate setup worked.
3031 if (abs(srate - temp) > 100) {
3033 sprintf(message, "RtAudio: OSS error ... audio device (%s) doesn't support sample rate of %d.",
3037 stream->sampleRate = sampleRate;
3039 if (ioctl(fd, SNDCTL_DSP_GETBLKSIZE, &buffer_bytes) == -1) {
3041 sprintf(message, "RtAudio: OSS error getting buffer size for device (%s).",
3046 // Save buffer size (in sample frames).
3047 *bufferSize = buffer_bytes / (formatBytes(stream->deviceFormat[mode]) * device_channels);
3048 stream->bufferSize = *bufferSize;
3050 if (mode == INPUT && stream->mode == OUTPUT &&
3051 stream->device[0] == device) {
3052 // We're doing duplex setup here.
3053 stream->deviceFormat[0] = stream->deviceFormat[1];
3054 stream->nDeviceChannels[0] = device_channels;
3057 // Set flags for buffer conversion
3058 stream->doConvertBuffer[mode] = false;
3059 if (stream->userFormat != stream->deviceFormat[mode])
3060 stream->doConvertBuffer[mode] = true;
3061 if (stream->nUserChannels[mode] < stream->nDeviceChannels[mode])
3062 stream->doConvertBuffer[mode] = true;
3064 // Allocate necessary internal buffers
3065 if ( stream->nUserChannels[0] != stream->nUserChannels[1] ) {
3068 if (stream->nUserChannels[0] >= stream->nUserChannels[1])
3069 buffer_bytes = stream->nUserChannels[0];
3071 buffer_bytes = stream->nUserChannels[1];
3073 buffer_bytes *= *bufferSize * formatBytes(stream->userFormat);
3074 if (stream->userBuffer) free(stream->userBuffer);
3075 stream->userBuffer = (char *) calloc(buffer_bytes, 1);
3076 if (stream->userBuffer == NULL) {
3078 sprintf(message, "RtAudio: OSS error allocating user buffer memory (%s).",
3084 if ( stream->doConvertBuffer[mode] ) {
3087 bool makeBuffer = true;
3088 if ( mode == OUTPUT )
3089 buffer_bytes = stream->nDeviceChannels[0] * formatBytes(stream->deviceFormat[0]);
3090 else { // mode == INPUT
3091 buffer_bytes = stream->nDeviceChannels[1] * formatBytes(stream->deviceFormat[1]);
3092 if ( stream->mode == OUTPUT && stream->deviceBuffer ) {
3093 long bytes_out = stream->nDeviceChannels[0] * formatBytes(stream->deviceFormat[0]);
3094 if ( buffer_bytes < bytes_out ) makeBuffer = false;
3099 buffer_bytes *= *bufferSize;
3100 if (stream->deviceBuffer) free(stream->deviceBuffer);
3101 stream->deviceBuffer = (char *) calloc(buffer_bytes, 1);
3102 if (stream->deviceBuffer == NULL) {
3104 free(stream->userBuffer);
3105 sprintf(message, "RtAudio: OSS error allocating device buffer memory (%s).",
3112 stream->device[mode] = device;
3113 stream->handle[mode] = fd;
3114 stream->state = STREAM_STOPPED;
3115 if ( stream->mode == OUTPUT && mode == INPUT ) {
3116 stream->mode = DUPLEX;
3117 if (stream->device[0] == device)
3118 stream->handle[0] = fd;
3121 stream->mode = mode;
3126 if (stream->handle[0]) {
3127 close(stream->handle[0]);
3128 stream->handle[0] = 0;
3130 error(RtError::WARNING);
3134 void RtAudio :: closeStream(int streamId)
3136 // We don't want an exception to be thrown here because this
3137 // function is called by our class destructor. So, do our own
3139 if ( streams.find( streamId ) == streams.end() ) {
3140 sprintf(message, "RtAudio: invalid stream identifier!");
3141 error(RtError::WARNING);
3145 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) streams[streamId];
3147 if (stream->callbackInfo.usingCallback) {
3148 pthread_cancel(stream->callbackInfo.thread);
3149 pthread_join(stream->callbackInfo.thread, NULL);
3152 if (stream->state == STREAM_RUNNING) {
3153 if (stream->mode == OUTPUT || stream->mode == DUPLEX)
3154 ioctl(stream->handle[0], SNDCTL_DSP_RESET, 0);
3155 if (stream->mode == INPUT || stream->mode == DUPLEX)
3156 ioctl(stream->handle[1], SNDCTL_DSP_RESET, 0);
3159 pthread_mutex_destroy(&stream->mutex);
3161 if (stream->handle[0])
3162 close(stream->handle[0]);
3164 if (stream->handle[1])
3165 close(stream->handle[1]);
3167 if (stream->userBuffer)
3168 free(stream->userBuffer);
3170 if (stream->deviceBuffer)
3171 free(stream->deviceBuffer);
3174 streams.erase(streamId);
3177 void RtAudio :: startStream(int streamId)
3179 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
3181 MUTEX_LOCK(&stream->mutex);
3183 stream->state = STREAM_RUNNING;
3185 // No need to do anything else here ... OSS automatically starts
3186 // when fed samples.
3188 MUTEX_UNLOCK(&stream->mutex);
3191 void RtAudio :: stopStream(int streamId)
3193 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
3195 MUTEX_LOCK(&stream->mutex);
3197 if (stream->state == STREAM_STOPPED)
3201 if (stream->mode == OUTPUT || stream->mode == DUPLEX) {
3202 err = ioctl(stream->handle[0], SNDCTL_DSP_SYNC, 0);
3204 sprintf(message, "RtAudio: OSS error stopping device (%s).",
3205 devices[stream->device[0]].name);
3206 error(RtError::DRIVER_ERROR);
3210 err = ioctl(stream->handle[1], SNDCTL_DSP_SYNC, 0);
3212 sprintf(message, "RtAudio: OSS error stopping device (%s).",
3213 devices[stream->device[1]].name);
3214 error(RtError::DRIVER_ERROR);
3217 stream->state = STREAM_STOPPED;
3220 MUTEX_UNLOCK(&stream->mutex);
3223 void RtAudio :: abortStream(int streamId)
3225 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
3227 MUTEX_LOCK(&stream->mutex);
3229 if (stream->state == STREAM_STOPPED)
3233 if (stream->mode == OUTPUT || stream->mode == DUPLEX) {
3234 err = ioctl(stream->handle[0], SNDCTL_DSP_RESET, 0);
3236 sprintf(message, "RtAudio: OSS error aborting device (%s).",
3237 devices[stream->device[0]].name);
3238 error(RtError::DRIVER_ERROR);
3242 err = ioctl(stream->handle[1], SNDCTL_DSP_RESET, 0);
3244 sprintf(message, "RtAudio: OSS error aborting device (%s).",
3245 devices[stream->device[1]].name);
3246 error(RtError::DRIVER_ERROR);
3249 stream->state = STREAM_STOPPED;
3252 MUTEX_UNLOCK(&stream->mutex);
3255 int RtAudio :: streamWillBlock(int streamId)
3257 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
3259 MUTEX_LOCK(&stream->mutex);
3261 int bytes = 0, channels = 0, frames = 0;
3262 if (stream->state == STREAM_STOPPED)
3265 audio_buf_info info;
3266 if (stream->mode == OUTPUT || stream->mode == DUPLEX) {
3267 ioctl(stream->handle[0], SNDCTL_DSP_GETOSPACE, &info);
3269 channels = stream->nDeviceChannels[0];
3272 if (stream->mode == INPUT || stream->mode == DUPLEX) {
3273 ioctl(stream->handle[1], SNDCTL_DSP_GETISPACE, &info);
3274 if (stream->mode == DUPLEX ) {
3275 bytes = (bytes < info.bytes) ? bytes : info.bytes;
3276 channels = stream->nDeviceChannels[0];
3280 channels = stream->nDeviceChannels[1];
3284 frames = (int) (bytes / (channels * formatBytes(stream->deviceFormat[0])));
3285 frames -= stream->bufferSize;
3286 if (frames < 0) frames = 0;
3289 MUTEX_UNLOCK(&stream->mutex);
3293 void RtAudio :: tickStream(int streamId)
3295 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
3298 if (stream->state == STREAM_STOPPED) {
3299 if (stream->callbackInfo.usingCallback) usleep(50000); // sleep 50 milliseconds
3302 else if (stream->callbackInfo.usingCallback) {
3303 RTAUDIO_CALLBACK callback = (RTAUDIO_CALLBACK) stream->callbackInfo.callback;
3304 stopStream = callback(stream->userBuffer, stream->bufferSize, stream->callbackInfo.userData);
3307 MUTEX_LOCK(&stream->mutex);
3309 // The state might change while waiting on a mutex.
3310 if (stream->state == STREAM_STOPPED)
3316 RTAUDIO_FORMAT format;
3317 if (stream->mode == OUTPUT || stream->mode == DUPLEX) {
3319 // Setup parameters and do buffer conversion if necessary.
3320 if (stream->doConvertBuffer[0]) {
3321 convertStreamBuffer(stream, OUTPUT);
3322 buffer = stream->deviceBuffer;
3323 samples = stream->bufferSize * stream->nDeviceChannels[0];
3324 format = stream->deviceFormat[0];
3327 buffer = stream->userBuffer;
3328 samples = stream->bufferSize * stream->nUserChannels[0];
3329 format = stream->userFormat;
3332 // Do byte swapping if necessary.
3333 if (stream->doByteSwap[0])
3334 byteSwapBuffer(buffer, samples, format);
3336 // Write samples to device.
3337 result = write(stream->handle[0], buffer, samples * formatBytes(format));
3340 // This could be an underrun, but the basic OSS API doesn't provide a means for determining that.
3341 sprintf(message, "RtAudio: OSS audio write error for device (%s).",
3342 devices[stream->device[0]].name);
3343 error(RtError::DRIVER_ERROR);
3347 if (stream->mode == INPUT || stream->mode == DUPLEX) {
3349 // Setup parameters.
3350 if (stream->doConvertBuffer[1]) {
3351 buffer = stream->deviceBuffer;
3352 samples = stream->bufferSize * stream->nDeviceChannels[1];
3353 format = stream->deviceFormat[1];
3356 buffer = stream->userBuffer;
3357 samples = stream->bufferSize * stream->nUserChannels[1];
3358 format = stream->userFormat;
3361 // Read samples from device.
3362 result = read(stream->handle[1], buffer, samples * formatBytes(format));
3365 // This could be an overrun, but the basic OSS API doesn't provide a means for determining that.
3366 sprintf(message, "RtAudio: OSS audio read error for device (%s).",
3367 devices[stream->device[1]].name);
3368 error(RtError::DRIVER_ERROR);
3371 // Do byte swapping if necessary.
3372 if (stream->doByteSwap[1])
3373 byteSwapBuffer(buffer, samples, format);
3375 // Do buffer conversion if necessary.
3376 if (stream->doConvertBuffer[1])
3377 convertStreamBuffer(stream, INPUT);
3381 MUTEX_UNLOCK(&stream->mutex);
3383 if (stream->callbackInfo.usingCallback && stopStream)
3384 this->stopStream(streamId);
3387 extern "C" void *callbackHandler(void *ptr)
3389 CALLBACK_INFO *info = (CALLBACK_INFO *) ptr;
3390 RtAudio *object = (RtAudio *) info->object;
3391 int stream = info->streamId;
3392 bool *usingCallback = &info->usingCallback;
3394 while ( *usingCallback ) {
3395 pthread_testcancel();
3397 object->tickStream(stream);
3399 catch (RtError &exception) {
3400 fprintf(stderr, "\nRtAudio: Callback thread error (%s) ... closing thread.\n\n",
3401 exception.getMessage());
3410 //******************** End of __LINUX_OSS__ *********************//
3412 #elif defined(__WINDOWS_ASIO__) // ASIO API on Windows
3414 // The ASIO API is designed around a callback scheme, so this
3415 // implementation is similar to that used for OS X CoreAudio. The
3416 // primary constraint with ASIO is that it only allows access to a
3417 // single driver at a time. Thus, it is not possible to have more
3418 // than one simultaneous RtAudio stream.
3420 // This implementation also requires a number of external ASIO files
3421 // and a few global variables. The ASIO callback scheme does not
3422 // allow for the passing of user data, so we must create a global
3423 // pointer to our callbackInfo structure.
3425 #include "asio/asiosys.h"
3426 #include "asio/asio.h"
3427 #include "asio/asiodrivers.h"
3430 AsioDrivers drivers;
3431 ASIOCallbacks asioCallbacks;
3432 CALLBACK_INFO *asioCallbackInfo;
3433 ASIODriverInfo driverInfo;
3435 void RtAudio :: initialize(void)
3437 nDevices = drivers.asioGetNumDev();
3438 if (nDevices <= 0) return;
3440 // Allocate the RTAUDIO_DEVICE structures.
3441 devices = (RTAUDIO_DEVICE *) calloc(nDevices, sizeof(RTAUDIO_DEVICE));
3442 if (devices == NULL) {
3443 sprintf(message, "RtAudio: memory allocation error!");
3444 error(RtError::MEMORY_ERROR);
3447 // Write device driver names to device structures and then probe the
3448 // device capabilities.
3449 for (int i=0; i<nDevices; i++) {
3450 if ( drivers.asioGetDriverName( i, devices[i].name, 128 ) == 0 )
3451 //probeDeviceInfo(&devices[i]);
3454 sprintf(message, "RtAudio: error getting ASIO driver name for device index %d!", i);
3455 error(RtError::WARNING);
3459 drivers.removeCurrentDriver();
3460 driverInfo.asioVersion = 2;
3461 // See note in DirectSound implementation about GetDesktopWindow().
3462 driverInfo.sysRef = GetForegroundWindow();
3465 int RtAudio :: getDefaultInputDevice(void)
3470 int RtAudio :: getDefaultOutputDevice(void)
3475 void RtAudio :: probeDeviceInfo(RTAUDIO_DEVICE *info)
3477 // Don't probe if a stream is already open.
3478 if ( streams.size() > 0 ) {
3479 sprintf(message, "RtAudio: unable to probe ASIO driver while a stream is open.");
3480 error(RtError::DEBUG_WARNING);
3484 if ( !drivers.loadDriver( info->name ) ) {
3485 sprintf(message, "RtAudio: ASIO error loading driver (%s).", info->name);
3486 error(RtError::DEBUG_WARNING);
3490 ASIOError result = ASIOInit( &driverInfo );
3491 if ( result != ASE_OK ) {
3493 if ( result == ASE_HWMalfunction )
3494 sprintf(details, "hardware malfunction");
3495 else if ( result == ASE_NoMemory )
3496 sprintf(details, "no memory");
3497 else if ( result == ASE_NotPresent )
3498 sprintf(details, "driver/hardware not present");
3500 sprintf(details, "unspecified");
3501 sprintf(message, "RtAudio: ASIO error (%s) initializing driver (%s).", details, info->name);
3502 error(RtError::DEBUG_WARNING);
3506 // Determine the device channel information.
3507 long inputChannels, outputChannels;
3508 result = ASIOGetChannels( &inputChannels, &outputChannels );
3509 if ( result != ASE_OK ) {
3510 drivers.removeCurrentDriver();
3511 sprintf(message, "RtAudio: ASIO error getting input/output channel count (%s).", info->name);
3512 error(RtError::DEBUG_WARNING);
3516 info->maxOutputChannels = outputChannels;
3517 if ( outputChannels > 0 ) info->minOutputChannels = 1;
3519 info->maxInputChannels = inputChannels;
3520 if ( inputChannels > 0 ) info->minInputChannels = 1;
3522 // If device opens for both playback and capture, we determine the channels.
3523 if (info->maxOutputChannels > 0 && info->maxInputChannels > 0) {
3524 info->hasDuplexSupport = true;
3525 info->maxDuplexChannels = (info->maxOutputChannels > info->maxInputChannels) ?
3526 info->maxInputChannels : info->maxOutputChannels;
3527 info->minDuplexChannels = (info->minOutputChannels > info->minInputChannels) ?
3528 info->minInputChannels : info->minOutputChannels;
3531 // Determine the supported sample rates.
3532 info->nSampleRates = 0;
3533 for (int i=0; i<MAX_SAMPLE_RATES; i++) {
3534 result = ASIOCanSampleRate( (ASIOSampleRate) SAMPLE_RATES[i] );
3535 if ( result == ASE_OK )
3536 info->sampleRates[info->nSampleRates++] = SAMPLE_RATES[i];
3539 if (info->nSampleRates == 0) {
3540 drivers.removeCurrentDriver();
3541 sprintf( message, "RtAudio: No supported sample rates found for ASIO driver (%s).", info->name );
3542 error(RtError::DEBUG_WARNING);
3546 // Determine supported data types ... just check first channel and assume rest are the same.
3547 ASIOChannelInfo channelInfo;
3548 channelInfo.channel = 0;
3549 channelInfo.isInput = true;
3550 if ( info->maxInputChannels <= 0 ) channelInfo.isInput = false;
3551 result = ASIOGetChannelInfo( &channelInfo );
3552 if ( result != ASE_OK ) {
3553 drivers.removeCurrentDriver();
3554 sprintf(message, "RtAudio: ASIO error getting driver (%s) channel information.", info->name);
3555 error(RtError::DEBUG_WARNING);
3559 if ( channelInfo.type == ASIOSTInt16MSB || channelInfo.type == ASIOSTInt16LSB )
3560 info->nativeFormats |= RTAUDIO_SINT16;
3561 else if ( channelInfo.type == ASIOSTInt32MSB || channelInfo.type == ASIOSTInt32LSB )
3562 info->nativeFormats |= RTAUDIO_SINT32;
3563 else if ( channelInfo.type == ASIOSTFloat32MSB || channelInfo.type == ASIOSTFloat32LSB )
3564 info->nativeFormats |= RTAUDIO_FLOAT32;
3565 else if ( channelInfo.type == ASIOSTFloat64MSB || channelInfo.type == ASIOSTFloat64LSB )
3566 info->nativeFormats |= RTAUDIO_FLOAT64;
3568 // Check that we have at least one supported format.
3569 if (info->nativeFormats == 0) {
3570 drivers.removeCurrentDriver();
3571 sprintf(message, "RtAudio: ASIO driver (%s) data format not supported by RtAudio.",
3573 error(RtError::DEBUG_WARNING);
3577 info->probed = true;
3578 drivers.removeCurrentDriver();
3581 void bufferSwitch(long index, ASIOBool processNow)
3583 RtAudio *object = (RtAudio *) asioCallbackInfo->object;
3585 object->callbackEvent( asioCallbackInfo->streamId, index, (void *)NULL, (void *)NULL );
3587 catch (RtError &exception) {
3588 fprintf(stderr, "\nCallback handler error (%s)!\n\n", exception.getMessage());
3595 void sampleRateChanged(ASIOSampleRate sRate)
3597 // The ASIO documentation says that this usually only happens during
3598 // external sync. Audio processing is not stopped by the driver,
3599 // actual sample rate might not have even changed, maybe only the
3600 // sample rate status of an AES/EBU or S/PDIF digital input at the
3603 RtAudio *object = (RtAudio *) asioCallbackInfo->object;
3605 object->stopStream( asioCallbackInfo->streamId );
3607 catch (RtError &exception) {
3608 fprintf(stderr, "\nRtAudio: sampleRateChanged() error (%s)!\n\n", exception.getMessage());
3612 fprintf(stderr, "\nRtAudio: ASIO driver reports sample rate changed to %d ... stream stopped!!!", (int) sRate);
3615 long asioMessages(long selector, long value, void* message, double* opt)
3619 case kAsioSelectorSupported:
3620 if(value == kAsioResetRequest
3621 || value == kAsioEngineVersion
3622 || value == kAsioResyncRequest
3623 || value == kAsioLatenciesChanged
3624 // The following three were added for ASIO 2.0, you don't
3625 // necessarily have to support them.
3626 || value == kAsioSupportsTimeInfo
3627 || value == kAsioSupportsTimeCode
3628 || value == kAsioSupportsInputMonitor)
3631 case kAsioResetRequest:
3632 // Defer the task and perform the reset of the driver during the
3633 // next "safe" situation. You cannot reset the driver right now,
3634 // as this code is called from the driver. Reset the driver is
3635 // done by completely destruct is. I.e. ASIOStop(),
3636 // ASIODisposeBuffers(), Destruction Afterwards you initialize the
3638 fprintf(stderr, "\nRtAudio: ASIO driver reset requested!!!");
3641 case kAsioResyncRequest:
3642 // This informs the application that the driver encountered some
3643 // non-fatal data loss. It is used for synchronization purposes
3644 // of different media. Added mainly to work around the Win16Mutex
3645 // problems in Windows 95/98 with the Windows Multimedia system,
3646 // which could lose data because the Mutex was held too long by
3647 // another thread. However a driver can issue it in other
3649 fprintf(stderr, "\nRtAudio: ASIO driver resync requested!!!");
3652 case kAsioLatenciesChanged:
3653 // This will inform the host application that the drivers were
3654 // latencies changed. Beware, it this does not mean that the
3655 // buffer sizes have changed! You might need to update internal
3657 fprintf(stderr, "\nRtAudio: ASIO driver latency may have changed!!!");
3660 case kAsioEngineVersion:
3661 // Return the supported ASIO version of the host application. If
3662 // a host application does not implement this selector, ASIO 1.0
3663 // is assumed by the driver.
3666 case kAsioSupportsTimeInfo:
3667 // Informs the driver whether the
3668 // asioCallbacks.bufferSwitchTimeInfo() callback is supported.
3669 // For compatibility with ASIO 1.0 drivers the host application
3670 // should always support the "old" bufferSwitch method, too.
3673 case kAsioSupportsTimeCode:
3674 // Informs the driver wether application is interested in time
3675 // code info. If an application does not need to know about time
3676 // code, the driver has less work to do.
3683 bool RtAudio :: probeDeviceOpen(int device, RTAUDIO_STREAM *stream,
3684 STREAM_MODE mode, int channels,
3685 int sampleRate, RTAUDIO_FORMAT format,
3686 int *bufferSize, int numberOfBuffers)
3688 // Don't attempt to load another driver if a stream is already open.
3689 if ( streams.size() > 0 ) {
3690 sprintf(message, "RtAudio: unable to load ASIO driver while a stream is open.");
3691 error(RtError::WARNING);
3695 // For ASIO, a duplex stream MUST use the same driver.
3696 if ( mode == INPUT && stream->mode == OUTPUT && stream->device[0] != device ) {
3697 sprintf(message, "RtAudio: ASIO duplex stream must use the same device for input and output.");
3698 error(RtError::WARNING);
3702 // Only load the driver once for duplex stream.
3704 if ( mode != INPUT || stream->mode != OUTPUT ) {
3705 if ( !drivers.loadDriver( devices[device].name ) ) {
3706 sprintf(message, "RtAudio: ASIO error loading driver (%s).", devices[device].name);
3707 error(RtError::DEBUG_WARNING);
3711 result = ASIOInit( &driverInfo );
3712 if ( result != ASE_OK ) {
3714 if ( result == ASE_HWMalfunction )
3715 sprintf(details, "hardware malfunction");
3716 else if ( result == ASE_NoMemory )
3717 sprintf(details, "no memory");
3718 else if ( result == ASE_NotPresent )
3719 sprintf(details, "driver/hardware not present");
3721 sprintf(details, "unspecified");
3722 sprintf(message, "RtAudio: ASIO error (%s) initializing driver (%s).", details, devices[device].name);
3723 error(RtError::DEBUG_WARNING);
3728 // Check the device channel count.
3729 long inputChannels, outputChannels;
3730 result = ASIOGetChannels( &inputChannels, &outputChannels );
3731 if ( result != ASE_OK ) {
3732 drivers.removeCurrentDriver();
3733 sprintf(message, "RtAudio: ASIO error getting input/output channel count (%s).",
3734 devices[device].name);
3735 error(RtError::DEBUG_WARNING);
3739 if ( ( mode == OUTPUT && channels > outputChannels) ||
3740 ( mode == INPUT && channels > inputChannels) ) {
3741 drivers.removeCurrentDriver();
3742 sprintf(message, "RtAudio: ASIO driver (%s) does not support requested channel count (%d).",
3743 devices[device].name, channels);
3744 error(RtError::DEBUG_WARNING);
3747 stream->nDeviceChannels[mode] = channels;
3748 stream->nUserChannels[mode] = channels;
3750 // Verify the sample rate is supported.
3751 result = ASIOCanSampleRate( (ASIOSampleRate) sampleRate );
3752 if ( result != ASE_OK ) {
3753 drivers.removeCurrentDriver();
3754 sprintf(message, "RtAudio: ASIO driver (%s) does not support requested sample rate (%d).",
3755 devices[device].name, sampleRate);
3756 error(RtError::DEBUG_WARNING);
3760 // Set the sample rate.
3761 result = ASIOSetSampleRate( (ASIOSampleRate) sampleRate );
3762 if ( result != ASE_OK ) {
3763 drivers.removeCurrentDriver();
3764 sprintf(message, "RtAudio: ASIO driver (%s) error setting sample rate (%d).",
3765 devices[device].name, sampleRate);
3766 error(RtError::DEBUG_WARNING);
3770 // Determine the driver data type.
3771 ASIOChannelInfo channelInfo;
3772 channelInfo.channel = 0;
3773 if ( mode == OUTPUT ) channelInfo.isInput = false;
3774 else channelInfo.isInput = true;
3775 result = ASIOGetChannelInfo( &channelInfo );
3776 if ( result != ASE_OK ) {
3777 drivers.removeCurrentDriver();
3778 sprintf(message, "RtAudio: ASIO driver (%s) error getting data format.",
3779 devices[device].name);
3780 error(RtError::DEBUG_WARNING);
3784 // Assuming WINDOWS host is always little-endian.
3785 stream->doByteSwap[mode] = false;
3786 stream->userFormat = format;
3787 stream->deviceFormat[mode] = 0;
3788 if ( channelInfo.type == ASIOSTInt16MSB || channelInfo.type == ASIOSTInt16LSB ) {
3789 stream->deviceFormat[mode] = RTAUDIO_SINT16;
3790 if ( channelInfo.type == ASIOSTInt16MSB ) stream->doByteSwap[mode] = true;
3792 else if ( channelInfo.type == ASIOSTInt32MSB || channelInfo.type == ASIOSTInt32LSB ) {
3793 stream->deviceFormat[mode] = RTAUDIO_SINT32;
3794 if ( channelInfo.type == ASIOSTInt32MSB ) stream->doByteSwap[mode] = true;
3796 else if ( channelInfo.type == ASIOSTFloat32MSB || channelInfo.type == ASIOSTFloat32LSB ) {
3797 stream->deviceFormat[mode] = RTAUDIO_FLOAT32;
3798 if ( channelInfo.type == ASIOSTFloat32MSB ) stream->doByteSwap[mode] = true;
3800 else if ( channelInfo.type == ASIOSTFloat64MSB || channelInfo.type == ASIOSTFloat64LSB ) {
3801 stream->deviceFormat[mode] = RTAUDIO_FLOAT64;
3802 if ( channelInfo.type == ASIOSTFloat64MSB ) stream->doByteSwap[mode] = true;
3805 if ( stream->deviceFormat[mode] == 0 ) {
3806 drivers.removeCurrentDriver();
3807 sprintf(message, "RtAudio: ASIO driver (%s) data format not supported by RtAudio.",
3808 devices[device].name);
3809 error(RtError::DEBUG_WARNING);
3813 // Set the buffer size. For a duplex stream, this will end up
3814 // setting the buffer size based on the input constraints, which
3816 long minSize, maxSize, preferSize, granularity;
3817 result = ASIOGetBufferSize( &minSize, &maxSize, &preferSize, &granularity );
3818 if ( result != ASE_OK ) {
3819 drivers.removeCurrentDriver();
3820 sprintf(message, "RtAudio: ASIO driver (%s) error getting buffer size.",
3821 devices[device].name);
3822 error(RtError::DEBUG_WARNING);
3826 if ( *bufferSize < minSize ) *bufferSize = minSize;
3827 else if ( *bufferSize > maxSize ) *bufferSize = maxSize;
3828 else if ( granularity == -1 ) {
3829 // Make sure bufferSize is a power of two.
3830 double power = log10( *bufferSize ) / log10( 2.0 );
3831 *bufferSize = pow( 2.0, floor(power+0.5) );
3832 if ( *bufferSize < minSize ) *bufferSize = minSize;
3833 else if ( *bufferSize > maxSize ) *bufferSize = maxSize;
3834 else *bufferSize = preferSize;
3837 if ( mode == INPUT && stream->mode == OUTPUT && stream->bufferSize != *bufferSize )
3838 cout << "possible input/output buffersize discrepancy" << endl;
3840 stream->bufferSize = *bufferSize;
3841 stream->nBuffers = 2;
3843 // ASIO always uses deinterleaved channels.
3844 stream->deInterleave[mode] = true;
3846 // Create the ASIO internal buffers. Since RtAudio sets up input
3847 // and output separately, we'll have to dispose of previously
3848 // created output buffers for a duplex stream.
3849 if ( mode == INPUT && stream->mode == OUTPUT ) {
3850 free(stream->callbackInfo.buffers);
3851 result = ASIODisposeBuffers();
3852 if ( result != ASE_OK ) {
3853 drivers.removeCurrentDriver();
3854 sprintf(message, "RtAudio: ASIO driver (%s) error disposing previously allocated buffers.",
3855 devices[device].name);
3856 error(RtError::DEBUG_WARNING);
3861 // Allocate, initialize, and save the bufferInfos in our stream callbackInfo structure.
3862 int i, nChannels = stream->nDeviceChannels[0] + stream->nDeviceChannels[1];
3863 stream->callbackInfo.buffers = 0;
3864 ASIOBufferInfo *bufferInfos = (ASIOBufferInfo *) malloc( nChannels * sizeof(ASIOBufferInfo) );
3865 stream->callbackInfo.buffers = (void *) bufferInfos;
3866 ASIOBufferInfo *infos = bufferInfos;
3867 for ( i=0; i<stream->nDeviceChannels[1]; i++, infos++ ) {
3868 infos->isInput = ASIOTrue;
3869 infos->channelNum = i;
3870 infos->buffers[0] = infos->buffers[1] = 0;
3873 for ( i=0; i<stream->nDeviceChannels[0]; i++, infos++ ) {
3874 infos->isInput = ASIOFalse;
3875 infos->channelNum = i;
3876 infos->buffers[0] = infos->buffers[1] = 0;
3879 // Set up the ASIO callback structure and create the ASIO data buffers.
3880 asioCallbacks.bufferSwitch = &bufferSwitch;
3881 asioCallbacks.sampleRateDidChange = &sampleRateChanged;
3882 asioCallbacks.asioMessage = &asioMessages;
3883 asioCallbacks.bufferSwitchTimeInfo = NULL;
3884 result = ASIOCreateBuffers( bufferInfos, nChannels, stream->bufferSize, &asioCallbacks);
3885 if ( result != ASE_OK ) {
3886 drivers.removeCurrentDriver();
3887 sprintf(message, "RtAudio: ASIO driver (%s) error creating buffers.",
3888 devices[device].name);
3889 error(RtError::DEBUG_WARNING);
3893 // Set flags for buffer conversion.
3894 stream->doConvertBuffer[mode] = false;
3895 if (stream->userFormat != stream->deviceFormat[mode])
3896 stream->doConvertBuffer[mode] = true;
3897 if (stream->nUserChannels[mode] < stream->nDeviceChannels[mode])
3898 stream->doConvertBuffer[mode] = true;
3899 if (stream->nUserChannels[mode] > 1 && stream->deInterleave[mode])
3900 stream->doConvertBuffer[mode] = true;
3902 // Allocate necessary internal buffers
3903 if ( stream->nUserChannels[0] != stream->nUserChannels[1] ) {
3906 if (stream->nUserChannels[0] >= stream->nUserChannels[1])
3907 buffer_bytes = stream->nUserChannels[0];
3909 buffer_bytes = stream->nUserChannels[1];
3911 buffer_bytes *= *bufferSize * formatBytes(stream->userFormat);
3912 if (stream->userBuffer) free(stream->userBuffer);
3913 stream->userBuffer = (char *) calloc(buffer_bytes, 1);
3914 if (stream->userBuffer == NULL)
3918 if ( stream->doConvertBuffer[mode] ) {
3921 bool makeBuffer = true;
3922 if ( mode == OUTPUT )
3923 buffer_bytes = stream->nDeviceChannels[0] * formatBytes(stream->deviceFormat[0]);
3924 else { // mode == INPUT
3925 buffer_bytes = stream->nDeviceChannels[1] * formatBytes(stream->deviceFormat[1]);
3926 if ( stream->mode == OUTPUT && stream->deviceBuffer ) {
3927 long bytes_out = stream->nDeviceChannels[0] * formatBytes(stream->deviceFormat[0]);
3928 if ( buffer_bytes < bytes_out ) makeBuffer = false;
3933 buffer_bytes *= *bufferSize;
3934 if (stream->deviceBuffer) free(stream->deviceBuffer);
3935 stream->deviceBuffer = (char *) calloc(buffer_bytes, 1);
3936 if (stream->deviceBuffer == NULL)
3941 stream->device[mode] = device;
3942 stream->state = STREAM_STOPPED;
3943 if ( stream->mode == OUTPUT && mode == INPUT )
3944 // We had already set up an output stream.
3945 stream->mode = DUPLEX;
3947 stream->mode = mode;
3948 stream->sampleRate = sampleRate;
3949 asioCallbackInfo = &stream->callbackInfo;
3950 stream->callbackInfo.object = (void *) this;
3951 stream->callbackInfo.waitTime = (unsigned long) (200.0 * stream->bufferSize / stream->sampleRate);
3956 ASIODisposeBuffers();
3957 drivers.removeCurrentDriver();
3959 if (stream->callbackInfo.buffers)
3960 free(stream->callbackInfo.buffers);
3961 stream->callbackInfo.buffers = 0;
3963 if (stream->userBuffer) {
3964 free(stream->userBuffer);
3965 stream->userBuffer = 0;
3967 sprintf(message, "RtAudio: error allocating buffer memory (%s).",
3968 devices[device].name);
3969 error(RtError::WARNING);
3973 void RtAudio :: cancelStreamCallback(int streamId)
3975 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
3977 if (stream->callbackInfo.usingCallback) {
3979 if (stream->state == STREAM_RUNNING)
3980 stopStream( streamId );
3982 MUTEX_LOCK(&stream->mutex);
3984 stream->callbackInfo.usingCallback = false;
3985 stream->callbackInfo.userData = NULL;
3986 stream->state = STREAM_STOPPED;
3987 stream->callbackInfo.callback = NULL;
3989 MUTEX_UNLOCK(&stream->mutex);
3993 void RtAudio :: closeStream(int streamId)
3995 // We don't want an exception to be thrown here because this
3996 // function is called by our class destructor. So, do our own
3998 if ( streams.find( streamId ) == streams.end() ) {
3999 sprintf(message, "RtAudio: invalid stream identifier!");
4000 error(RtError::WARNING);
4004 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) streams[streamId];
4006 if (stream->state == STREAM_RUNNING)
4009 ASIODisposeBuffers();
4011 drivers.removeCurrentDriver();
4013 DeleteCriticalSection(&stream->mutex);
4015 if (stream->callbackInfo.buffers)
4016 free(stream->callbackInfo.buffers);
4018 if (stream->userBuffer)
4019 free(stream->userBuffer);
4021 if (stream->deviceBuffer)
4022 free(stream->deviceBuffer);
4025 streams.erase(streamId);
4028 void RtAudio :: startStream(int streamId)
4030 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
4032 MUTEX_LOCK(&stream->mutex);
4034 if (stream->state == STREAM_RUNNING) {
4035 MUTEX_UNLOCK(&stream->mutex);
4039 stream->callbackInfo.blockTick = true;
4040 stream->callbackInfo.stopStream = false;
4041 stream->callbackInfo.streamId = streamId;
4042 ASIOError result = ASIOStart();
4043 if ( result != ASE_OK ) {
4044 sprintf(message, "RtAudio: ASIO error starting device (%s).",
4045 devices[stream->device[0]].name);
4046 MUTEX_UNLOCK(&stream->mutex);
4047 error(RtError::DRIVER_ERROR);
4049 stream->state = STREAM_RUNNING;
4051 MUTEX_UNLOCK(&stream->mutex);
4054 void RtAudio :: stopStream(int streamId)
4056 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
4058 MUTEX_LOCK(&stream->mutex);
4060 if (stream->state == STREAM_STOPPED) {
4061 MUTEX_UNLOCK(&stream->mutex);
4065 ASIOError result = ASIOStop();
4066 if ( result != ASE_OK ) {
4067 sprintf(message, "RtAudio: ASIO error stopping device (%s).",
4068 devices[stream->device[0]].name);
4069 MUTEX_UNLOCK(&stream->mutex);
4070 error(RtError::DRIVER_ERROR);
4072 stream->state = STREAM_STOPPED;
4074 MUTEX_UNLOCK(&stream->mutex);
4077 void RtAudio :: abortStream(int streamId)
4079 stopStream( streamId );
4082 // I don't know how this function can be implemented.
4083 int RtAudio :: streamWillBlock(int streamId)
4085 sprintf(message, "RtAudio: streamWillBlock() cannot be implemented for ASIO.");
4086 error(RtError::WARNING);
4090 void RtAudio :: tickStream(int streamId)
4092 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
4094 if (stream->state == STREAM_STOPPED)
4097 if (stream->callbackInfo.usingCallback) {
4098 sprintf(message, "RtAudio: tickStream() should not be used when a callback function is set!");
4099 error(RtError::WARNING);
4103 // Block waiting here until the user data is processed in callbackEvent().
4104 while ( stream->callbackInfo.blockTick )
4105 Sleep(stream->callbackInfo.waitTime);
4107 MUTEX_LOCK(&stream->mutex);
4109 stream->callbackInfo.blockTick = true;
4111 MUTEX_UNLOCK(&stream->mutex);
4114 void RtAudio :: callbackEvent(int streamId, int bufferIndex, void *inData, void *outData)
4116 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
4118 CALLBACK_INFO *info = asioCallbackInfo;
4119 if ( !info->usingCallback ) {
4120 // Block waiting here until we get new user data in tickStream().
4121 while ( !info->blockTick )
4122 Sleep(info->waitTime);
4124 else if ( info->stopStream ) {
4125 // Check if the stream should be stopped (via the previous user
4126 // callback return value). We stop the stream here, rather than
4127 // after the function call, so that output data can first be
4129 this->stopStream(asioCallbackInfo->streamId);
4133 MUTEX_LOCK(&stream->mutex);
4135 // Invoke user callback first, to get fresh output data.
4136 if ( info->usingCallback ) {
4137 RTAUDIO_CALLBACK callback = (RTAUDIO_CALLBACK) info->callback;
4138 if ( callback(stream->userBuffer, stream->bufferSize, info->userData) )
4139 info->stopStream = true;
4142 int nChannels = stream->nDeviceChannels[0] + stream->nDeviceChannels[1];
4144 ASIOBufferInfo *bufferInfos = (ASIOBufferInfo *) info->buffers;
4145 if ( stream->mode == OUTPUT || stream->mode == DUPLEX ) {
4147 bufferBytes = stream->bufferSize * formatBytes(stream->deviceFormat[0]);
4148 if (stream->doConvertBuffer[0]) {
4150 convertStreamBuffer(stream, OUTPUT);
4151 if ( stream->doByteSwap[0] )
4152 byteSwapBuffer(stream->deviceBuffer,
4153 stream->bufferSize * stream->nDeviceChannels[0],
4154 stream->deviceFormat[0]);
4156 // Always de-interleave ASIO output data.
4157 for ( int i=0; i<stream->nDeviceChannels[0]; i++, bufferInfos++ ) {
4158 memcpy(bufferInfos->buffers[bufferIndex],
4159 &stream->deviceBuffer[i*bufferBytes], bufferBytes );
4162 else { // single channel only
4164 if (stream->doByteSwap[0])
4165 byteSwapBuffer(stream->userBuffer,
4166 stream->bufferSize * stream->nUserChannels[0],
4167 stream->userFormat);
4169 memcpy(bufferInfos->buffers[bufferIndex], stream->userBuffer, bufferBytes );
4173 if ( stream->mode == INPUT || stream->mode == DUPLEX ) {
4175 bufferBytes = stream->bufferSize * formatBytes(stream->deviceFormat[1]);
4176 if (stream->doConvertBuffer[1]) {
4178 // Always interleave ASIO input data.
4179 for ( int i=0; i<stream->nDeviceChannels[1]; i++, bufferInfos++ )
4180 memcpy(&stream->deviceBuffer[i*bufferBytes], bufferInfos->buffers[bufferIndex], bufferBytes );
4182 if ( stream->doByteSwap[1] )
4183 byteSwapBuffer(stream->deviceBuffer,
4184 stream->bufferSize * stream->nDeviceChannels[1],
4185 stream->deviceFormat[1]);
4186 convertStreamBuffer(stream, INPUT);
4189 else { // single channel only
4190 memcpy(stream->userBuffer, bufferInfos->buffers[bufferIndex], bufferBytes );
4192 if (stream->doByteSwap[1])
4193 byteSwapBuffer(stream->userBuffer,
4194 stream->bufferSize * stream->nUserChannels[1],
4195 stream->userFormat);
4199 if ( !info->usingCallback )
4200 info->blockTick = false;
4202 MUTEX_UNLOCK(&stream->mutex);
4205 void RtAudio :: setStreamCallback(int streamId, RTAUDIO_CALLBACK callback, void *userData)
4207 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
4209 stream->callbackInfo.callback = (void *) callback;
4210 stream->callbackInfo.userData = userData;
4211 stream->callbackInfo.usingCallback = true;
4214 //******************** End of __WINDOWS_ASIO__ *********************//
4216 #elif defined(__WINDOWS_DS__) // Windows DirectSound API
4220 // Declarations for utility functions, callbacks, and structures
4221 // specific to the DirectSound implementation.
4222 static bool CALLBACK deviceCountCallback(LPGUID lpguid,
4223 LPCSTR lpcstrDescription,
4224 LPCSTR lpcstrModule,
4227 static bool CALLBACK deviceInfoCallback(LPGUID lpguid,
4228 LPCSTR lpcstrDescription,
4229 LPCSTR lpcstrModule,
4232 static bool CALLBACK defaultDeviceCallback(LPGUID lpguid,
4233 LPCSTR lpcstrDescription,
4234 LPCSTR lpcstrModule,
4237 static bool CALLBACK deviceIdCallback(LPGUID lpguid,
4238 LPCSTR lpcstrDescription,
4239 LPCSTR lpcstrModule,
4242 static char* getErrorString(int code);
4251 int RtAudio :: getDefaultInputDevice(void)
4254 info.name[0] = '\0';
4256 // Enumerate through devices to find the default output.
4257 HRESULT result = DirectSoundCaptureEnumerate((LPDSENUMCALLBACK)defaultDeviceCallback, &info);
4258 if ( FAILED(result) ) {
4259 sprintf(message, "RtAudio: Error performing default input device enumeration: %s.",
4260 getErrorString(result));
4261 error(RtError::WARNING);
4265 for ( int i=0; i<nDevices; i++ )
4266 if ( strncmp( devices[i].name, info.name, 64 ) == 0 ) return i;
4271 int RtAudio :: getDefaultOutputDevice(void)
4274 info.name[0] = '\0';
4276 // Enumerate through devices to find the default output.
4277 HRESULT result = DirectSoundEnumerate((LPDSENUMCALLBACK)defaultDeviceCallback, &info);
4278 if ( FAILED(result) ) {
4279 sprintf(message, "RtAudio: Error performing default output device enumeration: %s.",
4280 getErrorString(result));
4281 error(RtError::WARNING);
4285 for ( int i=0; i<nDevices; i++ )
4286 if ( strncmp(devices[i].name, info.name, 64 ) == 0 ) return i;
4291 void RtAudio :: initialize(void)
4293 int i, ins = 0, outs = 0, count = 0;
4297 // Count DirectSound devices.
4298 result = DirectSoundEnumerate((LPDSENUMCALLBACK)deviceCountCallback, &outs);
4299 if ( FAILED(result) ) {
4300 sprintf(message, "RtAudio: Unable to enumerate through sound playback devices: %s.",
4301 getErrorString(result));
4302 error(RtError::DRIVER_ERROR);
4305 // Count DirectSoundCapture devices.
4306 result = DirectSoundCaptureEnumerate((LPDSENUMCALLBACK)deviceCountCallback, &ins);
4307 if ( FAILED(result) ) {
4308 sprintf(message, "RtAudio: Unable to enumerate through sound capture devices: %s.",
4309 getErrorString(result));
4310 error(RtError::DRIVER_ERROR);
4314 if (count == 0) return;
4316 std::vector<enum_info> info(count);
4317 for (i=0; i<count; i++) {
4318 info[i].name[0] = '\0';
4319 if (i < outs) info[i].isInput = false;
4320 else info[i].isInput = true;
4323 // Get playback device info and check capabilities.
4324 result = DirectSoundEnumerate((LPDSENUMCALLBACK)deviceInfoCallback, &info[0]);
4325 if ( FAILED(result) ) {
4326 sprintf(message, "RtAudio: Unable to enumerate through sound playback devices: %s.",
4327 getErrorString(result));
4328 error(RtError::DRIVER_ERROR);
4331 // Get capture device info and check capabilities.
4332 result = DirectSoundCaptureEnumerate((LPDSENUMCALLBACK)deviceInfoCallback, &info[0]);
4333 if ( FAILED(result) ) {
4334 sprintf(message, "RtAudio: Unable to enumerate through sound capture devices: %s.",
4335 getErrorString(result));
4336 error(RtError::DRIVER_ERROR);
4339 // Parse the devices and check validity. Devices are considered
4340 // invalid if they cannot be opened, they report < 1 supported
4341 // channels, or they report no supported data (capture only).
4342 for (i=0; i<count; i++)
4343 if ( info[i].isValid ) nDevices++;
4345 if (nDevices == 0) return;
4347 // Allocate the RTAUDIO_DEVICE structures.
4348 devices = (RTAUDIO_DEVICE *) calloc(nDevices, sizeof(RTAUDIO_DEVICE));
4349 if (devices == NULL) {
4350 sprintf(message, "RtAudio: memory allocation error!");
4351 error(RtError::MEMORY_ERROR);
4354 // Copy the names to our devices structures.
4356 for (i=0; i<count; i++) {
4357 if ( info[i].isValid )
4358 strncpy(devices[index++].name, info[i].name, 64);
4361 //for (i=0;i<nDevices; i++)
4362 //probeDeviceInfo(&devices[i]);
4367 void RtAudio :: probeDeviceInfo(RTAUDIO_DEVICE *info)
4370 strncpy( dsinfo.name, info->name, 64 );
4371 dsinfo.isValid = false;
4373 // Enumerate through input devices to find the id (if it exists).
4374 HRESULT result = DirectSoundCaptureEnumerate((LPDSENUMCALLBACK)deviceIdCallback, &dsinfo);
4375 if ( FAILED(result) ) {
4376 sprintf(message, "RtAudio: Error performing input device id enumeration: %s.",
4377 getErrorString(result));
4378 error(RtError::WARNING);
4382 // Do capture probe first.
4383 if ( dsinfo.isValid == false )
4384 goto playback_probe;
4386 LPDIRECTSOUNDCAPTURE input;
4387 result = DirectSoundCaptureCreate( dsinfo.id, &input, NULL );
4388 if ( FAILED(result) ) {
4389 sprintf(message, "RtAudio: Could not create DirectSound capture object (%s): %s.",
4390 info->name, getErrorString(result));
4391 error(RtError::WARNING);
4392 goto playback_probe;
4396 in_caps.dwSize = sizeof(in_caps);
4397 result = input->GetCaps( &in_caps );
4398 if ( FAILED(result) ) {
4400 sprintf(message, "RtAudio: Could not get DirectSound capture capabilities (%s): %s.",
4401 info->name, getErrorString(result));
4402 error(RtError::WARNING);
4403 goto playback_probe;
4406 // Get input channel information.
4407 info->minInputChannels = 1;
4408 info->maxInputChannels = in_caps.dwChannels;
4410 // Get sample rate and format information.
4411 if( in_caps.dwChannels == 2 ) {
4412 if( in_caps.dwFormats & WAVE_FORMAT_1S16 ) info->nativeFormats |= RTAUDIO_SINT16;
4413 if( in_caps.dwFormats & WAVE_FORMAT_2S16 ) info->nativeFormats |= RTAUDIO_SINT16;
4414 if( in_caps.dwFormats & WAVE_FORMAT_4S16 ) info->nativeFormats |= RTAUDIO_SINT16;
4415 if( in_caps.dwFormats & WAVE_FORMAT_1S08 ) info->nativeFormats |= RTAUDIO_SINT8;
4416 if( in_caps.dwFormats & WAVE_FORMAT_2S08 ) info->nativeFormats |= RTAUDIO_SINT8;
4417 if( in_caps.dwFormats & WAVE_FORMAT_4S08 ) info->nativeFormats |= RTAUDIO_SINT8;
4419 if ( info->nativeFormats & RTAUDIO_SINT16 ) {
4420 if( in_caps.dwFormats & WAVE_FORMAT_1S16 ) info->sampleRates[info->nSampleRates++] = 11025;
4421 if( in_caps.dwFormats & WAVE_FORMAT_2S16 ) info->sampleRates[info->nSampleRates++] = 22050;
4422 if( in_caps.dwFormats & WAVE_FORMAT_4S16 ) info->sampleRates[info->nSampleRates++] = 44100;
4424 else if ( info->nativeFormats & RTAUDIO_SINT8 ) {
4425 if( in_caps.dwFormats & WAVE_FORMAT_1S08 ) info->sampleRates[info->nSampleRates++] = 11025;
4426 if( in_caps.dwFormats & WAVE_FORMAT_2S08 ) info->sampleRates[info->nSampleRates++] = 22050;
4427 if( in_caps.dwFormats & WAVE_FORMAT_4S08 ) info->sampleRates[info->nSampleRates++] = 44100;
4430 else if ( in_caps.dwChannels == 1 ) {
4431 if( in_caps.dwFormats & WAVE_FORMAT_1M16 ) info->nativeFormats |= RTAUDIO_SINT16;
4432 if( in_caps.dwFormats & WAVE_FORMAT_2M16 ) info->nativeFormats |= RTAUDIO_SINT16;
4433 if( in_caps.dwFormats & WAVE_FORMAT_4M16 ) info->nativeFormats |= RTAUDIO_SINT16;
4434 if( in_caps.dwFormats & WAVE_FORMAT_1M08 ) info->nativeFormats |= RTAUDIO_SINT8;
4435 if( in_caps.dwFormats & WAVE_FORMAT_2M08 ) info->nativeFormats |= RTAUDIO_SINT8;
4436 if( in_caps.dwFormats & WAVE_FORMAT_4M08 ) info->nativeFormats |= RTAUDIO_SINT8;
4438 if ( info->nativeFormats & RTAUDIO_SINT16 ) {
4439 if( in_caps.dwFormats & WAVE_FORMAT_1M16 ) info->sampleRates[info->nSampleRates++] = 11025;
4440 if( in_caps.dwFormats & WAVE_FORMAT_2M16 ) info->sampleRates[info->nSampleRates++] = 22050;
4441 if( in_caps.dwFormats & WAVE_FORMAT_4M16 ) info->sampleRates[info->nSampleRates++] = 44100;
4443 else if ( info->nativeFormats & RTAUDIO_SINT8 ) {
4444 if( in_caps.dwFormats & WAVE_FORMAT_1M08 ) info->sampleRates[info->nSampleRates++] = 11025;
4445 if( in_caps.dwFormats & WAVE_FORMAT_2M08 ) info->sampleRates[info->nSampleRates++] = 22050;
4446 if( in_caps.dwFormats & WAVE_FORMAT_4M08 ) info->sampleRates[info->nSampleRates++] = 44100;
4449 else info->minInputChannels = 0; // technically, this would be an error
4455 dsinfo.isValid = false;
4457 // Enumerate through output devices to find the id (if it exists).
4458 result = DirectSoundEnumerate((LPDSENUMCALLBACK)deviceIdCallback, &dsinfo);
4459 if ( FAILED(result) ) {
4460 sprintf(message, "RtAudio: Error performing output device id enumeration: %s.",
4461 getErrorString(result));
4462 error(RtError::WARNING);
4466 // Now do playback probe.
4467 if ( dsinfo.isValid == false )
4468 goto check_parameters;
4470 LPDIRECTSOUND output;
4472 result = DirectSoundCreate( dsinfo.id, &output, NULL );
4473 if ( FAILED(result) ) {
4474 sprintf(message, "RtAudio: Could not create DirectSound playback object (%s): %s.",
4475 info->name, getErrorString(result));
4476 error(RtError::WARNING);
4477 goto check_parameters;
4480 out_caps.dwSize = sizeof(out_caps);
4481 result = output->GetCaps( &out_caps );
4482 if ( FAILED(result) ) {
4484 sprintf(message, "RtAudio: Could not get DirectSound playback capabilities (%s): %s.",
4485 info->name, getErrorString(result));
4486 error(RtError::WARNING);
4487 goto check_parameters;
4490 // Get output channel information.
4491 info->minOutputChannels = 1;
4492 info->maxOutputChannels = ( out_caps.dwFlags & DSCAPS_PRIMARYSTEREO ) ? 2 : 1;
4494 // Get sample rate information. Use capture device rate information
4496 if ( info->nSampleRates == 0 ) {
4497 info->sampleRates[0] = (int) out_caps.dwMinSecondarySampleRate;
4498 info->sampleRates[1] = (int) out_caps.dwMaxSecondarySampleRate;
4499 if ( out_caps.dwFlags & DSCAPS_CONTINUOUSRATE )
4500 info->nSampleRates = -1;
4501 else if ( out_caps.dwMinSecondarySampleRate == out_caps.dwMaxSecondarySampleRate ) {
4502 if ( out_caps.dwMinSecondarySampleRate == 0 ) {
4503 // This is a bogus driver report ... fake the range and cross
4505 info->sampleRates[0] = 11025;
4506 info->sampleRates[1] = 48000;
4507 info->nSampleRates = -1; /* continuous range */
4508 sprintf(message, "RtAudio: bogus sample rates reported by DirectSound driver ... using defaults (%s).",
4510 error(RtError::DEBUG_WARNING);
4513 info->nSampleRates = 1;
4516 else if ( (out_caps.dwMinSecondarySampleRate < 1000.0) &&
4517 (out_caps.dwMaxSecondarySampleRate > 50000.0) ) {
4518 // This is a bogus driver report ... support for only two
4519 // distant rates. We'll assume this is a range.
4520 info->nSampleRates = -1;
4521 sprintf(message, "RtAudio: bogus sample rates reported by DirectSound driver ... using range (%s).",
4523 error(RtError::WARNING);
4525 else info->nSampleRates = 2;
4528 // Check input rates against output rate range
4529 for ( int i=info->nSampleRates-1; i>=0; i-- ) {
4530 if ( info->sampleRates[i] <= out_caps.dwMaxSecondarySampleRate )
4532 info->nSampleRates--;
4534 while ( info->sampleRates[0] < out_caps.dwMinSecondarySampleRate ) {
4535 info->nSampleRates--;
4536 for ( int i=0; i<info->nSampleRates; i++)
4537 info->sampleRates[i] = info->sampleRates[i+1];
4538 if ( info->nSampleRates <= 0 ) break;
4542 // Get format information.
4543 if ( out_caps.dwFlags & DSCAPS_PRIMARY16BIT ) info->nativeFormats |= RTAUDIO_SINT16;
4544 if ( out_caps.dwFlags & DSCAPS_PRIMARY8BIT ) info->nativeFormats |= RTAUDIO_SINT8;
4549 if ( info->maxInputChannels == 0 && info->maxOutputChannels == 0 )
4551 if ( info->nSampleRates == 0 || info->nativeFormats == 0 )
4554 // Determine duplex status.
4555 if (info->maxInputChannels < info->maxOutputChannels)
4556 info->maxDuplexChannels = info->maxInputChannels;
4558 info->maxDuplexChannels = info->maxOutputChannels;
4559 if (info->minInputChannels < info->minOutputChannels)
4560 info->minDuplexChannels = info->minInputChannels;
4562 info->minDuplexChannels = info->minOutputChannels;
4564 if ( info->maxDuplexChannels > 0 ) info->hasDuplexSupport = true;
4565 else info->hasDuplexSupport = false;
4567 info->probed = true;
4572 bool RtAudio :: probeDeviceOpen(int device, RTAUDIO_STREAM *stream,
4573 STREAM_MODE mode, int channels,
4574 int sampleRate, RTAUDIO_FORMAT format,
4575 int *bufferSize, int numberOfBuffers)
4578 HWND hWnd = GetForegroundWindow();
4579 // According to a note in PortAudio, using GetDesktopWindow()
4580 // instead of GetForegroundWindow() is supposed to avoid problems
4581 // that occur when the application's window is not the foreground
4582 // window. Also, if the application window closes before the
4583 // DirectSound buffer, DirectSound can crash. However, for console
4584 // applications, no sound was produced when using GetDesktopWindow().
4590 // Check the numberOfBuffers parameter and limit the lowest value to
4591 // two. This is a judgement call and a value of two is probably too
4592 // low for capture, but it should work for playback.
4593 if (numberOfBuffers < 2)
4596 nBuffers = numberOfBuffers;
4598 // Define the wave format structure (16-bit PCM, srate, channels)
4599 WAVEFORMATEX waveFormat;
4600 ZeroMemory(&waveFormat, sizeof(WAVEFORMATEX));
4601 waveFormat.wFormatTag = WAVE_FORMAT_PCM;
4602 waveFormat.nChannels = channels;
4603 waveFormat.nSamplesPerSec = (unsigned long) sampleRate;
4605 // Determine the data format.
4606 if ( devices[device].nativeFormats ) { // 8-bit and/or 16-bit support
4607 if ( format == RTAUDIO_SINT8 ) {
4608 if ( devices[device].nativeFormats & RTAUDIO_SINT8 )
4609 waveFormat.wBitsPerSample = 8;
4611 waveFormat.wBitsPerSample = 16;
4614 if ( devices[device].nativeFormats & RTAUDIO_SINT16 )
4615 waveFormat.wBitsPerSample = 16;
4617 waveFormat.wBitsPerSample = 8;
4621 sprintf(message, "RtAudio: no reported data formats for DirectSound device (%s).",
4622 devices[device].name);
4623 error(RtError::DEBUG_WARNING);
4627 waveFormat.nBlockAlign = waveFormat.nChannels * waveFormat.wBitsPerSample / 8;
4628 waveFormat.nAvgBytesPerSec = waveFormat.nSamplesPerSec * waveFormat.nBlockAlign;
4631 strncpy( dsinfo.name, devices[device].name, 64 );
4632 dsinfo.isValid = false;
4633 if ( mode == OUTPUT ) {
4635 if ( devices[device].maxOutputChannels < channels )
4638 // Enumerate through output devices to find the id (if it exists).
4639 result = DirectSoundEnumerate((LPDSENUMCALLBACK)deviceIdCallback, &dsinfo);
4640 if ( FAILED(result) ) {
4641 sprintf(message, "RtAudio: Error performing output device id enumeration: %s.",
4642 getErrorString(result));
4643 error(RtError::DEBUG_WARNING);
4647 if ( dsinfo.isValid == false ) {
4648 sprintf(message, "RtAudio: DS output device (%s) id not found!", devices[device].name);
4649 error(RtError::DEBUG_WARNING);
4653 LPGUID id = dsinfo.id;
4654 LPDIRECTSOUND object;
4655 LPDIRECTSOUNDBUFFER buffer;
4656 DSBUFFERDESC bufferDescription;
4658 result = DirectSoundCreate( id, &object, NULL );
4659 if ( FAILED(result) ) {
4660 sprintf(message, "RtAudio: Could not create DirectSound playback object (%s): %s.",
4661 devices[device].name, getErrorString(result));
4662 error(RtError::DEBUG_WARNING);
4666 // Set cooperative level to DSSCL_EXCLUSIVE
4667 result = object->SetCooperativeLevel(hWnd, DSSCL_EXCLUSIVE);
4668 if ( FAILED(result) ) {
4670 sprintf(message, "RtAudio: Unable to set DirectSound cooperative level (%s): %s.",
4671 devices[device].name, getErrorString(result));
4672 error(RtError::WARNING);
4676 // Even though we will write to the secondary buffer, we need to
4677 // access the primary buffer to set the correct output format.
4678 // The default is 8-bit, 22 kHz!
4679 // Setup the DS primary buffer description.
4680 ZeroMemory(&bufferDescription, sizeof(DSBUFFERDESC));
4681 bufferDescription.dwSize = sizeof(DSBUFFERDESC);
4682 bufferDescription.dwFlags = DSBCAPS_PRIMARYBUFFER;
4683 // Obtain the primary buffer
4684 result = object->CreateSoundBuffer(&bufferDescription, &buffer, NULL);
4685 if ( FAILED(result) ) {
4687 sprintf(message, "RtAudio: Unable to access DS primary buffer (%s): %s.",
4688 devices[device].name, getErrorString(result));
4689 error(RtError::WARNING);
4693 // Set the primary DS buffer sound format.
4694 result = buffer->SetFormat(&waveFormat);
4695 if ( FAILED(result) ) {
4697 sprintf(message, "RtAudio: Unable to set DS primary buffer format (%s): %s.",
4698 devices[device].name, getErrorString(result));
4699 error(RtError::WARNING);
4703 // Setup the secondary DS buffer description.
4704 buffer_size = channels * *bufferSize * nBuffers * waveFormat.wBitsPerSample / 8;
4705 ZeroMemory(&bufferDescription, sizeof(DSBUFFERDESC));
4706 bufferDescription.dwSize = sizeof(DSBUFFERDESC);
4707 bufferDescription.dwFlags = ( DSBCAPS_STICKYFOCUS |
4708 DSBCAPS_GETCURRENTPOSITION2 |
4709 DSBCAPS_LOCHARDWARE ); // Force hardware mixing
4710 bufferDescription.dwBufferBytes = buffer_size;
4711 bufferDescription.lpwfxFormat = &waveFormat;
4713 // Try to create the secondary DS buffer. If that doesn't work,
4714 // try to use software mixing. Otherwise, there's a problem.
4715 result = object->CreateSoundBuffer(&bufferDescription, &buffer, NULL);
4716 if ( FAILED(result) ) {
4717 bufferDescription.dwFlags = ( DSBCAPS_STICKYFOCUS |
4718 DSBCAPS_GETCURRENTPOSITION2 |
4719 DSBCAPS_LOCSOFTWARE ); // Force software mixing
4720 result = object->CreateSoundBuffer(&bufferDescription, &buffer, NULL);
4721 if ( FAILED(result) ) {
4723 sprintf(message, "RtAudio: Unable to create secondary DS buffer (%s): %s.",
4724 devices[device].name, getErrorString(result));
4725 error(RtError::WARNING);
4730 // Get the buffer size ... might be different from what we specified.
4732 dsbcaps.dwSize = sizeof(DSBCAPS);
4733 buffer->GetCaps(&dsbcaps);
4734 buffer_size = dsbcaps.dwBufferBytes;
4736 // Lock the DS buffer
4737 result = buffer->Lock(0, buffer_size, &audioPtr, &dataLen, NULL, NULL, 0);
4738 if ( FAILED(result) ) {
4740 sprintf(message, "RtAudio: Unable to lock DS buffer (%s): %s.",
4741 devices[device].name, getErrorString(result));
4742 error(RtError::WARNING);
4746 // Zero the DS buffer
4747 ZeroMemory(audioPtr, dataLen);
4749 // Unlock the DS buffer
4750 result = buffer->Unlock(audioPtr, dataLen, NULL, 0);
4751 if ( FAILED(result) ) {
4753 sprintf(message, "RtAudio: Unable to unlock DS buffer(%s): %s.",
4754 devices[device].name, getErrorString(result));
4755 error(RtError::WARNING);
4759 stream->handle[0].object = (void *) object;
4760 stream->handle[0].buffer = (void *) buffer;
4761 stream->nDeviceChannels[0] = channels;
4764 if ( mode == INPUT ) {
4766 if ( devices[device].maxInputChannels < channels )
4769 // Enumerate through input devices to find the id (if it exists).
4770 result = DirectSoundCaptureEnumerate((LPDSENUMCALLBACK)deviceIdCallback, &dsinfo);
4771 if ( FAILED(result) ) {
4772 sprintf(message, "RtAudio: Error performing input device id enumeration: %s.",
4773 getErrorString(result));
4774 error(RtError::DEBUG_WARNING);
4778 if ( dsinfo.isValid == false ) {
4779 sprintf(message, "RtAudio: DS input device (%s) id not found!", devices[device].name);
4780 error(RtError::DEBUG_WARNING);
4784 LPGUID id = dsinfo.id;
4785 LPDIRECTSOUNDCAPTURE object;
4786 LPDIRECTSOUNDCAPTUREBUFFER buffer;
4787 DSCBUFFERDESC bufferDescription;
4789 result = DirectSoundCaptureCreate( id, &object, NULL );
4790 if ( FAILED(result) ) {
4791 sprintf(message, "RtAudio: Could not create DirectSound capture object (%s): %s.",
4792 devices[device].name, getErrorString(result));
4793 error(RtError::WARNING);
4797 // Setup the secondary DS buffer description.
4798 buffer_size = channels * *bufferSize * nBuffers * waveFormat.wBitsPerSample / 8;
4799 ZeroMemory(&bufferDescription, sizeof(DSCBUFFERDESC));
4800 bufferDescription.dwSize = sizeof(DSCBUFFERDESC);
4801 bufferDescription.dwFlags = 0;
4802 bufferDescription.dwReserved = 0;
4803 bufferDescription.dwBufferBytes = buffer_size;
4804 bufferDescription.lpwfxFormat = &waveFormat;
4806 // Create the capture buffer.
4807 result = object->CreateCaptureBuffer(&bufferDescription, &buffer, NULL);
4808 if ( FAILED(result) ) {
4810 sprintf(message, "RtAudio: Unable to create DS capture buffer (%s): %s.",
4811 devices[device].name, getErrorString(result));
4812 error(RtError::WARNING);
4816 // Lock the capture buffer
4817 result = buffer->Lock(0, buffer_size, &audioPtr, &dataLen, NULL, NULL, 0);
4818 if ( FAILED(result) ) {
4820 sprintf(message, "RtAudio: Unable to lock DS capture buffer (%s): %s.",
4821 devices[device].name, getErrorString(result));
4822 error(RtError::WARNING);
4827 ZeroMemory(audioPtr, dataLen);
4829 // Unlock the buffer
4830 result = buffer->Unlock(audioPtr, dataLen, NULL, 0);
4831 if ( FAILED(result) ) {
4833 sprintf(message, "RtAudio: Unable to unlock DS capture buffer (%s): %s.",
4834 devices[device].name, getErrorString(result));
4835 error(RtError::WARNING);
4839 stream->handle[1].object = (void *) object;
4840 stream->handle[1].buffer = (void *) buffer;
4841 stream->nDeviceChannels[1] = channels;
4844 stream->userFormat = format;
4845 if ( waveFormat.wBitsPerSample == 8 )
4846 stream->deviceFormat[mode] = RTAUDIO_SINT8;
4848 stream->deviceFormat[mode] = RTAUDIO_SINT16;
4849 stream->nUserChannels[mode] = channels;
4850 *bufferSize = buffer_size / (channels * nBuffers * waveFormat.wBitsPerSample / 8);
4851 stream->bufferSize = *bufferSize;
4853 // Set flags for buffer conversion
4854 stream->doConvertBuffer[mode] = false;
4855 if (stream->userFormat != stream->deviceFormat[mode])
4856 stream->doConvertBuffer[mode] = true;
4857 if (stream->nUserChannels[mode] < stream->nDeviceChannels[mode])
4858 stream->doConvertBuffer[mode] = true;
4860 // Allocate necessary internal buffers
4861 if ( stream->nUserChannels[0] != stream->nUserChannels[1] ) {
4864 if (stream->nUserChannels[0] >= stream->nUserChannels[1])
4865 buffer_bytes = stream->nUserChannels[0];
4867 buffer_bytes = stream->nUserChannels[1];
4869 buffer_bytes *= *bufferSize * formatBytes(stream->userFormat);
4870 if (stream->userBuffer) free(stream->userBuffer);
4871 stream->userBuffer = (char *) calloc(buffer_bytes, 1);
4872 if (stream->userBuffer == NULL)
4876 if ( stream->doConvertBuffer[mode] ) {
4879 bool makeBuffer = true;
4880 if ( mode == OUTPUT )
4881 buffer_bytes = stream->nDeviceChannels[0] * formatBytes(stream->deviceFormat[0]);
4882 else { // mode == INPUT
4883 buffer_bytes = stream->nDeviceChannels[1] * formatBytes(stream->deviceFormat[1]);
4884 if ( stream->mode == OUTPUT && stream->deviceBuffer ) {
4885 long bytes_out = stream->nDeviceChannels[0] * formatBytes(stream->deviceFormat[0]);
4886 if ( buffer_bytes < bytes_out ) makeBuffer = false;
4891 buffer_bytes *= *bufferSize;
4892 if (stream->deviceBuffer) free(stream->deviceBuffer);
4893 stream->deviceBuffer = (char *) calloc(buffer_bytes, 1);
4894 if (stream->deviceBuffer == NULL)
4899 stream->device[mode] = device;
4900 stream->state = STREAM_STOPPED;
4901 if ( stream->mode == OUTPUT && mode == INPUT )
4902 // We had already set up an output stream.
4903 stream->mode = DUPLEX;
4905 stream->mode = mode;
4906 stream->nBuffers = nBuffers;
4907 stream->sampleRate = sampleRate;
4912 if (stream->handle[0].object) {
4913 LPDIRECTSOUND object = (LPDIRECTSOUND) stream->handle[0].object;
4914 LPDIRECTSOUNDBUFFER buffer = (LPDIRECTSOUNDBUFFER) stream->handle[0].buffer;
4917 stream->handle[0].buffer = NULL;
4920 stream->handle[0].object = NULL;
4922 if (stream->handle[1].object) {
4923 LPDIRECTSOUNDCAPTURE object = (LPDIRECTSOUNDCAPTURE) stream->handle[1].object;
4924 LPDIRECTSOUNDCAPTUREBUFFER buffer = (LPDIRECTSOUNDCAPTUREBUFFER) stream->handle[1].buffer;
4927 stream->handle[1].buffer = NULL;
4930 stream->handle[1].object = NULL;
4932 if (stream->userBuffer) {
4933 free(stream->userBuffer);
4934 stream->userBuffer = 0;
4936 sprintf(message, "RtAudio: error allocating buffer memory (%s).",
4937 devices[device].name);
4938 error(RtError::WARNING);
4942 void RtAudio :: cancelStreamCallback(int streamId)
4944 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
4946 if (stream->callbackInfo.usingCallback) {
4948 if (stream->state == STREAM_RUNNING)
4949 stopStream( streamId );
4951 MUTEX_LOCK(&stream->mutex);
4953 stream->callbackInfo.usingCallback = false;
4954 WaitForSingleObject( (HANDLE)stream->callbackInfo.thread, INFINITE );
4955 CloseHandle( (HANDLE)stream->callbackInfo.thread );
4956 stream->callbackInfo.thread = 0;
4957 stream->callbackInfo.callback = NULL;
4958 stream->callbackInfo.userData = NULL;
4960 MUTEX_UNLOCK(&stream->mutex);
4964 void RtAudio :: closeStream(int streamId)
4966 // We don't want an exception to be thrown here because this
4967 // function is called by our class destructor. So, do our own
4969 if ( streams.find( streamId ) == streams.end() ) {
4970 sprintf(message, "RtAudio: invalid stream identifier!");
4971 error(RtError::WARNING);
4975 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) streams[streamId];
4977 if (stream->callbackInfo.usingCallback) {
4978 stream->callbackInfo.usingCallback = false;
4979 WaitForSingleObject( (HANDLE)stream->callbackInfo.thread, INFINITE );
4980 CloseHandle( (HANDLE)stream->callbackInfo.thread );
4983 DeleteCriticalSection(&stream->mutex);
4985 if (stream->handle[0].object) {
4986 LPDIRECTSOUND object = (LPDIRECTSOUND) stream->handle[0].object;
4987 LPDIRECTSOUNDBUFFER buffer = (LPDIRECTSOUNDBUFFER) stream->handle[0].buffer;
4995 if (stream->handle[1].object) {
4996 LPDIRECTSOUNDCAPTURE object = (LPDIRECTSOUNDCAPTURE) stream->handle[1].object;
4997 LPDIRECTSOUNDCAPTUREBUFFER buffer = (LPDIRECTSOUNDCAPTUREBUFFER) stream->handle[1].buffer;
5005 if (stream->userBuffer)
5006 free(stream->userBuffer);
5008 if (stream->deviceBuffer)
5009 free(stream->deviceBuffer);
5012 streams.erase(streamId);
5015 void RtAudio :: startStream(int streamId)
5017 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
5019 MUTEX_LOCK(&stream->mutex);
5021 if (stream->state == STREAM_RUNNING)
5025 if (stream->mode == OUTPUT || stream->mode == DUPLEX) {
5026 LPDIRECTSOUNDBUFFER buffer = (LPDIRECTSOUNDBUFFER) stream->handle[0].buffer;
5027 result = buffer->Play(0, 0, DSBPLAY_LOOPING );
5028 if ( FAILED(result) ) {
5029 sprintf(message, "RtAudio: Unable to start DS buffer (%s): %s.",
5030 devices[stream->device[0]].name, getErrorString(result));
5031 error(RtError::DRIVER_ERROR);
5035 if (stream->mode == INPUT || stream->mode == DUPLEX) {
5036 LPDIRECTSOUNDCAPTUREBUFFER buffer = (LPDIRECTSOUNDCAPTUREBUFFER) stream->handle[1].buffer;
5037 result = buffer->Start(DSCBSTART_LOOPING );
5038 if ( FAILED(result) ) {
5039 sprintf(message, "RtAudio: Unable to start DS capture buffer (%s): %s.",
5040 devices[stream->device[1]].name, getErrorString(result));
5041 error(RtError::DRIVER_ERROR);
5044 stream->state = STREAM_RUNNING;
5047 MUTEX_UNLOCK(&stream->mutex);
5050 void RtAudio :: stopStream(int streamId)
5052 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
5054 MUTEX_LOCK(&stream->mutex);
5056 if (stream->state == STREAM_STOPPED) {
5057 MUTEX_UNLOCK(&stream->mutex);
5061 // There is no specific DirectSound API call to "drain" a buffer
5062 // before stopping. We can hack this for playback by writing zeroes
5063 // for another bufferSize * nBuffers frames. For capture, the
5064 // concept is less clear so we'll repeat what we do in the
5065 // abortStream() case.
5068 LPVOID buffer1 = NULL;
5069 LPVOID buffer2 = NULL;
5070 DWORD bufferSize1 = 0;
5071 DWORD bufferSize2 = 0;
5072 if (stream->mode == OUTPUT || stream->mode == DUPLEX) {
5074 DWORD currentPos, safePos;
5075 long buffer_bytes = stream->bufferSize * stream->nDeviceChannels[0];
5076 buffer_bytes *= formatBytes(stream->deviceFormat[0]);
5078 LPDIRECTSOUNDBUFFER dsBuffer = (LPDIRECTSOUNDBUFFER) stream->handle[0].buffer;
5079 UINT nextWritePos = stream->handle[0].bufferPointer;
5080 dsBufferSize = buffer_bytes * stream->nBuffers;
5082 // Write zeroes for nBuffer counts.
5083 for (int i=0; i<stream->nBuffers; i++) {
5085 // Find out where the read and "safe write" pointers are.
5086 result = dsBuffer->GetCurrentPosition(¤tPos, &safePos);
5087 if ( FAILED(result) ) {
5088 sprintf(message, "RtAudio: Unable to get current DS position (%s): %s.",
5089 devices[stream->device[0]].name, getErrorString(result));
5090 error(RtError::DRIVER_ERROR);
5093 if ( currentPos < nextWritePos ) currentPos += dsBufferSize; // unwrap offset
5094 DWORD endWrite = nextWritePos + buffer_bytes;
5096 // Check whether the entire write region is behind the play pointer.
5097 while ( currentPos < endWrite ) {
5098 float millis = (endWrite - currentPos) * 900.0;
5099 millis /= ( formatBytes(stream->deviceFormat[0]) * stream->sampleRate);
5100 if ( millis < 1.0 ) millis = 1.0;
5101 Sleep( (DWORD) millis );
5103 // Wake up, find out where we are now
5104 result = dsBuffer->GetCurrentPosition( ¤tPos, &safePos );
5105 if ( FAILED(result) ) {
5106 sprintf(message, "RtAudio: Unable to get current DS position (%s): %s.",
5107 devices[stream->device[0]].name, getErrorString(result));
5108 error(RtError::DRIVER_ERROR);
5110 if ( currentPos < nextWritePos ) currentPos += dsBufferSize; // unwrap offset
5113 // Lock free space in the buffer
5114 result = dsBuffer->Lock (nextWritePos, buffer_bytes, &buffer1,
5115 &bufferSize1, &buffer2, &bufferSize2, 0);
5116 if ( FAILED(result) ) {
5117 sprintf(message, "RtAudio: Unable to lock DS buffer during playback (%s): %s.",
5118 devices[stream->device[0]].name, getErrorString(result));
5119 error(RtError::DRIVER_ERROR);
5122 // Zero the free space
5123 ZeroMemory(buffer1, bufferSize1);
5124 if (buffer2 != NULL) ZeroMemory(buffer2, bufferSize2);
5126 // Update our buffer offset and unlock sound buffer
5127 dsBuffer->Unlock (buffer1, bufferSize1, buffer2, bufferSize2);
5128 if ( FAILED(result) ) {
5129 sprintf(message, "RtAudio: Unable to unlock DS buffer during playback (%s): %s.",
5130 devices[stream->device[0]].name, getErrorString(result));
5131 error(RtError::DRIVER_ERROR);
5133 nextWritePos = (nextWritePos + bufferSize1 + bufferSize2) % dsBufferSize;
5134 stream->handle[0].bufferPointer = nextWritePos;
5137 // If we play again, start at the beginning of the buffer.
5138 stream->handle[0].bufferPointer = 0;
5141 if (stream->mode == INPUT || stream->mode == DUPLEX) {
5142 LPDIRECTSOUNDCAPTUREBUFFER buffer = (LPDIRECTSOUNDCAPTUREBUFFER) stream->handle[1].buffer;
5146 result = buffer->Stop();
5147 if ( FAILED(result) ) {
5148 sprintf(message, "RtAudio: Unable to stop DS capture buffer (%s): %s",
5149 devices[stream->device[1]].name, getErrorString(result));
5150 error(RtError::DRIVER_ERROR);
5153 dsBufferSize = stream->bufferSize * stream->nDeviceChannels[1];
5154 dsBufferSize *= formatBytes(stream->deviceFormat[1]) * stream->nBuffers;
5156 // Lock the buffer and clear it so that if we start to play again,
5157 // we won't have old data playing.
5158 result = buffer->Lock(0, dsBufferSize, &buffer1, &bufferSize1, NULL, NULL, 0);
5159 if ( FAILED(result) ) {
5160 sprintf(message, "RtAudio: Unable to lock DS capture buffer (%s): %s.",
5161 devices[stream->device[1]].name, getErrorString(result));
5162 error(RtError::DRIVER_ERROR);
5165 // Zero the DS buffer
5166 ZeroMemory(buffer1, bufferSize1);
5168 // Unlock the DS buffer
5169 result = buffer->Unlock(buffer1, bufferSize1, NULL, 0);
5170 if ( FAILED(result) ) {
5171 sprintf(message, "RtAudio: Unable to unlock DS capture buffer (%s): %s.",
5172 devices[stream->device[1]].name, getErrorString(result));
5173 error(RtError::DRIVER_ERROR);
5176 // If we start recording again, we must begin at beginning of buffer.
5177 stream->handle[1].bufferPointer = 0;
5179 stream->state = STREAM_STOPPED;
5181 MUTEX_UNLOCK(&stream->mutex);
5184 void RtAudio :: abortStream(int streamId)
5186 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
5188 MUTEX_LOCK(&stream->mutex);
5190 if (stream->state == STREAM_STOPPED)
5197 if (stream->mode == OUTPUT || stream->mode == DUPLEX) {
5198 LPDIRECTSOUNDBUFFER buffer = (LPDIRECTSOUNDBUFFER) stream->handle[0].buffer;
5199 result = buffer->Stop();
5200 if ( FAILED(result) ) {
5201 sprintf(message, "RtAudio: Unable to stop DS buffer (%s): %s",
5202 devices[stream->device[0]].name, getErrorString(result));
5203 error(RtError::DRIVER_ERROR);
5206 dsBufferSize = stream->bufferSize * stream->nDeviceChannels[0];
5207 dsBufferSize *= formatBytes(stream->deviceFormat[0]) * stream->nBuffers;
5209 // Lock the buffer and clear it so that if we start to play again,
5210 // we won't have old data playing.
5211 result = buffer->Lock(0, dsBufferSize, &audioPtr, &dataLen, NULL, NULL, 0);
5212 if ( FAILED(result) ) {
5213 sprintf(message, "RtAudio: Unable to lock DS buffer (%s): %s.",
5214 devices[stream->device[0]].name, getErrorString(result));
5215 error(RtError::DRIVER_ERROR);
5218 // Zero the DS buffer
5219 ZeroMemory(audioPtr, dataLen);
5221 // Unlock the DS buffer
5222 result = buffer->Unlock(audioPtr, dataLen, NULL, 0);
5223 if ( FAILED(result) ) {
5224 sprintf(message, "RtAudio: Unable to unlock DS buffer (%s): %s.",
5225 devices[stream->device[0]].name, getErrorString(result));
5226 error(RtError::DRIVER_ERROR);
5229 // If we start playing again, we must begin at beginning of buffer.
5230 stream->handle[0].bufferPointer = 0;
5233 if (stream->mode == INPUT || stream->mode == DUPLEX) {
5234 LPDIRECTSOUNDCAPTUREBUFFER buffer = (LPDIRECTSOUNDCAPTUREBUFFER) stream->handle[1].buffer;
5238 result = buffer->Stop();
5239 if ( FAILED(result) ) {
5240 sprintf(message, "RtAudio: Unable to stop DS capture buffer (%s): %s",
5241 devices[stream->device[1]].name, getErrorString(result));
5242 error(RtError::DRIVER_ERROR);
5245 dsBufferSize = stream->bufferSize * stream->nDeviceChannels[1];
5246 dsBufferSize *= formatBytes(stream->deviceFormat[1]) * stream->nBuffers;
5248 // Lock the buffer and clear it so that if we start to play again,
5249 // we won't have old data playing.
5250 result = buffer->Lock(0, dsBufferSize, &audioPtr, &dataLen, NULL, NULL, 0);
5251 if ( FAILED(result) ) {
5252 sprintf(message, "RtAudio: Unable to lock DS capture buffer (%s): %s.",
5253 devices[stream->device[1]].name, getErrorString(result));
5254 error(RtError::DRIVER_ERROR);
5257 // Zero the DS buffer
5258 ZeroMemory(audioPtr, dataLen);
5260 // Unlock the DS buffer
5261 result = buffer->Unlock(audioPtr, dataLen, NULL, 0);
5262 if ( FAILED(result) ) {
5263 sprintf(message, "RtAudio: Unable to unlock DS capture buffer (%s): %s.",
5264 devices[stream->device[1]].name, getErrorString(result));
5265 error(RtError::DRIVER_ERROR);
5268 // If we start recording again, we must begin at beginning of buffer.
5269 stream->handle[1].bufferPointer = 0;
5271 stream->state = STREAM_STOPPED;
5274 MUTEX_UNLOCK(&stream->mutex);
5277 int RtAudio :: streamWillBlock(int streamId)
5279 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
5281 MUTEX_LOCK(&stream->mutex);
5285 if (stream->state == STREAM_STOPPED)
5289 DWORD currentPos, safePos;
5291 if (stream->mode == OUTPUT || stream->mode == DUPLEX) {
5293 LPDIRECTSOUNDBUFFER dsBuffer = (LPDIRECTSOUNDBUFFER) stream->handle[0].buffer;
5294 UINT nextWritePos = stream->handle[0].bufferPointer;
5295 channels = stream->nDeviceChannels[0];
5296 DWORD dsBufferSize = stream->bufferSize * channels;
5297 dsBufferSize *= formatBytes(stream->deviceFormat[0]) * stream->nBuffers;
5299 // Find out where the read and "safe write" pointers are.
5300 result = dsBuffer->GetCurrentPosition(¤tPos, &safePos);
5301 if ( FAILED(result) ) {
5302 sprintf(message, "RtAudio: Unable to get current DS position (%s): %s.",
5303 devices[stream->device[0]].name, getErrorString(result));
5304 error(RtError::DRIVER_ERROR);
5307 if ( currentPos < nextWritePos ) currentPos += dsBufferSize; // unwrap offset
5308 frames = currentPos - nextWritePos;
5309 frames /= channels * formatBytes(stream->deviceFormat[0]);
5312 if (stream->mode == INPUT || stream->mode == DUPLEX) {
5314 LPDIRECTSOUNDCAPTUREBUFFER dsBuffer = (LPDIRECTSOUNDCAPTUREBUFFER) stream->handle[1].buffer;
5315 UINT nextReadPos = stream->handle[1].bufferPointer;
5316 channels = stream->nDeviceChannels[1];
5317 DWORD dsBufferSize = stream->bufferSize * channels;
5318 dsBufferSize *= formatBytes(stream->deviceFormat[1]) * stream->nBuffers;
5320 // Find out where the write and "safe read" pointers are.
5321 result = dsBuffer->GetCurrentPosition(¤tPos, &safePos);
5322 if ( FAILED(result) ) {
5323 sprintf(message, "RtAudio: Unable to get current DS capture position (%s): %s.",
5324 devices[stream->device[1]].name, getErrorString(result));
5325 error(RtError::DRIVER_ERROR);
5328 if ( safePos < nextReadPos ) safePos += dsBufferSize; // unwrap offset
5330 if (stream->mode == DUPLEX ) {
5331 // Take largest value of the two.
5332 int temp = safePos - nextReadPos;
5333 temp /= channels * formatBytes(stream->deviceFormat[1]);
5334 frames = ( temp > frames ) ? temp : frames;
5337 frames = safePos - nextReadPos;
5338 frames /= channels * formatBytes(stream->deviceFormat[1]);
5342 frames = stream->bufferSize - frames;
5343 if (frames < 0) frames = 0;
5346 MUTEX_UNLOCK(&stream->mutex);
5350 void RtAudio :: tickStream(int streamId)
5352 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
5355 if (stream->state == STREAM_STOPPED) {
5356 if (stream->callbackInfo.usingCallback) Sleep(50); // sleep 50 milliseconds
5359 else if (stream->callbackInfo.usingCallback) {
5360 RTAUDIO_CALLBACK callback = (RTAUDIO_CALLBACK) stream->callbackInfo.callback;
5361 stopStream = callback(stream->userBuffer, stream->bufferSize, stream->callbackInfo.userData);
5364 MUTEX_LOCK(&stream->mutex);
5366 // The state might change while waiting on a mutex.
5367 if (stream->state == STREAM_STOPPED) {
5368 MUTEX_UNLOCK(&stream->mutex);
5373 DWORD currentPos, safePos;
5374 LPVOID buffer1 = NULL;
5375 LPVOID buffer2 = NULL;
5376 DWORD bufferSize1 = 0;
5377 DWORD bufferSize2 = 0;
5380 if (stream->mode == OUTPUT || stream->mode == DUPLEX) {
5382 // Setup parameters and do buffer conversion if necessary.
5383 if (stream->doConvertBuffer[0]) {
5384 convertStreamBuffer(stream, OUTPUT);
5385 buffer = stream->deviceBuffer;
5386 buffer_bytes = stream->bufferSize * stream->nDeviceChannels[0];
5387 buffer_bytes *= formatBytes(stream->deviceFormat[0]);
5390 buffer = stream->userBuffer;
5391 buffer_bytes = stream->bufferSize * stream->nUserChannels[0];
5392 buffer_bytes *= formatBytes(stream->userFormat);
5395 // No byte swapping necessary in DirectSound implementation.
5397 LPDIRECTSOUNDBUFFER dsBuffer = (LPDIRECTSOUNDBUFFER) stream->handle[0].buffer;
5398 UINT nextWritePos = stream->handle[0].bufferPointer;
5399 DWORD dsBufferSize = buffer_bytes * stream->nBuffers;
5401 // Find out where the read and "safe write" pointers are.
5402 result = dsBuffer->GetCurrentPosition(¤tPos, &safePos);
5403 if ( FAILED(result) ) {
5404 sprintf(message, "RtAudio: Unable to get current DS position (%s): %s.",
5405 devices[stream->device[0]].name, getErrorString(result));
5406 error(RtError::DRIVER_ERROR);
5409 if ( currentPos < nextWritePos ) currentPos += dsBufferSize; // unwrap offset
5410 DWORD endWrite = nextWritePos + buffer_bytes;
5412 // Check whether the entire write region is behind the play pointer.
5413 while ( currentPos < endWrite ) {
5414 // If we are here, then we must wait until the play pointer gets
5415 // beyond the write region. The approach here is to use the
5416 // Sleep() function to suspend operation until safePos catches
5417 // up. Calculate number of milliseconds to wait as:
5418 // time = distance * (milliseconds/second) * fudgefactor /
5419 // ((bytes/sample) * (samples/second))
5420 // A "fudgefactor" less than 1 is used because it was found
5421 // that sleeping too long was MUCH worse than sleeping for
5422 // several shorter periods.
5423 float millis = (endWrite - currentPos) * 900.0;
5424 millis /= ( formatBytes(stream->deviceFormat[0]) * stream->sampleRate);
5425 if ( millis < 1.0 ) millis = 1.0;
5426 Sleep( (DWORD) millis );
5428 // Wake up, find out where we are now
5429 result = dsBuffer->GetCurrentPosition( ¤tPos, &safePos );
5430 if ( FAILED(result) ) {
5431 sprintf(message, "RtAudio: Unable to get current DS position (%s): %s.",
5432 devices[stream->device[0]].name, getErrorString(result));
5433 error(RtError::DRIVER_ERROR);
5435 if ( currentPos < nextWritePos ) currentPos += dsBufferSize; // unwrap offset
5438 // Lock free space in the buffer
5439 result = dsBuffer->Lock (nextWritePos, buffer_bytes, &buffer1,
5440 &bufferSize1, &buffer2, &bufferSize2, 0);
5441 if ( FAILED(result) ) {
5442 sprintf(message, "RtAudio: Unable to lock DS buffer during playback (%s): %s.",
5443 devices[stream->device[0]].name, getErrorString(result));
5444 error(RtError::DRIVER_ERROR);
5447 // Copy our buffer into the DS buffer
5448 CopyMemory(buffer1, buffer, bufferSize1);
5449 if (buffer2 != NULL) CopyMemory(buffer2, buffer+bufferSize1, bufferSize2);
5451 // Update our buffer offset and unlock sound buffer
5452 dsBuffer->Unlock (buffer1, bufferSize1, buffer2, bufferSize2);
5453 if ( FAILED(result) ) {
5454 sprintf(message, "RtAudio: Unable to unlock DS buffer during playback (%s): %s.",
5455 devices[stream->device[0]].name, getErrorString(result));
5456 error(RtError::DRIVER_ERROR);
5458 nextWritePos = (nextWritePos + bufferSize1 + bufferSize2) % dsBufferSize;
5459 stream->handle[0].bufferPointer = nextWritePos;
5462 if (stream->mode == INPUT || stream->mode == DUPLEX) {
5464 // Setup parameters.
5465 if (stream->doConvertBuffer[1]) {
5466 buffer = stream->deviceBuffer;
5467 buffer_bytes = stream->bufferSize * stream->nDeviceChannels[1];
5468 buffer_bytes *= formatBytes(stream->deviceFormat[1]);
5471 buffer = stream->userBuffer;
5472 buffer_bytes = stream->bufferSize * stream->nUserChannels[1];
5473 buffer_bytes *= formatBytes(stream->userFormat);
5476 LPDIRECTSOUNDCAPTUREBUFFER dsBuffer = (LPDIRECTSOUNDCAPTUREBUFFER) stream->handle[1].buffer;
5477 UINT nextReadPos = stream->handle[1].bufferPointer;
5478 DWORD dsBufferSize = buffer_bytes * stream->nBuffers;
5480 // Find out where the write and "safe read" pointers are.
5481 result = dsBuffer->GetCurrentPosition(¤tPos, &safePos);
5482 if ( FAILED(result) ) {
5483 sprintf(message, "RtAudio: Unable to get current DS capture position (%s): %s.",
5484 devices[stream->device[1]].name, getErrorString(result));
5485 error(RtError::DRIVER_ERROR);
5488 if ( safePos < nextReadPos ) safePos += dsBufferSize; // unwrap offset
5489 DWORD endRead = nextReadPos + buffer_bytes;
5491 // Check whether the entire write region is behind the play pointer.
5492 while ( safePos < endRead ) {
5493 // See comments for playback.
5494 float millis = (endRead - safePos) * 900.0;
5495 millis /= ( formatBytes(stream->deviceFormat[1]) * stream->sampleRate);
5496 if ( millis < 1.0 ) millis = 1.0;
5497 Sleep( (DWORD) millis );
5499 // Wake up, find out where we are now
5500 result = dsBuffer->GetCurrentPosition( ¤tPos, &safePos );
5501 if ( FAILED(result) ) {
5502 sprintf(message, "RtAudio: Unable to get current DS capture position (%s): %s.",
5503 devices[stream->device[1]].name, getErrorString(result));
5504 error(RtError::DRIVER_ERROR);
5507 if ( safePos < nextReadPos ) safePos += dsBufferSize; // unwrap offset
5510 // Lock free space in the buffer
5511 result = dsBuffer->Lock (nextReadPos, buffer_bytes, &buffer1,
5512 &bufferSize1, &buffer2, &bufferSize2, 0);
5513 if ( FAILED(result) ) {
5514 sprintf(message, "RtAudio: Unable to lock DS buffer during capture (%s): %s.",
5515 devices[stream->device[1]].name, getErrorString(result));
5516 error(RtError::DRIVER_ERROR);
5519 // Copy our buffer into the DS buffer
5520 CopyMemory(buffer, buffer1, bufferSize1);
5521 if (buffer2 != NULL) CopyMemory(buffer+bufferSize1, buffer2, bufferSize2);
5523 // Update our buffer offset and unlock sound buffer
5524 nextReadPos = (nextReadPos + bufferSize1 + bufferSize2) % dsBufferSize;
5525 dsBuffer->Unlock (buffer1, bufferSize1, buffer2, bufferSize2);
5526 if ( FAILED(result) ) {
5527 sprintf(message, "RtAudio: Unable to unlock DS buffer during capture (%s): %s.",
5528 devices[stream->device[1]].name, getErrorString(result));
5529 error(RtError::DRIVER_ERROR);
5531 stream->handle[1].bufferPointer = nextReadPos;
5533 // No byte swapping necessary in DirectSound implementation.
5535 // Do buffer conversion if necessary.
5536 if (stream->doConvertBuffer[1])
5537 convertStreamBuffer(stream, INPUT);
5540 MUTEX_UNLOCK(&stream->mutex);
5542 if (stream->callbackInfo.usingCallback && stopStream)
5543 this->stopStream(streamId);
5546 // Definitions for utility functions and callbacks
5547 // specific to the DirectSound implementation.
5549 extern "C" unsigned __stdcall callbackHandler(void *ptr)
5551 CALLBACK_INFO *info = (CALLBACK_INFO *) ptr;
5552 RtAudio *object = (RtAudio *) info->object;
5553 int stream = info->streamId;
5554 bool *usingCallback = &info->usingCallback;
5556 while ( *usingCallback ) {
5558 object->tickStream(stream);
5560 catch (RtError &exception) {
5561 fprintf(stderr, "\nRtAudio: Callback thread error (%s) ... closing thread.\n\n",
5562 exception.getMessage());
5571 void RtAudio :: setStreamCallback(int streamId, RTAUDIO_CALLBACK callback, void *userData)
5573 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
5575 CALLBACK_INFO *info = (CALLBACK_INFO *) &stream->callbackInfo;
5576 if ( info->usingCallback ) {
5577 sprintf(message, "RtAudio: A callback is already set for this stream!");
5578 error(RtError::WARNING);
5582 info->callback = (void *) callback;
5583 info->userData = userData;
5584 info->usingCallback = true;
5585 info->object = (void *) this;
5586 info->streamId = streamId;
5589 info->thread = _beginthreadex(NULL, 0, &callbackHandler,
5590 &stream->callbackInfo, 0, &thread_id);
5591 if (info->thread == 0) {
5592 info->usingCallback = false;
5593 sprintf(message, "RtAudio: error starting callback thread!");
5594 error(RtError::THREAD_ERROR);
5597 // When spawning multiple threads in quick succession, it appears to be
5598 // necessary to wait a bit for each to initialize ... another windoism!
5602 static bool CALLBACK deviceCountCallback(LPGUID lpguid,
5603 LPCSTR lpcstrDescription,
5604 LPCSTR lpcstrModule,
5607 int *pointer = ((int *) lpContext);
5613 static bool CALLBACK deviceInfoCallback(LPGUID lpguid,
5614 LPCSTR lpcstrDescription,
5615 LPCSTR lpcstrModule,
5618 enum_info *info = ((enum_info *) lpContext);
5619 while (strlen(info->name) > 0) info++;
5621 strncpy(info->name, lpcstrDescription, 64);
5625 info->isValid = false;
5626 if (info->isInput == true) {
5628 LPDIRECTSOUNDCAPTURE object;
5630 hr = DirectSoundCaptureCreate( lpguid, &object, NULL );
5631 if( hr != DS_OK ) return true;
5633 caps.dwSize = sizeof(caps);
5634 hr = object->GetCaps( &caps );
5636 if (caps.dwChannels > 0 && caps.dwFormats > 0)
5637 info->isValid = true;
5643 LPDIRECTSOUND object;
5644 hr = DirectSoundCreate( lpguid, &object, NULL );
5645 if( hr != DS_OK ) return true;
5647 caps.dwSize = sizeof(caps);
5648 hr = object->GetCaps( &caps );
5650 if ( caps.dwFlags & DSCAPS_PRIMARYMONO || caps.dwFlags & DSCAPS_PRIMARYSTEREO )
5651 info->isValid = true;
5659 static bool CALLBACK defaultDeviceCallback(LPGUID lpguid,
5660 LPCSTR lpcstrDescription,
5661 LPCSTR lpcstrModule,
5664 enum_info *info = ((enum_info *) lpContext);
5666 if ( lpguid == NULL ) {
5667 strncpy(info->name, lpcstrDescription, 64);
5674 static bool CALLBACK deviceIdCallback(LPGUID lpguid,
5675 LPCSTR lpcstrDescription,
5676 LPCSTR lpcstrModule,
5679 enum_info *info = ((enum_info *) lpContext);
5681 if ( strncmp( info->name, lpcstrDescription, 64 ) == 0 ) {
5683 info->isValid = true;
5690 static char* getErrorString(int code)
5694 case DSERR_ALLOCATED:
5695 return "Direct Sound already allocated";
5697 case DSERR_CONTROLUNAVAIL:
5698 return "Direct Sound control unavailable";
5700 case DSERR_INVALIDPARAM:
5701 return "Direct Sound invalid parameter";
5703 case DSERR_INVALIDCALL:
5704 return "Direct Sound invalid call";
5707 return "Direct Sound generic error";
5709 case DSERR_PRIOLEVELNEEDED:
5710 return "Direct Sound Priority level needed";
5712 case DSERR_OUTOFMEMORY:
5713 return "Direct Sound out of memory";
5715 case DSERR_BADFORMAT:
5716 return "Direct Sound bad format";
5718 case DSERR_UNSUPPORTED:
5719 return "Direct Sound unsupported error";
5721 case DSERR_NODRIVER:
5722 return "Direct Sound no driver error";
5724 case DSERR_ALREADYINITIALIZED:
5725 return "Direct Sound already initialized";
5727 case DSERR_NOAGGREGATION:
5728 return "Direct Sound no aggregation";
5730 case DSERR_BUFFERLOST:
5731 return "Direct Sound buffer lost";
5733 case DSERR_OTHERAPPHASPRIO:
5734 return "Direct Sound other app has priority";
5736 case DSERR_UNINITIALIZED:
5737 return "Direct Sound uninitialized";
5740 return "Direct Sound unknown error";
5744 //******************** End of __WINDOWS_DS__ *********************//
5746 #elif defined(__IRIX_AL__) // SGI's AL API for IRIX
5751 void RtAudio :: initialize(void)
5753 // Count cards and devices
5756 // Determine the total number of input and output devices.
5757 nDevices = alQueryValues(AL_SYSTEM, AL_DEVICES, 0, 0, 0, 0);
5759 sprintf(message, "RtAudio: AL error counting devices: %s.",
5760 alGetErrorString(oserror()));
5761 error(RtError::DRIVER_ERROR);
5764 if (nDevices <= 0) return;
5766 ALvalue *vls = (ALvalue *) new ALvalue[nDevices];
5768 // Allocate the RTAUDIO_DEVICE structures.
5769 devices = (RTAUDIO_DEVICE *) calloc(nDevices, sizeof(RTAUDIO_DEVICE));
5770 if (devices == NULL) {
5771 sprintf(message, "RtAudio: memory allocation error!");
5772 error(RtError::MEMORY_ERROR);
5775 // Write device ascii identifiers and resource ids to device info
5780 pvs[0].param = AL_NAME;
5781 pvs[0].value.ptr = name;
5784 outs = alQueryValues(AL_SYSTEM, AL_DEFAULT_OUTPUT, vls, nDevices, 0, 0);
5786 sprintf(message, "RtAudio: AL error getting output devices: %s.",
5787 alGetErrorString(oserror()));
5788 error(RtError::DRIVER_ERROR);
5791 for (i=0; i<outs; i++) {
5792 if (alGetParams(vls[i].i, pvs, 1) < 0) {
5793 sprintf(message, "RtAudio: AL error querying output devices: %s.",
5794 alGetErrorString(oserror()));
5795 error(RtError::DRIVER_ERROR);
5797 strncpy(devices[i].name, name, 32);
5798 devices[i].id[0] = vls[i].i;
5801 ins = alQueryValues(AL_SYSTEM, AL_DEFAULT_INPUT, &vls[outs], nDevices-outs, 0, 0);
5803 sprintf(message, "RtAudio: AL error getting input devices: %s.",
5804 alGetErrorString(oserror()));
5805 error(RtError::DRIVER_ERROR);
5808 for (i=outs; i<ins+outs; i++) {
5809 if (alGetParams(vls[i].i, pvs, 1) < 0) {
5810 sprintf(message, "RtAudio: AL error querying input devices: %s.",
5811 alGetErrorString(oserror()));
5812 error(RtError::DRIVER_ERROR);
5814 strncpy(devices[i].name, name, 32);
5815 devices[i].id[1] = vls[i].i;
5823 int RtAudio :: getDefaultInputDevice(void)
5826 int result = alQueryValues(AL_SYSTEM, AL_DEFAULT_INPUT, &value, 1, 0, 0);
5828 sprintf(message, "RtAudio: AL error getting default input device id: %s.",
5829 alGetErrorString(oserror()));
5830 error(RtError::WARNING);
5833 for ( int i=0; i<nDevices; i++ )
5834 if ( devices[i].id[1] == value.i ) return i;
5840 int RtAudio :: getDefaultOutputDevice(void)
5843 int result = alQueryValues(AL_SYSTEM, AL_DEFAULT_OUTPUT, &value, 1, 0, 0);
5845 sprintf(message, "RtAudio: AL error getting default output device id: %s.",
5846 alGetErrorString(oserror()));
5847 error(RtError::WARNING);
5850 for ( int i=0; i<nDevices; i++ )
5851 if ( devices[i].id[0] == value.i ) return i;
5857 void RtAudio :: probeDeviceInfo(RTAUDIO_DEVICE *info)
5859 int resource, result, i;
5863 // Get output resource ID if it exists.
5864 resource = info->id[0];
5867 // Probe output device parameters.
5868 result = alQueryValues(resource, AL_CHANNELS, &value, 1, 0, 0);
5870 sprintf(message, "RtAudio: AL error getting device (%s) channels: %s.",
5871 info->name, alGetErrorString(oserror()));
5872 error(RtError::WARNING);
5875 info->maxOutputChannels = value.i;
5876 info->minOutputChannels = 1;
5879 result = alGetParamInfo(resource, AL_RATE, &pinfo);
5881 sprintf(message, "RtAudio: AL error getting device (%s) rates: %s.",
5882 info->name, alGetErrorString(oserror()));
5883 error(RtError::WARNING);
5886 info->nSampleRates = 0;
5887 for (i=0; i<MAX_SAMPLE_RATES; i++) {
5888 if ( SAMPLE_RATES[i] >= pinfo.min.i && SAMPLE_RATES[i] <= pinfo.max.i ) {
5889 info->sampleRates[info->nSampleRates] = SAMPLE_RATES[i];
5890 info->nSampleRates++;
5895 // The AL library supports all our formats, except 24-bit and 32-bit ints.
5896 info->nativeFormats = (RTAUDIO_FORMAT) 51;
5899 // Now get input resource ID if it exists.
5900 resource = info->id[1];
5903 // Probe input device parameters.
5904 result = alQueryValues(resource, AL_CHANNELS, &value, 1, 0, 0);
5906 sprintf(message, "RtAudio: AL error getting device (%s) channels: %s.",
5907 info->name, alGetErrorString(oserror()));
5908 error(RtError::WARNING);
5911 info->maxInputChannels = value.i;
5912 info->minInputChannels = 1;
5915 result = alGetParamInfo(resource, AL_RATE, &pinfo);
5917 sprintf(message, "RtAudio: AL error getting device (%s) rates: %s.",
5918 info->name, alGetErrorString(oserror()));
5919 error(RtError::WARNING);
5922 // In the case of the default device, these values will
5923 // overwrite the rates determined for the output device. Since
5924 // the input device is most likely to be more limited than the
5925 // output device, this is ok.
5926 info->nSampleRates = 0;
5927 for (i=0; i<MAX_SAMPLE_RATES; i++) {
5928 if ( SAMPLE_RATES[i] >= pinfo.min.i && SAMPLE_RATES[i] <= pinfo.max.i ) {
5929 info->sampleRates[info->nSampleRates] = SAMPLE_RATES[i];
5930 info->nSampleRates++;
5935 // The AL library supports all our formats, except 24-bit and 32-bit ints.
5936 info->nativeFormats = (RTAUDIO_FORMAT) 51;
5939 if ( info->maxInputChannels == 0 && info->maxOutputChannels == 0 )
5941 if ( info->nSampleRates == 0 )
5944 // Determine duplex status.
5945 if (info->maxInputChannels < info->maxOutputChannels)
5946 info->maxDuplexChannels = info->maxInputChannels;
5948 info->maxDuplexChannels = info->maxOutputChannels;
5949 if (info->minInputChannels < info->minOutputChannels)
5950 info->minDuplexChannels = info->minInputChannels;
5952 info->minDuplexChannels = info->minOutputChannels;
5954 if ( info->maxDuplexChannels > 0 ) info->hasDuplexSupport = true;
5955 else info->hasDuplexSupport = false;
5957 info->probed = true;
5962 bool RtAudio :: probeDeviceOpen(int device, RTAUDIO_STREAM *stream,
5963 STREAM_MODE mode, int channels,
5964 int sampleRate, RTAUDIO_FORMAT format,
5965 int *bufferSize, int numberOfBuffers)
5967 int result, resource, nBuffers;
5972 // Get a new ALconfig structure.
5973 al_config = alNewConfig();
5975 sprintf(message,"RtAudio: can't get AL config: %s.",
5976 alGetErrorString(oserror()));
5977 error(RtError::WARNING);
5981 // Set the channels.
5982 result = alSetChannels(al_config, channels);
5984 sprintf(message,"RtAudio: can't set %d channels in AL config: %s.",
5985 channels, alGetErrorString(oserror()));
5986 error(RtError::WARNING);
5990 // Attempt to set the queue size. The al API doesn't provide a
5991 // means for querying the minimum/maximum buffer size of a device,
5992 // so if the specified size doesn't work, take whatever the
5993 // al_config structure returns.
5994 if ( numberOfBuffers < 1 )
5997 nBuffers = numberOfBuffers;
5998 long buffer_size = *bufferSize * nBuffers;
5999 result = alSetQueueSize(al_config, buffer_size); // in sample frames
6001 // Get the buffer size specified by the al_config and try that.
6002 buffer_size = alGetQueueSize(al_config);
6003 result = alSetQueueSize(al_config, buffer_size);
6005 sprintf(message,"RtAudio: can't set buffer size (%ld) in AL config: %s.",
6006 buffer_size, alGetErrorString(oserror()));
6007 error(RtError::WARNING);
6010 *bufferSize = buffer_size / nBuffers;
6013 // Set the data format.
6014 stream->userFormat = format;
6015 stream->deviceFormat[mode] = format;
6016 if (format == RTAUDIO_SINT8) {
6017 result = alSetSampFmt(al_config, AL_SAMPFMT_TWOSCOMP);
6018 result = alSetWidth(al_config, AL_SAMPLE_8);
6020 else if (format == RTAUDIO_SINT16) {
6021 result = alSetSampFmt(al_config, AL_SAMPFMT_TWOSCOMP);
6022 result = alSetWidth(al_config, AL_SAMPLE_16);
6024 else if (format == RTAUDIO_SINT24) {
6025 // Our 24-bit format assumes the upper 3 bytes of a 4 byte word.
6026 // The AL library uses the lower 3 bytes, so we'll need to do our
6028 result = alSetSampFmt(al_config, AL_SAMPFMT_FLOAT);
6029 stream->deviceFormat[mode] = RTAUDIO_FLOAT32;
6031 else if (format == RTAUDIO_SINT32) {
6032 // The AL library doesn't seem to support the 32-bit integer
6033 // format, so we'll need to do our own conversion.
6034 result = alSetSampFmt(al_config, AL_SAMPFMT_FLOAT);
6035 stream->deviceFormat[mode] = RTAUDIO_FLOAT32;
6037 else if (format == RTAUDIO_FLOAT32)
6038 result = alSetSampFmt(al_config, AL_SAMPFMT_FLOAT);
6039 else if (format == RTAUDIO_FLOAT64)
6040 result = alSetSampFmt(al_config, AL_SAMPFMT_DOUBLE);
6042 if ( result == -1 ) {
6043 sprintf(message,"RtAudio: AL error setting sample format in AL config: %s.",
6044 alGetErrorString(oserror()));
6045 error(RtError::WARNING);
6049 if (mode == OUTPUT) {
6053 resource = AL_DEFAULT_OUTPUT;
6055 resource = devices[device].id[0];
6056 result = alSetDevice(al_config, resource);
6057 if ( result == -1 ) {
6058 sprintf(message,"RtAudio: AL error setting device (%s) in AL config: %s.",
6059 devices[device].name, alGetErrorString(oserror()));
6060 error(RtError::WARNING);
6065 port = alOpenPort("RtAudio Output Port", "w", al_config);
6067 sprintf(message,"RtAudio: AL error opening output port: %s.",
6068 alGetErrorString(oserror()));
6069 error(RtError::WARNING);
6073 // Set the sample rate
6074 pvs[0].param = AL_MASTER_CLOCK;
6075 pvs[0].value.i = AL_CRYSTAL_MCLK_TYPE;
6076 pvs[1].param = AL_RATE;
6077 pvs[1].value.ll = alDoubleToFixed((double)sampleRate);
6078 result = alSetParams(resource, pvs, 2);
6081 sprintf(message,"RtAudio: AL error setting sample rate (%d) for device (%s): %s.",
6082 sampleRate, devices[device].name, alGetErrorString(oserror()));
6083 error(RtError::WARNING);
6087 else { // mode == INPUT
6091 resource = AL_DEFAULT_INPUT;
6093 resource = devices[device].id[1];
6094 result = alSetDevice(al_config, resource);
6095 if ( result == -1 ) {
6096 sprintf(message,"RtAudio: AL error setting device (%s) in AL config: %s.",
6097 devices[device].name, alGetErrorString(oserror()));
6098 error(RtError::WARNING);
6103 port = alOpenPort("RtAudio Output Port", "r", al_config);
6105 sprintf(message,"RtAudio: AL error opening input port: %s.",
6106 alGetErrorString(oserror()));
6107 error(RtError::WARNING);
6111 // Set the sample rate
6112 pvs[0].param = AL_MASTER_CLOCK;
6113 pvs[0].value.i = AL_CRYSTAL_MCLK_TYPE;
6114 pvs[1].param = AL_RATE;
6115 pvs[1].value.ll = alDoubleToFixed((double)sampleRate);
6116 result = alSetParams(resource, pvs, 2);
6119 sprintf(message,"RtAudio: AL error setting sample rate (%d) for device (%s): %s.",
6120 sampleRate, devices[device].name, alGetErrorString(oserror()));
6121 error(RtError::WARNING);
6126 alFreeConfig(al_config);
6128 stream->nUserChannels[mode] = channels;
6129 stream->nDeviceChannels[mode] = channels;
6131 // Set handle and flags for buffer conversion
6132 stream->handle[mode] = port;
6133 stream->doConvertBuffer[mode] = false;
6134 if (stream->userFormat != stream->deviceFormat[mode])
6135 stream->doConvertBuffer[mode] = true;
6137 // Allocate necessary internal buffers
6138 if ( stream->nUserChannels[0] != stream->nUserChannels[1] ) {
6141 if (stream->nUserChannels[0] >= stream->nUserChannels[1])
6142 buffer_bytes = stream->nUserChannels[0];
6144 buffer_bytes = stream->nUserChannels[1];
6146 buffer_bytes *= *bufferSize * formatBytes(stream->userFormat);
6147 if (stream->userBuffer) free(stream->userBuffer);
6148 stream->userBuffer = (char *) calloc(buffer_bytes, 1);
6149 if (stream->userBuffer == NULL)
6153 if ( stream->doConvertBuffer[mode] ) {
6156 bool makeBuffer = true;
6157 if ( mode == OUTPUT )
6158 buffer_bytes = stream->nDeviceChannels[0] * formatBytes(stream->deviceFormat[0]);
6159 else { // mode == INPUT
6160 buffer_bytes = stream->nDeviceChannels[1] * formatBytes(stream->deviceFormat[1]);
6161 if ( stream->mode == OUTPUT && stream->deviceBuffer ) {
6162 long bytes_out = stream->nDeviceChannels[0] * formatBytes(stream->deviceFormat[0]);
6163 if ( buffer_bytes < bytes_out ) makeBuffer = false;
6168 buffer_bytes *= *bufferSize;
6169 if (stream->deviceBuffer) free(stream->deviceBuffer);
6170 stream->deviceBuffer = (char *) calloc(buffer_bytes, 1);
6171 if (stream->deviceBuffer == NULL)
6176 stream->device[mode] = device;
6177 stream->state = STREAM_STOPPED;
6178 if ( stream->mode == OUTPUT && mode == INPUT )
6179 // We had already set up an output stream.
6180 stream->mode = DUPLEX;
6182 stream->mode = mode;
6183 stream->nBuffers = nBuffers;
6184 stream->bufferSize = *bufferSize;
6185 stream->sampleRate = sampleRate;
6190 if (stream->handle[0]) {
6191 alClosePort(stream->handle[0]);
6192 stream->handle[0] = 0;
6194 if (stream->handle[1]) {
6195 alClosePort(stream->handle[1]);
6196 stream->handle[1] = 0;
6198 if (stream->userBuffer) {
6199 free(stream->userBuffer);
6200 stream->userBuffer = 0;
6202 sprintf(message, "RtAudio: ALSA error allocating buffer memory for device (%s).",
6203 devices[device].name);
6204 error(RtError::WARNING);
6208 void RtAudio :: closeStream(int streamId)
6210 // We don't want an exception to be thrown here because this
6211 // function is called by our class destructor. So, do our own
6213 if ( streams.find( streamId ) == streams.end() ) {
6214 sprintf(message, "RtAudio: invalid stream identifier!");
6215 error(RtError::WARNING);
6219 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) streams[streamId];
6221 if (stream->callbackInfo.usingCallback) {
6222 pthread_cancel(stream->callbackInfo.thread);
6223 pthread_join(stream->callbackInfo.thread, NULL);
6226 pthread_mutex_destroy(&stream->mutex);
6228 if (stream->handle[0])
6229 alClosePort(stream->handle[0]);
6231 if (stream->handle[1])
6232 alClosePort(stream->handle[1]);
6234 if (stream->userBuffer)
6235 free(stream->userBuffer);
6237 if (stream->deviceBuffer)
6238 free(stream->deviceBuffer);
6241 streams.erase(streamId);
6244 void RtAudio :: startStream(int streamId)
6246 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
6248 if (stream->state == STREAM_RUNNING)
6251 // The AL port is ready as soon as it is opened.
6252 stream->state = STREAM_RUNNING;
6255 void RtAudio :: stopStream(int streamId)
6257 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
6259 MUTEX_LOCK(&stream->mutex);
6261 if (stream->state == STREAM_STOPPED)
6265 int buffer_size = stream->bufferSize * stream->nBuffers;
6267 if (stream->mode == OUTPUT || stream->mode == DUPLEX)
6268 alZeroFrames(stream->handle[0], buffer_size);
6270 if (stream->mode == INPUT || stream->mode == DUPLEX) {
6271 result = alDiscardFrames(stream->handle[1], buffer_size);
6273 sprintf(message, "RtAudio: AL error draining stream device (%s): %s.",
6274 devices[stream->device[1]].name, alGetErrorString(oserror()));
6275 error(RtError::DRIVER_ERROR);
6278 stream->state = STREAM_STOPPED;
6281 MUTEX_UNLOCK(&stream->mutex);
6284 void RtAudio :: abortStream(int streamId)
6286 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
6288 MUTEX_LOCK(&stream->mutex);
6290 if (stream->state == STREAM_STOPPED)
6293 if (stream->mode == OUTPUT || stream->mode == DUPLEX) {
6295 int buffer_size = stream->bufferSize * stream->nBuffers;
6296 int result = alDiscardFrames(stream->handle[0], buffer_size);
6298 sprintf(message, "RtAudio: AL error aborting stream device (%s): %s.",
6299 devices[stream->device[0]].name, alGetErrorString(oserror()));
6300 error(RtError::DRIVER_ERROR);
6304 // There is no clear action to take on the input stream, since the
6305 // port will continue to run in any event.
6306 stream->state = STREAM_STOPPED;
6309 MUTEX_UNLOCK(&stream->mutex);
6312 int RtAudio :: streamWillBlock(int streamId)
6314 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
6316 MUTEX_LOCK(&stream->mutex);
6319 if (stream->state == STREAM_STOPPED)
6323 if (stream->mode == OUTPUT || stream->mode == DUPLEX) {
6324 err = alGetFillable(stream->handle[0]);
6326 sprintf(message, "RtAudio: AL error getting available frames for stream (%s): %s.",
6327 devices[stream->device[0]].name, alGetErrorString(oserror()));
6328 error(RtError::DRIVER_ERROR);
6334 if (stream->mode == INPUT || stream->mode == DUPLEX) {
6335 err = alGetFilled(stream->handle[1]);
6337 sprintf(message, "RtAudio: AL error getting available frames for stream (%s): %s.",
6338 devices[stream->device[1]].name, alGetErrorString(oserror()));
6339 error(RtError::DRIVER_ERROR);
6341 if (frames > err) frames = err;
6344 frames = stream->bufferSize - frames;
6345 if (frames < 0) frames = 0;
6348 MUTEX_UNLOCK(&stream->mutex);
6352 void RtAudio :: tickStream(int streamId)
6354 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
6357 if (stream->state == STREAM_STOPPED) {
6358 if (stream->callbackInfo.usingCallback) usleep(50000); // sleep 50 milliseconds
6361 else if (stream->callbackInfo.usingCallback) {
6362 RTAUDIO_CALLBACK callback = (RTAUDIO_CALLBACK) stream->callbackInfo.callback;
6363 stopStream = callback(stream->userBuffer, stream->bufferSize, stream->callbackInfo.userData);
6366 MUTEX_LOCK(&stream->mutex);
6368 // The state might change while waiting on a mutex.
6369 if (stream->state == STREAM_STOPPED)
6374 RTAUDIO_FORMAT format;
6375 if (stream->mode == OUTPUT || stream->mode == DUPLEX) {
6377 // Setup parameters and do buffer conversion if necessary.
6378 if (stream->doConvertBuffer[0]) {
6379 convertStreamBuffer(stream, OUTPUT);
6380 buffer = stream->deviceBuffer;
6381 channels = stream->nDeviceChannels[0];
6382 format = stream->deviceFormat[0];
6385 buffer = stream->userBuffer;
6386 channels = stream->nUserChannels[0];
6387 format = stream->userFormat;
6390 // Do byte swapping if necessary.
6391 if (stream->doByteSwap[0])
6392 byteSwapBuffer(buffer, stream->bufferSize * channels, format);
6394 // Write interleaved samples to device.
6395 alWriteFrames(stream->handle[0], buffer, stream->bufferSize);
6398 if (stream->mode == INPUT || stream->mode == DUPLEX) {
6400 // Setup parameters.
6401 if (stream->doConvertBuffer[1]) {
6402 buffer = stream->deviceBuffer;
6403 channels = stream->nDeviceChannels[1];
6404 format = stream->deviceFormat[1];
6407 buffer = stream->userBuffer;
6408 channels = stream->nUserChannels[1];
6409 format = stream->userFormat;
6412 // Read interleaved samples from device.
6413 alReadFrames(stream->handle[1], buffer, stream->bufferSize);
6415 // Do byte swapping if necessary.
6416 if (stream->doByteSwap[1])
6417 byteSwapBuffer(buffer, stream->bufferSize * channels, format);
6419 // Do buffer conversion if necessary.
6420 if (stream->doConvertBuffer[1])
6421 convertStreamBuffer(stream, INPUT);
6425 MUTEX_UNLOCK(&stream->mutex);
6427 if (stream->callbackInfo.usingCallback && stopStream)
6428 this->stopStream(streamId);
6431 extern "C" void *callbackHandler(void *ptr)
6433 CALLBACK_INFO *info = (CALLBACK_INFO *) ptr;
6434 RtAudio *object = (RtAudio *) info->object;
6435 int stream = info->streamId;
6436 bool *usingCallback = &info->usingCallback;
6438 while ( *usingCallback ) {
6439 pthread_testcancel();
6441 object->tickStream(stream);
6443 catch (RtError &exception) {
6444 fprintf(stderr, "\nRtAudio: Callback thread error (%s) ... closing thread.\n\n",
6445 exception.getMessage());
6453 //******************** End of __IRIX_AL__ *********************//
6458 // *************************************************** //
6460 // Private common (OS-independent) RtAudio methods.
6462 // *************************************************** //
6464 // This method can be modified to control the behavior of error
6465 // message reporting and throwing.
6466 void RtAudio :: error(RtError::TYPE type)
6468 if (type == RtError::WARNING) {
6469 fprintf(stderr, "\n%s\n\n", message);
6471 else if (type == RtError::DEBUG_WARNING) {
6472 #if defined(__RTAUDIO_DEBUG__)
6473 fprintf(stderr, "\n%s\n\n", message);
6477 fprintf(stderr, "\n%s\n\n", message);
6478 throw RtError(message, type);
6482 void *RtAudio :: verifyStream(int streamId)
6484 // Verify the stream key.
6485 if ( streams.find( streamId ) == streams.end() ) {
6486 sprintf(message, "RtAudio: invalid stream identifier!");
6487 error(RtError::INVALID_STREAM);
6490 return streams[streamId];
6493 void RtAudio :: clearDeviceInfo(RTAUDIO_DEVICE *info)
6495 // Don't clear the name or DEVICE_ID fields here ... they are
6496 // typically set prior to a call of this function.
6497 info->probed = false;
6498 info->maxOutputChannels = 0;
6499 info->maxInputChannels = 0;
6500 info->maxDuplexChannels = 0;
6501 info->minOutputChannels = 0;
6502 info->minInputChannels = 0;
6503 info->minDuplexChannels = 0;
6504 info->hasDuplexSupport = false;
6505 info->nSampleRates = 0;
6506 for (int i=0; i<MAX_SAMPLE_RATES; i++)
6507 info->sampleRates[i] = 0;
6508 info->nativeFormats = 0;
6511 int RtAudio :: formatBytes(RTAUDIO_FORMAT format)
6513 if (format == RTAUDIO_SINT16)
6515 else if (format == RTAUDIO_SINT24 || format == RTAUDIO_SINT32 ||
6516 format == RTAUDIO_FLOAT32)
6518 else if (format == RTAUDIO_FLOAT64)
6520 else if (format == RTAUDIO_SINT8)
6523 sprintf(message,"RtAudio: undefined format in formatBytes().");
6524 error(RtError::WARNING);
6529 void RtAudio :: convertStreamBuffer(RTAUDIO_STREAM *stream, STREAM_MODE mode)
6531 // This method does format conversion, input/output channel compensation, and
6532 // data interleaving/deinterleaving. 24-bit integers are assumed to occupy
6533 // the upper three bytes of a 32-bit integer.
6535 int j, jump_in, jump_out, channels;
6536 RTAUDIO_FORMAT format_in, format_out;
6537 char *input, *output;
6539 if (mode == INPUT) { // convert device to user buffer
6540 input = stream->deviceBuffer;
6541 output = stream->userBuffer;
6542 jump_in = stream->nDeviceChannels[1];
6543 jump_out = stream->nUserChannels[1];
6544 format_in = stream->deviceFormat[1];
6545 format_out = stream->userFormat;
6547 else { // convert user to device buffer
6548 input = stream->userBuffer;
6549 output = stream->deviceBuffer;
6550 jump_in = stream->nUserChannels[0];
6551 jump_out = stream->nDeviceChannels[0];
6552 format_in = stream->userFormat;
6553 format_out = stream->deviceFormat[0];
6555 // clear our device buffer when in/out duplex device channels are different
6556 if ( stream->mode == DUPLEX &&
6557 stream->nDeviceChannels[0] != stream->nDeviceChannels[1] )
6558 memset(output, 0, stream->bufferSize * jump_out * formatBytes(format_out));
6561 channels = (jump_in < jump_out) ? jump_in : jump_out;
6563 // Set up the interleave/deinterleave offsets
6564 std::vector<int> offset_in(channels);
6565 std::vector<int> offset_out(channels);
6566 if (mode == INPUT && stream->deInterleave[1]) {
6567 for (int k=0; k<channels; k++) {
6568 offset_in[k] = k * stream->bufferSize;
6573 else if (mode == OUTPUT && stream->deInterleave[0]) {
6574 for (int k=0; k<channels; k++) {
6576 offset_out[k] = k * stream->bufferSize;
6581 for (int k=0; k<channels; k++) {
6587 if (format_out == RTAUDIO_FLOAT64) {
6589 FLOAT64 *out = (FLOAT64 *)output;
6591 if (format_in == RTAUDIO_SINT8) {
6592 signed char *in = (signed char *)input;
6593 scale = 1.0 / 128.0;
6594 for (int i=0; i<stream->bufferSize; i++) {
6595 for (j=0; j<channels; j++) {
6596 out[offset_out[j]] = (FLOAT64) in[offset_in[j]];
6597 out[offset_out[j]] *= scale;
6603 else if (format_in == RTAUDIO_SINT16) {
6604 INT16 *in = (INT16 *)input;
6605 scale = 1.0 / 32768.0;
6606 for (int i=0; i<stream->bufferSize; i++) {
6607 for (j=0; j<channels; j++) {
6608 out[offset_out[j]] = (FLOAT64) in[offset_in[j]];
6609 out[offset_out[j]] *= scale;
6615 else if (format_in == RTAUDIO_SINT24) {
6616 INT32 *in = (INT32 *)input;
6617 scale = 1.0 / 2147483648.0;
6618 for (int i=0; i<stream->bufferSize; i++) {
6619 for (j=0; j<channels; j++) {
6620 out[offset_out[j]] = (FLOAT64) (in[offset_in[j]] & 0xffffff00);
6621 out[offset_out[j]] *= scale;
6627 else if (format_in == RTAUDIO_SINT32) {
6628 INT32 *in = (INT32 *)input;
6629 scale = 1.0 / 2147483648.0;
6630 for (int i=0; i<stream->bufferSize; i++) {
6631 for (j=0; j<channels; j++) {
6632 out[offset_out[j]] = (FLOAT64) in[offset_in[j]];
6633 out[offset_out[j]] *= scale;
6639 else if (format_in == RTAUDIO_FLOAT32) {
6640 FLOAT32 *in = (FLOAT32 *)input;
6641 for (int i=0; i<stream->bufferSize; i++) {
6642 for (j=0; j<channels; j++) {
6643 out[offset_out[j]] = (FLOAT64) in[offset_in[j]];
6649 else if (format_in == RTAUDIO_FLOAT64) {
6650 // Channel compensation and/or (de)interleaving only.
6651 FLOAT64 *in = (FLOAT64 *)input;
6652 for (int i=0; i<stream->bufferSize; i++) {
6653 for (j=0; j<channels; j++) {
6654 out[offset_out[j]] = in[offset_in[j]];
6661 else if (format_out == RTAUDIO_FLOAT32) {
6663 FLOAT32 *out = (FLOAT32 *)output;
6665 if (format_in == RTAUDIO_SINT8) {
6666 signed char *in = (signed char *)input;
6667 scale = 1.0 / 128.0;
6668 for (int i=0; i<stream->bufferSize; i++) {
6669 for (j=0; j<channels; j++) {
6670 out[offset_out[j]] = (FLOAT32) in[offset_in[j]];
6671 out[offset_out[j]] *= scale;
6677 else if (format_in == RTAUDIO_SINT16) {
6678 INT16 *in = (INT16 *)input;
6679 scale = 1.0 / 32768.0;
6680 for (int i=0; i<stream->bufferSize; i++) {
6681 for (j=0; j<channels; j++) {
6682 out[offset_out[j]] = (FLOAT32) in[offset_in[j]];
6683 out[offset_out[j]] *= scale;
6689 else if (format_in == RTAUDIO_SINT24) {
6690 INT32 *in = (INT32 *)input;
6691 scale = 1.0 / 2147483648.0;
6692 for (int i=0; i<stream->bufferSize; i++) {
6693 for (j=0; j<channels; j++) {
6694 out[offset_out[j]] = (FLOAT32) (in[offset_in[j]] & 0xffffff00);
6695 out[offset_out[j]] *= scale;
6701 else if (format_in == RTAUDIO_SINT32) {
6702 INT32 *in = (INT32 *)input;
6703 scale = 1.0 / 2147483648.0;
6704 for (int i=0; i<stream->bufferSize; i++) {
6705 for (j=0; j<channels; j++) {
6706 out[offset_out[j]] = (FLOAT32) in[offset_in[j]];
6707 out[offset_out[j]] *= scale;
6713 else if (format_in == RTAUDIO_FLOAT32) {
6714 // Channel compensation and/or (de)interleaving only.
6715 FLOAT32 *in = (FLOAT32 *)input;
6716 for (int i=0; i<stream->bufferSize; i++) {
6717 for (j=0; j<channels; j++) {
6718 out[offset_out[j]] = in[offset_in[j]];
6724 else if (format_in == RTAUDIO_FLOAT64) {
6725 FLOAT64 *in = (FLOAT64 *)input;
6726 for (int i=0; i<stream->bufferSize; i++) {
6727 for (j=0; j<channels; j++) {
6728 out[offset_out[j]] = (FLOAT32) in[offset_in[j]];
6735 else if (format_out == RTAUDIO_SINT32) {
6736 INT32 *out = (INT32 *)output;
6737 if (format_in == RTAUDIO_SINT8) {
6738 signed char *in = (signed char *)input;
6739 for (int i=0; i<stream->bufferSize; i++) {
6740 for (j=0; j<channels; j++) {
6741 out[offset_out[j]] = (INT32) in[offset_in[j]];
6742 out[offset_out[j]] <<= 24;
6748 else if (format_in == RTAUDIO_SINT16) {
6749 INT16 *in = (INT16 *)input;
6750 for (int i=0; i<stream->bufferSize; i++) {
6751 for (j=0; j<channels; j++) {
6752 out[offset_out[j]] = (INT32) in[offset_in[j]];
6753 out[offset_out[j]] <<= 16;
6759 else if (format_in == RTAUDIO_SINT24) {
6760 INT32 *in = (INT32 *)input;
6761 for (int i=0; i<stream->bufferSize; i++) {
6762 for (j=0; j<channels; j++) {
6763 out[offset_out[j]] = (INT32) in[offset_in[j]];
6769 else if (format_in == RTAUDIO_SINT32) {
6770 // Channel compensation and/or (de)interleaving only.
6771 INT32 *in = (INT32 *)input;
6772 for (int i=0; i<stream->bufferSize; i++) {
6773 for (j=0; j<channels; j++) {
6774 out[offset_out[j]] = in[offset_in[j]];
6780 else if (format_in == RTAUDIO_FLOAT32) {
6781 FLOAT32 *in = (FLOAT32 *)input;
6782 for (int i=0; i<stream->bufferSize; i++) {
6783 for (j=0; j<channels; j++) {
6784 out[offset_out[j]] = (INT32) (in[offset_in[j]] * 2147483647.0);
6790 else if (format_in == RTAUDIO_FLOAT64) {
6791 FLOAT64 *in = (FLOAT64 *)input;
6792 for (int i=0; i<stream->bufferSize; i++) {
6793 for (j=0; j<channels; j++) {
6794 out[offset_out[j]] = (INT32) (in[offset_in[j]] * 2147483647.0);
6801 else if (format_out == RTAUDIO_SINT24) {
6802 INT32 *out = (INT32 *)output;
6803 if (format_in == RTAUDIO_SINT8) {
6804 signed char *in = (signed char *)input;
6805 for (int i=0; i<stream->bufferSize; i++) {
6806 for (j=0; j<channels; j++) {
6807 out[offset_out[j]] = (INT32) in[offset_in[j]];
6808 out[offset_out[j]] <<= 24;
6814 else if (format_in == RTAUDIO_SINT16) {
6815 INT16 *in = (INT16 *)input;
6816 for (int i=0; i<stream->bufferSize; i++) {
6817 for (j=0; j<channels; j++) {
6818 out[offset_out[j]] = (INT32) in[offset_in[j]];
6819 out[offset_out[j]] <<= 16;
6825 else if (format_in == RTAUDIO_SINT24) {
6826 // Channel compensation and/or (de)interleaving only.
6827 INT32 *in = (INT32 *)input;
6828 for (int i=0; i<stream->bufferSize; i++) {
6829 for (j=0; j<channels; j++) {
6830 out[offset_out[j]] = in[offset_in[j]];
6836 else if (format_in == RTAUDIO_SINT32) {
6837 INT32 *in = (INT32 *)input;
6838 for (int i=0; i<stream->bufferSize; i++) {
6839 for (j=0; j<channels; j++) {
6840 out[offset_out[j]] = (INT32) (in[offset_in[j]] & 0xffffff00);
6846 else if (format_in == RTAUDIO_FLOAT32) {
6847 FLOAT32 *in = (FLOAT32 *)input;
6848 for (int i=0; i<stream->bufferSize; i++) {
6849 for (j=0; j<channels; j++) {
6850 out[offset_out[j]] = (INT32) (in[offset_in[j]] * 2147483647.0);
6856 else if (format_in == RTAUDIO_FLOAT64) {
6857 FLOAT64 *in = (FLOAT64 *)input;
6858 for (int i=0; i<stream->bufferSize; i++) {
6859 for (j=0; j<channels; j++) {
6860 out[offset_out[j]] = (INT32) (in[offset_in[j]] * 2147483647.0);
6867 else if (format_out == RTAUDIO_SINT16) {
6868 INT16 *out = (INT16 *)output;
6869 if (format_in == RTAUDIO_SINT8) {
6870 signed char *in = (signed char *)input;
6871 for (int i=0; i<stream->bufferSize; i++) {
6872 for (j=0; j<channels; j++) {
6873 out[offset_out[j]] = (INT16) in[offset_in[j]];
6874 out[offset_out[j]] <<= 8;
6880 else if (format_in == RTAUDIO_SINT16) {
6881 // Channel compensation and/or (de)interleaving only.
6882 INT16 *in = (INT16 *)input;
6883 for (int i=0; i<stream->bufferSize; i++) {
6884 for (j=0; j<channels; j++) {
6885 out[offset_out[j]] = in[offset_in[j]];
6891 else if (format_in == RTAUDIO_SINT24) {
6892 INT32 *in = (INT32 *)input;
6893 for (int i=0; i<stream->bufferSize; i++) {
6894 for (j=0; j<channels; j++) {
6895 out[offset_out[j]] = (INT16) ((in[offset_in[j]] >> 16) & 0x0000ffff);
6901 else if (format_in == RTAUDIO_SINT32) {
6902 INT32 *in = (INT32 *)input;
6903 for (int i=0; i<stream->bufferSize; i++) {
6904 for (j=0; j<channels; j++) {
6905 out[offset_out[j]] = (INT16) ((in[offset_in[j]] >> 16) & 0x0000ffff);
6911 else if (format_in == RTAUDIO_FLOAT32) {
6912 FLOAT32 *in = (FLOAT32 *)input;
6913 for (int i=0; i<stream->bufferSize; i++) {
6914 for (j=0; j<channels; j++) {
6915 out[offset_out[j]] = (INT16) (in[offset_in[j]] * 32767.0);
6921 else if (format_in == RTAUDIO_FLOAT64) {
6922 FLOAT64 *in = (FLOAT64 *)input;
6923 for (int i=0; i<stream->bufferSize; i++) {
6924 for (j=0; j<channels; j++) {
6925 out[offset_out[j]] = (INT16) (in[offset_in[j]] * 32767.0);
6932 else if (format_out == RTAUDIO_SINT8) {
6933 signed char *out = (signed char *)output;
6934 if (format_in == RTAUDIO_SINT8) {
6935 // Channel compensation and/or (de)interleaving only.
6936 signed char *in = (signed char *)input;
6937 for (int i=0; i<stream->bufferSize; i++) {
6938 for (j=0; j<channels; j++) {
6939 out[offset_out[j]] = in[offset_in[j]];
6945 if (format_in == RTAUDIO_SINT16) {
6946 INT16 *in = (INT16 *)input;
6947 for (int i=0; i<stream->bufferSize; i++) {
6948 for (j=0; j<channels; j++) {
6949 out[offset_out[j]] = (signed char) ((in[offset_in[j]] >> 8) & 0x00ff);
6955 else if (format_in == RTAUDIO_SINT24) {
6956 INT32 *in = (INT32 *)input;
6957 for (int i=0; i<stream->bufferSize; i++) {
6958 for (j=0; j<channels; j++) {
6959 out[offset_out[j]] = (signed char) ((in[offset_in[j]] >> 24) & 0x000000ff);
6965 else if (format_in == RTAUDIO_SINT32) {
6966 INT32 *in = (INT32 *)input;
6967 for (int i=0; i<stream->bufferSize; i++) {
6968 for (j=0; j<channels; j++) {
6969 out[offset_out[j]] = (signed char) ((in[offset_in[j]] >> 24) & 0x000000ff);
6975 else if (format_in == RTAUDIO_FLOAT32) {
6976 FLOAT32 *in = (FLOAT32 *)input;
6977 for (int i=0; i<stream->bufferSize; i++) {
6978 for (j=0; j<channels; j++) {
6979 out[offset_out[j]] = (signed char) (in[offset_in[j]] * 127.0);
6985 else if (format_in == RTAUDIO_FLOAT64) {
6986 FLOAT64 *in = (FLOAT64 *)input;
6987 for (int i=0; i<stream->bufferSize; i++) {
6988 for (j=0; j<channels; j++) {
6989 out[offset_out[j]] = (signed char) (in[offset_in[j]] * 127.0);
6998 void RtAudio :: byteSwapBuffer(char *buffer, int samples, RTAUDIO_FORMAT format)
7004 if (format == RTAUDIO_SINT16) {
7005 for (int i=0; i<samples; i++) {
7006 // Swap 1st and 2nd bytes.
7011 // Increment 2 bytes.
7015 else if (format == RTAUDIO_SINT24 ||
7016 format == RTAUDIO_SINT32 ||
7017 format == RTAUDIO_FLOAT32) {
7018 for (int i=0; i<samples; i++) {
7019 // Swap 1st and 4th bytes.
7024 // Swap 2nd and 3rd bytes.
7030 // Increment 4 bytes.
7034 else if (format == RTAUDIO_FLOAT64) {
7035 for (int i=0; i<samples; i++) {
7036 // Swap 1st and 8th bytes
7041 // Swap 2nd and 7th bytes
7047 // Swap 3rd and 6th bytes
7053 // Swap 4th and 5th bytes
7059 // Increment 8 bytes.
7066 // *************************************************** //
7068 // RtError class definition.
7070 // *************************************************** //
7072 RtError :: RtError(const char *p, TYPE tipe)
7075 strncpy(error_message, p, 256);
7078 RtError :: ~RtError()
7082 void RtError :: printMessage()
7084 printf("\n%s\n\n", error_message);