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 /************************************************************************/
46 // Static variable definitions.
47 const unsigned int RtAudio :: SAMPLE_RATES[] = {
48 4000, 5512, 8000, 9600, 11025, 16000, 22050,
49 32000, 44100, 48000, 88200, 96000, 176400, 192000
51 const RtAudio::RTAUDIO_FORMAT RtAudio :: RTAUDIO_SINT8 = 1;
52 const RtAudio::RTAUDIO_FORMAT RtAudio :: RTAUDIO_SINT16 = 2;
53 const RtAudio::RTAUDIO_FORMAT RtAudio :: RTAUDIO_SINT24 = 4;
54 const RtAudio::RTAUDIO_FORMAT RtAudio :: RTAUDIO_SINT32 = 8;
55 const RtAudio::RTAUDIO_FORMAT RtAudio :: RTAUDIO_FLOAT32 = 16;
56 const RtAudio::RTAUDIO_FORMAT RtAudio :: RTAUDIO_FLOAT64 = 32;
58 #if defined(__WINDOWS_DS__) || defined(__WINDOWS_ASIO__)
59 #define MUTEX_INITIALIZE(A) InitializeCriticalSection(A)
60 #define MUTEX_LOCK(A) EnterCriticalSection(A)
61 #define MUTEX_UNLOCK(A) LeaveCriticalSection(A)
63 #define MUTEX_INITIALIZE(A) pthread_mutex_init(A, NULL)
64 #define MUTEX_LOCK(A) pthread_mutex_lock(A)
65 #define MUTEX_UNLOCK(A) pthread_mutex_unlock(A)
68 // *************************************************** //
70 // Public common (OS-independent) methods.
72 // *************************************************** //
79 sprintf(message, "RtAudio: no audio devices found!");
80 error(RtError::NO_DEVICES_FOUND);
84 RtAudio :: RtAudio(int *streamId,
85 int outputDevice, int outputChannels,
86 int inputDevice, int inputChannels,
87 RTAUDIO_FORMAT format, int sampleRate,
88 int *bufferSize, int numberOfBuffers)
93 sprintf(message, "RtAudio: no audio devices found!");
94 error(RtError::NO_DEVICES_FOUND);
98 *streamId = openStream(outputDevice, outputChannels, inputDevice, inputChannels,
99 format, sampleRate, bufferSize, numberOfBuffers);
101 catch (RtError &exception) {
102 // deallocate the RTAUDIO_DEVICE structures
103 if (devices) free(devices);
108 RtAudio :: ~RtAudio()
110 // close any existing streams
111 while ( streams.size() )
112 closeStream( streams.begin()->first );
114 // deallocate the RTAUDIO_DEVICE structures
115 if (devices) free(devices);
118 int RtAudio :: openStream(int outputDevice, int outputChannels,
119 int inputDevice, int inputChannels,
120 RTAUDIO_FORMAT format, int sampleRate,
121 int *bufferSize, int numberOfBuffers)
123 static int streamKey = 0; // Unique stream identifier ... OK for multiple instances.
125 if (outputChannels < 1 && inputChannels < 1) {
126 sprintf(message,"RtAudio: one or both 'channel' parameters must be greater than zero.");
127 error(RtError::INVALID_PARAMETER);
130 if ( formatBytes(format) == 0 ) {
131 sprintf(message,"RtAudio: 'format' parameter value is undefined.");
132 error(RtError::INVALID_PARAMETER);
135 if ( outputChannels > 0 ) {
136 if (outputDevice > nDevices || outputDevice < 0) {
137 sprintf(message,"RtAudio: 'outputDevice' parameter value (%d) is invalid.", outputDevice);
138 error(RtError::INVALID_PARAMETER);
142 if ( inputChannels > 0 ) {
143 if (inputDevice > nDevices || inputDevice < 0) {
144 sprintf(message,"RtAudio: 'inputDevice' parameter value (%d) is invalid.", inputDevice);
145 error(RtError::INVALID_PARAMETER);
149 // Allocate a new stream structure.
150 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) calloc(1, sizeof(RTAUDIO_STREAM));
151 if (stream == NULL) {
152 sprintf(message, "RtAudio: memory allocation error!");
153 error(RtError::MEMORY_ERROR);
155 stream->mode = UNINITIALIZED;
156 MUTEX_INITIALIZE(&stream->mutex);
158 bool result = FAILURE;
159 int device, defaultDevice = 0;
162 if ( outputChannels > 0 ) {
165 channels = outputChannels;
167 if ( outputDevice == 0 ) { // Try default device first.
168 defaultDevice = getDefaultOutputDevice();
169 device = defaultDevice;
172 device = outputDevice - 1;
174 for (int i=-1; i<nDevices; i++) {
176 if ( i == defaultDevice ) continue;
179 if (devices[device].probed == false) {
180 // If the device wasn't successfully probed before, try it
182 clearDeviceInfo(&devices[device]);
183 probeDeviceInfo(&devices[device]);
185 if ( devices[device].probed )
186 result = probeDeviceOpen(device, stream, mode, channels, sampleRate,
187 format, bufferSize, numberOfBuffers);
188 if (result == SUCCESS) break;
189 if ( outputDevice > 0 ) break;
193 if ( inputChannels > 0 && ( result == SUCCESS || outputChannels <= 0 ) ) {
196 channels = inputChannels;
198 if ( inputDevice == 0 ) { // Try default device first.
199 defaultDevice = getDefaultInputDevice();
200 device = defaultDevice;
203 device = inputDevice - 1;
205 for (int i=-1; i<nDevices; i++) {
207 if ( i == defaultDevice ) continue;
210 if (devices[device].probed == false) {
211 // If the device wasn't successfully probed before, try it
213 clearDeviceInfo(&devices[device]);
214 probeDeviceInfo(&devices[device]);
216 if ( devices[device].probed )
217 result = probeDeviceOpen(device, stream, mode, channels, sampleRate,
218 format, bufferSize, numberOfBuffers);
219 if (result == SUCCESS) break;
220 if ( outputDevice > 0 ) break;
224 streams[++streamKey] = (void *) stream;
225 if ( result == SUCCESS )
228 // If we get here, all attempted probes failed. Close any opened
229 // devices and delete the allocated stream.
230 closeStream(streamKey);
231 if ( ( outputDevice == 0 && outputChannels > 0 )
232 || ( inputDevice == 0 && inputChannels > 0 ) )
233 sprintf(message,"RtAudio: no devices found for given parameters.");
235 sprintf(message,"RtAudio: unable to open specified device(s) with given stream parameters.");
236 error(RtError::INVALID_PARAMETER);
241 int RtAudio :: getDeviceCount(void)
246 void RtAudio :: getDeviceInfo(int device, RTAUDIO_DEVICE *info)
248 if (device > nDevices || device < 1) {
249 sprintf(message, "RtAudio: invalid device specifier (%d)!", device);
250 error(RtError::INVALID_DEVICE);
253 int deviceIndex = device - 1;
255 // If the device wasn't successfully probed before, try it now (or again).
256 if (devices[deviceIndex].probed == false) {
257 clearDeviceInfo(&devices[deviceIndex]);
258 probeDeviceInfo(&devices[deviceIndex]);
261 // Clear the info structure.
262 memset(info, 0, sizeof(RTAUDIO_DEVICE));
264 strncpy(info->name, devices[deviceIndex].name, 128);
265 info->probed = devices[deviceIndex].probed;
266 if ( info->probed == true ) {
267 info->maxOutputChannels = devices[deviceIndex].maxOutputChannels;
268 info->maxInputChannels = devices[deviceIndex].maxInputChannels;
269 info->maxDuplexChannels = devices[deviceIndex].maxDuplexChannels;
270 info->minOutputChannels = devices[deviceIndex].minOutputChannels;
271 info->minInputChannels = devices[deviceIndex].minInputChannels;
272 info->minDuplexChannels = devices[deviceIndex].minDuplexChannels;
273 info->hasDuplexSupport = devices[deviceIndex].hasDuplexSupport;
274 info->nSampleRates = devices[deviceIndex].nSampleRates;
275 if (info->nSampleRates == -1) {
276 info->sampleRates[0] = devices[deviceIndex].sampleRates[0];
277 info->sampleRates[1] = devices[deviceIndex].sampleRates[1];
280 for (int i=0; i<info->nSampleRates; i++)
281 info->sampleRates[i] = devices[deviceIndex].sampleRates[i];
283 info->nativeFormats = devices[deviceIndex].nativeFormats;
284 if ( deviceIndex == getDefaultOutputDevice() ||
285 deviceIndex == getDefaultInputDevice() )
286 info->isDefault = true;
292 char * const RtAudio :: getStreamBuffer(int streamId)
294 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
296 return stream->userBuffer;
299 #if defined(__LINUX_ALSA__) || defined(__LINUX_OSS__) || defined(__IRIX_AL__)
301 extern "C" void *callbackHandler(void * ptr);
303 void RtAudio :: setStreamCallback(int streamId, RTAUDIO_CALLBACK callback, void *userData)
305 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
307 CALLBACK_INFO *info = (CALLBACK_INFO *) &stream->callbackInfo;
308 if ( info->usingCallback ) {
309 sprintf(message, "RtAudio: A callback is already set for this stream!");
310 error(RtError::WARNING);
314 info->callback = (void *) callback;
315 info->userData = userData;
316 info->usingCallback = true;
317 info->object = (void *) this;
318 info->streamId = streamId;
320 int err = pthread_create(&info->thread, NULL, callbackHandler, &stream->callbackInfo);
323 info->usingCallback = false;
324 sprintf(message, "RtAudio: error starting callback thread!");
325 error(RtError::THREAD_ERROR);
329 void RtAudio :: cancelStreamCallback(int streamId)
331 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
333 if (stream->callbackInfo.usingCallback) {
335 if (stream->state == STREAM_RUNNING)
336 stopStream( streamId );
338 MUTEX_LOCK(&stream->mutex);
340 stream->callbackInfo.usingCallback = false;
341 pthread_cancel(stream->callbackInfo.thread);
342 pthread_join(stream->callbackInfo.thread, NULL);
343 stream->callbackInfo.thread = 0;
344 stream->callbackInfo.callback = NULL;
345 stream->callbackInfo.userData = NULL;
347 MUTEX_UNLOCK(&stream->mutex);
353 // *************************************************** //
355 // OS/API-specific methods.
357 // *************************************************** //
359 #if defined(__MACOSX_CORE__)
361 // The OS X CoreAudio API is designed to use a separate callback
362 // procedure for each of its audio devices. A single RtAudio duplex
363 // stream using two different devices is supported here, though it
364 // cannot be guaranteed to always behave correctly because we cannot
365 // synchronize these two callbacks. This same functionality can be
366 // achieved with better synchrony by opening two separate streams for
367 // the devices and using RtAudio blocking calls (i.e. tickStream()).
369 // The possibility of having multiple RtAudio streams accessing the
370 // same CoreAudio device is not currently supported. The problem
371 // involves the inability to install our callbackHandler function for
372 // the same device more than once. I experimented with a workaround
373 // for this, but it requires an additional buffer for mixing output
374 // data before filling the CoreAudio device buffer. In the end, I
375 // decided it wasn't worth supporting.
377 // Property listeners are currently not used. The issue is what could
378 // be done if a critical stream parameter (buffer size, sample rate,
379 // device disconnect) notification arrived. The listeners entail
380 // quite a bit of extra code and most likely, a user program wouldn't
381 // be prepared for the result anyway. Some initial listener code is
384 void RtAudio :: initialize(void)
386 OSStatus err = noErr;
388 AudioDeviceID *deviceList = NULL;
391 // Find out how many audio devices there are, if any.
392 err = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDevices, &dataSize, NULL);
394 sprintf(message, "RtAudio: OSX error getting device info!");
395 error(RtError::SYSTEM_ERROR);
398 nDevices = dataSize / sizeof(AudioDeviceID);
399 if (nDevices == 0) return;
401 // Allocate the RTAUDIO_DEVICE structures.
402 devices = (RTAUDIO_DEVICE *) calloc(nDevices, sizeof(RTAUDIO_DEVICE));
403 if (devices == NULL) {
404 sprintf(message, "RtAudio: memory allocation error!");
405 error(RtError::MEMORY_ERROR);
408 // Make space for the devices we are about to get.
409 deviceList = (AudioDeviceID *) malloc( dataSize );
410 if (deviceList == NULL) {
411 sprintf(message, "RtAudio: memory allocation error!");
412 error(RtError::MEMORY_ERROR);
415 // Get the array of AudioDeviceIDs.
416 err = AudioHardwareGetProperty(kAudioHardwarePropertyDevices, &dataSize, (void *) deviceList);
419 sprintf(message, "RtAudio: OSX error getting device properties!");
420 error(RtError::SYSTEM_ERROR);
423 // Write device identifiers to device structures and then
424 // probe the device capabilities.
425 for (int i=0; i<nDevices; i++) {
426 devices[i].id[0] = deviceList[i];
427 //probeDeviceInfo(&devices[i]);
433 int RtAudio :: getDefaultInputDevice(void)
436 UInt32 dataSize = sizeof( AudioDeviceID );
438 OSStatus result = AudioHardwareGetProperty( kAudioHardwarePropertyDefaultInputDevice,
441 if (result != noErr) {
442 sprintf( message, "RtAudio: OSX error getting default input device." );
443 error(RtError::WARNING);
447 for ( int i=0; i<nDevices; i++ ) {
448 if ( id == devices[i].id[0] ) return i;
454 int RtAudio :: getDefaultOutputDevice(void)
457 UInt32 dataSize = sizeof( AudioDeviceID );
459 OSStatus result = AudioHardwareGetProperty( kAudioHardwarePropertyDefaultOutputDevice,
462 if (result != noErr) {
463 sprintf( message, "RtAudio: OSX error getting default output device." );
464 error(RtError::WARNING);
468 for ( int i=0; i<nDevices; i++ ) {
469 if ( id == devices[i].id[0] ) return i;
475 static bool deviceSupportsFormat( AudioDeviceID id, bool isInput,
476 AudioStreamBasicDescription *desc, bool isDuplex )
478 OSStatus result = noErr;
479 UInt32 dataSize = sizeof( AudioStreamBasicDescription );
481 result = AudioDeviceGetProperty( id, 0, isInput,
482 kAudioDevicePropertyStreamFormatSupported,
485 if (result == kAudioHardwareNoError) {
487 result = AudioDeviceGetProperty( id, 0, true,
488 kAudioDevicePropertyStreamFormatSupported,
492 if (result != kAudioHardwareNoError)
501 void RtAudio :: probeDeviceInfo(RTAUDIO_DEVICE *info)
503 OSStatus err = noErr;
505 // Get the device manufacturer and name.
508 UInt32 dataSize = 256;
509 err = AudioDeviceGetProperty( info->id[0], 0, false,
510 kAudioDevicePropertyDeviceManufacturer,
513 sprintf( message, "RtAudio: OSX error getting device manufacturer." );
514 error(RtError::DEBUG_WARNING);
517 strncpy(fullname, name, 256);
518 strcat(fullname, ": " );
521 err = AudioDeviceGetProperty( info->id[0], 0, false,
522 kAudioDevicePropertyDeviceName,
525 sprintf( message, "RtAudio: OSX error getting device name." );
526 error(RtError::DEBUG_WARNING);
529 strncat(fullname, name, 254);
530 strncat(info->name, fullname, 128);
532 // Get output channel information.
533 unsigned int i, minChannels, maxChannels, nStreams = 0;
534 AudioBufferList *bufferList = nil;
535 err = AudioDeviceGetPropertyInfo( info->id[0], 0, false,
536 kAudioDevicePropertyStreamConfiguration,
538 if (err == noErr && dataSize > 0) {
539 bufferList = (AudioBufferList *) malloc( dataSize );
540 if (bufferList == NULL) {
541 sprintf(message, "RtAudio: memory allocation error!");
542 error(RtError::DEBUG_WARNING);
546 err = AudioDeviceGetProperty( info->id[0], 0, false,
547 kAudioDevicePropertyStreamConfiguration,
548 &dataSize, bufferList );
552 nStreams = bufferList->mNumberBuffers;
553 for ( i=0; i<nStreams; i++ ) {
554 maxChannels += bufferList->mBuffers[i].mNumberChannels;
555 if ( bufferList->mBuffers[i].mNumberChannels < minChannels )
556 minChannels = bufferList->mBuffers[i].mNumberChannels;
560 if (err != noErr || dataSize <= 0) {
561 sprintf( message, "RtAudio: OSX error getting output channels for device (%s).", info->name );
562 error(RtError::DEBUG_WARNING);
568 if ( maxChannels > 0 )
569 info->maxOutputChannels = maxChannels;
570 if ( minChannels > 0 )
571 info->minOutputChannels = minChannels;
574 // Get input channel information.
576 err = AudioDeviceGetPropertyInfo( info->id[0], 0, true,
577 kAudioDevicePropertyStreamConfiguration,
579 if (err == noErr && dataSize > 0) {
580 bufferList = (AudioBufferList *) malloc( dataSize );
581 if (bufferList == NULL) {
582 sprintf(message, "RtAudio: memory allocation error!");
583 error(RtError::DEBUG_WARNING);
586 err = AudioDeviceGetProperty( info->id[0], 0, true,
587 kAudioDevicePropertyStreamConfiguration,
588 &dataSize, bufferList );
592 nStreams = bufferList->mNumberBuffers;
593 for ( i=0; i<nStreams; i++ ) {
594 if ( bufferList->mBuffers[i].mNumberChannels < minChannels )
595 minChannels = bufferList->mBuffers[i].mNumberChannels;
596 maxChannels += bufferList->mBuffers[i].mNumberChannels;
600 if (err != noErr || dataSize <= 0) {
601 sprintf( message, "RtAudio: OSX error getting input channels for device (%s).", info->name );
602 error(RtError::DEBUG_WARNING);
608 if ( maxChannels > 0 )
609 info->maxInputChannels = maxChannels;
610 if ( minChannels > 0 )
611 info->minInputChannels = minChannels;
614 // If device opens for both playback and capture, we determine the channels.
615 if (info->maxOutputChannels > 0 && info->maxInputChannels > 0) {
616 info->hasDuplexSupport = true;
617 info->maxDuplexChannels = (info->maxOutputChannels > info->maxInputChannels) ?
618 info->maxInputChannels : info->maxOutputChannels;
619 info->minDuplexChannels = (info->minOutputChannels > info->minInputChannels) ?
620 info->minInputChannels : info->minOutputChannels;
623 // Probe the device sample rate and data format parameters. The
624 // core audio query mechanism is performed on a "stream"
625 // description, which can have a variable number of channels and
626 // apply to input or output only.
628 // Create a stream description structure.
629 AudioStreamBasicDescription description;
630 dataSize = sizeof( AudioStreamBasicDescription );
631 memset(&description, 0, sizeof(AudioStreamBasicDescription));
632 bool isInput = false;
633 if ( info->maxOutputChannels == 0 ) isInput = true;
634 bool isDuplex = false;
635 if ( info->maxDuplexChannels > 0 ) isDuplex = true;
637 // Determine the supported sample rates.
638 info->nSampleRates = 0;
639 for (i=0; i<MAX_SAMPLE_RATES; i++) {
640 description.mSampleRate = (double) SAMPLE_RATES[i];
641 if ( deviceSupportsFormat( info->id[0], isInput, &description, isDuplex ) )
642 info->sampleRates[info->nSampleRates++] = SAMPLE_RATES[i];
645 if (info->nSampleRates == 0) {
646 sprintf( message, "RtAudio: No supported sample rates found for OSX device (%s).", info->name );
647 error(RtError::DEBUG_WARNING);
651 // Check for continuous sample rate support.
652 description.mSampleRate = kAudioStreamAnyRate;
653 if ( deviceSupportsFormat( info->id[0], isInput, &description, isDuplex ) ) {
654 info->sampleRates[1] = info->sampleRates[info->nSampleRates-1];
655 info->nSampleRates = -1;
658 // Determine the supported data formats.
659 info->nativeFormats = 0;
660 description.mFormatID = kAudioFormatLinearPCM;
661 description.mBitsPerChannel = 8;
662 description.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsPacked | kLinearPCMFormatFlagIsBigEndian;
663 if ( deviceSupportsFormat( info->id[0], isInput, &description, isDuplex ) )
664 info->nativeFormats |= RTAUDIO_SINT8;
666 description.mFormatFlags &= ~kLinearPCMFormatFlagIsBigEndian;
667 if ( deviceSupportsFormat( info->id[0], isInput, &description, isDuplex ) )
668 info->nativeFormats |= RTAUDIO_SINT8;
671 description.mBitsPerChannel = 16;
672 description.mFormatFlags |= kLinearPCMFormatFlagIsBigEndian;
673 if ( deviceSupportsFormat( info->id[0], isInput, &description, isDuplex ) )
674 info->nativeFormats |= RTAUDIO_SINT16;
676 description.mFormatFlags &= ~kLinearPCMFormatFlagIsBigEndian;
677 if ( deviceSupportsFormat( info->id[0], isInput, &description, isDuplex ) )
678 info->nativeFormats |= RTAUDIO_SINT16;
681 description.mBitsPerChannel = 32;
682 description.mFormatFlags |= kLinearPCMFormatFlagIsBigEndian;
683 if ( deviceSupportsFormat( info->id[0], isInput, &description, isDuplex ) )
684 info->nativeFormats |= RTAUDIO_SINT32;
686 description.mFormatFlags &= ~kLinearPCMFormatFlagIsBigEndian;
687 if ( deviceSupportsFormat( info->id[0], isInput, &description, isDuplex ) )
688 info->nativeFormats |= RTAUDIO_SINT32;
691 description.mBitsPerChannel = 24;
692 description.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsAlignedHigh | kLinearPCMFormatFlagIsBigEndian;
693 if ( deviceSupportsFormat( info->id[0], isInput, &description, isDuplex ) )
694 info->nativeFormats |= RTAUDIO_SINT24;
696 description.mFormatFlags &= ~kLinearPCMFormatFlagIsBigEndian;
697 if ( deviceSupportsFormat( info->id[0], isInput, &description, isDuplex ) )
698 info->nativeFormats |= RTAUDIO_SINT24;
701 description.mBitsPerChannel = 32;
702 description.mFormatFlags = kLinearPCMFormatFlagIsFloat | kLinearPCMFormatFlagIsPacked | kLinearPCMFormatFlagIsBigEndian;
703 if ( deviceSupportsFormat( info->id[0], isInput, &description, isDuplex ) )
704 info->nativeFormats |= RTAUDIO_FLOAT32;
706 description.mFormatFlags &= ~kLinearPCMFormatFlagIsBigEndian;
707 if ( deviceSupportsFormat( info->id[0], isInput, &description, isDuplex ) )
708 info->nativeFormats |= RTAUDIO_FLOAT32;
711 description.mBitsPerChannel = 64;
712 description.mFormatFlags |= kLinearPCMFormatFlagIsBigEndian;
713 if ( deviceSupportsFormat( info->id[0], isInput, &description, isDuplex ) )
714 info->nativeFormats |= RTAUDIO_FLOAT64;
716 description.mFormatFlags &= ~kLinearPCMFormatFlagIsBigEndian;
717 if ( deviceSupportsFormat( info->id[0], isInput, &description, isDuplex ) )
718 info->nativeFormats |= RTAUDIO_FLOAT64;
721 // Check that we have at least one supported format.
722 if (info->nativeFormats == 0) {
723 sprintf(message, "RtAudio: OSX PCM device (%s) data format not supported by RtAudio.",
725 error(RtError::DEBUG_WARNING);
732 OSStatus callbackHandler(AudioDeviceID inDevice,
733 const AudioTimeStamp* inNow,
734 const AudioBufferList* inInputData,
735 const AudioTimeStamp* inInputTime,
736 AudioBufferList* outOutputData,
737 const AudioTimeStamp* inOutputTime,
740 CALLBACK_INFO *info = (CALLBACK_INFO *) infoPointer;
742 RtAudio *object = (RtAudio *) info->object;
744 object->callbackEvent( info->streamId, inDevice, (void *)inInputData, (void *)outOutputData );
746 catch (RtError &exception) {
747 fprintf(stderr, "\nCallback handler error (%s)!\n\n", exception.getMessage());
748 return kAudioHardwareUnspecifiedError;
751 return kAudioHardwareNoError;
755 OSStatus deviceListener(AudioDeviceID inDevice,
758 AudioDevicePropertyID propertyID,
761 CALLBACK_INFO *info = (CALLBACK_INFO *) infoPointer;
763 RtAudio *object = (RtAudio *) info->object;
765 object->settingChange( info->streamId );
767 catch (RtError &exception) {
768 fprintf(stderr, "\nDevice listener error (%s)!\n\n", exception.getMessage());
769 return kAudioHardwareUnspecifiedError;
772 return kAudioHardwareNoError;
776 bool RtAudio :: probeDeviceOpen(int device, RTAUDIO_STREAM *stream,
777 STREAM_MODE mode, int channels,
778 int sampleRate, RTAUDIO_FORMAT format,
779 int *bufferSize, int numberOfBuffers)
781 // Check to make sure we don't already have a stream accessing this device.
782 RTAUDIO_STREAM *streamPtr;
783 std::map<int, void *>::const_iterator i;
784 for ( i=streams.begin(); i!=streams.end(); ++i ) {
785 streamPtr = (RTAUDIO_STREAM *) i->second;
786 if ( streamPtr->device[0] == device || streamPtr->device[1] == device ) {
787 sprintf(message, "RtAudio: no current OS X support for multiple streams accessing the same device!");
788 error(RtError::WARNING);
793 // Setup for stream mode.
794 bool isInput = false;
795 AudioDeviceID id = devices[device].id[0];
796 if ( mode == INPUT ) isInput = true;
798 // Search for a stream which contains the desired number of channels.
799 OSStatus err = noErr;
801 unsigned int deviceChannels, nStreams;
802 UInt32 iChannel = 0, iStream = 0;
803 AudioBufferList *bufferList = nil;
804 err = AudioDeviceGetPropertyInfo( id, 0, isInput,
805 kAudioDevicePropertyStreamConfiguration,
808 if (err == noErr && dataSize > 0) {
809 bufferList = (AudioBufferList *) malloc( dataSize );
810 if (bufferList == NULL) {
811 sprintf(message, "RtAudio: memory allocation error!");
812 error(RtError::DEBUG_WARNING);
815 err = AudioDeviceGetProperty( id, 0, isInput,
816 kAudioDevicePropertyStreamConfiguration,
817 &dataSize, bufferList );
820 stream->deInterleave[mode] = false;
821 nStreams = bufferList->mNumberBuffers;
822 for ( iStream=0; iStream<nStreams; iStream++ ) {
823 if ( bufferList->mBuffers[iStream].mNumberChannels >= (unsigned int) channels ) break;
824 iChannel += bufferList->mBuffers[iStream].mNumberChannels;
826 // If we didn't find a single stream above, see if we can meet
827 // the channel specification in mono mode (i.e. using separate
828 // non-interleaved buffers). This can only work if there are N
829 // consecutive one-channel streams, where N is the number of
832 if ( iStream >= nStreams && nStreams >= (unsigned int) channels ) {
834 for ( iStream=0; iStream<nStreams; iStream++ ) {
835 if ( bufferList->mBuffers[iStream].mNumberChannels == 1 )
839 if ( counter == channels ) {
840 iStream -= channels - 1;
841 iChannel -= channels - 1;
842 stream->deInterleave[mode] = true;
845 iChannel += bufferList->mBuffers[iStream].mNumberChannels;
850 if (err != noErr || dataSize <= 0) {
851 if ( bufferList ) free( bufferList );
852 sprintf( message, "RtAudio: OSX error getting channels for device (%s).", devices[device].name );
853 error(RtError::DEBUG_WARNING);
857 if (iStream >= nStreams) {
859 sprintf( message, "RtAudio: unable to find OSX audio stream on device (%s) for requested channels (%d).",
860 devices[device].name, channels );
861 error(RtError::DEBUG_WARNING);
865 // This is ok even for mono mode ... it gets updated later.
866 deviceChannels = bufferList->mBuffers[iStream].mNumberChannels;
869 // Determine the buffer size.
870 AudioValueRange bufferRange;
871 dataSize = sizeof(AudioValueRange);
872 err = AudioDeviceGetProperty( id, 0, isInput,
873 kAudioDevicePropertyBufferSizeRange,
874 &dataSize, &bufferRange);
876 sprintf( message, "RtAudio: OSX error getting buffer size range for device (%s).",
877 devices[device].name );
878 error(RtError::DEBUG_WARNING);
882 long bufferBytes = *bufferSize * deviceChannels * formatBytes(RTAUDIO_FLOAT32);
883 if (bufferRange.mMinimum > bufferBytes) bufferBytes = (int) bufferRange.mMinimum;
884 else if (bufferRange.mMaximum < bufferBytes) bufferBytes = (int) bufferRange.mMaximum;
886 // Set the buffer size. For mono mode, I'm assuming we only need to
887 // make this setting for the first channel.
888 UInt32 theSize = (UInt32) bufferBytes;
889 dataSize = sizeof( UInt32);
890 err = AudioDeviceSetProperty(id, NULL, 0, isInput,
891 kAudioDevicePropertyBufferSize,
894 sprintf( message, "RtAudio: OSX error setting the buffer size for device (%s).",
895 devices[device].name );
896 error(RtError::DEBUG_WARNING);
900 // If attempting to setup a duplex stream, the bufferSize parameter
901 // MUST be the same in both directions!
902 *bufferSize = bufferBytes / ( deviceChannels * formatBytes(RTAUDIO_FLOAT32) );
903 if ( stream->mode == OUTPUT && mode == INPUT && *bufferSize != stream->bufferSize ) {
904 sprintf( message, "RtAudio: OSX error setting buffer size for duplex stream on device (%s).",
905 devices[device].name );
906 error(RtError::DEBUG_WARNING);
910 stream->bufferSize = *bufferSize;
911 stream->nBuffers = 1;
913 // Set the stream format description. Do for each channel in mono mode.
914 AudioStreamBasicDescription description;
915 dataSize = sizeof( AudioStreamBasicDescription );
916 if ( stream->deInterleave[mode] ) nStreams = channels;
918 for ( unsigned int i=0; i<nStreams; i++, iChannel++ ) {
920 err = AudioDeviceGetProperty( id, iChannel, isInput,
921 kAudioDevicePropertyStreamFormat,
922 &dataSize, &description );
924 sprintf( message, "RtAudio: OSX error getting stream format for device (%s).", devices[device].name );
925 error(RtError::DEBUG_WARNING);
929 // Set the sample rate and data format id.
930 description.mSampleRate = (double) sampleRate;
931 description.mFormatID = kAudioFormatLinearPCM;
932 err = AudioDeviceSetProperty( id, NULL, iChannel, isInput,
933 kAudioDevicePropertyStreamFormat,
934 dataSize, &description );
936 sprintf( message, "RtAudio: OSX error setting sample rate or data format for device (%s).", devices[device].name );
937 error(RtError::DEBUG_WARNING);
942 // Check whether we need byte-swapping (assuming OS X host is big-endian).
943 iChannel -= nStreams;
944 err = AudioDeviceGetProperty( id, iChannel, isInput,
945 kAudioDevicePropertyStreamFormat,
946 &dataSize, &description );
948 sprintf( message, "RtAudio: OSX error getting stream format for device (%s).", devices[device].name );
949 error(RtError::DEBUG_WARNING);
953 stream->doByteSwap[mode] = false;
954 if ( !description.mFormatFlags & kLinearPCMFormatFlagIsBigEndian )
955 stream->doByteSwap[mode] = true;
957 // From the CoreAudio documentation, PCM data must be supplied as
959 stream->userFormat = format;
960 stream->deviceFormat[mode] = RTAUDIO_FLOAT32;
962 if ( stream->deInterleave[mode] )
963 stream->nDeviceChannels[mode] = channels;
965 stream->nDeviceChannels[mode] = description.mChannelsPerFrame;
966 stream->nUserChannels[mode] = channels;
968 // Set handle and flags for buffer conversion.
969 stream->handle[mode] = iStream;
970 stream->doConvertBuffer[mode] = false;
971 if (stream->userFormat != stream->deviceFormat[mode])
972 stream->doConvertBuffer[mode] = true;
973 if (stream->nUserChannels[mode] < stream->nDeviceChannels[mode])
974 stream->doConvertBuffer[mode] = true;
975 if (stream->nUserChannels[mode] > 1 && stream->deInterleave[mode])
976 stream->doConvertBuffer[mode] = true;
978 // Allocate necessary internal buffers.
979 if ( stream->nUserChannels[0] != stream->nUserChannels[1] ) {
982 if (stream->nUserChannels[0] >= stream->nUserChannels[1])
983 buffer_bytes = stream->nUserChannels[0];
985 buffer_bytes = stream->nUserChannels[1];
987 buffer_bytes *= *bufferSize * formatBytes(stream->userFormat);
988 if (stream->userBuffer) free(stream->userBuffer);
989 stream->userBuffer = (char *) calloc(buffer_bytes, 1);
990 if (stream->userBuffer == NULL)
994 if ( stream->deInterleave[mode] ) {
997 bool makeBuffer = true;
998 if ( mode == OUTPUT )
999 buffer_bytes = stream->nDeviceChannels[0] * formatBytes(stream->deviceFormat[0]);
1000 else { // mode == INPUT
1001 buffer_bytes = stream->nDeviceChannels[1] * formatBytes(stream->deviceFormat[1]);
1002 if ( stream->mode == OUTPUT && stream->deviceBuffer ) {
1003 long bytes_out = stream->nDeviceChannels[0] * formatBytes(stream->deviceFormat[0]);
1004 if ( buffer_bytes < bytes_out ) makeBuffer = false;
1009 buffer_bytes *= *bufferSize;
1010 if (stream->deviceBuffer) free(stream->deviceBuffer);
1011 stream->deviceBuffer = (char *) calloc(buffer_bytes, 1);
1012 if (stream->deviceBuffer == NULL)
1015 // If not de-interleaving, we point stream->deviceBuffer to the
1016 // OS X supplied device buffer before doing any necessary data
1017 // conversions. This presents a problem if we have a duplex
1018 // stream using one device which needs de-interleaving and
1019 // another device which doesn't. So, save a pointer to our own
1020 // device buffer in the CALLBACK_INFO structure.
1021 stream->callbackInfo.buffers = stream->deviceBuffer;
1025 stream->sampleRate = sampleRate;
1026 stream->device[mode] = device;
1027 stream->state = STREAM_STOPPED;
1028 stream->callbackInfo.object = (void *) this;
1029 stream->callbackInfo.waitTime = (unsigned long) (200000.0 * stream->bufferSize / stream->sampleRate);
1030 stream->callbackInfo.device[mode] = id;
1031 if ( stream->mode == OUTPUT && mode == INPUT && stream->device[0] == device )
1032 // Only one callback procedure per device.
1033 stream->mode = DUPLEX;
1035 err = AudioDeviceAddIOProc( id, callbackHandler, (void *) &stream->callbackInfo );
1037 sprintf( message, "RtAudio: OSX error setting callback for device (%s).", devices[device].name );
1038 error(RtError::DEBUG_WARNING);
1041 if ( stream->mode == OUTPUT && mode == INPUT )
1042 stream->mode = DUPLEX;
1044 stream->mode = mode;
1047 // If we wanted to use property listeners, they would be setup here.
1052 if (stream->userBuffer) {
1053 free(stream->userBuffer);
1054 stream->userBuffer = 0;
1056 sprintf(message, "RtAudio: OSX error allocating buffer memory (%s).", devices[device].name);
1057 error(RtError::WARNING);
1061 void RtAudio :: cancelStreamCallback(int streamId)
1063 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
1065 if (stream->callbackInfo.usingCallback) {
1067 if (stream->state == STREAM_RUNNING)
1068 stopStream( streamId );
1070 MUTEX_LOCK(&stream->mutex);
1072 stream->callbackInfo.usingCallback = false;
1073 stream->callbackInfo.userData = NULL;
1074 stream->state = STREAM_STOPPED;
1075 stream->callbackInfo.callback = NULL;
1077 MUTEX_UNLOCK(&stream->mutex);
1081 void RtAudio :: closeStream(int streamId)
1083 // We don't want an exception to be thrown here because this
1084 // function is called by our class destructor. So, do our own
1086 if ( streams.find( streamId ) == streams.end() ) {
1087 sprintf(message, "RtAudio: invalid stream identifier!");
1088 error(RtError::WARNING);
1092 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) streams[streamId];
1095 if (stream->mode == OUTPUT || stream->mode == DUPLEX) {
1096 id = devices[stream->device[0]].id[0];
1097 if (stream->state == STREAM_RUNNING)
1098 AudioDeviceStop( id, callbackHandler );
1099 AudioDeviceRemoveIOProc( id, callbackHandler );
1102 if (stream->mode == INPUT || ( stream->mode == DUPLEX && stream->device[0] != stream->device[1]) ) {
1103 id = devices[stream->device[1]].id[0];
1104 if (stream->state == STREAM_RUNNING)
1105 AudioDeviceStop( id, callbackHandler );
1106 AudioDeviceRemoveIOProc( id, callbackHandler );
1109 pthread_mutex_destroy(&stream->mutex);
1111 if (stream->userBuffer)
1112 free(stream->userBuffer);
1114 if ( stream->deInterleave[0] || stream->deInterleave[1] )
1115 free(stream->callbackInfo.buffers);
1118 streams.erase(streamId);
1121 void RtAudio :: startStream(int streamId)
1123 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
1125 MUTEX_LOCK(&stream->mutex);
1127 if (stream->state == STREAM_RUNNING)
1131 if (stream->mode == OUTPUT || stream->mode == DUPLEX) {
1133 err = AudioDeviceStart(devices[stream->device[0]].id[0], callbackHandler);
1135 sprintf(message, "RtAudio: OSX error starting callback procedure on device (%s).",
1136 devices[stream->device[0]].name);
1137 MUTEX_UNLOCK(&stream->mutex);
1138 error(RtError::DRIVER_ERROR);
1142 if (stream->mode == INPUT || ( stream->mode == DUPLEX && stream->device[0] != stream->device[1]) ) {
1144 err = AudioDeviceStart(devices[stream->device[1]].id[0], callbackHandler);
1146 sprintf(message, "RtAudio: OSX error starting input callback procedure on device (%s).",
1147 devices[stream->device[0]].name);
1148 MUTEX_UNLOCK(&stream->mutex);
1149 error(RtError::DRIVER_ERROR);
1153 stream->callbackInfo.streamId = streamId;
1154 stream->state = STREAM_RUNNING;
1155 stream->callbackInfo.blockTick = true;
1156 stream->callbackInfo.stopStream = false;
1159 MUTEX_UNLOCK(&stream->mutex);
1162 void RtAudio :: stopStream(int streamId)
1164 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
1166 MUTEX_LOCK(&stream->mutex);
1168 if (stream->state == STREAM_STOPPED)
1172 if (stream->mode == OUTPUT || stream->mode == DUPLEX) {
1174 err = AudioDeviceStop(devices[stream->device[0]].id[0], callbackHandler);
1176 sprintf(message, "RtAudio: OSX error stopping callback procedure on device (%s).",
1177 devices[stream->device[0]].name);
1178 MUTEX_UNLOCK(&stream->mutex);
1179 error(RtError::DRIVER_ERROR);
1183 if (stream->mode == INPUT || ( stream->mode == DUPLEX && stream->device[0] != stream->device[1]) ) {
1185 err = AudioDeviceStop(devices[stream->device[1]].id[0], callbackHandler);
1187 sprintf(message, "RtAudio: OSX error stopping input callback procedure on device (%s).",
1188 devices[stream->device[0]].name);
1189 MUTEX_UNLOCK(&stream->mutex);
1190 error(RtError::DRIVER_ERROR);
1194 stream->state = STREAM_STOPPED;
1197 MUTEX_UNLOCK(&stream->mutex);
1200 void RtAudio :: abortStream(int streamId)
1202 stopStream( streamId );
1205 // I don't know how this function can be implemented.
1206 int RtAudio :: streamWillBlock(int streamId)
1208 sprintf(message, "RtAudio: streamWillBlock() cannot be implemented for OS X.");
1209 error(RtError::WARNING);
1213 void RtAudio :: tickStream(int streamId)
1215 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
1217 if (stream->state == STREAM_STOPPED)
1220 if (stream->callbackInfo.usingCallback) {
1221 sprintf(message, "RtAudio: tickStream() should not be used when a callback function is set!");
1222 error(RtError::WARNING);
1226 // Block waiting here until the user data is processed in callbackEvent().
1227 while ( stream->callbackInfo.blockTick )
1228 usleep(stream->callbackInfo.waitTime);
1230 MUTEX_LOCK(&stream->mutex);
1232 stream->callbackInfo.blockTick = true;
1234 MUTEX_UNLOCK(&stream->mutex);
1237 void RtAudio :: callbackEvent( int streamId, DEVICE_ID deviceId, void *inData, void *outData )
1239 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
1241 CALLBACK_INFO *info;
1242 AudioBufferList *inBufferList = (AudioBufferList *) inData;
1243 AudioBufferList *outBufferList = (AudioBufferList *) outData;
1245 if (stream->state == STREAM_STOPPED) return;
1247 info = (CALLBACK_INFO *) &stream->callbackInfo;
1248 if ( !info->usingCallback ) {
1249 // Block waiting here until we get new user data in tickStream().
1250 while ( !info->blockTick )
1251 usleep(info->waitTime);
1253 else if ( info->stopStream ) {
1254 // Check if the stream should be stopped (via the previous user
1255 // callback return value). We stop the stream here, rather than
1256 // after the function call, so that output data can first be
1258 this->stopStream(info->streamId);
1262 MUTEX_LOCK(&stream->mutex);
1264 if ( stream->mode == INPUT || ( stream->mode == DUPLEX && deviceId == info->device[1] ) ) {
1266 if (stream->doConvertBuffer[1]) {
1268 if ( stream->deInterleave[1] ) {
1269 stream->deviceBuffer = (char *) stream->callbackInfo.buffers;
1270 int bufferBytes = inBufferList->mBuffers[stream->handle[1]].mDataByteSize;
1271 for ( int i=0; i<stream->nDeviceChannels[1]; i++ ) {
1272 memcpy(&stream->deviceBuffer[i*bufferBytes],
1273 inBufferList->mBuffers[stream->handle[1]+i].mData, bufferBytes );
1277 stream->deviceBuffer = (char *) inBufferList->mBuffers[stream->handle[1]].mData;
1279 if ( stream->doByteSwap[1] )
1280 byteSwapBuffer(stream->deviceBuffer,
1281 stream->bufferSize * stream->nDeviceChannels[1],
1282 stream->deviceFormat[1]);
1283 convertStreamBuffer(stream, INPUT);
1287 memcpy(stream->userBuffer,
1288 inBufferList->mBuffers[stream->handle[1]].mData,
1289 inBufferList->mBuffers[stream->handle[1]].mDataByteSize );
1291 if (stream->doByteSwap[1])
1292 byteSwapBuffer(stream->userBuffer,
1293 stream->bufferSize * stream->nUserChannels[1],
1294 stream->userFormat);
1298 // Don't invoke the user callback if duplex mode, the input/output
1299 // devices are different, and this function is called for the output
1301 if ( info->usingCallback && (stream->mode != DUPLEX || deviceId == info->device[1] ) ) {
1302 RTAUDIO_CALLBACK callback = (RTAUDIO_CALLBACK) info->callback;
1303 info->stopStream = callback(stream->userBuffer, stream->bufferSize, info->userData);
1306 if ( stream->mode == OUTPUT || ( stream->mode == DUPLEX && deviceId == info->device[0] ) ) {
1308 if (stream->doConvertBuffer[0]) {
1310 if ( !stream->deInterleave[0] )
1311 stream->deviceBuffer = (char *) outBufferList->mBuffers[stream->handle[0]].mData;
1313 stream->deviceBuffer = (char *) stream->callbackInfo.buffers;
1315 convertStreamBuffer(stream, OUTPUT);
1316 if ( stream->doByteSwap[0] )
1317 byteSwapBuffer(stream->deviceBuffer,
1318 stream->bufferSize * stream->nDeviceChannels[0],
1319 stream->deviceFormat[0]);
1321 if ( stream->deInterleave[0] ) {
1322 int bufferBytes = outBufferList->mBuffers[stream->handle[0]].mDataByteSize;
1323 for ( int i=0; i<stream->nDeviceChannels[0]; i++ ) {
1324 memcpy(outBufferList->mBuffers[stream->handle[0]+i].mData,
1325 &stream->deviceBuffer[i*bufferBytes], bufferBytes );
1331 if (stream->doByteSwap[0])
1332 byteSwapBuffer(stream->userBuffer,
1333 stream->bufferSize * stream->nUserChannels[0],
1334 stream->userFormat);
1336 memcpy(outBufferList->mBuffers[stream->handle[0]].mData,
1338 outBufferList->mBuffers[stream->handle[0]].mDataByteSize );
1342 if ( !info->usingCallback && (stream->mode != DUPLEX || deviceId == info->device[1] ) )
1343 info->blockTick = false;
1345 MUTEX_UNLOCK(&stream->mutex);
1349 void RtAudio :: setStreamCallback(int streamId, RTAUDIO_CALLBACK callback, void *userData)
1351 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
1353 stream->callbackInfo.callback = (void *) callback;
1354 stream->callbackInfo.userData = userData;
1355 stream->callbackInfo.usingCallback = true;
1358 //******************** End of __MACOSX_CORE__ *********************//
1360 #elif defined(__LINUX_ALSA__)
1362 #define MAX_DEVICES 16
1364 void RtAudio :: initialize(void)
1366 int card, result, device;
1369 char deviceNames[MAX_DEVICES][32];
1371 snd_ctl_card_info_t *info;
1372 snd_ctl_card_info_alloca(&info);
1374 // Count cards and devices
1377 snd_card_next(&card);
1378 while ( card >= 0 ) {
1379 sprintf(name, "hw:%d", card);
1380 result = snd_ctl_open(&handle, name, 0);
1382 sprintf(message, "RtAudio: ALSA control open (%i): %s.", card, snd_strerror(result));
1383 error(RtError::DEBUG_WARNING);
1386 result = snd_ctl_card_info(handle, info);
1388 sprintf(message, "RtAudio: ALSA control hardware info (%i): %s.", card, snd_strerror(result));
1389 error(RtError::DEBUG_WARNING);
1392 cardId = snd_ctl_card_info_get_id(info);
1395 result = snd_ctl_pcm_next_device(handle, &device);
1397 sprintf(message, "RtAudio: ALSA control next device (%i): %s.", card, snd_strerror(result));
1398 error(RtError::DEBUG_WARNING);
1403 if ( strlen(cardId) )
1404 sprintf( deviceNames[nDevices++], "hw:%s,%d", cardId, device );
1406 sprintf( deviceNames[nDevices++], "hw:%d,%d", card, device );
1407 if ( nDevices > MAX_DEVICES ) break;
1409 if ( nDevices > MAX_DEVICES ) break;
1411 snd_ctl_close(handle);
1412 snd_card_next(&card);
1415 if (nDevices == 0) return;
1417 // Allocate the RTAUDIO_DEVICE structures.
1418 devices = (RTAUDIO_DEVICE *) calloc(nDevices, sizeof(RTAUDIO_DEVICE));
1419 if (devices == NULL) {
1420 sprintf(message, "RtAudio: memory allocation error!");
1421 error(RtError::MEMORY_ERROR);
1424 // Write device ascii identifiers to device structures and then
1425 // probe the device capabilities.
1426 for (int i=0; i<nDevices; i++) {
1427 strncpy(devices[i].name, deviceNames[i], 32);
1428 //probeDeviceInfo(&devices[i]);
1432 int RtAudio :: getDefaultInputDevice(void)
1434 // No ALSA API functions for default devices.
1438 int RtAudio :: getDefaultOutputDevice(void)
1440 // No ALSA API functions for default devices.
1444 void RtAudio :: probeDeviceInfo(RTAUDIO_DEVICE *info)
1447 int open_mode = SND_PCM_ASYNC;
1450 snd_pcm_stream_t stream;
1451 snd_pcm_info_t *pcminfo;
1452 snd_pcm_info_alloca(&pcminfo);
1453 snd_pcm_hw_params_t *params;
1454 snd_pcm_hw_params_alloca(¶ms);
1458 // Open the control interface for this card.
1459 strncpy( name, info->name, 32 );
1460 card = strtok(name, ",");
1461 err = snd_ctl_open(&chandle, card, 0);
1463 sprintf(message, "RtAudio: ALSA control open (%s): %s.", card, snd_strerror(err));
1464 error(RtError::DEBUG_WARNING);
1467 unsigned int dev = (unsigned int) atoi( strtok(NULL, ",") );
1469 // First try for playback
1470 stream = SND_PCM_STREAM_PLAYBACK;
1471 snd_pcm_info_set_device(pcminfo, dev);
1472 snd_pcm_info_set_subdevice(pcminfo, 0);
1473 snd_pcm_info_set_stream(pcminfo, stream);
1475 if ((err = snd_ctl_pcm_info(chandle, pcminfo)) < 0) {
1476 if (err == -ENOENT) {
1477 sprintf(message, "RtAudio: ALSA pcm device (%s) doesn't handle output!", info->name);
1478 error(RtError::DEBUG_WARNING);
1481 sprintf(message, "RtAudio: ALSA snd_ctl_pcm_info error for device (%s) output: %s",
1482 info->name, snd_strerror(err));
1483 error(RtError::DEBUG_WARNING);
1488 err = snd_pcm_open(&handle, info->name, stream, open_mode | SND_PCM_NONBLOCK );
1491 sprintf(message, "RtAudio: ALSA pcm playback device (%s) is busy: %s.",
1492 info->name, snd_strerror(err));
1494 sprintf(message, "RtAudio: ALSA pcm playback open (%s) error: %s.",
1495 info->name, snd_strerror(err));
1496 error(RtError::DEBUG_WARNING);
1500 // We have an open device ... allocate the parameter structure.
1501 err = snd_pcm_hw_params_any(handle, params);
1503 snd_pcm_close(handle);
1504 sprintf(message, "RtAudio: ALSA hardware probe error (%s): %s.",
1505 info->name, snd_strerror(err));
1506 error(RtError::WARNING);
1510 // Get output channel information.
1511 info->minOutputChannels = snd_pcm_hw_params_get_channels_min(params);
1512 info->maxOutputChannels = snd_pcm_hw_params_get_channels_max(params);
1514 snd_pcm_close(handle);
1517 // Now try for capture
1518 stream = SND_PCM_STREAM_CAPTURE;
1519 snd_pcm_info_set_stream(pcminfo, stream);
1521 err = snd_ctl_pcm_info(chandle, pcminfo);
1522 snd_ctl_close(chandle);
1524 if (err == -ENOENT) {
1525 sprintf(message, "RtAudio: ALSA pcm device (%s) doesn't handle input!", info->name);
1526 error(RtError::DEBUG_WARNING);
1529 sprintf(message, "RtAudio: ALSA snd_ctl_pcm_info error for device (%s) input: %s",
1530 info->name, snd_strerror(err));
1531 error(RtError::DEBUG_WARNING);
1533 if (info->maxOutputChannels == 0)
1534 // didn't open for playback either ... device invalid
1536 goto probe_parameters;
1539 err = snd_pcm_open(&handle, info->name, stream, open_mode | SND_PCM_NONBLOCK);
1542 sprintf(message, "RtAudio: ALSA pcm capture device (%s) is busy: %s.",
1543 info->name, snd_strerror(err));
1545 sprintf(message, "RtAudio: ALSA pcm capture open (%s) error: %s.",
1546 info->name, snd_strerror(err));
1547 error(RtError::DEBUG_WARNING);
1548 if (info->maxOutputChannels == 0)
1549 // didn't open for playback either ... device invalid
1551 goto probe_parameters;
1554 // We have an open capture device ... allocate the parameter structure.
1555 err = snd_pcm_hw_params_any(handle, params);
1557 snd_pcm_close(handle);
1558 sprintf(message, "RtAudio: ALSA hardware probe error (%s): %s.",
1559 info->name, snd_strerror(err));
1560 error(RtError::WARNING);
1561 if (info->maxOutputChannels > 0)
1562 goto probe_parameters;
1567 // Get input channel information.
1568 info->minInputChannels = snd_pcm_hw_params_get_channels_min(params);
1569 info->maxInputChannels = snd_pcm_hw_params_get_channels_max(params);
1571 snd_pcm_close(handle);
1573 // If device opens for both playback and capture, we determine the channels.
1574 if (info->maxOutputChannels == 0 || info->maxInputChannels == 0)
1575 goto probe_parameters;
1577 info->hasDuplexSupport = true;
1578 info->maxDuplexChannels = (info->maxOutputChannels > info->maxInputChannels) ?
1579 info->maxInputChannels : info->maxOutputChannels;
1580 info->minDuplexChannels = (info->minOutputChannels > info->minInputChannels) ?
1581 info->minInputChannels : info->minOutputChannels;
1584 // At this point, we just need to figure out the supported data
1585 // formats and sample rates. We'll proceed by opening the device in
1586 // the direction with the maximum number of channels, or playback if
1587 // they are equal. This might limit our sample rate options, but so
1590 if (info->maxOutputChannels >= info->maxInputChannels)
1591 stream = SND_PCM_STREAM_PLAYBACK;
1593 stream = SND_PCM_STREAM_CAPTURE;
1595 err = snd_pcm_open(&handle, info->name, stream, open_mode);
1597 sprintf(message, "RtAudio: ALSA pcm (%s) won't reopen during probe: %s.",
1598 info->name, snd_strerror(err));
1599 error(RtError::WARNING);
1603 // We have an open device ... allocate the parameter structure.
1604 err = snd_pcm_hw_params_any(handle, params);
1606 snd_pcm_close(handle);
1607 sprintf(message, "RtAudio: ALSA hardware reopen probe error (%s): %s.",
1608 info->name, snd_strerror(err));
1609 error(RtError::WARNING);
1613 // Test a non-standard sample rate to see if continuous rate is supported.
1615 if (snd_pcm_hw_params_test_rate(handle, params, 35500, dir) == 0) {
1616 // It appears that continuous sample rate support is available.
1617 info->nSampleRates = -1;
1618 info->sampleRates[0] = snd_pcm_hw_params_get_rate_min(params, &dir);
1619 info->sampleRates[1] = snd_pcm_hw_params_get_rate_max(params, &dir);
1622 // No continuous rate support ... test our discrete set of sample rate values.
1623 info->nSampleRates = 0;
1624 for (int i=0; i<MAX_SAMPLE_RATES; i++) {
1625 if (snd_pcm_hw_params_test_rate(handle, params, SAMPLE_RATES[i], dir) == 0) {
1626 info->sampleRates[info->nSampleRates] = SAMPLE_RATES[i];
1627 info->nSampleRates++;
1630 if (info->nSampleRates == 0) {
1631 snd_pcm_close(handle);
1636 // Probe the supported data formats ... we don't care about endian-ness just yet
1637 snd_pcm_format_t format;
1638 info->nativeFormats = 0;
1639 format = SND_PCM_FORMAT_S8;
1640 if (snd_pcm_hw_params_test_format(handle, params, format) == 0)
1641 info->nativeFormats |= RTAUDIO_SINT8;
1642 format = SND_PCM_FORMAT_S16;
1643 if (snd_pcm_hw_params_test_format(handle, params, format) == 0)
1644 info->nativeFormats |= RTAUDIO_SINT16;
1645 format = SND_PCM_FORMAT_S24;
1646 if (snd_pcm_hw_params_test_format(handle, params, format) == 0)
1647 info->nativeFormats |= RTAUDIO_SINT24;
1648 format = SND_PCM_FORMAT_S32;
1649 if (snd_pcm_hw_params_test_format(handle, params, format) == 0)
1650 info->nativeFormats |= RTAUDIO_SINT32;
1651 format = SND_PCM_FORMAT_FLOAT;
1652 if (snd_pcm_hw_params_test_format(handle, params, format) == 0)
1653 info->nativeFormats |= RTAUDIO_FLOAT32;
1654 format = SND_PCM_FORMAT_FLOAT64;
1655 if (snd_pcm_hw_params_test_format(handle, params, format) == 0)
1656 info->nativeFormats |= RTAUDIO_FLOAT64;
1658 // Check that we have at least one supported format
1659 if (info->nativeFormats == 0) {
1660 snd_pcm_close(handle);
1661 sprintf(message, "RtAudio: ALSA PCM device (%s) data format not supported by RtAudio.",
1663 error(RtError::WARNING);
1667 // That's all ... close the device and return
1668 snd_pcm_close(handle);
1669 info->probed = true;
1673 bool RtAudio :: probeDeviceOpen(int device, RTAUDIO_STREAM *stream,
1674 STREAM_MODE mode, int channels,
1675 int sampleRate, RTAUDIO_FORMAT format,
1676 int *bufferSize, int numberOfBuffers)
1678 #if defined(__RTAUDIO_DEBUG__)
1680 snd_output_stdio_attach(&out, stderr, 0);
1683 // I'm not using the "plug" interface ... too much inconsistent behavior.
1684 const char *name = devices[device].name;
1686 snd_pcm_stream_t alsa_stream;
1688 alsa_stream = SND_PCM_STREAM_PLAYBACK;
1690 alsa_stream = SND_PCM_STREAM_CAPTURE;
1694 int alsa_open_mode = SND_PCM_ASYNC;
1695 err = snd_pcm_open(&handle, name, alsa_stream, alsa_open_mode);
1697 sprintf(message,"RtAudio: ALSA pcm device (%s) won't open: %s.",
1698 name, snd_strerror(err));
1699 error(RtError::WARNING);
1703 // Fill the parameter structure.
1704 snd_pcm_hw_params_t *hw_params;
1705 snd_pcm_hw_params_alloca(&hw_params);
1706 err = snd_pcm_hw_params_any(handle, hw_params);
1708 snd_pcm_close(handle);
1709 sprintf(message, "RtAudio: ALSA error getting parameter handle (%s): %s.",
1710 name, snd_strerror(err));
1711 error(RtError::WARNING);
1715 #if defined(__RTAUDIO_DEBUG__)
1716 fprintf(stderr, "\nRtAudio: ALSA dump hardware params just after device open:\n\n");
1717 snd_pcm_hw_params_dump(hw_params, out);
1721 // Set access ... try interleaved access first, then non-interleaved
1722 if ( !snd_pcm_hw_params_test_access( handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED) ) {
1723 err = snd_pcm_hw_params_set_access(handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED);
1725 else if ( !snd_pcm_hw_params_test_access( handle, hw_params, SND_PCM_ACCESS_RW_NONINTERLEAVED) ) {
1726 err = snd_pcm_hw_params_set_access(handle, hw_params, SND_PCM_ACCESS_RW_NONINTERLEAVED);
1727 stream->deInterleave[mode] = true;
1730 snd_pcm_close(handle);
1731 sprintf(message, "RtAudio: ALSA device (%s) access not supported by RtAudio.", name);
1732 error(RtError::WARNING);
1737 snd_pcm_close(handle);
1738 sprintf(message, "RtAudio: ALSA error setting access ( (%s): %s.", name, snd_strerror(err));
1739 error(RtError::WARNING);
1743 // Determine how to set the device format.
1744 stream->userFormat = format;
1745 snd_pcm_format_t device_format;
1747 if (format == RTAUDIO_SINT8)
1748 device_format = SND_PCM_FORMAT_S8;
1749 else if (format == RTAUDIO_SINT16)
1750 device_format = SND_PCM_FORMAT_S16;
1751 else if (format == RTAUDIO_SINT24)
1752 device_format = SND_PCM_FORMAT_S24;
1753 else if (format == RTAUDIO_SINT32)
1754 device_format = SND_PCM_FORMAT_S32;
1755 else if (format == RTAUDIO_FLOAT32)
1756 device_format = SND_PCM_FORMAT_FLOAT;
1757 else if (format == RTAUDIO_FLOAT64)
1758 device_format = SND_PCM_FORMAT_FLOAT64;
1760 if (snd_pcm_hw_params_test_format(handle, hw_params, device_format) == 0) {
1761 stream->deviceFormat[mode] = format;
1765 // The user requested format is not natively supported by the device.
1766 device_format = SND_PCM_FORMAT_FLOAT64;
1767 if (snd_pcm_hw_params_test_format(handle, hw_params, device_format) == 0) {
1768 stream->deviceFormat[mode] = RTAUDIO_FLOAT64;
1772 device_format = SND_PCM_FORMAT_FLOAT;
1773 if (snd_pcm_hw_params_test_format(handle, hw_params, device_format) == 0) {
1774 stream->deviceFormat[mode] = RTAUDIO_FLOAT32;
1778 device_format = SND_PCM_FORMAT_S32;
1779 if (snd_pcm_hw_params_test_format(handle, hw_params, device_format) == 0) {
1780 stream->deviceFormat[mode] = RTAUDIO_SINT32;
1784 device_format = SND_PCM_FORMAT_S24;
1785 if (snd_pcm_hw_params_test_format(handle, hw_params, device_format) == 0) {
1786 stream->deviceFormat[mode] = RTAUDIO_SINT24;
1790 device_format = SND_PCM_FORMAT_S16;
1791 if (snd_pcm_hw_params_test_format(handle, hw_params, device_format) == 0) {
1792 stream->deviceFormat[mode] = RTAUDIO_SINT16;
1796 device_format = SND_PCM_FORMAT_S8;
1797 if (snd_pcm_hw_params_test_format(handle, hw_params, device_format) == 0) {
1798 stream->deviceFormat[mode] = RTAUDIO_SINT8;
1802 // If we get here, no supported format was found.
1803 sprintf(message,"RtAudio: ALSA pcm device (%s) data format not supported by RtAudio.", name);
1804 snd_pcm_close(handle);
1805 error(RtError::WARNING);
1809 err = snd_pcm_hw_params_set_format(handle, hw_params, device_format);
1811 snd_pcm_close(handle);
1812 sprintf(message, "RtAudio: ALSA error setting format (%s): %s.",
1813 name, snd_strerror(err));
1814 error(RtError::WARNING);
1818 // Determine whether byte-swaping is necessary.
1819 stream->doByteSwap[mode] = false;
1820 if (device_format != SND_PCM_FORMAT_S8) {
1821 err = snd_pcm_format_cpu_endian(device_format);
1823 stream->doByteSwap[mode] = true;
1825 snd_pcm_close(handle);
1826 sprintf(message, "RtAudio: ALSA error getting format endian-ness (%s): %s.",
1827 name, snd_strerror(err));
1828 error(RtError::WARNING);
1833 // Set the sample rate.
1834 err = snd_pcm_hw_params_set_rate(handle, hw_params, (unsigned int)sampleRate, 0);
1836 snd_pcm_close(handle);
1837 sprintf(message, "RtAudio: ALSA error setting sample rate (%d) on device (%s): %s.",
1838 sampleRate, name, snd_strerror(err));
1839 error(RtError::WARNING);
1843 // Determine the number of channels for this device. We support a possible
1844 // minimum device channel number > than the value requested by the user.
1845 stream->nUserChannels[mode] = channels;
1846 int device_channels = snd_pcm_hw_params_get_channels_max(hw_params);
1847 if (device_channels < channels) {
1848 snd_pcm_close(handle);
1849 sprintf(message, "RtAudio: channels (%d) not supported by device (%s).",
1851 error(RtError::WARNING);
1855 device_channels = snd_pcm_hw_params_get_channels_min(hw_params);
1856 if (device_channels < channels) device_channels = channels;
1857 stream->nDeviceChannels[mode] = device_channels;
1859 // Set the device channels.
1860 err = snd_pcm_hw_params_set_channels(handle, hw_params, device_channels);
1862 snd_pcm_close(handle);
1863 sprintf(message, "RtAudio: ALSA error setting channels (%d) on device (%s): %s.",
1864 device_channels, name, snd_strerror(err));
1865 error(RtError::WARNING);
1869 // Set the buffer number, which in ALSA is referred to as the "period".
1871 int periods = numberOfBuffers;
1872 // Even though the hardware might allow 1 buffer, it won't work reliably.
1873 if (periods < 2) periods = 2;
1874 err = snd_pcm_hw_params_get_periods_min(hw_params, &dir);
1875 if (err > periods) periods = err;
1876 err = snd_pcm_hw_params_get_periods_max(hw_params, &dir);
1877 if (err < periods) periods = err;
1879 err = snd_pcm_hw_params_set_periods(handle, hw_params, periods, 0);
1881 snd_pcm_close(handle);
1882 sprintf(message, "RtAudio: ALSA error setting periods (%s): %s.",
1883 name, snd_strerror(err));
1884 error(RtError::WARNING);
1888 // Set the buffer (or period) size.
1889 err = snd_pcm_hw_params_get_period_size_min(hw_params, &dir);
1890 if (err > *bufferSize) *bufferSize = err;
1892 err = snd_pcm_hw_params_set_period_size(handle, hw_params, *bufferSize, 0);
1894 snd_pcm_close(handle);
1895 sprintf(message, "RtAudio: ALSA error setting period size (%s): %s.",
1896 name, snd_strerror(err));
1897 error(RtError::WARNING);
1901 // If attempting to setup a duplex stream, the bufferSize parameter
1902 // MUST be the same in both directions!
1903 if ( stream->mode == OUTPUT && mode == INPUT && *bufferSize != stream->bufferSize ) {
1904 sprintf( message, "RtAudio: ALSA error setting buffer size for duplex stream on device (%s).",
1906 error(RtError::DEBUG_WARNING);
1910 stream->bufferSize = *bufferSize;
1912 // Install the hardware configuration
1913 err = snd_pcm_hw_params(handle, hw_params);
1915 snd_pcm_close(handle);
1916 sprintf(message, "RtAudio: ALSA error installing hardware configuration (%s): %s.",
1917 name, snd_strerror(err));
1918 error(RtError::WARNING);
1922 #if defined(__RTAUDIO_DEBUG__)
1923 fprintf(stderr, "\nRtAudio: ALSA dump hardware params after installation:\n\n");
1924 snd_pcm_hw_params_dump(hw_params, out);
1928 // Install the software configuration
1929 snd_pcm_sw_params_t *sw_params = NULL;
1930 snd_pcm_sw_params_alloca(&sw_params);
1931 snd_pcm_sw_params_current(handle, sw_params);
1932 err = snd_pcm_sw_params(handle, sw_params);
1934 snd_pcm_close(handle);
1935 sprintf(message, "RtAudio: ALSA error installing software configuration (%s): %s.",
1936 name, snd_strerror(err));
1937 error(RtError::WARNING);
1942 // Set handle and flags for buffer conversion
1943 stream->handle[mode] = handle;
1944 stream->doConvertBuffer[mode] = false;
1945 if (stream->userFormat != stream->deviceFormat[mode])
1946 stream->doConvertBuffer[mode] = true;
1947 if (stream->nUserChannels[mode] < stream->nDeviceChannels[mode])
1948 stream->doConvertBuffer[mode] = true;
1949 if (stream->nUserChannels[mode] > 1 && stream->deInterleave[mode])
1950 stream->doConvertBuffer[mode] = true;
1952 // Allocate necessary internal buffers
1953 if ( stream->nUserChannels[0] != stream->nUserChannels[1] ) {
1956 if (stream->nUserChannels[0] >= stream->nUserChannels[1])
1957 buffer_bytes = stream->nUserChannels[0];
1959 buffer_bytes = stream->nUserChannels[1];
1961 buffer_bytes *= *bufferSize * formatBytes(stream->userFormat);
1962 if (stream->userBuffer) free(stream->userBuffer);
1963 stream->userBuffer = (char *) calloc(buffer_bytes, 1);
1964 if (stream->userBuffer == NULL)
1968 if ( stream->doConvertBuffer[mode] ) {
1971 bool makeBuffer = true;
1972 if ( mode == OUTPUT )
1973 buffer_bytes = stream->nDeviceChannels[0] * formatBytes(stream->deviceFormat[0]);
1974 else { // mode == INPUT
1975 buffer_bytes = stream->nDeviceChannels[1] * formatBytes(stream->deviceFormat[1]);
1976 if ( stream->mode == OUTPUT && stream->deviceBuffer ) {
1977 long bytes_out = stream->nDeviceChannels[0] * formatBytes(stream->deviceFormat[0]);
1978 if ( buffer_bytes < bytes_out ) makeBuffer = false;
1983 buffer_bytes *= *bufferSize;
1984 if (stream->deviceBuffer) free(stream->deviceBuffer);
1985 stream->deviceBuffer = (char *) calloc(buffer_bytes, 1);
1986 if (stream->deviceBuffer == NULL)
1991 stream->device[mode] = device;
1992 stream->state = STREAM_STOPPED;
1993 if ( stream->mode == OUTPUT && mode == INPUT )
1994 // We had already set up an output stream.
1995 stream->mode = DUPLEX;
1997 stream->mode = mode;
1998 stream->nBuffers = periods;
1999 stream->sampleRate = sampleRate;
2004 if (stream->handle[0]) {
2005 snd_pcm_close(stream->handle[0]);
2006 stream->handle[0] = 0;
2008 if (stream->handle[1]) {
2009 snd_pcm_close(stream->handle[1]);
2010 stream->handle[1] = 0;
2012 if (stream->userBuffer) {
2013 free(stream->userBuffer);
2014 stream->userBuffer = 0;
2016 sprintf(message, "RtAudio: ALSA error allocating buffer memory (%s).", name);
2017 error(RtError::WARNING);
2021 void RtAudio :: closeStream(int streamId)
2023 // We don't want an exception to be thrown here because this
2024 // function is called by our class destructor. So, do our own
2026 if ( streams.find( streamId ) == streams.end() ) {
2027 sprintf(message, "RtAudio: invalid stream identifier!");
2028 error(RtError::WARNING);
2032 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) streams[streamId];
2034 if (stream->callbackInfo.usingCallback) {
2035 pthread_cancel(stream->callbackInfo.thread);
2036 pthread_join(stream->callbackInfo.thread, NULL);
2039 if (stream->state == STREAM_RUNNING) {
2040 if (stream->mode == OUTPUT || stream->mode == DUPLEX)
2041 snd_pcm_drop(stream->handle[0]);
2042 if (stream->mode == INPUT || stream->mode == DUPLEX)
2043 snd_pcm_drop(stream->handle[1]);
2046 pthread_mutex_destroy(&stream->mutex);
2048 if (stream->handle[0])
2049 snd_pcm_close(stream->handle[0]);
2051 if (stream->handle[1])
2052 snd_pcm_close(stream->handle[1]);
2054 if (stream->userBuffer)
2055 free(stream->userBuffer);
2057 if (stream->deviceBuffer)
2058 free(stream->deviceBuffer);
2061 streams.erase(streamId);
2064 void RtAudio :: startStream(int streamId)
2066 // This method calls snd_pcm_prepare if the device isn't already in that state.
2068 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
2070 MUTEX_LOCK(&stream->mutex);
2072 if (stream->state == STREAM_RUNNING)
2076 snd_pcm_state_t state;
2077 if (stream->mode == OUTPUT || stream->mode == DUPLEX) {
2078 state = snd_pcm_state(stream->handle[0]);
2079 if (state != SND_PCM_STATE_PREPARED) {
2080 err = snd_pcm_prepare(stream->handle[0]);
2082 sprintf(message, "RtAudio: ALSA error preparing pcm device (%s): %s.",
2083 devices[stream->device[0]].name, snd_strerror(err));
2084 MUTEX_UNLOCK(&stream->mutex);
2085 error(RtError::DRIVER_ERROR);
2090 if (stream->mode == INPUT || stream->mode == DUPLEX) {
2091 state = snd_pcm_state(stream->handle[1]);
2092 if (state != SND_PCM_STATE_PREPARED) {
2093 err = snd_pcm_prepare(stream->handle[1]);
2095 sprintf(message, "RtAudio: ALSA error preparing pcm device (%s): %s.",
2096 devices[stream->device[1]].name, snd_strerror(err));
2097 MUTEX_UNLOCK(&stream->mutex);
2098 error(RtError::DRIVER_ERROR);
2102 stream->state = STREAM_RUNNING;
2105 MUTEX_UNLOCK(&stream->mutex);
2108 void RtAudio :: stopStream(int streamId)
2110 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
2112 MUTEX_LOCK(&stream->mutex);
2114 if (stream->state == STREAM_STOPPED)
2118 if (stream->mode == OUTPUT || stream->mode == DUPLEX) {
2119 err = snd_pcm_drain(stream->handle[0]);
2121 sprintf(message, "RtAudio: ALSA error draining pcm device (%s): %s.",
2122 devices[stream->device[0]].name, snd_strerror(err));
2123 MUTEX_UNLOCK(&stream->mutex);
2124 error(RtError::DRIVER_ERROR);
2128 if (stream->mode == INPUT || stream->mode == DUPLEX) {
2129 err = snd_pcm_drain(stream->handle[1]);
2131 sprintf(message, "RtAudio: ALSA error draining pcm device (%s): %s.",
2132 devices[stream->device[1]].name, snd_strerror(err));
2133 MUTEX_UNLOCK(&stream->mutex);
2134 error(RtError::DRIVER_ERROR);
2137 stream->state = STREAM_STOPPED;
2140 MUTEX_UNLOCK(&stream->mutex);
2143 void RtAudio :: abortStream(int streamId)
2145 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
2147 MUTEX_LOCK(&stream->mutex);
2149 if (stream->state == STREAM_STOPPED)
2153 if (stream->mode == OUTPUT || stream->mode == DUPLEX) {
2154 err = snd_pcm_drop(stream->handle[0]);
2156 sprintf(message, "RtAudio: ALSA error draining pcm device (%s): %s.",
2157 devices[stream->device[0]].name, snd_strerror(err));
2158 MUTEX_UNLOCK(&stream->mutex);
2159 error(RtError::DRIVER_ERROR);
2163 if (stream->mode == INPUT || stream->mode == DUPLEX) {
2164 err = snd_pcm_drop(stream->handle[1]);
2166 sprintf(message, "RtAudio: ALSA error draining pcm device (%s): %s.",
2167 devices[stream->device[1]].name, snd_strerror(err));
2168 MUTEX_UNLOCK(&stream->mutex);
2169 error(RtError::DRIVER_ERROR);
2172 stream->state = STREAM_STOPPED;
2175 MUTEX_UNLOCK(&stream->mutex);
2178 int RtAudio :: streamWillBlock(int streamId)
2180 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
2182 MUTEX_LOCK(&stream->mutex);
2184 int err = 0, frames = 0;
2185 if (stream->state == STREAM_STOPPED)
2188 if (stream->mode == OUTPUT || stream->mode == DUPLEX) {
2189 err = snd_pcm_avail_update(stream->handle[0]);
2191 sprintf(message, "RtAudio: ALSA error getting available frames for device (%s): %s.",
2192 devices[stream->device[0]].name, snd_strerror(err));
2193 MUTEX_UNLOCK(&stream->mutex);
2194 error(RtError::DRIVER_ERROR);
2200 if (stream->mode == INPUT || stream->mode == DUPLEX) {
2201 err = snd_pcm_avail_update(stream->handle[1]);
2203 sprintf(message, "RtAudio: ALSA error getting available frames for device (%s): %s.",
2204 devices[stream->device[1]].name, snd_strerror(err));
2205 MUTEX_UNLOCK(&stream->mutex);
2206 error(RtError::DRIVER_ERROR);
2208 if (frames > err) frames = err;
2211 frames = stream->bufferSize - frames;
2212 if (frames < 0) frames = 0;
2215 MUTEX_UNLOCK(&stream->mutex);
2219 void RtAudio :: tickStream(int streamId)
2221 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
2224 if (stream->state == STREAM_STOPPED) {
2225 if (stream->callbackInfo.usingCallback) usleep(50000); // sleep 50 milliseconds
2228 else if (stream->callbackInfo.usingCallback) {
2229 RTAUDIO_CALLBACK callback = (RTAUDIO_CALLBACK) stream->callbackInfo.callback;
2230 stopStream = callback(stream->userBuffer, stream->bufferSize, stream->callbackInfo.userData);
2233 MUTEX_LOCK(&stream->mutex);
2235 // The state might change while waiting on a mutex.
2236 if (stream->state == STREAM_STOPPED)
2242 RTAUDIO_FORMAT format;
2243 if (stream->mode == OUTPUT || stream->mode == DUPLEX) {
2245 // Setup parameters and do buffer conversion if necessary.
2246 if (stream->doConvertBuffer[0]) {
2247 convertStreamBuffer(stream, OUTPUT);
2248 buffer = stream->deviceBuffer;
2249 channels = stream->nDeviceChannels[0];
2250 format = stream->deviceFormat[0];
2253 buffer = stream->userBuffer;
2254 channels = stream->nUserChannels[0];
2255 format = stream->userFormat;
2258 // Do byte swapping if necessary.
2259 if (stream->doByteSwap[0])
2260 byteSwapBuffer(buffer, stream->bufferSize * channels, format);
2262 // Write samples to device in interleaved/non-interleaved format.
2263 if (stream->deInterleave[0]) {
2264 void *bufs[channels];
2265 size_t offset = stream->bufferSize * formatBytes(format);
2266 for (int i=0; i<channels; i++)
2267 bufs[i] = (void *) (buffer + (i * offset));
2268 err = snd_pcm_writen(stream->handle[0], bufs, stream->bufferSize);
2271 err = snd_pcm_writei(stream->handle[0], buffer, stream->bufferSize);
2273 if (err < stream->bufferSize) {
2274 // Either an error or underrun occured.
2275 if (err == -EPIPE) {
2276 snd_pcm_state_t state = snd_pcm_state(stream->handle[0]);
2277 if (state == SND_PCM_STATE_XRUN) {
2278 sprintf(message, "RtAudio: ALSA underrun detected.");
2279 error(RtError::WARNING);
2280 err = snd_pcm_prepare(stream->handle[0]);
2282 sprintf(message, "RtAudio: ALSA error preparing handle after underrun: %s.",
2284 MUTEX_UNLOCK(&stream->mutex);
2285 error(RtError::DRIVER_ERROR);
2289 sprintf(message, "RtAudio: ALSA error, current state is %s.",
2290 snd_pcm_state_name(state));
2291 MUTEX_UNLOCK(&stream->mutex);
2292 error(RtError::DRIVER_ERROR);
2297 sprintf(message, "RtAudio: ALSA audio write error for device (%s): %s.",
2298 devices[stream->device[0]].name, snd_strerror(err));
2299 MUTEX_UNLOCK(&stream->mutex);
2300 error(RtError::DRIVER_ERROR);
2305 if (stream->mode == INPUT || stream->mode == DUPLEX) {
2307 // Setup parameters.
2308 if (stream->doConvertBuffer[1]) {
2309 buffer = stream->deviceBuffer;
2310 channels = stream->nDeviceChannels[1];
2311 format = stream->deviceFormat[1];
2314 buffer = stream->userBuffer;
2315 channels = stream->nUserChannels[1];
2316 format = stream->userFormat;
2319 // Read samples from device in interleaved/non-interleaved format.
2320 if (stream->deInterleave[1]) {
2321 void *bufs[channels];
2322 size_t offset = stream->bufferSize * formatBytes(format);
2323 for (int i=0; i<channels; i++)
2324 bufs[i] = (void *) (buffer + (i * offset));
2325 err = snd_pcm_readn(stream->handle[1], bufs, stream->bufferSize);
2328 err = snd_pcm_readi(stream->handle[1], buffer, stream->bufferSize);
2330 if (err < stream->bufferSize) {
2331 // Either an error or underrun occured.
2332 if (err == -EPIPE) {
2333 snd_pcm_state_t state = snd_pcm_state(stream->handle[1]);
2334 if (state == SND_PCM_STATE_XRUN) {
2335 sprintf(message, "RtAudio: ALSA overrun detected.");
2336 error(RtError::WARNING);
2337 err = snd_pcm_prepare(stream->handle[1]);
2339 sprintf(message, "RtAudio: ALSA error preparing handle after overrun: %s.",
2341 MUTEX_UNLOCK(&stream->mutex);
2342 error(RtError::DRIVER_ERROR);
2346 sprintf(message, "RtAudio: ALSA error, current state is %s.",
2347 snd_pcm_state_name(state));
2348 MUTEX_UNLOCK(&stream->mutex);
2349 error(RtError::DRIVER_ERROR);
2354 sprintf(message, "RtAudio: ALSA audio read error for device (%s): %s.",
2355 devices[stream->device[1]].name, snd_strerror(err));
2356 MUTEX_UNLOCK(&stream->mutex);
2357 error(RtError::DRIVER_ERROR);
2361 // Do byte swapping if necessary.
2362 if (stream->doByteSwap[1])
2363 byteSwapBuffer(buffer, stream->bufferSize * channels, format);
2365 // Do buffer conversion if necessary.
2366 if (stream->doConvertBuffer[1])
2367 convertStreamBuffer(stream, INPUT);
2371 MUTEX_UNLOCK(&stream->mutex);
2373 if (stream->callbackInfo.usingCallback && stopStream)
2374 this->stopStream(streamId);
2377 extern "C" void *callbackHandler(void *ptr)
2379 CALLBACK_INFO *info = (CALLBACK_INFO *) ptr;
2380 RtAudio *object = (RtAudio *) info->object;
2381 int stream = info->streamId;
2382 bool *usingCallback = &info->usingCallback;
2384 while ( *usingCallback ) {
2385 pthread_testcancel();
2387 object->tickStream(stream);
2389 catch (RtError &exception) {
2390 fprintf(stderr, "\nRtAudio: Callback thread error (%s) ... closing thread.\n\n",
2391 exception.getMessage());
2399 //******************** End of __LINUX_ALSA__ *********************//
2401 #elif defined(__LINUX_OSS__)
2403 #include <sys/stat.h>
2404 #include <sys/types.h>
2405 #include <sys/ioctl.h>
2408 #include <sys/soundcard.h>
2412 #define DAC_NAME "/dev/dsp"
2413 #define MAX_DEVICES 16
2414 #define MAX_CHANNELS 16
2416 void RtAudio :: initialize(void)
2418 // Count cards and devices
2421 // We check /dev/dsp before probing devices. /dev/dsp is supposed to
2422 // be a link to the "default" audio device, of the form /dev/dsp0,
2423 // /dev/dsp1, etc... However, I've seen many cases where /dev/dsp was a
2424 // real device, so we need to check for that. Also, sometimes the
2425 // link is to /dev/dspx and other times just dspx. I'm not sure how
2426 // the latter works, but it does.
2427 char device_name[16];
2428 struct stat dspstat;
2431 if (lstat(DAC_NAME, &dspstat) == 0) {
2432 if (S_ISLNK(dspstat.st_mode)) {
2433 i = readlink(DAC_NAME, device_name, sizeof(device_name));
2435 device_name[i] = '\0';
2436 if (i > 8) { // check for "/dev/dspx"
2437 if (!strncmp(DAC_NAME, device_name, 8))
2438 dsplink = atoi(&device_name[8]);
2440 else if (i > 3) { // check for "dspx"
2441 if (!strncmp("dsp", device_name, 3))
2442 dsplink = atoi(&device_name[3]);
2446 sprintf(message, "RtAudio: cannot read value of symbolic link %s.", DAC_NAME);
2447 error(RtError::SYSTEM_ERROR);
2452 sprintf(message, "RtAudio: cannot stat %s.", DAC_NAME);
2453 error(RtError::SYSTEM_ERROR);
2456 // The OSS API doesn't provide a routine for determining the number
2457 // of devices. Thus, we'll just pursue a brute force method. The
2458 // idea is to start with /dev/dsp(0) and continue with higher device
2459 // numbers until we reach MAX_DSP_DEVICES. This should tell us how
2460 // many devices we have ... it is not a fullproof scheme, but hopefully
2461 // it will work most of the time.
2464 char names[MAX_DEVICES][16];
2465 for (i=-1; i<MAX_DEVICES; i++) {
2467 // Probe /dev/dsp first, since it is supposed to be the default device.
2469 sprintf(device_name, "%s", DAC_NAME);
2470 else if (i == dsplink)
2471 continue; // We've aready probed this device via /dev/dsp link ... try next device.
2473 sprintf(device_name, "%s%d", DAC_NAME, i);
2475 // First try to open the device for playback, then record mode.
2476 fd = open(device_name, O_WRONLY | O_NONBLOCK);
2478 // Open device for playback failed ... either busy or doesn't exist.
2479 if (errno != EBUSY && errno != EAGAIN) {
2480 // Try to open for capture
2481 fd = open(device_name, O_RDONLY | O_NONBLOCK);
2483 // Open device for record failed.
2484 if (errno != EBUSY && errno != EAGAIN)
2487 sprintf(message, "RtAudio: OSS record device (%s) is busy.", device_name);
2488 error(RtError::WARNING);
2489 // still count it for now
2494 sprintf(message, "RtAudio: OSS playback device (%s) is busy.", device_name);
2495 error(RtError::WARNING);
2496 // still count it for now
2500 if (fd >= 0) close(fd);
2501 strncpy(names[nDevices], device_name, 16);
2505 if (nDevices == 0) return;
2507 // Allocate the RTAUDIO_DEVICE structures.
2508 devices = (RTAUDIO_DEVICE *) calloc(nDevices, sizeof(RTAUDIO_DEVICE));
2509 if (devices == NULL) {
2510 sprintf(message, "RtAudio: memory allocation error!");
2511 error(RtError::MEMORY_ERROR);
2514 // Write device ascii identifiers to device control structure and then probe capabilities.
2515 for (i=0; i<nDevices; i++) {
2516 strncpy(devices[i].name, names[i], 16);
2517 //probeDeviceInfo(&devices[i]);
2523 int RtAudio :: getDefaultInputDevice(void)
2525 // No OSS API functions for default devices.
2529 int RtAudio :: getDefaultOutputDevice(void)
2531 // No OSS API functions for default devices.
2535 void RtAudio :: probeDeviceInfo(RTAUDIO_DEVICE *info)
2537 int i, fd, channels, mask;
2539 // The OSS API doesn't provide a means for probing the capabilities
2540 // of devices. Thus, we'll just pursue a brute force method.
2542 // First try for playback
2543 fd = open(info->name, O_WRONLY | O_NONBLOCK);
2545 // Open device failed ... either busy or doesn't exist
2546 if (errno == EBUSY || errno == EAGAIN)
2547 sprintf(message, "RtAudio: OSS playback device (%s) is busy and cannot be probed.",
2550 sprintf(message, "RtAudio: OSS playback device (%s) open error.", info->name);
2551 error(RtError::DEBUG_WARNING);
2555 // We have an open device ... see how many channels it can handle
2556 for (i=MAX_CHANNELS; i>0; i--) {
2558 if (ioctl(fd, SNDCTL_DSP_CHANNELS, &channels) == -1) {
2559 // This would normally indicate some sort of hardware error, but under ALSA's
2560 // OSS emulation, it sometimes indicates an invalid channel value. Further,
2561 // the returned channel value is not changed. So, we'll ignore the possible
2563 continue; // try next channel number
2565 // Check to see whether the device supports the requested number of channels
2566 if (channels != i ) continue; // try next channel number
2567 // If here, we found the largest working channel value
2570 info->maxOutputChannels = i;
2572 // Now find the minimum number of channels it can handle
2573 for (i=1; i<=info->maxOutputChannels; i++) {
2575 if (ioctl(fd, SNDCTL_DSP_CHANNELS, &channels) == -1 || channels != i)
2576 continue; // try next channel number
2577 // If here, we found the smallest working channel value
2580 info->minOutputChannels = i;
2584 // Now try for capture
2585 fd = open(info->name, O_RDONLY | O_NONBLOCK);
2587 // Open device for capture failed ... either busy or doesn't exist
2588 if (errno == EBUSY || errno == EAGAIN)
2589 sprintf(message, "RtAudio: OSS capture device (%s) is busy and cannot be probed.",
2592 sprintf(message, "RtAudio: OSS capture device (%s) open error.", info->name);
2593 error(RtError::DEBUG_WARNING);
2594 if (info->maxOutputChannels == 0)
2595 // didn't open for playback either ... device invalid
2597 goto probe_parameters;
2600 // We have the device open for capture ... see how many channels it can handle
2601 for (i=MAX_CHANNELS; i>0; i--) {
2603 if (ioctl(fd, SNDCTL_DSP_CHANNELS, &channels) == -1 || channels != i) {
2604 continue; // as above
2606 // If here, we found a working channel value
2609 info->maxInputChannels = i;
2611 // Now find the minimum number of channels it can handle
2612 for (i=1; i<=info->maxInputChannels; i++) {
2614 if (ioctl(fd, SNDCTL_DSP_CHANNELS, &channels) == -1 || channels != i)
2615 continue; // try next channel number
2616 // If here, we found the smallest working channel value
2619 info->minInputChannels = i;
2622 if (info->maxOutputChannels == 0 && info->maxInputChannels == 0) {
2623 sprintf(message, "RtAudio: OSS device (%s) reports zero channels for input and output.",
2625 error(RtError::DEBUG_WARNING);
2629 // If device opens for both playback and capture, we determine the channels.
2630 if (info->maxOutputChannels == 0 || info->maxInputChannels == 0)
2631 goto probe_parameters;
2633 fd = open(info->name, O_RDWR | O_NONBLOCK);
2635 goto probe_parameters;
2637 ioctl(fd, SNDCTL_DSP_SETDUPLEX, 0);
2638 ioctl(fd, SNDCTL_DSP_GETCAPS, &mask);
2639 if (mask & DSP_CAP_DUPLEX) {
2640 info->hasDuplexSupport = true;
2641 // We have the device open for duplex ... see how many channels it can handle
2642 for (i=MAX_CHANNELS; i>0; i--) {
2644 if (ioctl(fd, SNDCTL_DSP_CHANNELS, &channels) == -1 || channels != i)
2645 continue; // as above
2646 // If here, we found a working channel value
2649 info->maxDuplexChannels = i;
2651 // Now find the minimum number of channels it can handle
2652 for (i=1; i<=info->maxDuplexChannels; i++) {
2654 if (ioctl(fd, SNDCTL_DSP_CHANNELS, &channels) == -1 || channels != i)
2655 continue; // try next channel number
2656 // If here, we found the smallest working channel value
2659 info->minDuplexChannels = i;
2664 // At this point, we need to figure out the supported data formats
2665 // and sample rates. We'll proceed by openning the device in the
2666 // direction with the maximum number of channels, or playback if
2667 // they are equal. This might limit our sample rate options, but so
2670 if (info->maxOutputChannels >= info->maxInputChannels) {
2671 fd = open(info->name, O_WRONLY | O_NONBLOCK);
2672 channels = info->maxOutputChannels;
2675 fd = open(info->name, O_RDONLY | O_NONBLOCK);
2676 channels = info->maxInputChannels;
2680 // We've got some sort of conflict ... abort
2681 sprintf(message, "RtAudio: OSS device (%s) won't reopen during probe.",
2683 error(RtError::DEBUG_WARNING);
2687 // We have an open device ... set to maximum channels.
2689 if (ioctl(fd, SNDCTL_DSP_CHANNELS, &channels) == -1 || channels != i) {
2690 // We've got some sort of conflict ... abort
2692 sprintf(message, "RtAudio: OSS device (%s) won't revert to previous channel setting.",
2694 error(RtError::DEBUG_WARNING);
2698 if (ioctl(fd, SNDCTL_DSP_GETFMTS, &mask) == -1) {
2700 sprintf(message, "RtAudio: OSS device (%s) can't get supported audio formats.",
2702 error(RtError::DEBUG_WARNING);
2706 // Probe the supported data formats ... we don't care about endian-ness just yet.
2708 info->nativeFormats = 0;
2709 #if defined (AFMT_S32_BE)
2710 // This format does not seem to be in the 2.4 kernel version of OSS soundcard.h
2711 if (mask & AFMT_S32_BE) {
2712 format = AFMT_S32_BE;
2713 info->nativeFormats |= RTAUDIO_SINT32;
2716 #if defined (AFMT_S32_LE)
2717 /* This format is not in the 2.4.4 kernel version of OSS soundcard.h */
2718 if (mask & AFMT_S32_LE) {
2719 format = AFMT_S32_LE;
2720 info->nativeFormats |= RTAUDIO_SINT32;
2723 if (mask & AFMT_S8) {
2725 info->nativeFormats |= RTAUDIO_SINT8;
2727 if (mask & AFMT_S16_BE) {
2728 format = AFMT_S16_BE;
2729 info->nativeFormats |= RTAUDIO_SINT16;
2731 if (mask & AFMT_S16_LE) {
2732 format = AFMT_S16_LE;
2733 info->nativeFormats |= RTAUDIO_SINT16;
2736 // Check that we have at least one supported format
2737 if (info->nativeFormats == 0) {
2739 sprintf(message, "RtAudio: OSS device (%s) data format not supported by RtAudio.",
2741 error(RtError::DEBUG_WARNING);
2747 if (ioctl(fd, SNDCTL_DSP_SETFMT, &format) == -1 || format != i) {
2749 sprintf(message, "RtAudio: OSS device (%s) error setting data format.",
2751 error(RtError::DEBUG_WARNING);
2755 // Probe the supported sample rates ... first get lower limit
2757 if (ioctl(fd, SNDCTL_DSP_SPEED, &speed) == -1) {
2758 // If we get here, we're probably using an ALSA driver with OSS-emulation,
2759 // which doesn't conform to the OSS specification. In this case,
2760 // we'll probe our predefined list of sample rates for working values.
2761 info->nSampleRates = 0;
2762 for (i=0; i<MAX_SAMPLE_RATES; i++) {
2763 speed = SAMPLE_RATES[i];
2764 if (ioctl(fd, SNDCTL_DSP_SPEED, &speed) != -1) {
2765 info->sampleRates[info->nSampleRates] = SAMPLE_RATES[i];
2766 info->nSampleRates++;
2769 if (info->nSampleRates == 0) {
2775 info->sampleRates[0] = speed;
2777 // Now get upper limit
2779 if (ioctl(fd, SNDCTL_DSP_SPEED, &speed) == -1) {
2781 sprintf(message, "RtAudio: OSS device (%s) error setting sample rate.",
2783 error(RtError::DEBUG_WARNING);
2786 info->sampleRates[1] = speed;
2787 info->nSampleRates = -1;
2789 finished: // That's all ... close the device and return
2791 info->probed = true;
2795 bool RtAudio :: probeDeviceOpen(int device, RTAUDIO_STREAM *stream,
2796 STREAM_MODE mode, int channels,
2797 int sampleRate, RTAUDIO_FORMAT format,
2798 int *bufferSize, int numberOfBuffers)
2800 int buffers, buffer_bytes, device_channels, device_format;
2801 int srate, temp, fd;
2803 const char *name = devices[device].name;
2806 fd = open(name, O_WRONLY | O_NONBLOCK);
2807 else { // mode == INPUT
2808 if (stream->mode == OUTPUT && stream->device[0] == device) {
2809 // We just set the same device for playback ... close and reopen for duplex (OSS only).
2810 close(stream->handle[0]);
2811 stream->handle[0] = 0;
2812 // First check that the number previously set channels is the same.
2813 if (stream->nUserChannels[0] != channels) {
2814 sprintf(message, "RtAudio: input/output channels must be equal for OSS duplex device (%s).", name);
2817 fd = open(name, O_RDWR | O_NONBLOCK);
2820 fd = open(name, O_RDONLY | O_NONBLOCK);
2824 if (errno == EBUSY || errno == EAGAIN)
2825 sprintf(message, "RtAudio: OSS device (%s) is busy and cannot be opened.",
2828 sprintf(message, "RtAudio: OSS device (%s) cannot be opened.", name);
2832 // Now reopen in blocking mode.
2835 fd = open(name, O_WRONLY | O_SYNC);
2836 else { // mode == INPUT
2837 if (stream->mode == OUTPUT && stream->device[0] == device)
2838 fd = open(name, O_RDWR | O_SYNC);
2840 fd = open(name, O_RDONLY | O_SYNC);
2844 sprintf(message, "RtAudio: OSS device (%s) cannot be opened.", name);
2848 // Get the sample format mask
2850 if (ioctl(fd, SNDCTL_DSP_GETFMTS, &mask) == -1) {
2852 sprintf(message, "RtAudio: OSS device (%s) can't get supported audio formats.",
2857 // Determine how to set the device format.
2858 stream->userFormat = format;
2860 stream->doByteSwap[mode] = false;
2861 if (format == RTAUDIO_SINT8) {
2862 if (mask & AFMT_S8) {
2863 device_format = AFMT_S8;
2864 stream->deviceFormat[mode] = RTAUDIO_SINT8;
2867 else if (format == RTAUDIO_SINT16) {
2868 if (mask & AFMT_S16_NE) {
2869 device_format = AFMT_S16_NE;
2870 stream->deviceFormat[mode] = RTAUDIO_SINT16;
2872 #if BYTE_ORDER == LITTLE_ENDIAN
2873 else if (mask & AFMT_S16_BE) {
2874 device_format = AFMT_S16_BE;
2875 stream->deviceFormat[mode] = RTAUDIO_SINT16;
2876 stream->doByteSwap[mode] = true;
2879 else if (mask & AFMT_S16_LE) {
2880 device_format = AFMT_S16_LE;
2881 stream->deviceFormat[mode] = RTAUDIO_SINT16;
2882 stream->doByteSwap[mode] = true;
2886 #if defined (AFMT_S32_NE) && defined (AFMT_S32_LE) && defined (AFMT_S32_BE)
2887 else if (format == RTAUDIO_SINT32) {
2888 if (mask & AFMT_S32_NE) {
2889 device_format = AFMT_S32_NE;
2890 stream->deviceFormat[mode] = RTAUDIO_SINT32;
2892 #if BYTE_ORDER == LITTLE_ENDIAN
2893 else if (mask & AFMT_S32_BE) {
2894 device_format = AFMT_S32_BE;
2895 stream->deviceFormat[mode] = RTAUDIO_SINT32;
2896 stream->doByteSwap[mode] = true;
2899 else if (mask & AFMT_S32_LE) {
2900 device_format = AFMT_S32_LE;
2901 stream->deviceFormat[mode] = RTAUDIO_SINT32;
2902 stream->doByteSwap[mode] = true;
2908 if (device_format == -1) {
2909 // The user requested format is not natively supported by the device.
2910 if (mask & AFMT_S16_NE) {
2911 device_format = AFMT_S16_NE;
2912 stream->deviceFormat[mode] = RTAUDIO_SINT16;
2914 #if BYTE_ORDER == LITTLE_ENDIAN
2915 else if (mask & AFMT_S16_BE) {
2916 device_format = AFMT_S16_BE;
2917 stream->deviceFormat[mode] = RTAUDIO_SINT16;
2918 stream->doByteSwap[mode] = true;
2921 else if (mask & AFMT_S16_LE) {
2922 device_format = AFMT_S16_LE;
2923 stream->deviceFormat[mode] = RTAUDIO_SINT16;
2924 stream->doByteSwap[mode] = true;
2927 #if defined (AFMT_S32_NE) && defined (AFMT_S32_LE) && defined (AFMT_S32_BE)
2928 else if (mask & AFMT_S32_NE) {
2929 device_format = AFMT_S32_NE;
2930 stream->deviceFormat[mode] = RTAUDIO_SINT32;
2932 #if BYTE_ORDER == LITTLE_ENDIAN
2933 else if (mask & AFMT_S32_BE) {
2934 device_format = AFMT_S32_BE;
2935 stream->deviceFormat[mode] = RTAUDIO_SINT32;
2936 stream->doByteSwap[mode] = true;
2939 else if (mask & AFMT_S32_LE) {
2940 device_format = AFMT_S32_LE;
2941 stream->deviceFormat[mode] = RTAUDIO_SINT32;
2942 stream->doByteSwap[mode] = true;
2946 else if (mask & AFMT_S8) {
2947 device_format = AFMT_S8;
2948 stream->deviceFormat[mode] = RTAUDIO_SINT8;
2952 if (stream->deviceFormat[mode] == 0) {
2953 // This really shouldn't happen ...
2955 sprintf(message, "RtAudio: OSS device (%s) data format not supported by RtAudio.",
2960 // Determine the number of channels for this device. Note that the
2961 // channel value requested by the user might be < min_X_Channels.
2962 stream->nUserChannels[mode] = channels;
2963 device_channels = channels;
2964 if (mode == OUTPUT) {
2965 if (channels < devices[device].minOutputChannels)
2966 device_channels = devices[device].minOutputChannels;
2968 else { // mode == INPUT
2969 if (stream->mode == OUTPUT && stream->device[0] == device) {
2970 // We're doing duplex setup here.
2971 if (channels < devices[device].minDuplexChannels)
2972 device_channels = devices[device].minDuplexChannels;
2975 if (channels < devices[device].minInputChannels)
2976 device_channels = devices[device].minInputChannels;
2979 stream->nDeviceChannels[mode] = device_channels;
2981 // Attempt to set the buffer size. According to OSS, the minimum
2982 // number of buffers is two. The supposed minimum buffer size is 16
2983 // bytes, so that will be our lower bound. The argument to this
2984 // call is in the form 0xMMMMSSSS (hex), where the buffer size (in
2985 // bytes) is given as 2^SSSS and the number of buffers as 2^MMMM.
2986 // We'll check the actual value used near the end of the setup
2988 buffer_bytes = *bufferSize * formatBytes(stream->deviceFormat[mode]) * device_channels;
2989 if (buffer_bytes < 16) buffer_bytes = 16;
2990 buffers = numberOfBuffers;
2991 if (buffers < 2) buffers = 2;
2992 temp = ((int) buffers << 16) + (int)(log10((double)buffer_bytes)/log10(2.0));
2993 if (ioctl(fd, SNDCTL_DSP_SETFRAGMENT, &temp)) {
2995 sprintf(message, "RtAudio: OSS error setting fragment size for device (%s).",
2999 stream->nBuffers = buffers;
3001 // Set the data format.
3002 temp = device_format;
3003 if (ioctl(fd, SNDCTL_DSP_SETFMT, &device_format) == -1 || device_format != temp) {
3005 sprintf(message, "RtAudio: OSS error setting data format for device (%s).",
3010 // Set the number of channels.
3011 temp = device_channels;
3012 if (ioctl(fd, SNDCTL_DSP_CHANNELS, &device_channels) == -1 || device_channels != temp) {
3014 sprintf(message, "RtAudio: OSS error setting %d channels on device (%s).",
3019 // Set the sample rate.
3022 if (ioctl(fd, SNDCTL_DSP_SPEED, &srate) == -1) {
3024 sprintf(message, "RtAudio: OSS error setting sample rate = %d on device (%s).",
3029 // Verify the sample rate setup worked.
3030 if (abs(srate - temp) > 100) {
3032 sprintf(message, "RtAudio: OSS error ... audio device (%s) doesn't support sample rate of %d.",
3036 stream->sampleRate = sampleRate;
3038 if (ioctl(fd, SNDCTL_DSP_GETBLKSIZE, &buffer_bytes) == -1) {
3040 sprintf(message, "RtAudio: OSS error getting buffer size for device (%s).",
3045 // Save buffer size (in sample frames).
3046 *bufferSize = buffer_bytes / (formatBytes(stream->deviceFormat[mode]) * device_channels);
3047 stream->bufferSize = *bufferSize;
3049 if (mode == INPUT && stream->mode == OUTPUT &&
3050 stream->device[0] == device) {
3051 // We're doing duplex setup here.
3052 stream->deviceFormat[0] = stream->deviceFormat[1];
3053 stream->nDeviceChannels[0] = device_channels;
3056 // Set flags for buffer conversion
3057 stream->doConvertBuffer[mode] = false;
3058 if (stream->userFormat != stream->deviceFormat[mode])
3059 stream->doConvertBuffer[mode] = true;
3060 if (stream->nUserChannels[mode] < stream->nDeviceChannels[mode])
3061 stream->doConvertBuffer[mode] = true;
3063 // Allocate necessary internal buffers
3064 if ( stream->nUserChannels[0] != stream->nUserChannels[1] ) {
3067 if (stream->nUserChannels[0] >= stream->nUserChannels[1])
3068 buffer_bytes = stream->nUserChannels[0];
3070 buffer_bytes = stream->nUserChannels[1];
3072 buffer_bytes *= *bufferSize * formatBytes(stream->userFormat);
3073 if (stream->userBuffer) free(stream->userBuffer);
3074 stream->userBuffer = (char *) calloc(buffer_bytes, 1);
3075 if (stream->userBuffer == NULL) {
3077 sprintf(message, "RtAudio: OSS error allocating user buffer memory (%s).",
3083 if ( stream->doConvertBuffer[mode] ) {
3086 bool makeBuffer = true;
3087 if ( mode == OUTPUT )
3088 buffer_bytes = stream->nDeviceChannels[0] * formatBytes(stream->deviceFormat[0]);
3089 else { // mode == INPUT
3090 buffer_bytes = stream->nDeviceChannels[1] * formatBytes(stream->deviceFormat[1]);
3091 if ( stream->mode == OUTPUT && stream->deviceBuffer ) {
3092 long bytes_out = stream->nDeviceChannels[0] * formatBytes(stream->deviceFormat[0]);
3093 if ( buffer_bytes < bytes_out ) makeBuffer = false;
3098 buffer_bytes *= *bufferSize;
3099 if (stream->deviceBuffer) free(stream->deviceBuffer);
3100 stream->deviceBuffer = (char *) calloc(buffer_bytes, 1);
3101 if (stream->deviceBuffer == NULL) {
3103 free(stream->userBuffer);
3104 sprintf(message, "RtAudio: OSS error allocating device buffer memory (%s).",
3111 stream->device[mode] = device;
3112 stream->handle[mode] = fd;
3113 stream->state = STREAM_STOPPED;
3114 if ( stream->mode == OUTPUT && mode == INPUT ) {
3115 stream->mode = DUPLEX;
3116 if (stream->device[0] == device)
3117 stream->handle[0] = fd;
3120 stream->mode = mode;
3125 if (stream->handle[0]) {
3126 close(stream->handle[0]);
3127 stream->handle[0] = 0;
3129 error(RtError::WARNING);
3133 void RtAudio :: closeStream(int streamId)
3135 // We don't want an exception to be thrown here because this
3136 // function is called by our class destructor. So, do our own
3138 if ( streams.find( streamId ) == streams.end() ) {
3139 sprintf(message, "RtAudio: invalid stream identifier!");
3140 error(RtError::WARNING);
3144 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) streams[streamId];
3146 if (stream->callbackInfo.usingCallback) {
3147 pthread_cancel(stream->callbackInfo.thread);
3148 pthread_join(stream->callbackInfo.thread, NULL);
3151 if (stream->state == STREAM_RUNNING) {
3152 if (stream->mode == OUTPUT || stream->mode == DUPLEX)
3153 ioctl(stream->handle[0], SNDCTL_DSP_RESET, 0);
3154 if (stream->mode == INPUT || stream->mode == DUPLEX)
3155 ioctl(stream->handle[1], SNDCTL_DSP_RESET, 0);
3158 pthread_mutex_destroy(&stream->mutex);
3160 if (stream->handle[0])
3161 close(stream->handle[0]);
3163 if (stream->handle[1])
3164 close(stream->handle[1]);
3166 if (stream->userBuffer)
3167 free(stream->userBuffer);
3169 if (stream->deviceBuffer)
3170 free(stream->deviceBuffer);
3173 streams.erase(streamId);
3176 void RtAudio :: startStream(int streamId)
3178 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
3180 MUTEX_LOCK(&stream->mutex);
3182 stream->state = STREAM_RUNNING;
3184 // No need to do anything else here ... OSS automatically starts
3185 // when fed samples.
3187 MUTEX_UNLOCK(&stream->mutex);
3190 void RtAudio :: stopStream(int streamId)
3192 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
3194 MUTEX_LOCK(&stream->mutex);
3196 if (stream->state == STREAM_STOPPED)
3200 if (stream->mode == OUTPUT || stream->mode == DUPLEX) {
3201 err = ioctl(stream->handle[0], SNDCTL_DSP_SYNC, 0);
3203 sprintf(message, "RtAudio: OSS error stopping device (%s).",
3204 devices[stream->device[0]].name);
3205 error(RtError::DRIVER_ERROR);
3209 err = ioctl(stream->handle[1], SNDCTL_DSP_SYNC, 0);
3211 sprintf(message, "RtAudio: OSS error stopping device (%s).",
3212 devices[stream->device[1]].name);
3213 error(RtError::DRIVER_ERROR);
3216 stream->state = STREAM_STOPPED;
3219 MUTEX_UNLOCK(&stream->mutex);
3222 void RtAudio :: abortStream(int streamId)
3224 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
3226 MUTEX_LOCK(&stream->mutex);
3228 if (stream->state == STREAM_STOPPED)
3232 if (stream->mode == OUTPUT || stream->mode == DUPLEX) {
3233 err = ioctl(stream->handle[0], SNDCTL_DSP_RESET, 0);
3235 sprintf(message, "RtAudio: OSS error aborting device (%s).",
3236 devices[stream->device[0]].name);
3237 error(RtError::DRIVER_ERROR);
3241 err = ioctl(stream->handle[1], SNDCTL_DSP_RESET, 0);
3243 sprintf(message, "RtAudio: OSS error aborting device (%s).",
3244 devices[stream->device[1]].name);
3245 error(RtError::DRIVER_ERROR);
3248 stream->state = STREAM_STOPPED;
3251 MUTEX_UNLOCK(&stream->mutex);
3254 int RtAudio :: streamWillBlock(int streamId)
3256 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
3258 MUTEX_LOCK(&stream->mutex);
3260 int bytes = 0, channels = 0, frames = 0;
3261 if (stream->state == STREAM_STOPPED)
3264 audio_buf_info info;
3265 if (stream->mode == OUTPUT || stream->mode == DUPLEX) {
3266 ioctl(stream->handle[0], SNDCTL_DSP_GETOSPACE, &info);
3268 channels = stream->nDeviceChannels[0];
3271 if (stream->mode == INPUT || stream->mode == DUPLEX) {
3272 ioctl(stream->handle[1], SNDCTL_DSP_GETISPACE, &info);
3273 if (stream->mode == DUPLEX ) {
3274 bytes = (bytes < info.bytes) ? bytes : info.bytes;
3275 channels = stream->nDeviceChannels[0];
3279 channels = stream->nDeviceChannels[1];
3283 frames = (int) (bytes / (channels * formatBytes(stream->deviceFormat[0])));
3284 frames -= stream->bufferSize;
3285 if (frames < 0) frames = 0;
3288 MUTEX_UNLOCK(&stream->mutex);
3292 void RtAudio :: tickStream(int streamId)
3294 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
3297 if (stream->state == STREAM_STOPPED) {
3298 if (stream->callbackInfo.usingCallback) usleep(50000); // sleep 50 milliseconds
3301 else if (stream->callbackInfo.usingCallback) {
3302 RTAUDIO_CALLBACK callback = (RTAUDIO_CALLBACK) stream->callbackInfo.callback;
3303 stopStream = callback(stream->userBuffer, stream->bufferSize, stream->callbackInfo.userData);
3306 MUTEX_LOCK(&stream->mutex);
3308 // The state might change while waiting on a mutex.
3309 if (stream->state == STREAM_STOPPED)
3315 RTAUDIO_FORMAT format;
3316 if (stream->mode == OUTPUT || stream->mode == DUPLEX) {
3318 // Setup parameters and do buffer conversion if necessary.
3319 if (stream->doConvertBuffer[0]) {
3320 convertStreamBuffer(stream, OUTPUT);
3321 buffer = stream->deviceBuffer;
3322 samples = stream->bufferSize * stream->nDeviceChannels[0];
3323 format = stream->deviceFormat[0];
3326 buffer = stream->userBuffer;
3327 samples = stream->bufferSize * stream->nUserChannels[0];
3328 format = stream->userFormat;
3331 // Do byte swapping if necessary.
3332 if (stream->doByteSwap[0])
3333 byteSwapBuffer(buffer, samples, format);
3335 // Write samples to device.
3336 result = write(stream->handle[0], buffer, samples * formatBytes(format));
3339 // This could be an underrun, but the basic OSS API doesn't provide a means for determining that.
3340 sprintf(message, "RtAudio: OSS audio write error for device (%s).",
3341 devices[stream->device[0]].name);
3342 error(RtError::DRIVER_ERROR);
3346 if (stream->mode == INPUT || stream->mode == DUPLEX) {
3348 // Setup parameters.
3349 if (stream->doConvertBuffer[1]) {
3350 buffer = stream->deviceBuffer;
3351 samples = stream->bufferSize * stream->nDeviceChannels[1];
3352 format = stream->deviceFormat[1];
3355 buffer = stream->userBuffer;
3356 samples = stream->bufferSize * stream->nUserChannels[1];
3357 format = stream->userFormat;
3360 // Read samples from device.
3361 result = read(stream->handle[1], buffer, samples * formatBytes(format));
3364 // This could be an overrun, but the basic OSS API doesn't provide a means for determining that.
3365 sprintf(message, "RtAudio: OSS audio read error for device (%s).",
3366 devices[stream->device[1]].name);
3367 error(RtError::DRIVER_ERROR);
3370 // Do byte swapping if necessary.
3371 if (stream->doByteSwap[1])
3372 byteSwapBuffer(buffer, samples, format);
3374 // Do buffer conversion if necessary.
3375 if (stream->doConvertBuffer[1])
3376 convertStreamBuffer(stream, INPUT);
3380 MUTEX_UNLOCK(&stream->mutex);
3382 if (stream->callbackInfo.usingCallback && stopStream)
3383 this->stopStream(streamId);
3386 extern "C" void *callbackHandler(void *ptr)
3388 CALLBACK_INFO *info = (CALLBACK_INFO *) ptr;
3389 RtAudio *object = (RtAudio *) info->object;
3390 int stream = info->streamId;
3391 bool *usingCallback = &info->usingCallback;
3393 while ( *usingCallback ) {
3394 pthread_testcancel();
3396 object->tickStream(stream);
3398 catch (RtError &exception) {
3399 fprintf(stderr, "\nRtAudio: Callback thread error (%s) ... closing thread.\n\n",
3400 exception.getMessage());
3409 //******************** End of __LINUX_OSS__ *********************//
3411 #elif defined(__WINDOWS_ASIO__) // ASIO API on Windows
3413 // The ASIO API is designed around a callback scheme, so this
3414 // implementation is similar to that used for OS X CoreAudio. The
3415 // primary constraint with ASIO is that it only allows access to a
3416 // single driver at a time. Thus, it is not possible to have more
3417 // than one simultaneous RtAudio stream.
3419 // This implementation also requires a number of external ASIO files
3420 // and a few global variables. The ASIO callback scheme does not
3421 // allow for the passing of user data, so we must create a global
3422 // pointer to our callbackInfo structure.
3424 #include "asio/asiosys.h"
3425 #include "asio/asio.h"
3426 #include "asio/asiodrivers.h"
3429 AsioDrivers drivers;
3430 ASIOCallbacks asioCallbacks;
3431 CALLBACK_INFO *asioCallbackInfo;
3432 ASIODriverInfo driverInfo;
3434 void RtAudio :: initialize(void)
3436 nDevices = drivers.asioGetNumDev();
3437 if (nDevices <= 0) return;
3439 // Allocate the RTAUDIO_DEVICE structures.
3440 devices = (RTAUDIO_DEVICE *) calloc(nDevices, sizeof(RTAUDIO_DEVICE));
3441 if (devices == NULL) {
3442 sprintf(message, "RtAudio: memory allocation error!");
3443 error(RtError::MEMORY_ERROR);
3446 // Write device driver names to device structures and then probe the
3447 // device capabilities.
3448 for (int i=0; i<nDevices; i++) {
3449 if ( drivers.asioGetDriverName( i, devices[i].name, 128 ) == 0 )
3450 //probeDeviceInfo(&devices[i]);
3453 sprintf(message, "RtAudio: error getting ASIO driver name for device index %d!", i);
3454 error(RtError::WARNING);
3458 drivers.removeCurrentDriver();
3459 driverInfo.asioVersion = 2;
3460 // See note in DirectSound implementation about GetDesktopWindow().
3461 driverInfo.sysRef = GetForegroundWindow();
3464 int RtAudio :: getDefaultInputDevice(void)
3469 int RtAudio :: getDefaultOutputDevice(void)
3474 void RtAudio :: probeDeviceInfo(RTAUDIO_DEVICE *info)
3476 // Don't probe if a stream is already open.
3477 if ( streams.size() > 0 ) {
3478 sprintf(message, "RtAudio: unable to probe ASIO driver while a stream is open.");
3479 error(RtError::DEBUG_WARNING);
3483 if ( !drivers.loadDriver( info->name ) ) {
3484 sprintf(message, "RtAudio: ASIO error loading driver (%s).", info->name);
3485 error(RtError::DEBUG_WARNING);
3489 ASIOError result = ASIOInit( &driverInfo );
3490 if ( result != ASE_OK ) {
3492 if ( result == ASE_HWMalfunction )
3493 sprintf(details, "hardware malfunction");
3494 else if ( result == ASE_NoMemory )
3495 sprintf(details, "no memory");
3496 else if ( result == ASE_NotPresent )
3497 sprintf(details, "driver/hardware not present");
3499 sprintf(details, "unspecified");
3500 sprintf(message, "RtAudio: ASIO error (%s) initializing driver (%s).", details, info->name);
3501 error(RtError::DEBUG_WARNING);
3505 // Determine the device channel information.
3506 long inputChannels, outputChannels;
3507 result = ASIOGetChannels( &inputChannels, &outputChannels );
3508 if ( result != ASE_OK ) {
3509 drivers.removeCurrentDriver();
3510 sprintf(message, "RtAudio: ASIO error getting input/output channel count (%s).", info->name);
3511 error(RtError::DEBUG_WARNING);
3515 info->maxOutputChannels = outputChannels;
3516 if ( outputChannels > 0 ) info->minOutputChannels = 1;
3518 info->maxInputChannels = inputChannels;
3519 if ( inputChannels > 0 ) info->minInputChannels = 1;
3521 // If device opens for both playback and capture, we determine the channels.
3522 if (info->maxOutputChannels > 0 && info->maxInputChannels > 0) {
3523 info->hasDuplexSupport = true;
3524 info->maxDuplexChannels = (info->maxOutputChannels > info->maxInputChannels) ?
3525 info->maxInputChannels : info->maxOutputChannels;
3526 info->minDuplexChannels = (info->minOutputChannels > info->minInputChannels) ?
3527 info->minInputChannels : info->minOutputChannels;
3530 // Determine the supported sample rates.
3531 info->nSampleRates = 0;
3532 for (int i=0; i<MAX_SAMPLE_RATES; i++) {
3533 result = ASIOCanSampleRate( (ASIOSampleRate) SAMPLE_RATES[i] );
3534 if ( result == ASE_OK )
3535 info->sampleRates[info->nSampleRates++] = SAMPLE_RATES[i];
3538 if (info->nSampleRates == 0) {
3539 drivers.removeCurrentDriver();
3540 sprintf( message, "RtAudio: No supported sample rates found for ASIO driver (%s).", info->name );
3541 error(RtError::DEBUG_WARNING);
3545 // Determine supported data types ... just check first channel and assume rest are the same.
3546 ASIOChannelInfo channelInfo;
3547 channelInfo.channel = 0;
3548 channelInfo.isInput = true;
3549 if ( info->maxInputChannels <= 0 ) channelInfo.isInput = false;
3550 result = ASIOGetChannelInfo( &channelInfo );
3551 if ( result != ASE_OK ) {
3552 drivers.removeCurrentDriver();
3553 sprintf(message, "RtAudio: ASIO error getting driver (%s) channel information.", info->name);
3554 error(RtError::DEBUG_WARNING);
3558 if ( channelInfo.type == ASIOSTInt16MSB || channelInfo.type == ASIOSTInt16LSB )
3559 info->nativeFormats |= RTAUDIO_SINT16;
3560 else if ( channelInfo.type == ASIOSTInt32MSB || channelInfo.type == ASIOSTInt32LSB )
3561 info->nativeFormats |= RTAUDIO_SINT32;
3562 else if ( channelInfo.type == ASIOSTFloat32MSB || channelInfo.type == ASIOSTFloat32LSB )
3563 info->nativeFormats |= RTAUDIO_FLOAT32;
3564 else if ( channelInfo.type == ASIOSTFloat64MSB || channelInfo.type == ASIOSTFloat64LSB )
3565 info->nativeFormats |= RTAUDIO_FLOAT64;
3567 // Check that we have at least one supported format.
3568 if (info->nativeFormats == 0) {
3569 drivers.removeCurrentDriver();
3570 sprintf(message, "RtAudio: ASIO driver (%s) data format not supported by RtAudio.",
3572 error(RtError::DEBUG_WARNING);
3576 info->probed = true;
3577 drivers.removeCurrentDriver();
3580 void bufferSwitch(long index, ASIOBool processNow)
3582 RtAudio *object = (RtAudio *) asioCallbackInfo->object;
3584 object->callbackEvent( asioCallbackInfo->streamId, index, (void *)NULL, (void *)NULL );
3586 catch (RtError &exception) {
3587 fprintf(stderr, "\nCallback handler error (%s)!\n\n", exception.getMessage());
3594 void sampleRateChanged(ASIOSampleRate sRate)
3596 // The ASIO documentation says that this usually only happens during
3597 // external sync. Audio processing is not stopped by the driver,
3598 // actual sample rate might not have even changed, maybe only the
3599 // sample rate status of an AES/EBU or S/PDIF digital input at the
3602 RtAudio *object = (RtAudio *) asioCallbackInfo->object;
3604 object->stopStream( asioCallbackInfo->streamId );
3606 catch (RtError &exception) {
3607 fprintf(stderr, "\nRtAudio: sampleRateChanged() error (%s)!\n\n", exception.getMessage());
3611 fprintf(stderr, "\nRtAudio: ASIO driver reports sample rate changed to %d ... stream stopped!!!", (int) sRate);
3614 long asioMessages(long selector, long value, void* message, double* opt)
3618 case kAsioSelectorSupported:
3619 if(value == kAsioResetRequest
3620 || value == kAsioEngineVersion
3621 || value == kAsioResyncRequest
3622 || value == kAsioLatenciesChanged
3623 // The following three were added for ASIO 2.0, you don't
3624 // necessarily have to support them.
3625 || value == kAsioSupportsTimeInfo
3626 || value == kAsioSupportsTimeCode
3627 || value == kAsioSupportsInputMonitor)
3630 case kAsioResetRequest:
3631 // Defer the task and perform the reset of the driver during the
3632 // next "safe" situation. You cannot reset the driver right now,
3633 // as this code is called from the driver. Reset the driver is
3634 // done by completely destruct is. I.e. ASIOStop(),
3635 // ASIODisposeBuffers(), Destruction Afterwards you initialize the
3637 fprintf(stderr, "\nRtAudio: ASIO driver reset requested!!!");
3640 case kAsioResyncRequest:
3641 // This informs the application that the driver encountered some
3642 // non-fatal data loss. It is used for synchronization purposes
3643 // of different media. Added mainly to work around the Win16Mutex
3644 // problems in Windows 95/98 with the Windows Multimedia system,
3645 // which could lose data because the Mutex was held too long by
3646 // another thread. However a driver can issue it in other
3648 fprintf(stderr, "\nRtAudio: ASIO driver resync requested!!!");
3651 case kAsioLatenciesChanged:
3652 // This will inform the host application that the drivers were
3653 // latencies changed. Beware, it this does not mean that the
3654 // buffer sizes have changed! You might need to update internal
3656 fprintf(stderr, "\nRtAudio: ASIO driver latency may have changed!!!");
3659 case kAsioEngineVersion:
3660 // Return the supported ASIO version of the host application. If
3661 // a host application does not implement this selector, ASIO 1.0
3662 // is assumed by the driver.
3665 case kAsioSupportsTimeInfo:
3666 // Informs the driver whether the
3667 // asioCallbacks.bufferSwitchTimeInfo() callback is supported.
3668 // For compatibility with ASIO 1.0 drivers the host application
3669 // should always support the "old" bufferSwitch method, too.
3672 case kAsioSupportsTimeCode:
3673 // Informs the driver wether application is interested in time
3674 // code info. If an application does not need to know about time
3675 // code, the driver has less work to do.
3682 bool RtAudio :: probeDeviceOpen(int device, RTAUDIO_STREAM *stream,
3683 STREAM_MODE mode, int channels,
3684 int sampleRate, RTAUDIO_FORMAT format,
3685 int *bufferSize, int numberOfBuffers)
3687 // Don't attempt to load another driver if a stream is already open.
3688 if ( streams.size() > 0 ) {
3689 sprintf(message, "RtAudio: unable to load ASIO driver while a stream is open.");
3690 error(RtError::WARNING);
3694 // For ASIO, a duplex stream MUST use the same driver.
3695 if ( mode == INPUT && stream->mode == OUTPUT && stream->device[0] != device ) {
3696 sprintf(message, "RtAudio: ASIO duplex stream must use the same device for input and output.");
3697 error(RtError::WARNING);
3701 // Only load the driver once for duplex stream.
3703 if ( mode != INPUT || stream->mode != OUTPUT ) {
3704 if ( !drivers.loadDriver( devices[device].name ) ) {
3705 sprintf(message, "RtAudio: ASIO error loading driver (%s).", devices[device].name);
3706 error(RtError::DEBUG_WARNING);
3710 result = ASIOInit( &driverInfo );
3711 if ( result != ASE_OK ) {
3713 if ( result == ASE_HWMalfunction )
3714 sprintf(details, "hardware malfunction");
3715 else if ( result == ASE_NoMemory )
3716 sprintf(details, "no memory");
3717 else if ( result == ASE_NotPresent )
3718 sprintf(details, "driver/hardware not present");
3720 sprintf(details, "unspecified");
3721 sprintf(message, "RtAudio: ASIO error (%s) initializing driver (%s).", details, devices[device].name);
3722 error(RtError::DEBUG_WARNING);
3727 // Check the device channel count.
3728 long inputChannels, outputChannels;
3729 result = ASIOGetChannels( &inputChannels, &outputChannels );
3730 if ( result != ASE_OK ) {
3731 drivers.removeCurrentDriver();
3732 sprintf(message, "RtAudio: ASIO error getting input/output channel count (%s).",
3733 devices[device].name);
3734 error(RtError::DEBUG_WARNING);
3738 if ( ( mode == OUTPUT && channels > outputChannels) ||
3739 ( mode == INPUT && channels > inputChannels) ) {
3740 drivers.removeCurrentDriver();
3741 sprintf(message, "RtAudio: ASIO driver (%s) does not support requested channel count (%d).",
3742 devices[device].name, channels);
3743 error(RtError::DEBUG_WARNING);
3746 stream->nDeviceChannels[mode] = channels;
3747 stream->nUserChannels[mode] = channels;
3749 // Verify the sample rate is supported.
3750 result = ASIOCanSampleRate( (ASIOSampleRate) sampleRate );
3751 if ( result != ASE_OK ) {
3752 drivers.removeCurrentDriver();
3753 sprintf(message, "RtAudio: ASIO driver (%s) does not support requested sample rate (%d).",
3754 devices[device].name, sampleRate);
3755 error(RtError::DEBUG_WARNING);
3759 // Set the sample rate.
3760 result = ASIOSetSampleRate( (ASIOSampleRate) sampleRate );
3761 if ( result != ASE_OK ) {
3762 drivers.removeCurrentDriver();
3763 sprintf(message, "RtAudio: ASIO driver (%s) error setting sample rate (%d).",
3764 devices[device].name, sampleRate);
3765 error(RtError::DEBUG_WARNING);
3769 // Determine the driver data type.
3770 ASIOChannelInfo channelInfo;
3771 channelInfo.channel = 0;
3772 if ( mode == OUTPUT ) channelInfo.isInput = false;
3773 else channelInfo.isInput = true;
3774 result = ASIOGetChannelInfo( &channelInfo );
3775 if ( result != ASE_OK ) {
3776 drivers.removeCurrentDriver();
3777 sprintf(message, "RtAudio: ASIO driver (%s) error getting data format.",
3778 devices[device].name);
3779 error(RtError::DEBUG_WARNING);
3783 // Assuming WINDOWS host is always little-endian.
3784 stream->doByteSwap[mode] = false;
3785 stream->userFormat = format;
3786 stream->deviceFormat[mode] = 0;
3787 if ( channelInfo.type == ASIOSTInt16MSB || channelInfo.type == ASIOSTInt16LSB ) {
3788 stream->deviceFormat[mode] = RTAUDIO_SINT16;
3789 if ( channelInfo.type == ASIOSTInt16MSB ) stream->doByteSwap[mode] = true;
3791 else if ( channelInfo.type == ASIOSTInt32MSB || channelInfo.type == ASIOSTInt32LSB ) {
3792 stream->deviceFormat[mode] = RTAUDIO_SINT32;
3793 if ( channelInfo.type == ASIOSTInt32MSB ) stream->doByteSwap[mode] = true;
3795 else if ( channelInfo.type == ASIOSTFloat32MSB || channelInfo.type == ASIOSTFloat32LSB ) {
3796 stream->deviceFormat[mode] = RTAUDIO_FLOAT32;
3797 if ( channelInfo.type == ASIOSTFloat32MSB ) stream->doByteSwap[mode] = true;
3799 else if ( channelInfo.type == ASIOSTFloat64MSB || channelInfo.type == ASIOSTFloat64LSB ) {
3800 stream->deviceFormat[mode] = RTAUDIO_FLOAT64;
3801 if ( channelInfo.type == ASIOSTFloat64MSB ) stream->doByteSwap[mode] = true;
3804 if ( stream->deviceFormat[mode] == 0 ) {
3805 drivers.removeCurrentDriver();
3806 sprintf(message, "RtAudio: ASIO driver (%s) data format not supported by RtAudio.",
3807 devices[device].name);
3808 error(RtError::DEBUG_WARNING);
3812 // Set the buffer size. For a duplex stream, this will end up
3813 // setting the buffer size based on the input constraints, which
3815 long minSize, maxSize, preferSize, granularity;
3816 result = ASIOGetBufferSize( &minSize, &maxSize, &preferSize, &granularity );
3817 if ( result != ASE_OK ) {
3818 drivers.removeCurrentDriver();
3819 sprintf(message, "RtAudio: ASIO driver (%s) error getting buffer size.",
3820 devices[device].name);
3821 error(RtError::DEBUG_WARNING);
3825 if ( *bufferSize < minSize ) *bufferSize = minSize;
3826 else if ( *bufferSize > maxSize ) *bufferSize = maxSize;
3827 else if ( granularity == -1 ) {
3828 // Make sure bufferSize is a power of two.
3829 double power = log10( *bufferSize ) / log10( 2.0 );
3830 *bufferSize = pow( 2.0, floor(power+0.5) );
3831 if ( *bufferSize < minSize ) *bufferSize = minSize;
3832 else if ( *bufferSize > maxSize ) *bufferSize = maxSize;
3833 else *bufferSize = preferSize;
3836 if ( mode == INPUT && stream->mode == OUTPUT && stream->bufferSize != *bufferSize )
3837 cout << "possible input/output buffersize discrepancy" << endl;
3839 stream->bufferSize = *bufferSize;
3840 stream->nBuffers = 2;
3842 // ASIO always uses deinterleaved channels.
3843 stream->deInterleave[mode] = true;
3845 // Create the ASIO internal buffers. Since RtAudio sets up input
3846 // and output separately, we'll have to dispose of previously
3847 // created output buffers for a duplex stream.
3848 if ( mode == INPUT && stream->mode == OUTPUT ) {
3849 free(stream->callbackInfo.buffers);
3850 result = ASIODisposeBuffers();
3851 if ( result != ASE_OK ) {
3852 drivers.removeCurrentDriver();
3853 sprintf(message, "RtAudio: ASIO driver (%s) error disposing previously allocated buffers.",
3854 devices[device].name);
3855 error(RtError::DEBUG_WARNING);
3860 // Allocate, initialize, and save the bufferInfos in our stream callbackInfo structure.
3861 int i, nChannels = stream->nDeviceChannels[0] + stream->nDeviceChannels[1];
3862 stream->callbackInfo.buffers = 0;
3863 ASIOBufferInfo *bufferInfos = (ASIOBufferInfo *) malloc( nChannels * sizeof(ASIOBufferInfo) );
3864 stream->callbackInfo.buffers = (void *) bufferInfos;
3865 ASIOBufferInfo *infos = bufferInfos;
3866 for ( i=0; i<stream->nDeviceChannels[1]; i++, infos++ ) {
3867 infos->isInput = ASIOTrue;
3868 infos->channelNum = i;
3869 infos->buffers[0] = infos->buffers[1] = 0;
3872 for ( i=0; i<stream->nDeviceChannels[0]; i++, infos++ ) {
3873 infos->isInput = ASIOFalse;
3874 infos->channelNum = i;
3875 infos->buffers[0] = infos->buffers[1] = 0;
3878 // Set up the ASIO callback structure and create the ASIO data buffers.
3879 asioCallbacks.bufferSwitch = &bufferSwitch;
3880 asioCallbacks.sampleRateDidChange = &sampleRateChanged;
3881 asioCallbacks.asioMessage = &asioMessages;
3882 asioCallbacks.bufferSwitchTimeInfo = NULL;
3883 result = ASIOCreateBuffers( bufferInfos, nChannels, stream->bufferSize, &asioCallbacks);
3884 if ( result != ASE_OK ) {
3885 drivers.removeCurrentDriver();
3886 sprintf(message, "RtAudio: ASIO driver (%s) error creating buffers.",
3887 devices[device].name);
3888 error(RtError::DEBUG_WARNING);
3892 // Set flags for buffer conversion.
3893 stream->doConvertBuffer[mode] = false;
3894 if (stream->userFormat != stream->deviceFormat[mode])
3895 stream->doConvertBuffer[mode] = true;
3896 if (stream->nUserChannels[mode] < stream->nDeviceChannels[mode])
3897 stream->doConvertBuffer[mode] = true;
3898 if (stream->nUserChannels[mode] > 1 && stream->deInterleave[mode])
3899 stream->doConvertBuffer[mode] = true;
3901 // Allocate necessary internal buffers
3902 if ( stream->nUserChannels[0] != stream->nUserChannels[1] ) {
3905 if (stream->nUserChannels[0] >= stream->nUserChannels[1])
3906 buffer_bytes = stream->nUserChannels[0];
3908 buffer_bytes = stream->nUserChannels[1];
3910 buffer_bytes *= *bufferSize * formatBytes(stream->userFormat);
3911 if (stream->userBuffer) free(stream->userBuffer);
3912 stream->userBuffer = (char *) calloc(buffer_bytes, 1);
3913 if (stream->userBuffer == NULL)
3917 if ( stream->doConvertBuffer[mode] ) {
3920 bool makeBuffer = true;
3921 if ( mode == OUTPUT )
3922 buffer_bytes = stream->nDeviceChannels[0] * formatBytes(stream->deviceFormat[0]);
3923 else { // mode == INPUT
3924 buffer_bytes = stream->nDeviceChannels[1] * formatBytes(stream->deviceFormat[1]);
3925 if ( stream->mode == OUTPUT && stream->deviceBuffer ) {
3926 long bytes_out = stream->nDeviceChannels[0] * formatBytes(stream->deviceFormat[0]);
3927 if ( buffer_bytes < bytes_out ) makeBuffer = false;
3932 buffer_bytes *= *bufferSize;
3933 if (stream->deviceBuffer) free(stream->deviceBuffer);
3934 stream->deviceBuffer = (char *) calloc(buffer_bytes, 1);
3935 if (stream->deviceBuffer == NULL)
3940 stream->device[mode] = device;
3941 stream->state = STREAM_STOPPED;
3942 if ( stream->mode == OUTPUT && mode == INPUT )
3943 // We had already set up an output stream.
3944 stream->mode = DUPLEX;
3946 stream->mode = mode;
3947 stream->sampleRate = sampleRate;
3948 asioCallbackInfo = &stream->callbackInfo;
3949 stream->callbackInfo.object = (void *) this;
3950 stream->callbackInfo.waitTime = (unsigned long) (200.0 * stream->bufferSize / stream->sampleRate);
3955 ASIODisposeBuffers();
3956 drivers.removeCurrentDriver();
3958 if (stream->callbackInfo.buffers)
3959 free(stream->callbackInfo.buffers);
3960 stream->callbackInfo.buffers = 0;
3962 if (stream->userBuffer) {
3963 free(stream->userBuffer);
3964 stream->userBuffer = 0;
3966 sprintf(message, "RtAudio: error allocating buffer memory (%s).",
3967 devices[device].name);
3968 error(RtError::WARNING);
3972 void RtAudio :: cancelStreamCallback(int streamId)
3974 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
3976 if (stream->callbackInfo.usingCallback) {
3978 if (stream->state == STREAM_RUNNING)
3979 stopStream( streamId );
3981 MUTEX_LOCK(&stream->mutex);
3983 stream->callbackInfo.usingCallback = false;
3984 stream->callbackInfo.userData = NULL;
3985 stream->state = STREAM_STOPPED;
3986 stream->callbackInfo.callback = NULL;
3988 MUTEX_UNLOCK(&stream->mutex);
3992 void RtAudio :: closeStream(int streamId)
3994 // We don't want an exception to be thrown here because this
3995 // function is called by our class destructor. So, do our own
3997 if ( streams.find( streamId ) == streams.end() ) {
3998 sprintf(message, "RtAudio: invalid stream identifier!");
3999 error(RtError::WARNING);
4003 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) streams[streamId];
4005 if (stream->state == STREAM_RUNNING)
4008 ASIODisposeBuffers();
4010 drivers.removeCurrentDriver();
4012 DeleteCriticalSection(&stream->mutex);
4014 if (stream->callbackInfo.buffers)
4015 free(stream->callbackInfo.buffers);
4017 if (stream->userBuffer)
4018 free(stream->userBuffer);
4020 if (stream->deviceBuffer)
4021 free(stream->deviceBuffer);
4024 streams.erase(streamId);
4027 void RtAudio :: startStream(int streamId)
4029 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
4031 MUTEX_LOCK(&stream->mutex);
4033 if (stream->state == STREAM_RUNNING) {
4034 MUTEX_UNLOCK(&stream->mutex);
4038 stream->callbackInfo.blockTick = true;
4039 stream->callbackInfo.stopStream = false;
4040 stream->callbackInfo.streamId = streamId;
4041 ASIOError result = ASIOStart();
4042 if ( result != ASE_OK ) {
4043 sprintf(message, "RtAudio: ASIO error starting device (%s).",
4044 devices[stream->device[0]].name);
4045 MUTEX_UNLOCK(&stream->mutex);
4046 error(RtError::DRIVER_ERROR);
4048 stream->state = STREAM_RUNNING;
4050 MUTEX_UNLOCK(&stream->mutex);
4053 void RtAudio :: stopStream(int streamId)
4055 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
4057 MUTEX_LOCK(&stream->mutex);
4059 if (stream->state == STREAM_STOPPED) {
4060 MUTEX_UNLOCK(&stream->mutex);
4064 ASIOError result = ASIOStop();
4065 if ( result != ASE_OK ) {
4066 sprintf(message, "RtAudio: ASIO error stopping device (%s).",
4067 devices[stream->device[0]].name);
4068 MUTEX_UNLOCK(&stream->mutex);
4069 error(RtError::DRIVER_ERROR);
4071 stream->state = STREAM_STOPPED;
4073 MUTEX_UNLOCK(&stream->mutex);
4076 void RtAudio :: abortStream(int streamId)
4078 stopStream( streamId );
4081 // I don't know how this function can be implemented.
4082 int RtAudio :: streamWillBlock(int streamId)
4084 sprintf(message, "RtAudio: streamWillBlock() cannot be implemented for ASIO.");
4085 error(RtError::WARNING);
4089 void RtAudio :: tickStream(int streamId)
4091 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
4093 if (stream->state == STREAM_STOPPED)
4096 if (stream->callbackInfo.usingCallback) {
4097 sprintf(message, "RtAudio: tickStream() should not be used when a callback function is set!");
4098 error(RtError::WARNING);
4102 // Block waiting here until the user data is processed in callbackEvent().
4103 while ( stream->callbackInfo.blockTick )
4104 Sleep(stream->callbackInfo.waitTime);
4106 MUTEX_LOCK(&stream->mutex);
4108 stream->callbackInfo.blockTick = true;
4110 MUTEX_UNLOCK(&stream->mutex);
4113 void RtAudio :: callbackEvent(int streamId, int bufferIndex, void *inData, void *outData)
4115 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
4117 CALLBACK_INFO *info = asioCallbackInfo;
4118 if ( !info->usingCallback ) {
4119 // Block waiting here until we get new user data in tickStream().
4120 while ( !info->blockTick )
4121 Sleep(info->waitTime);
4123 else if ( info->stopStream ) {
4124 // Check if the stream should be stopped (via the previous user
4125 // callback return value). We stop the stream here, rather than
4126 // after the function call, so that output data can first be
4128 this->stopStream(asioCallbackInfo->streamId);
4132 MUTEX_LOCK(&stream->mutex);
4133 int nChannels = stream->nDeviceChannels[0] + stream->nDeviceChannels[1];
4135 ASIOBufferInfo *bufferInfos = (ASIOBufferInfo *) info->buffers;
4136 if ( stream->mode == INPUT || stream->mode == DUPLEX ) {
4138 bufferBytes = stream->bufferSize * formatBytes(stream->deviceFormat[1]);
4139 if (stream->doConvertBuffer[1]) {
4141 // Always interleave ASIO input data.
4142 for ( int i=0; i<stream->nDeviceChannels[1]; i++, bufferInfos++ )
4143 memcpy(&stream->deviceBuffer[i*bufferBytes], bufferInfos->buffers[bufferIndex], bufferBytes );
4145 if ( stream->doByteSwap[1] )
4146 byteSwapBuffer(stream->deviceBuffer,
4147 stream->bufferSize * stream->nDeviceChannels[1],
4148 stream->deviceFormat[1]);
4149 convertStreamBuffer(stream, INPUT);
4152 else { // single channel only
4153 memcpy(stream->userBuffer, bufferInfos->buffers[bufferIndex], bufferBytes );
4155 if (stream->doByteSwap[1])
4156 byteSwapBuffer(stream->userBuffer,
4157 stream->bufferSize * stream->nUserChannels[1],
4158 stream->userFormat);
4162 if ( info->usingCallback ) {
4163 RTAUDIO_CALLBACK callback = (RTAUDIO_CALLBACK) info->callback;
4164 if ( callback(stream->userBuffer, stream->bufferSize, info->userData) )
4165 info->stopStream = true;
4168 if ( stream->mode == OUTPUT || stream->mode == DUPLEX ) {
4170 bufferBytes = stream->bufferSize * formatBytes(stream->deviceFormat[0]);
4171 if (stream->doConvertBuffer[0]) {
4173 convertStreamBuffer(stream, OUTPUT);
4174 if ( stream->doByteSwap[0] )
4175 byteSwapBuffer(stream->deviceBuffer,
4176 stream->bufferSize * stream->nDeviceChannels[0],
4177 stream->deviceFormat[0]);
4179 // Always de-interleave ASIO output data.
4180 for ( int i=0; i<stream->nDeviceChannels[0]; i++, bufferInfos++ ) {
4181 memcpy(bufferInfos->buffers[bufferIndex],
4182 &stream->deviceBuffer[i*bufferBytes], bufferBytes );
4185 else { // single channel only
4187 if (stream->doByteSwap[0])
4188 byteSwapBuffer(stream->userBuffer,
4189 stream->bufferSize * stream->nUserChannels[0],
4190 stream->userFormat);
4192 memcpy(bufferInfos->buffers[bufferIndex], stream->userBuffer, bufferBytes );
4196 if ( !info->usingCallback )
4197 info->blockTick = false;
4199 MUTEX_UNLOCK(&stream->mutex);
4202 void RtAudio :: setStreamCallback(int streamId, RTAUDIO_CALLBACK callback, void *userData)
4204 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
4206 stream->callbackInfo.callback = (void *) callback;
4207 stream->callbackInfo.userData = userData;
4208 stream->callbackInfo.usingCallback = true;
4211 //******************** End of __WINDOWS_ASIO__ *********************//
4213 #elif defined(__WINDOWS_DS__) // Windows DirectSound API
4217 // Declarations for utility functions, callbacks, and structures
4218 // specific to the DirectSound implementation.
4219 static bool CALLBACK deviceCountCallback(LPGUID lpguid,
4220 LPCSTR lpcstrDescription,
4221 LPCSTR lpcstrModule,
4224 static bool CALLBACK deviceInfoCallback(LPGUID lpguid,
4225 LPCSTR lpcstrDescription,
4226 LPCSTR lpcstrModule,
4229 static bool CALLBACK defaultDeviceCallback(LPGUID lpguid,
4230 LPCSTR lpcstrDescription,
4231 LPCSTR lpcstrModule,
4234 static bool CALLBACK deviceIdCallback(LPGUID lpguid,
4235 LPCSTR lpcstrDescription,
4236 LPCSTR lpcstrModule,
4239 static char* getErrorString(int code);
4248 int RtAudio :: getDefaultInputDevice(void)
4251 info.name[0] = '\0';
4253 // Enumerate through devices to find the default output.
4254 HRESULT result = DirectSoundCaptureEnumerate((LPDSENUMCALLBACK)defaultDeviceCallback, &info);
4255 if ( FAILED(result) ) {
4256 sprintf(message, "RtAudio: Error performing default input device enumeration: %s.",
4257 getErrorString(result));
4258 error(RtError::WARNING);
4262 for ( int i=0; i<nDevices; i++ )
4263 if ( strncmp( devices[i].name, info.name, 64 ) == 0 ) return i;
4268 int RtAudio :: getDefaultOutputDevice(void)
4271 info.name[0] = '\0';
4273 // Enumerate through devices to find the default output.
4274 HRESULT result = DirectSoundEnumerate((LPDSENUMCALLBACK)defaultDeviceCallback, &info);
4275 if ( FAILED(result) ) {
4276 sprintf(message, "RtAudio: Error performing default output device enumeration: %s.",
4277 getErrorString(result));
4278 error(RtError::WARNING);
4282 for ( int i=0; i<nDevices; i++ )
4283 if ( strncmp(devices[i].name, info.name, 64 ) == 0 ) return i;
4288 void RtAudio :: initialize(void)
4290 int i, ins = 0, outs = 0, count = 0;
4294 // Count DirectSound devices.
4295 result = DirectSoundEnumerate((LPDSENUMCALLBACK)deviceCountCallback, &outs);
4296 if ( FAILED(result) ) {
4297 sprintf(message, "RtAudio: Unable to enumerate through sound playback devices: %s.",
4298 getErrorString(result));
4299 error(RtError::DRIVER_ERROR);
4302 // Count DirectSoundCapture devices.
4303 result = DirectSoundCaptureEnumerate((LPDSENUMCALLBACK)deviceCountCallback, &ins);
4304 if ( FAILED(result) ) {
4305 sprintf(message, "RtAudio: Unable to enumerate through sound capture devices: %s.",
4306 getErrorString(result));
4307 error(RtError::DRIVER_ERROR);
4311 if (count == 0) return;
4313 std::vector<enum_info> info(count);
4314 for (i=0; i<count; i++) {
4315 info[i].name[0] = '\0';
4316 if (i < outs) info[i].isInput = false;
4317 else info[i].isInput = true;
4320 // Get playback device info and check capabilities.
4321 result = DirectSoundEnumerate((LPDSENUMCALLBACK)deviceInfoCallback, &info[0]);
4322 if ( FAILED(result) ) {
4323 sprintf(message, "RtAudio: Unable to enumerate through sound playback devices: %s.",
4324 getErrorString(result));
4325 error(RtError::DRIVER_ERROR);
4328 // Get capture device info and check capabilities.
4329 result = DirectSoundCaptureEnumerate((LPDSENUMCALLBACK)deviceInfoCallback, &info[0]);
4330 if ( FAILED(result) ) {
4331 sprintf(message, "RtAudio: Unable to enumerate through sound capture devices: %s.",
4332 getErrorString(result));
4333 error(RtError::DRIVER_ERROR);
4336 // Parse the devices and check validity. Devices are considered
4337 // invalid if they cannot be opened, they report < 1 supported
4338 // channels, or they report no supported data (capture only).
4339 for (i=0; i<count; i++)
4340 if ( info[i].isValid ) nDevices++;
4342 if (nDevices == 0) return;
4344 // Allocate the RTAUDIO_DEVICE structures.
4345 devices = (RTAUDIO_DEVICE *) calloc(nDevices, sizeof(RTAUDIO_DEVICE));
4346 if (devices == NULL) {
4347 sprintf(message, "RtAudio: memory allocation error!");
4348 error(RtError::MEMORY_ERROR);
4351 // Copy the names to our devices structures.
4353 for (i=0; i<count; i++) {
4354 if ( info[i].isValid )
4355 strncpy(devices[index++].name, info[i].name, 64);
4358 //for (i=0;i<nDevices; i++)
4359 //probeDeviceInfo(&devices[i]);
4364 void RtAudio :: probeDeviceInfo(RTAUDIO_DEVICE *info)
4367 strncpy( dsinfo.name, info->name, 64 );
4368 dsinfo.isValid = false;
4370 // Enumerate through input devices to find the id (if it exists).
4371 HRESULT result = DirectSoundCaptureEnumerate((LPDSENUMCALLBACK)deviceIdCallback, &dsinfo);
4372 if ( FAILED(result) ) {
4373 sprintf(message, "RtAudio: Error performing input device id enumeration: %s.",
4374 getErrorString(result));
4375 error(RtError::WARNING);
4379 // Do capture probe first.
4380 if ( dsinfo.isValid == false )
4381 goto playback_probe;
4383 LPDIRECTSOUNDCAPTURE input;
4384 result = DirectSoundCaptureCreate( dsinfo.id, &input, NULL );
4385 if ( FAILED(result) ) {
4386 sprintf(message, "RtAudio: Could not create DirectSound capture object (%s): %s.",
4387 info->name, getErrorString(result));
4388 error(RtError::WARNING);
4389 goto playback_probe;
4393 in_caps.dwSize = sizeof(in_caps);
4394 result = input->GetCaps( &in_caps );
4395 if ( FAILED(result) ) {
4397 sprintf(message, "RtAudio: Could not get DirectSound capture capabilities (%s): %s.",
4398 info->name, getErrorString(result));
4399 error(RtError::WARNING);
4400 goto playback_probe;
4403 // Get input channel information.
4404 info->minInputChannels = 1;
4405 info->maxInputChannels = in_caps.dwChannels;
4407 // Get sample rate and format information.
4408 if( in_caps.dwChannels == 2 ) {
4409 if( in_caps.dwFormats & WAVE_FORMAT_1S16 ) info->nativeFormats |= RTAUDIO_SINT16;
4410 if( in_caps.dwFormats & WAVE_FORMAT_2S16 ) info->nativeFormats |= RTAUDIO_SINT16;
4411 if( in_caps.dwFormats & WAVE_FORMAT_4S16 ) info->nativeFormats |= RTAUDIO_SINT16;
4412 if( in_caps.dwFormats & WAVE_FORMAT_1S08 ) info->nativeFormats |= RTAUDIO_SINT8;
4413 if( in_caps.dwFormats & WAVE_FORMAT_2S08 ) info->nativeFormats |= RTAUDIO_SINT8;
4414 if( in_caps.dwFormats & WAVE_FORMAT_4S08 ) info->nativeFormats |= RTAUDIO_SINT8;
4416 if ( info->nativeFormats & RTAUDIO_SINT16 ) {
4417 if( in_caps.dwFormats & WAVE_FORMAT_1S16 ) info->sampleRates[info->nSampleRates++] = 11025;
4418 if( in_caps.dwFormats & WAVE_FORMAT_2S16 ) info->sampleRates[info->nSampleRates++] = 22050;
4419 if( in_caps.dwFormats & WAVE_FORMAT_4S16 ) info->sampleRates[info->nSampleRates++] = 44100;
4421 else if ( info->nativeFormats & RTAUDIO_SINT8 ) {
4422 if( in_caps.dwFormats & WAVE_FORMAT_1S08 ) info->sampleRates[info->nSampleRates++] = 11025;
4423 if( in_caps.dwFormats & WAVE_FORMAT_2S08 ) info->sampleRates[info->nSampleRates++] = 22050;
4424 if( in_caps.dwFormats & WAVE_FORMAT_4S08 ) info->sampleRates[info->nSampleRates++] = 44100;
4427 else if ( in_caps.dwChannels == 1 ) {
4428 if( in_caps.dwFormats & WAVE_FORMAT_1M16 ) info->nativeFormats |= RTAUDIO_SINT16;
4429 if( in_caps.dwFormats & WAVE_FORMAT_2M16 ) info->nativeFormats |= RTAUDIO_SINT16;
4430 if( in_caps.dwFormats & WAVE_FORMAT_4M16 ) info->nativeFormats |= RTAUDIO_SINT16;
4431 if( in_caps.dwFormats & WAVE_FORMAT_1M08 ) info->nativeFormats |= RTAUDIO_SINT8;
4432 if( in_caps.dwFormats & WAVE_FORMAT_2M08 ) info->nativeFormats |= RTAUDIO_SINT8;
4433 if( in_caps.dwFormats & WAVE_FORMAT_4M08 ) info->nativeFormats |= RTAUDIO_SINT8;
4435 if ( info->nativeFormats & RTAUDIO_SINT16 ) {
4436 if( in_caps.dwFormats & WAVE_FORMAT_1M16 ) info->sampleRates[info->nSampleRates++] = 11025;
4437 if( in_caps.dwFormats & WAVE_FORMAT_2M16 ) info->sampleRates[info->nSampleRates++] = 22050;
4438 if( in_caps.dwFormats & WAVE_FORMAT_4M16 ) info->sampleRates[info->nSampleRates++] = 44100;
4440 else if ( info->nativeFormats & RTAUDIO_SINT8 ) {
4441 if( in_caps.dwFormats & WAVE_FORMAT_1M08 ) info->sampleRates[info->nSampleRates++] = 11025;
4442 if( in_caps.dwFormats & WAVE_FORMAT_2M08 ) info->sampleRates[info->nSampleRates++] = 22050;
4443 if( in_caps.dwFormats & WAVE_FORMAT_4M08 ) info->sampleRates[info->nSampleRates++] = 44100;
4446 else info->minInputChannels = 0; // technically, this would be an error
4452 dsinfo.isValid = false;
4454 // Enumerate through output devices to find the id (if it exists).
4455 result = DirectSoundEnumerate((LPDSENUMCALLBACK)deviceIdCallback, &dsinfo);
4456 if ( FAILED(result) ) {
4457 sprintf(message, "RtAudio: Error performing output device id enumeration: %s.",
4458 getErrorString(result));
4459 error(RtError::WARNING);
4463 // Now do playback probe.
4464 if ( dsinfo.isValid == false )
4465 goto check_parameters;
4467 LPDIRECTSOUND output;
4469 result = DirectSoundCreate( dsinfo.id, &output, NULL );
4470 if ( FAILED(result) ) {
4471 sprintf(message, "RtAudio: Could not create DirectSound playback object (%s): %s.",
4472 info->name, getErrorString(result));
4473 error(RtError::WARNING);
4474 goto check_parameters;
4477 out_caps.dwSize = sizeof(out_caps);
4478 result = output->GetCaps( &out_caps );
4479 if ( FAILED(result) ) {
4481 sprintf(message, "RtAudio: Could not get DirectSound playback capabilities (%s): %s.",
4482 info->name, getErrorString(result));
4483 error(RtError::WARNING);
4484 goto check_parameters;
4487 // Get output channel information.
4488 info->minOutputChannels = 1;
4489 info->maxOutputChannels = ( out_caps.dwFlags & DSCAPS_PRIMARYSTEREO ) ? 2 : 1;
4491 // Get sample rate information. Use capture device rate information
4493 if ( info->nSampleRates == 0 ) {
4494 info->sampleRates[0] = (int) out_caps.dwMinSecondarySampleRate;
4495 info->sampleRates[1] = (int) out_caps.dwMaxSecondarySampleRate;
4496 if ( out_caps.dwFlags & DSCAPS_CONTINUOUSRATE )
4497 info->nSampleRates = -1;
4498 else if ( out_caps.dwMinSecondarySampleRate == out_caps.dwMaxSecondarySampleRate ) {
4499 if ( out_caps.dwMinSecondarySampleRate == 0 ) {
4500 // This is a bogus driver report ... fake the range and cross
4502 info->sampleRates[0] = 11025;
4503 info->sampleRates[1] = 48000;
4504 info->nSampleRates = -1; /* continuous range */
4505 sprintf(message, "RtAudio: bogus sample rates reported by DirectSound driver ... using defaults (%s).",
4507 error(RtError::DEBUG_WARNING);
4510 info->nSampleRates = 1;
4513 else if ( (out_caps.dwMinSecondarySampleRate < 1000.0) &&
4514 (out_caps.dwMaxSecondarySampleRate > 50000.0) ) {
4515 // This is a bogus driver report ... support for only two
4516 // distant rates. We'll assume this is a range.
4517 info->nSampleRates = -1;
4518 sprintf(message, "RtAudio: bogus sample rates reported by DirectSound driver ... using range (%s).",
4520 error(RtError::WARNING);
4522 else info->nSampleRates = 2;
4525 // Check input rates against output rate range
4526 for ( int i=info->nSampleRates-1; i>=0; i-- ) {
4527 if ( info->sampleRates[i] <= out_caps.dwMaxSecondarySampleRate )
4529 info->nSampleRates--;
4531 while ( info->sampleRates[0] < out_caps.dwMinSecondarySampleRate ) {
4532 info->nSampleRates--;
4533 for ( int i=0; i<info->nSampleRates; i++)
4534 info->sampleRates[i] = info->sampleRates[i+1];
4535 if ( info->nSampleRates <= 0 ) break;
4539 // Get format information.
4540 if ( out_caps.dwFlags & DSCAPS_PRIMARY16BIT ) info->nativeFormats |= RTAUDIO_SINT16;
4541 if ( out_caps.dwFlags & DSCAPS_PRIMARY8BIT ) info->nativeFormats |= RTAUDIO_SINT8;
4546 if ( info->maxInputChannels == 0 && info->maxOutputChannels == 0 )
4548 if ( info->nSampleRates == 0 || info->nativeFormats == 0 )
4551 // Determine duplex status.
4552 if (info->maxInputChannels < info->maxOutputChannels)
4553 info->maxDuplexChannels = info->maxInputChannels;
4555 info->maxDuplexChannels = info->maxOutputChannels;
4556 if (info->minInputChannels < info->minOutputChannels)
4557 info->minDuplexChannels = info->minInputChannels;
4559 info->minDuplexChannels = info->minOutputChannels;
4561 if ( info->maxDuplexChannels > 0 ) info->hasDuplexSupport = true;
4562 else info->hasDuplexSupport = false;
4564 info->probed = true;
4569 bool RtAudio :: probeDeviceOpen(int device, RTAUDIO_STREAM *stream,
4570 STREAM_MODE mode, int channels,
4571 int sampleRate, RTAUDIO_FORMAT format,
4572 int *bufferSize, int numberOfBuffers)
4575 HWND hWnd = GetForegroundWindow();
4576 // According to a note in PortAudio, using GetDesktopWindow()
4577 // instead of GetForegroundWindow() is supposed to avoid problems
4578 // that occur when the application's window is not the foreground
4579 // window. Also, if the application window closes before the
4580 // DirectSound buffer, DirectSound can crash. However, for console
4581 // applications, no sound was produced when using GetDesktopWindow().
4587 // Check the numberOfBuffers parameter and limit the lowest value to
4588 // two. This is a judgement call and a value of two is probably too
4589 // low for capture, but it should work for playback.
4590 if (numberOfBuffers < 2)
4593 nBuffers = numberOfBuffers;
4595 // Define the wave format structure (16-bit PCM, srate, channels)
4596 WAVEFORMATEX waveFormat;
4597 ZeroMemory(&waveFormat, sizeof(WAVEFORMATEX));
4598 waveFormat.wFormatTag = WAVE_FORMAT_PCM;
4599 waveFormat.nChannels = channels;
4600 waveFormat.nSamplesPerSec = (unsigned long) sampleRate;
4602 // Determine the data format.
4603 if ( devices[device].nativeFormats ) { // 8-bit and/or 16-bit support
4604 if ( format == RTAUDIO_SINT8 ) {
4605 if ( devices[device].nativeFormats & RTAUDIO_SINT8 )
4606 waveFormat.wBitsPerSample = 8;
4608 waveFormat.wBitsPerSample = 16;
4611 if ( devices[device].nativeFormats & RTAUDIO_SINT16 )
4612 waveFormat.wBitsPerSample = 16;
4614 waveFormat.wBitsPerSample = 8;
4618 sprintf(message, "RtAudio: no reported data formats for DirectSound device (%s).",
4619 devices[device].name);
4620 error(RtError::DEBUG_WARNING);
4624 waveFormat.nBlockAlign = waveFormat.nChannels * waveFormat.wBitsPerSample / 8;
4625 waveFormat.nAvgBytesPerSec = waveFormat.nSamplesPerSec * waveFormat.nBlockAlign;
4628 strncpy( dsinfo.name, devices[device].name, 64 );
4629 dsinfo.isValid = false;
4630 if ( mode == OUTPUT ) {
4632 if ( devices[device].maxOutputChannels < channels )
4635 // Enumerate through output devices to find the id (if it exists).
4636 result = DirectSoundEnumerate((LPDSENUMCALLBACK)deviceIdCallback, &dsinfo);
4637 if ( FAILED(result) ) {
4638 sprintf(message, "RtAudio: Error performing output device id enumeration: %s.",
4639 getErrorString(result));
4640 error(RtError::DEBUG_WARNING);
4644 if ( dsinfo.isValid == false ) {
4645 sprintf(message, "RtAudio: DS output device (%s) id not found!", devices[device].name);
4646 error(RtError::DEBUG_WARNING);
4650 LPGUID id = dsinfo.id;
4651 LPDIRECTSOUND object;
4652 LPDIRECTSOUNDBUFFER buffer;
4653 DSBUFFERDESC bufferDescription;
4655 result = DirectSoundCreate( id, &object, NULL );
4656 if ( FAILED(result) ) {
4657 sprintf(message, "RtAudio: Could not create DirectSound playback object (%s): %s.",
4658 devices[device].name, getErrorString(result));
4659 error(RtError::DEBUG_WARNING);
4663 // Set cooperative level to DSSCL_EXCLUSIVE
4664 result = object->SetCooperativeLevel(hWnd, DSSCL_EXCLUSIVE);
4665 if ( FAILED(result) ) {
4667 sprintf(message, "RtAudio: Unable to set DirectSound cooperative level (%s): %s.",
4668 devices[device].name, getErrorString(result));
4669 error(RtError::WARNING);
4673 // Even though we will write to the secondary buffer, we need to
4674 // access the primary buffer to set the correct output format.
4675 // The default is 8-bit, 22 kHz!
4676 // Setup the DS primary buffer description.
4677 ZeroMemory(&bufferDescription, sizeof(DSBUFFERDESC));
4678 bufferDescription.dwSize = sizeof(DSBUFFERDESC);
4679 bufferDescription.dwFlags = DSBCAPS_PRIMARYBUFFER;
4680 // Obtain the primary buffer
4681 result = object->CreateSoundBuffer(&bufferDescription, &buffer, NULL);
4682 if ( FAILED(result) ) {
4684 sprintf(message, "RtAudio: Unable to access DS primary buffer (%s): %s.",
4685 devices[device].name, getErrorString(result));
4686 error(RtError::WARNING);
4690 // Set the primary DS buffer sound format.
4691 result = buffer->SetFormat(&waveFormat);
4692 if ( FAILED(result) ) {
4694 sprintf(message, "RtAudio: Unable to set DS primary buffer format (%s): %s.",
4695 devices[device].name, getErrorString(result));
4696 error(RtError::WARNING);
4700 // Setup the secondary DS buffer description.
4701 buffer_size = channels * *bufferSize * nBuffers * waveFormat.wBitsPerSample / 8;
4702 ZeroMemory(&bufferDescription, sizeof(DSBUFFERDESC));
4703 bufferDescription.dwSize = sizeof(DSBUFFERDESC);
4704 bufferDescription.dwFlags = ( DSBCAPS_STICKYFOCUS |
4705 DSBCAPS_GETCURRENTPOSITION2 |
4706 DSBCAPS_LOCHARDWARE ); // Force hardware mixing
4707 bufferDescription.dwBufferBytes = buffer_size;
4708 bufferDescription.lpwfxFormat = &waveFormat;
4710 // Try to create the secondary DS buffer. If that doesn't work,
4711 // try to use software mixing. Otherwise, there's a problem.
4712 result = object->CreateSoundBuffer(&bufferDescription, &buffer, NULL);
4713 if ( FAILED(result) ) {
4714 bufferDescription.dwFlags = ( DSBCAPS_STICKYFOCUS |
4715 DSBCAPS_GETCURRENTPOSITION2 |
4716 DSBCAPS_LOCSOFTWARE ); // Force software mixing
4717 result = object->CreateSoundBuffer(&bufferDescription, &buffer, NULL);
4718 if ( FAILED(result) ) {
4720 sprintf(message, "RtAudio: Unable to create secondary DS buffer (%s): %s.",
4721 devices[device].name, getErrorString(result));
4722 error(RtError::WARNING);
4727 // Get the buffer size ... might be different from what we specified.
4729 dsbcaps.dwSize = sizeof(DSBCAPS);
4730 buffer->GetCaps(&dsbcaps);
4731 buffer_size = dsbcaps.dwBufferBytes;
4733 // Lock the DS buffer
4734 result = buffer->Lock(0, buffer_size, &audioPtr, &dataLen, NULL, NULL, 0);
4735 if ( FAILED(result) ) {
4737 sprintf(message, "RtAudio: Unable to lock DS buffer (%s): %s.",
4738 devices[device].name, getErrorString(result));
4739 error(RtError::WARNING);
4743 // Zero the DS buffer
4744 ZeroMemory(audioPtr, dataLen);
4746 // Unlock the DS buffer
4747 result = buffer->Unlock(audioPtr, dataLen, NULL, 0);
4748 if ( FAILED(result) ) {
4750 sprintf(message, "RtAudio: Unable to unlock DS buffer(%s): %s.",
4751 devices[device].name, getErrorString(result));
4752 error(RtError::WARNING);
4756 stream->handle[0].object = (void *) object;
4757 stream->handle[0].buffer = (void *) buffer;
4758 stream->nDeviceChannels[0] = channels;
4761 if ( mode == INPUT ) {
4763 if ( devices[device].maxInputChannels < channels )
4766 // Enumerate through input devices to find the id (if it exists).
4767 result = DirectSoundCaptureEnumerate((LPDSENUMCALLBACK)deviceIdCallback, &dsinfo);
4768 if ( FAILED(result) ) {
4769 sprintf(message, "RtAudio: Error performing input device id enumeration: %s.",
4770 getErrorString(result));
4771 error(RtError::DEBUG_WARNING);
4775 if ( dsinfo.isValid == false ) {
4776 sprintf(message, "RtAudio: DS input device (%s) id not found!", devices[device].name);
4777 error(RtError::DEBUG_WARNING);
4781 LPGUID id = dsinfo.id;
4782 LPDIRECTSOUNDCAPTURE object;
4783 LPDIRECTSOUNDCAPTUREBUFFER buffer;
4784 DSCBUFFERDESC bufferDescription;
4786 result = DirectSoundCaptureCreate( id, &object, NULL );
4787 if ( FAILED(result) ) {
4788 sprintf(message, "RtAudio: Could not create DirectSound capture object (%s): %s.",
4789 devices[device].name, getErrorString(result));
4790 error(RtError::WARNING);
4794 // Setup the secondary DS buffer description.
4795 buffer_size = channels * *bufferSize * nBuffers * waveFormat.wBitsPerSample / 8;
4796 ZeroMemory(&bufferDescription, sizeof(DSCBUFFERDESC));
4797 bufferDescription.dwSize = sizeof(DSCBUFFERDESC);
4798 bufferDescription.dwFlags = 0;
4799 bufferDescription.dwReserved = 0;
4800 bufferDescription.dwBufferBytes = buffer_size;
4801 bufferDescription.lpwfxFormat = &waveFormat;
4803 // Create the capture buffer.
4804 result = object->CreateCaptureBuffer(&bufferDescription, &buffer, NULL);
4805 if ( FAILED(result) ) {
4807 sprintf(message, "RtAudio: Unable to create DS capture buffer (%s): %s.",
4808 devices[device].name, getErrorString(result));
4809 error(RtError::WARNING);
4813 // Lock the capture buffer
4814 result = buffer->Lock(0, buffer_size, &audioPtr, &dataLen, NULL, NULL, 0);
4815 if ( FAILED(result) ) {
4817 sprintf(message, "RtAudio: Unable to lock DS capture buffer (%s): %s.",
4818 devices[device].name, getErrorString(result));
4819 error(RtError::WARNING);
4824 ZeroMemory(audioPtr, dataLen);
4826 // Unlock the buffer
4827 result = buffer->Unlock(audioPtr, dataLen, NULL, 0);
4828 if ( FAILED(result) ) {
4830 sprintf(message, "RtAudio: Unable to unlock DS capture buffer (%s): %s.",
4831 devices[device].name, getErrorString(result));
4832 error(RtError::WARNING);
4836 stream->handle[1].object = (void *) object;
4837 stream->handle[1].buffer = (void *) buffer;
4838 stream->nDeviceChannels[1] = channels;
4841 stream->userFormat = format;
4842 if ( waveFormat.wBitsPerSample == 8 )
4843 stream->deviceFormat[mode] = RTAUDIO_SINT8;
4845 stream->deviceFormat[mode] = RTAUDIO_SINT16;
4846 stream->nUserChannels[mode] = channels;
4847 *bufferSize = buffer_size / (channels * nBuffers * waveFormat.wBitsPerSample / 8);
4848 stream->bufferSize = *bufferSize;
4850 // Set flags for buffer conversion
4851 stream->doConvertBuffer[mode] = false;
4852 if (stream->userFormat != stream->deviceFormat[mode])
4853 stream->doConvertBuffer[mode] = true;
4854 if (stream->nUserChannels[mode] < stream->nDeviceChannels[mode])
4855 stream->doConvertBuffer[mode] = true;
4857 // Allocate necessary internal buffers
4858 if ( stream->nUserChannels[0] != stream->nUserChannels[1] ) {
4861 if (stream->nUserChannels[0] >= stream->nUserChannels[1])
4862 buffer_bytes = stream->nUserChannels[0];
4864 buffer_bytes = stream->nUserChannels[1];
4866 buffer_bytes *= *bufferSize * formatBytes(stream->userFormat);
4867 if (stream->userBuffer) free(stream->userBuffer);
4868 stream->userBuffer = (char *) calloc(buffer_bytes, 1);
4869 if (stream->userBuffer == NULL)
4873 if ( stream->doConvertBuffer[mode] ) {
4876 bool makeBuffer = true;
4877 if ( mode == OUTPUT )
4878 buffer_bytes = stream->nDeviceChannels[0] * formatBytes(stream->deviceFormat[0]);
4879 else { // mode == INPUT
4880 buffer_bytes = stream->nDeviceChannels[1] * formatBytes(stream->deviceFormat[1]);
4881 if ( stream->mode == OUTPUT && stream->deviceBuffer ) {
4882 long bytes_out = stream->nDeviceChannels[0] * formatBytes(stream->deviceFormat[0]);
4883 if ( buffer_bytes < bytes_out ) makeBuffer = false;
4888 buffer_bytes *= *bufferSize;
4889 if (stream->deviceBuffer) free(stream->deviceBuffer);
4890 stream->deviceBuffer = (char *) calloc(buffer_bytes, 1);
4891 if (stream->deviceBuffer == NULL)
4896 stream->device[mode] = device;
4897 stream->state = STREAM_STOPPED;
4898 if ( stream->mode == OUTPUT && mode == INPUT )
4899 // We had already set up an output stream.
4900 stream->mode = DUPLEX;
4902 stream->mode = mode;
4903 stream->nBuffers = nBuffers;
4904 stream->sampleRate = sampleRate;
4909 if (stream->handle[0].object) {
4910 LPDIRECTSOUND object = (LPDIRECTSOUND) stream->handle[0].object;
4911 LPDIRECTSOUNDBUFFER buffer = (LPDIRECTSOUNDBUFFER) stream->handle[0].buffer;
4914 stream->handle[0].buffer = NULL;
4917 stream->handle[0].object = NULL;
4919 if (stream->handle[1].object) {
4920 LPDIRECTSOUNDCAPTURE object = (LPDIRECTSOUNDCAPTURE) stream->handle[1].object;
4921 LPDIRECTSOUNDCAPTUREBUFFER buffer = (LPDIRECTSOUNDCAPTUREBUFFER) stream->handle[1].buffer;
4924 stream->handle[1].buffer = NULL;
4927 stream->handle[1].object = NULL;
4929 if (stream->userBuffer) {
4930 free(stream->userBuffer);
4931 stream->userBuffer = 0;
4933 sprintf(message, "RtAudio: error allocating buffer memory (%s).",
4934 devices[device].name);
4935 error(RtError::WARNING);
4939 void RtAudio :: cancelStreamCallback(int streamId)
4941 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
4943 if (stream->callbackInfo.usingCallback) {
4945 if (stream->state == STREAM_RUNNING)
4946 stopStream( streamId );
4948 MUTEX_LOCK(&stream->mutex);
4950 stream->callbackInfo.usingCallback = false;
4951 WaitForSingleObject( (HANDLE)stream->callbackInfo.thread, INFINITE );
4952 CloseHandle( (HANDLE)stream->callbackInfo.thread );
4953 stream->callbackInfo.thread = 0;
4954 stream->callbackInfo.callback = NULL;
4955 stream->callbackInfo.userData = NULL;
4957 MUTEX_UNLOCK(&stream->mutex);
4961 void RtAudio :: closeStream(int streamId)
4963 // We don't want an exception to be thrown here because this
4964 // function is called by our class destructor. So, do our own
4966 if ( streams.find( streamId ) == streams.end() ) {
4967 sprintf(message, "RtAudio: invalid stream identifier!");
4968 error(RtError::WARNING);
4972 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) streams[streamId];
4974 if (stream->callbackInfo.usingCallback) {
4975 stream->callbackInfo.usingCallback = false;
4976 WaitForSingleObject( (HANDLE)stream->callbackInfo.thread, INFINITE );
4977 CloseHandle( (HANDLE)stream->callbackInfo.thread );
4980 DeleteCriticalSection(&stream->mutex);
4982 if (stream->handle[0].object) {
4983 LPDIRECTSOUND object = (LPDIRECTSOUND) stream->handle[0].object;
4984 LPDIRECTSOUNDBUFFER buffer = (LPDIRECTSOUNDBUFFER) stream->handle[0].buffer;
4992 if (stream->handle[1].object) {
4993 LPDIRECTSOUNDCAPTURE object = (LPDIRECTSOUNDCAPTURE) stream->handle[1].object;
4994 LPDIRECTSOUNDCAPTUREBUFFER buffer = (LPDIRECTSOUNDCAPTUREBUFFER) stream->handle[1].buffer;
5002 if (stream->userBuffer)
5003 free(stream->userBuffer);
5005 if (stream->deviceBuffer)
5006 free(stream->deviceBuffer);
5009 streams.erase(streamId);
5012 void RtAudio :: startStream(int streamId)
5014 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
5016 MUTEX_LOCK(&stream->mutex);
5018 if (stream->state == STREAM_RUNNING)
5022 if (stream->mode == OUTPUT || stream->mode == DUPLEX) {
5023 LPDIRECTSOUNDBUFFER buffer = (LPDIRECTSOUNDBUFFER) stream->handle[0].buffer;
5024 result = buffer->Play(0, 0, DSBPLAY_LOOPING );
5025 if ( FAILED(result) ) {
5026 sprintf(message, "RtAudio: Unable to start DS buffer (%s): %s.",
5027 devices[stream->device[0]].name, getErrorString(result));
5028 error(RtError::DRIVER_ERROR);
5032 if (stream->mode == INPUT || stream->mode == DUPLEX) {
5033 LPDIRECTSOUNDCAPTUREBUFFER buffer = (LPDIRECTSOUNDCAPTUREBUFFER) stream->handle[1].buffer;
5034 result = buffer->Start(DSCBSTART_LOOPING );
5035 if ( FAILED(result) ) {
5036 sprintf(message, "RtAudio: Unable to start DS capture buffer (%s): %s.",
5037 devices[stream->device[1]].name, getErrorString(result));
5038 error(RtError::DRIVER_ERROR);
5041 stream->state = STREAM_RUNNING;
5044 MUTEX_UNLOCK(&stream->mutex);
5047 void RtAudio :: stopStream(int streamId)
5049 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
5051 MUTEX_LOCK(&stream->mutex);
5053 if (stream->state == STREAM_STOPPED) {
5054 MUTEX_UNLOCK(&stream->mutex);
5058 // There is no specific DirectSound API call to "drain" a buffer
5059 // before stopping. We can hack this for playback by writing zeroes
5060 // for another bufferSize * nBuffers frames. For capture, the
5061 // concept is less clear so we'll repeat what we do in the
5062 // abortStream() case.
5065 LPVOID buffer1 = NULL;
5066 LPVOID buffer2 = NULL;
5067 DWORD bufferSize1 = 0;
5068 DWORD bufferSize2 = 0;
5069 if (stream->mode == OUTPUT || stream->mode == DUPLEX) {
5071 DWORD currentPos, safePos;
5072 long buffer_bytes = stream->bufferSize * stream->nDeviceChannels[0];
5073 buffer_bytes *= formatBytes(stream->deviceFormat[0]);
5075 LPDIRECTSOUNDBUFFER dsBuffer = (LPDIRECTSOUNDBUFFER) stream->handle[0].buffer;
5076 UINT nextWritePos = stream->handle[0].bufferPointer;
5077 dsBufferSize = buffer_bytes * stream->nBuffers;
5079 // Write zeroes for nBuffer counts.
5080 for (int i=0; i<stream->nBuffers; i++) {
5082 // Find out where the read and "safe write" pointers are.
5083 result = dsBuffer->GetCurrentPosition(¤tPos, &safePos);
5084 if ( FAILED(result) ) {
5085 sprintf(message, "RtAudio: Unable to get current DS position (%s): %s.",
5086 devices[stream->device[0]].name, getErrorString(result));
5087 error(RtError::DRIVER_ERROR);
5090 if ( currentPos < nextWritePos ) currentPos += dsBufferSize; // unwrap offset
5091 DWORD endWrite = nextWritePos + buffer_bytes;
5093 // Check whether the entire write region is behind the play pointer.
5094 while ( currentPos < endWrite ) {
5095 float millis = (endWrite - currentPos) * 900.0;
5096 millis /= ( formatBytes(stream->deviceFormat[0]) * stream->sampleRate);
5097 if ( millis < 1.0 ) millis = 1.0;
5098 Sleep( (DWORD) millis );
5100 // Wake up, find out where we are now
5101 result = dsBuffer->GetCurrentPosition( ¤tPos, &safePos );
5102 if ( FAILED(result) ) {
5103 sprintf(message, "RtAudio: Unable to get current DS position (%s): %s.",
5104 devices[stream->device[0]].name, getErrorString(result));
5105 error(RtError::DRIVER_ERROR);
5107 if ( currentPos < nextWritePos ) currentPos += dsBufferSize; // unwrap offset
5110 // Lock free space in the buffer
5111 result = dsBuffer->Lock (nextWritePos, buffer_bytes, &buffer1,
5112 &bufferSize1, &buffer2, &bufferSize2, 0);
5113 if ( FAILED(result) ) {
5114 sprintf(message, "RtAudio: Unable to lock DS buffer during playback (%s): %s.",
5115 devices[stream->device[0]].name, getErrorString(result));
5116 error(RtError::DRIVER_ERROR);
5119 // Zero the free space
5120 ZeroMemory(buffer1, bufferSize1);
5121 if (buffer2 != NULL) ZeroMemory(buffer2, bufferSize2);
5123 // Update our buffer offset and unlock sound buffer
5124 dsBuffer->Unlock (buffer1, bufferSize1, buffer2, bufferSize2);
5125 if ( FAILED(result) ) {
5126 sprintf(message, "RtAudio: Unable to unlock DS buffer during playback (%s): %s.",
5127 devices[stream->device[0]].name, getErrorString(result));
5128 error(RtError::DRIVER_ERROR);
5130 nextWritePos = (nextWritePos + bufferSize1 + bufferSize2) % dsBufferSize;
5131 stream->handle[0].bufferPointer = nextWritePos;
5134 // If we play again, start at the beginning of the buffer.
5135 stream->handle[0].bufferPointer = 0;
5138 if (stream->mode == INPUT || stream->mode == DUPLEX) {
5139 LPDIRECTSOUNDCAPTUREBUFFER buffer = (LPDIRECTSOUNDCAPTUREBUFFER) stream->handle[1].buffer;
5143 result = buffer->Stop();
5144 if ( FAILED(result) ) {
5145 sprintf(message, "RtAudio: Unable to stop DS capture buffer (%s): %s",
5146 devices[stream->device[1]].name, getErrorString(result));
5147 error(RtError::DRIVER_ERROR);
5150 dsBufferSize = stream->bufferSize * stream->nDeviceChannels[1];
5151 dsBufferSize *= formatBytes(stream->deviceFormat[1]) * stream->nBuffers;
5153 // Lock the buffer and clear it so that if we start to play again,
5154 // we won't have old data playing.
5155 result = buffer->Lock(0, dsBufferSize, &buffer1, &bufferSize1, NULL, NULL, 0);
5156 if ( FAILED(result) ) {
5157 sprintf(message, "RtAudio: Unable to lock DS capture buffer (%s): %s.",
5158 devices[stream->device[1]].name, getErrorString(result));
5159 error(RtError::DRIVER_ERROR);
5162 // Zero the DS buffer
5163 ZeroMemory(buffer1, bufferSize1);
5165 // Unlock the DS buffer
5166 result = buffer->Unlock(buffer1, bufferSize1, NULL, 0);
5167 if ( FAILED(result) ) {
5168 sprintf(message, "RtAudio: Unable to unlock DS capture buffer (%s): %s.",
5169 devices[stream->device[1]].name, getErrorString(result));
5170 error(RtError::DRIVER_ERROR);
5173 // If we start recording again, we must begin at beginning of buffer.
5174 stream->handle[1].bufferPointer = 0;
5176 stream->state = STREAM_STOPPED;
5178 MUTEX_UNLOCK(&stream->mutex);
5181 void RtAudio :: abortStream(int streamId)
5183 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
5185 MUTEX_LOCK(&stream->mutex);
5187 if (stream->state == STREAM_STOPPED)
5194 if (stream->mode == OUTPUT || stream->mode == DUPLEX) {
5195 LPDIRECTSOUNDBUFFER buffer = (LPDIRECTSOUNDBUFFER) stream->handle[0].buffer;
5196 result = buffer->Stop();
5197 if ( FAILED(result) ) {
5198 sprintf(message, "RtAudio: Unable to stop DS buffer (%s): %s",
5199 devices[stream->device[0]].name, getErrorString(result));
5200 error(RtError::DRIVER_ERROR);
5203 dsBufferSize = stream->bufferSize * stream->nDeviceChannels[0];
5204 dsBufferSize *= formatBytes(stream->deviceFormat[0]) * stream->nBuffers;
5206 // Lock the buffer and clear it so that if we start to play again,
5207 // we won't have old data playing.
5208 result = buffer->Lock(0, dsBufferSize, &audioPtr, &dataLen, NULL, NULL, 0);
5209 if ( FAILED(result) ) {
5210 sprintf(message, "RtAudio: Unable to lock DS buffer (%s): %s.",
5211 devices[stream->device[0]].name, getErrorString(result));
5212 error(RtError::DRIVER_ERROR);
5215 // Zero the DS buffer
5216 ZeroMemory(audioPtr, dataLen);
5218 // Unlock the DS buffer
5219 result = buffer->Unlock(audioPtr, dataLen, NULL, 0);
5220 if ( FAILED(result) ) {
5221 sprintf(message, "RtAudio: Unable to unlock DS buffer (%s): %s.",
5222 devices[stream->device[0]].name, getErrorString(result));
5223 error(RtError::DRIVER_ERROR);
5226 // If we start playing again, we must begin at beginning of buffer.
5227 stream->handle[0].bufferPointer = 0;
5230 if (stream->mode == INPUT || stream->mode == DUPLEX) {
5231 LPDIRECTSOUNDCAPTUREBUFFER buffer = (LPDIRECTSOUNDCAPTUREBUFFER) stream->handle[1].buffer;
5235 result = buffer->Stop();
5236 if ( FAILED(result) ) {
5237 sprintf(message, "RtAudio: Unable to stop DS capture buffer (%s): %s",
5238 devices[stream->device[1]].name, getErrorString(result));
5239 error(RtError::DRIVER_ERROR);
5242 dsBufferSize = stream->bufferSize * stream->nDeviceChannels[1];
5243 dsBufferSize *= formatBytes(stream->deviceFormat[1]) * stream->nBuffers;
5245 // Lock the buffer and clear it so that if we start to play again,
5246 // we won't have old data playing.
5247 result = buffer->Lock(0, dsBufferSize, &audioPtr, &dataLen, NULL, NULL, 0);
5248 if ( FAILED(result) ) {
5249 sprintf(message, "RtAudio: Unable to lock DS capture buffer (%s): %s.",
5250 devices[stream->device[1]].name, getErrorString(result));
5251 error(RtError::DRIVER_ERROR);
5254 // Zero the DS buffer
5255 ZeroMemory(audioPtr, dataLen);
5257 // Unlock the DS buffer
5258 result = buffer->Unlock(audioPtr, dataLen, NULL, 0);
5259 if ( FAILED(result) ) {
5260 sprintf(message, "RtAudio: Unable to unlock DS capture buffer (%s): %s.",
5261 devices[stream->device[1]].name, getErrorString(result));
5262 error(RtError::DRIVER_ERROR);
5265 // If we start recording again, we must begin at beginning of buffer.
5266 stream->handle[1].bufferPointer = 0;
5268 stream->state = STREAM_STOPPED;
5271 MUTEX_UNLOCK(&stream->mutex);
5274 int RtAudio :: streamWillBlock(int streamId)
5276 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
5278 MUTEX_LOCK(&stream->mutex);
5282 if (stream->state == STREAM_STOPPED)
5286 DWORD currentPos, safePos;
5288 if (stream->mode == OUTPUT || stream->mode == DUPLEX) {
5290 LPDIRECTSOUNDBUFFER dsBuffer = (LPDIRECTSOUNDBUFFER) stream->handle[0].buffer;
5291 UINT nextWritePos = stream->handle[0].bufferPointer;
5292 channels = stream->nDeviceChannels[0];
5293 DWORD dsBufferSize = stream->bufferSize * channels;
5294 dsBufferSize *= formatBytes(stream->deviceFormat[0]) * stream->nBuffers;
5296 // Find out where the read and "safe write" pointers are.
5297 result = dsBuffer->GetCurrentPosition(¤tPos, &safePos);
5298 if ( FAILED(result) ) {
5299 sprintf(message, "RtAudio: Unable to get current DS position (%s): %s.",
5300 devices[stream->device[0]].name, getErrorString(result));
5301 error(RtError::DRIVER_ERROR);
5304 if ( currentPos < nextWritePos ) currentPos += dsBufferSize; // unwrap offset
5305 frames = currentPos - nextWritePos;
5306 frames /= channels * formatBytes(stream->deviceFormat[0]);
5309 if (stream->mode == INPUT || stream->mode == DUPLEX) {
5311 LPDIRECTSOUNDCAPTUREBUFFER dsBuffer = (LPDIRECTSOUNDCAPTUREBUFFER) stream->handle[1].buffer;
5312 UINT nextReadPos = stream->handle[1].bufferPointer;
5313 channels = stream->nDeviceChannels[1];
5314 DWORD dsBufferSize = stream->bufferSize * channels;
5315 dsBufferSize *= formatBytes(stream->deviceFormat[1]) * stream->nBuffers;
5317 // Find out where the write and "safe read" pointers are.
5318 result = dsBuffer->GetCurrentPosition(¤tPos, &safePos);
5319 if ( FAILED(result) ) {
5320 sprintf(message, "RtAudio: Unable to get current DS capture position (%s): %s.",
5321 devices[stream->device[1]].name, getErrorString(result));
5322 error(RtError::DRIVER_ERROR);
5325 if ( safePos < nextReadPos ) safePos += dsBufferSize; // unwrap offset
5327 if (stream->mode == DUPLEX ) {
5328 // Take largest value of the two.
5329 int temp = safePos - nextReadPos;
5330 temp /= channels * formatBytes(stream->deviceFormat[1]);
5331 frames = ( temp > frames ) ? temp : frames;
5334 frames = safePos - nextReadPos;
5335 frames /= channels * formatBytes(stream->deviceFormat[1]);
5339 frames = stream->bufferSize - frames;
5340 if (frames < 0) frames = 0;
5343 MUTEX_UNLOCK(&stream->mutex);
5347 void RtAudio :: tickStream(int streamId)
5349 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
5352 if (stream->state == STREAM_STOPPED) {
5353 if (stream->callbackInfo.usingCallback) Sleep(50); // sleep 50 milliseconds
5356 else if (stream->callbackInfo.usingCallback) {
5357 RTAUDIO_CALLBACK callback = (RTAUDIO_CALLBACK) stream->callbackInfo.callback;
5358 stopStream = callback(stream->userBuffer, stream->bufferSize, stream->callbackInfo.userData);
5361 MUTEX_LOCK(&stream->mutex);
5363 // The state might change while waiting on a mutex.
5364 if (stream->state == STREAM_STOPPED) {
5365 MUTEX_UNLOCK(&stream->mutex);
5370 DWORD currentPos, safePos;
5371 LPVOID buffer1 = NULL;
5372 LPVOID buffer2 = NULL;
5373 DWORD bufferSize1 = 0;
5374 DWORD bufferSize2 = 0;
5377 if (stream->mode == OUTPUT || stream->mode == DUPLEX) {
5379 // Setup parameters and do buffer conversion if necessary.
5380 if (stream->doConvertBuffer[0]) {
5381 convertStreamBuffer(stream, OUTPUT);
5382 buffer = stream->deviceBuffer;
5383 buffer_bytes = stream->bufferSize * stream->nDeviceChannels[0];
5384 buffer_bytes *= formatBytes(stream->deviceFormat[0]);
5387 buffer = stream->userBuffer;
5388 buffer_bytes = stream->bufferSize * stream->nUserChannels[0];
5389 buffer_bytes *= formatBytes(stream->userFormat);
5392 // No byte swapping necessary in DirectSound implementation.
5394 LPDIRECTSOUNDBUFFER dsBuffer = (LPDIRECTSOUNDBUFFER) stream->handle[0].buffer;
5395 UINT nextWritePos = stream->handle[0].bufferPointer;
5396 DWORD dsBufferSize = buffer_bytes * stream->nBuffers;
5398 // Find out where the read and "safe write" pointers are.
5399 result = dsBuffer->GetCurrentPosition(¤tPos, &safePos);
5400 if ( FAILED(result) ) {
5401 sprintf(message, "RtAudio: Unable to get current DS position (%s): %s.",
5402 devices[stream->device[0]].name, getErrorString(result));
5403 error(RtError::DRIVER_ERROR);
5406 if ( currentPos < nextWritePos ) currentPos += dsBufferSize; // unwrap offset
5407 DWORD endWrite = nextWritePos + buffer_bytes;
5409 // Check whether the entire write region is behind the play pointer.
5410 while ( currentPos < endWrite ) {
5411 // If we are here, then we must wait until the play pointer gets
5412 // beyond the write region. The approach here is to use the
5413 // Sleep() function to suspend operation until safePos catches
5414 // up. Calculate number of milliseconds to wait as:
5415 // time = distance * (milliseconds/second) * fudgefactor /
5416 // ((bytes/sample) * (samples/second))
5417 // A "fudgefactor" less than 1 is used because it was found
5418 // that sleeping too long was MUCH worse than sleeping for
5419 // several shorter periods.
5420 float millis = (endWrite - currentPos) * 900.0;
5421 millis /= ( formatBytes(stream->deviceFormat[0]) * stream->sampleRate);
5422 if ( millis < 1.0 ) millis = 1.0;
5423 Sleep( (DWORD) millis );
5425 // Wake up, find out where we are now
5426 result = dsBuffer->GetCurrentPosition( ¤tPos, &safePos );
5427 if ( FAILED(result) ) {
5428 sprintf(message, "RtAudio: Unable to get current DS position (%s): %s.",
5429 devices[stream->device[0]].name, getErrorString(result));
5430 error(RtError::DRIVER_ERROR);
5432 if ( currentPos < nextWritePos ) currentPos += dsBufferSize; // unwrap offset
5435 // Lock free space in the buffer
5436 result = dsBuffer->Lock (nextWritePos, buffer_bytes, &buffer1,
5437 &bufferSize1, &buffer2, &bufferSize2, 0);
5438 if ( FAILED(result) ) {
5439 sprintf(message, "RtAudio: Unable to lock DS buffer during playback (%s): %s.",
5440 devices[stream->device[0]].name, getErrorString(result));
5441 error(RtError::DRIVER_ERROR);
5444 // Copy our buffer into the DS buffer
5445 CopyMemory(buffer1, buffer, bufferSize1);
5446 if (buffer2 != NULL) CopyMemory(buffer2, buffer+bufferSize1, bufferSize2);
5448 // Update our buffer offset and unlock sound buffer
5449 dsBuffer->Unlock (buffer1, bufferSize1, buffer2, bufferSize2);
5450 if ( FAILED(result) ) {
5451 sprintf(message, "RtAudio: Unable to unlock DS buffer during playback (%s): %s.",
5452 devices[stream->device[0]].name, getErrorString(result));
5453 error(RtError::DRIVER_ERROR);
5455 nextWritePos = (nextWritePos + bufferSize1 + bufferSize2) % dsBufferSize;
5456 stream->handle[0].bufferPointer = nextWritePos;
5459 if (stream->mode == INPUT || stream->mode == DUPLEX) {
5461 // Setup parameters.
5462 if (stream->doConvertBuffer[1]) {
5463 buffer = stream->deviceBuffer;
5464 buffer_bytes = stream->bufferSize * stream->nDeviceChannels[1];
5465 buffer_bytes *= formatBytes(stream->deviceFormat[1]);
5468 buffer = stream->userBuffer;
5469 buffer_bytes = stream->bufferSize * stream->nUserChannels[1];
5470 buffer_bytes *= formatBytes(stream->userFormat);
5473 LPDIRECTSOUNDCAPTUREBUFFER dsBuffer = (LPDIRECTSOUNDCAPTUREBUFFER) stream->handle[1].buffer;
5474 UINT nextReadPos = stream->handle[1].bufferPointer;
5475 DWORD dsBufferSize = buffer_bytes * stream->nBuffers;
5477 // Find out where the write and "safe read" pointers are.
5478 result = dsBuffer->GetCurrentPosition(¤tPos, &safePos);
5479 if ( FAILED(result) ) {
5480 sprintf(message, "RtAudio: Unable to get current DS capture position (%s): %s.",
5481 devices[stream->device[1]].name, getErrorString(result));
5482 error(RtError::DRIVER_ERROR);
5485 if ( safePos < nextReadPos ) safePos += dsBufferSize; // unwrap offset
5486 DWORD endRead = nextReadPos + buffer_bytes;
5488 // Check whether the entire write region is behind the play pointer.
5489 while ( safePos < endRead ) {
5490 // See comments for playback.
5491 float millis = (endRead - safePos) * 900.0;
5492 millis /= ( formatBytes(stream->deviceFormat[1]) * stream->sampleRate);
5493 if ( millis < 1.0 ) millis = 1.0;
5494 Sleep( (DWORD) millis );
5496 // Wake up, find out where we are now
5497 result = dsBuffer->GetCurrentPosition( ¤tPos, &safePos );
5498 if ( FAILED(result) ) {
5499 sprintf(message, "RtAudio: Unable to get current DS capture position (%s): %s.",
5500 devices[stream->device[1]].name, getErrorString(result));
5501 error(RtError::DRIVER_ERROR);
5504 if ( safePos < nextReadPos ) safePos += dsBufferSize; // unwrap offset
5507 // Lock free space in the buffer
5508 result = dsBuffer->Lock (nextReadPos, buffer_bytes, &buffer1,
5509 &bufferSize1, &buffer2, &bufferSize2, 0);
5510 if ( FAILED(result) ) {
5511 sprintf(message, "RtAudio: Unable to lock DS buffer during capture (%s): %s.",
5512 devices[stream->device[1]].name, getErrorString(result));
5513 error(RtError::DRIVER_ERROR);
5516 // Copy our buffer into the DS buffer
5517 CopyMemory(buffer, buffer1, bufferSize1);
5518 if (buffer2 != NULL) CopyMemory(buffer+bufferSize1, buffer2, bufferSize2);
5520 // Update our buffer offset and unlock sound buffer
5521 nextReadPos = (nextReadPos + bufferSize1 + bufferSize2) % dsBufferSize;
5522 dsBuffer->Unlock (buffer1, bufferSize1, buffer2, bufferSize2);
5523 if ( FAILED(result) ) {
5524 sprintf(message, "RtAudio: Unable to unlock DS buffer during capture (%s): %s.",
5525 devices[stream->device[1]].name, getErrorString(result));
5526 error(RtError::DRIVER_ERROR);
5528 stream->handle[1].bufferPointer = nextReadPos;
5530 // No byte swapping necessary in DirectSound implementation.
5532 // Do buffer conversion if necessary.
5533 if (stream->doConvertBuffer[1])
5534 convertStreamBuffer(stream, INPUT);
5537 MUTEX_UNLOCK(&stream->mutex);
5539 if (stream->callbackInfo.usingCallback && stopStream)
5540 this->stopStream(streamId);
5543 // Definitions for utility functions and callbacks
5544 // specific to the DirectSound implementation.
5546 extern "C" unsigned __stdcall callbackHandler(void *ptr)
5548 CALLBACK_INFO *info = (CALLBACK_INFO *) ptr;
5549 RtAudio *object = (RtAudio *) info->object;
5550 int stream = info->streamId;
5551 bool *usingCallback = &info->usingCallback;
5553 while ( *usingCallback ) {
5555 object->tickStream(stream);
5557 catch (RtError &exception) {
5558 fprintf(stderr, "\nRtAudio: Callback thread error (%s) ... closing thread.\n\n",
5559 exception.getMessage());
5568 void RtAudio :: setStreamCallback(int streamId, RTAUDIO_CALLBACK callback, void *userData)
5570 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
5572 CALLBACK_INFO *info = (CALLBACK_INFO *) &stream->callbackInfo;
5573 if ( info->usingCallback ) {
5574 sprintf(message, "RtAudio: A callback is already set for this stream!");
5575 error(RtError::WARNING);
5579 info->callback = (void *) callback;
5580 info->userData = userData;
5581 info->usingCallback = true;
5582 info->object = (void *) this;
5583 info->streamId = streamId;
5586 info->thread = _beginthreadex(NULL, 0, &callbackHandler,
5587 &stream->callbackInfo, 0, &thread_id);
5588 if (info->thread == 0) {
5589 info->usingCallback = false;
5590 sprintf(message, "RtAudio: error starting callback thread!");
5591 error(RtError::THREAD_ERROR);
5594 // When spawning multiple threads in quick succession, it appears to be
5595 // necessary to wait a bit for each to initialize ... another windoism!
5599 static bool CALLBACK deviceCountCallback(LPGUID lpguid,
5600 LPCSTR lpcstrDescription,
5601 LPCSTR lpcstrModule,
5604 int *pointer = ((int *) lpContext);
5610 static bool CALLBACK deviceInfoCallback(LPGUID lpguid,
5611 LPCSTR lpcstrDescription,
5612 LPCSTR lpcstrModule,
5615 enum_info *info = ((enum_info *) lpContext);
5616 while (strlen(info->name) > 0) info++;
5618 strncpy(info->name, lpcstrDescription, 64);
5622 info->isValid = false;
5623 if (info->isInput == true) {
5625 LPDIRECTSOUNDCAPTURE object;
5627 hr = DirectSoundCaptureCreate( lpguid, &object, NULL );
5628 if( hr != DS_OK ) return true;
5630 caps.dwSize = sizeof(caps);
5631 hr = object->GetCaps( &caps );
5633 if (caps.dwChannels > 0 && caps.dwFormats > 0)
5634 info->isValid = true;
5640 LPDIRECTSOUND object;
5641 hr = DirectSoundCreate( lpguid, &object, NULL );
5642 if( hr != DS_OK ) return true;
5644 caps.dwSize = sizeof(caps);
5645 hr = object->GetCaps( &caps );
5647 if ( caps.dwFlags & DSCAPS_PRIMARYMONO || caps.dwFlags & DSCAPS_PRIMARYSTEREO )
5648 info->isValid = true;
5656 static bool CALLBACK defaultDeviceCallback(LPGUID lpguid,
5657 LPCSTR lpcstrDescription,
5658 LPCSTR lpcstrModule,
5661 enum_info *info = ((enum_info *) lpContext);
5663 if ( lpguid == NULL ) {
5664 strncpy(info->name, lpcstrDescription, 64);
5671 static bool CALLBACK deviceIdCallback(LPGUID lpguid,
5672 LPCSTR lpcstrDescription,
5673 LPCSTR lpcstrModule,
5676 enum_info *info = ((enum_info *) lpContext);
5678 if ( strncmp( info->name, lpcstrDescription, 64 ) == 0 ) {
5680 info->isValid = true;
5687 static char* getErrorString(int code)
5691 case DSERR_ALLOCATED:
5692 return "Direct Sound already allocated";
5694 case DSERR_CONTROLUNAVAIL:
5695 return "Direct Sound control unavailable";
5697 case DSERR_INVALIDPARAM:
5698 return "Direct Sound invalid parameter";
5700 case DSERR_INVALIDCALL:
5701 return "Direct Sound invalid call";
5704 return "Direct Sound generic error";
5706 case DSERR_PRIOLEVELNEEDED:
5707 return "Direct Sound Priority level needed";
5709 case DSERR_OUTOFMEMORY:
5710 return "Direct Sound out of memory";
5712 case DSERR_BADFORMAT:
5713 return "Direct Sound bad format";
5715 case DSERR_UNSUPPORTED:
5716 return "Direct Sound unsupported error";
5718 case DSERR_NODRIVER:
5719 return "Direct Sound no driver error";
5721 case DSERR_ALREADYINITIALIZED:
5722 return "Direct Sound already initialized";
5724 case DSERR_NOAGGREGATION:
5725 return "Direct Sound no aggregation";
5727 case DSERR_BUFFERLOST:
5728 return "Direct Sound buffer lost";
5730 case DSERR_OTHERAPPHASPRIO:
5731 return "Direct Sound other app has priority";
5733 case DSERR_UNINITIALIZED:
5734 return "Direct Sound uninitialized";
5737 return "Direct Sound unknown error";
5741 //******************** End of __WINDOWS_DS__ *********************//
5743 #elif defined(__IRIX_AL__) // SGI's AL API for IRIX
5748 void RtAudio :: initialize(void)
5750 // Count cards and devices
5753 // Determine the total number of input and output devices.
5754 nDevices = alQueryValues(AL_SYSTEM, AL_DEVICES, 0, 0, 0, 0);
5756 sprintf(message, "RtAudio: AL error counting devices: %s.",
5757 alGetErrorString(oserror()));
5758 error(RtError::DRIVER_ERROR);
5761 if (nDevices <= 0) return;
5763 ALvalue *vls = (ALvalue *) new ALvalue[nDevices];
5765 // Allocate the RTAUDIO_DEVICE structures.
5766 devices = (RTAUDIO_DEVICE *) calloc(nDevices, sizeof(RTAUDIO_DEVICE));
5767 if (devices == NULL) {
5768 sprintf(message, "RtAudio: memory allocation error!");
5769 error(RtError::MEMORY_ERROR);
5772 // Write device ascii identifiers and resource ids to device info
5777 pvs[0].param = AL_NAME;
5778 pvs[0].value.ptr = name;
5781 outs = alQueryValues(AL_SYSTEM, AL_DEFAULT_OUTPUT, vls, nDevices, 0, 0);
5783 sprintf(message, "RtAudio: AL error getting output devices: %s.",
5784 alGetErrorString(oserror()));
5785 error(RtError::DRIVER_ERROR);
5788 for (i=0; i<outs; i++) {
5789 if (alGetParams(vls[i].i, pvs, 1) < 0) {
5790 sprintf(message, "RtAudio: AL error querying output devices: %s.",
5791 alGetErrorString(oserror()));
5792 error(RtError::DRIVER_ERROR);
5794 strncpy(devices[i].name, name, 32);
5795 devices[i].id[0] = vls[i].i;
5798 ins = alQueryValues(AL_SYSTEM, AL_DEFAULT_INPUT, &vls[outs], nDevices-outs, 0, 0);
5800 sprintf(message, "RtAudio: AL error getting input devices: %s.",
5801 alGetErrorString(oserror()));
5802 error(RtError::DRIVER_ERROR);
5805 for (i=outs; i<ins+outs; i++) {
5806 if (alGetParams(vls[i].i, pvs, 1) < 0) {
5807 sprintf(message, "RtAudio: AL error querying input devices: %s.",
5808 alGetErrorString(oserror()));
5809 error(RtError::DRIVER_ERROR);
5811 strncpy(devices[i].name, name, 32);
5812 devices[i].id[1] = vls[i].i;
5820 int RtAudio :: getDefaultInputDevice(void)
5823 int result = alQueryValues(AL_SYSTEM, AL_DEFAULT_INPUT, &value, 1, 0, 0);
5825 sprintf(message, "RtAudio: AL error getting default input device id: %s.",
5826 alGetErrorString(oserror()));
5827 error(RtError::WARNING);
5830 for ( int i=0; i<nDevices; i++ )
5831 if ( devices[i].id[1] == value.i ) return i;
5837 int RtAudio :: getDefaultOutputDevice(void)
5840 int result = alQueryValues(AL_SYSTEM, AL_DEFAULT_OUTPUT, &value, 1, 0, 0);
5842 sprintf(message, "RtAudio: AL error getting default output device id: %s.",
5843 alGetErrorString(oserror()));
5844 error(RtError::WARNING);
5847 for ( int i=0; i<nDevices; i++ )
5848 if ( devices[i].id[0] == value.i ) return i;
5854 void RtAudio :: probeDeviceInfo(RTAUDIO_DEVICE *info)
5856 int resource, result, i;
5860 // Get output resource ID if it exists.
5861 resource = info->id[0];
5864 // Probe output device parameters.
5865 result = alQueryValues(resource, AL_CHANNELS, &value, 1, 0, 0);
5867 sprintf(message, "RtAudio: AL error getting device (%s) channels: %s.",
5868 info->name, alGetErrorString(oserror()));
5869 error(RtError::WARNING);
5872 info->maxOutputChannels = value.i;
5873 info->minOutputChannels = 1;
5876 result = alGetParamInfo(resource, AL_RATE, &pinfo);
5878 sprintf(message, "RtAudio: AL error getting device (%s) rates: %s.",
5879 info->name, alGetErrorString(oserror()));
5880 error(RtError::WARNING);
5883 info->nSampleRates = 0;
5884 for (i=0; i<MAX_SAMPLE_RATES; i++) {
5885 if ( SAMPLE_RATES[i] >= pinfo.min.i && SAMPLE_RATES[i] <= pinfo.max.i ) {
5886 info->sampleRates[info->nSampleRates] = SAMPLE_RATES[i];
5887 info->nSampleRates++;
5892 // The AL library supports all our formats, except 24-bit and 32-bit ints.
5893 info->nativeFormats = (RTAUDIO_FORMAT) 51;
5896 // Now get input resource ID if it exists.
5897 resource = info->id[1];
5900 // Probe input device parameters.
5901 result = alQueryValues(resource, AL_CHANNELS, &value, 1, 0, 0);
5903 sprintf(message, "RtAudio: AL error getting device (%s) channels: %s.",
5904 info->name, alGetErrorString(oserror()));
5905 error(RtError::WARNING);
5908 info->maxInputChannels = value.i;
5909 info->minInputChannels = 1;
5912 result = alGetParamInfo(resource, AL_RATE, &pinfo);
5914 sprintf(message, "RtAudio: AL error getting device (%s) rates: %s.",
5915 info->name, alGetErrorString(oserror()));
5916 error(RtError::WARNING);
5919 // In the case of the default device, these values will
5920 // overwrite the rates determined for the output device. Since
5921 // the input device is most likely to be more limited than the
5922 // output device, this is ok.
5923 info->nSampleRates = 0;
5924 for (i=0; i<MAX_SAMPLE_RATES; i++) {
5925 if ( SAMPLE_RATES[i] >= pinfo.min.i && SAMPLE_RATES[i] <= pinfo.max.i ) {
5926 info->sampleRates[info->nSampleRates] = SAMPLE_RATES[i];
5927 info->nSampleRates++;
5932 // The AL library supports all our formats, except 24-bit and 32-bit ints.
5933 info->nativeFormats = (RTAUDIO_FORMAT) 51;
5936 if ( info->maxInputChannels == 0 && info->maxOutputChannels == 0 )
5938 if ( info->nSampleRates == 0 )
5941 // Determine duplex status.
5942 if (info->maxInputChannels < info->maxOutputChannels)
5943 info->maxDuplexChannels = info->maxInputChannels;
5945 info->maxDuplexChannels = info->maxOutputChannels;
5946 if (info->minInputChannels < info->minOutputChannels)
5947 info->minDuplexChannels = info->minInputChannels;
5949 info->minDuplexChannels = info->minOutputChannels;
5951 if ( info->maxDuplexChannels > 0 ) info->hasDuplexSupport = true;
5952 else info->hasDuplexSupport = false;
5954 info->probed = true;
5959 bool RtAudio :: probeDeviceOpen(int device, RTAUDIO_STREAM *stream,
5960 STREAM_MODE mode, int channels,
5961 int sampleRate, RTAUDIO_FORMAT format,
5962 int *bufferSize, int numberOfBuffers)
5964 int result, resource, nBuffers;
5969 // Get a new ALconfig structure.
5970 al_config = alNewConfig();
5972 sprintf(message,"RtAudio: can't get AL config: %s.",
5973 alGetErrorString(oserror()));
5974 error(RtError::WARNING);
5978 // Set the channels.
5979 result = alSetChannels(al_config, channels);
5981 sprintf(message,"RtAudio: can't set %d channels in AL config: %s.",
5982 channels, alGetErrorString(oserror()));
5983 error(RtError::WARNING);
5987 // Attempt to set the queue size. The al API doesn't provide a
5988 // means for querying the minimum/maximum buffer size of a device,
5989 // so if the specified size doesn't work, take whatever the
5990 // al_config structure returns.
5991 if ( numberOfBuffers < 1 )
5994 nBuffers = numberOfBuffers;
5995 long buffer_size = *bufferSize * nBuffers;
5996 result = alSetQueueSize(al_config, buffer_size); // in sample frames
5998 // Get the buffer size specified by the al_config and try that.
5999 buffer_size = alGetQueueSize(al_config);
6000 result = alSetQueueSize(al_config, buffer_size);
6002 sprintf(message,"RtAudio: can't set buffer size (%ld) in AL config: %s.",
6003 buffer_size, alGetErrorString(oserror()));
6004 error(RtError::WARNING);
6007 *bufferSize = buffer_size / nBuffers;
6010 // Set the data format.
6011 stream->userFormat = format;
6012 stream->deviceFormat[mode] = format;
6013 if (format == RTAUDIO_SINT8) {
6014 result = alSetSampFmt(al_config, AL_SAMPFMT_TWOSCOMP);
6015 result = alSetWidth(al_config, AL_SAMPLE_8);
6017 else if (format == RTAUDIO_SINT16) {
6018 result = alSetSampFmt(al_config, AL_SAMPFMT_TWOSCOMP);
6019 result = alSetWidth(al_config, AL_SAMPLE_16);
6021 else if (format == RTAUDIO_SINT24) {
6022 // Our 24-bit format assumes the upper 3 bytes of a 4 byte word.
6023 // The AL library uses the lower 3 bytes, so we'll need to do our
6025 result = alSetSampFmt(al_config, AL_SAMPFMT_FLOAT);
6026 stream->deviceFormat[mode] = RTAUDIO_FLOAT32;
6028 else if (format == RTAUDIO_SINT32) {
6029 // The AL library doesn't seem to support the 32-bit integer
6030 // format, so we'll need to do our own conversion.
6031 result = alSetSampFmt(al_config, AL_SAMPFMT_FLOAT);
6032 stream->deviceFormat[mode] = RTAUDIO_FLOAT32;
6034 else if (format == RTAUDIO_FLOAT32)
6035 result = alSetSampFmt(al_config, AL_SAMPFMT_FLOAT);
6036 else if (format == RTAUDIO_FLOAT64)
6037 result = alSetSampFmt(al_config, AL_SAMPFMT_DOUBLE);
6039 if ( result == -1 ) {
6040 sprintf(message,"RtAudio: AL error setting sample format in AL config: %s.",
6041 alGetErrorString(oserror()));
6042 error(RtError::WARNING);
6046 if (mode == OUTPUT) {
6050 resource = AL_DEFAULT_OUTPUT;
6052 resource = devices[device].id[0];
6053 result = alSetDevice(al_config, resource);
6054 if ( result == -1 ) {
6055 sprintf(message,"RtAudio: AL error setting device (%s) in AL config: %s.",
6056 devices[device].name, alGetErrorString(oserror()));
6057 error(RtError::WARNING);
6062 port = alOpenPort("RtAudio Output Port", "w", al_config);
6064 sprintf(message,"RtAudio: AL error opening output port: %s.",
6065 alGetErrorString(oserror()));
6066 error(RtError::WARNING);
6070 // Set the sample rate
6071 pvs[0].param = AL_MASTER_CLOCK;
6072 pvs[0].value.i = AL_CRYSTAL_MCLK_TYPE;
6073 pvs[1].param = AL_RATE;
6074 pvs[1].value.ll = alDoubleToFixed((double)sampleRate);
6075 result = alSetParams(resource, pvs, 2);
6078 sprintf(message,"RtAudio: AL error setting sample rate (%d) for device (%s): %s.",
6079 sampleRate, devices[device].name, alGetErrorString(oserror()));
6080 error(RtError::WARNING);
6084 else { // mode == INPUT
6088 resource = AL_DEFAULT_INPUT;
6090 resource = devices[device].id[1];
6091 result = alSetDevice(al_config, resource);
6092 if ( result == -1 ) {
6093 sprintf(message,"RtAudio: AL error setting device (%s) in AL config: %s.",
6094 devices[device].name, alGetErrorString(oserror()));
6095 error(RtError::WARNING);
6100 port = alOpenPort("RtAudio Output Port", "r", al_config);
6102 sprintf(message,"RtAudio: AL error opening input port: %s.",
6103 alGetErrorString(oserror()));
6104 error(RtError::WARNING);
6108 // Set the sample rate
6109 pvs[0].param = AL_MASTER_CLOCK;
6110 pvs[0].value.i = AL_CRYSTAL_MCLK_TYPE;
6111 pvs[1].param = AL_RATE;
6112 pvs[1].value.ll = alDoubleToFixed((double)sampleRate);
6113 result = alSetParams(resource, pvs, 2);
6116 sprintf(message,"RtAudio: AL error setting sample rate (%d) for device (%s): %s.",
6117 sampleRate, devices[device].name, alGetErrorString(oserror()));
6118 error(RtError::WARNING);
6123 alFreeConfig(al_config);
6125 stream->nUserChannels[mode] = channels;
6126 stream->nDeviceChannels[mode] = channels;
6128 // Set handle and flags for buffer conversion
6129 stream->handle[mode] = port;
6130 stream->doConvertBuffer[mode] = false;
6131 if (stream->userFormat != stream->deviceFormat[mode])
6132 stream->doConvertBuffer[mode] = true;
6134 // Allocate necessary internal buffers
6135 if ( stream->nUserChannels[0] != stream->nUserChannels[1] ) {
6138 if (stream->nUserChannels[0] >= stream->nUserChannels[1])
6139 buffer_bytes = stream->nUserChannels[0];
6141 buffer_bytes = stream->nUserChannels[1];
6143 buffer_bytes *= *bufferSize * formatBytes(stream->userFormat);
6144 if (stream->userBuffer) free(stream->userBuffer);
6145 stream->userBuffer = (char *) calloc(buffer_bytes, 1);
6146 if (stream->userBuffer == NULL)
6150 if ( stream->doConvertBuffer[mode] ) {
6153 bool makeBuffer = true;
6154 if ( mode == OUTPUT )
6155 buffer_bytes = stream->nDeviceChannels[0] * formatBytes(stream->deviceFormat[0]);
6156 else { // mode == INPUT
6157 buffer_bytes = stream->nDeviceChannels[1] * formatBytes(stream->deviceFormat[1]);
6158 if ( stream->mode == OUTPUT && stream->deviceBuffer ) {
6159 long bytes_out = stream->nDeviceChannels[0] * formatBytes(stream->deviceFormat[0]);
6160 if ( buffer_bytes < bytes_out ) makeBuffer = false;
6165 buffer_bytes *= *bufferSize;
6166 if (stream->deviceBuffer) free(stream->deviceBuffer);
6167 stream->deviceBuffer = (char *) calloc(buffer_bytes, 1);
6168 if (stream->deviceBuffer == NULL)
6173 stream->device[mode] = device;
6174 stream->state = STREAM_STOPPED;
6175 if ( stream->mode == OUTPUT && mode == INPUT )
6176 // We had already set up an output stream.
6177 stream->mode = DUPLEX;
6179 stream->mode = mode;
6180 stream->nBuffers = nBuffers;
6181 stream->bufferSize = *bufferSize;
6182 stream->sampleRate = sampleRate;
6187 if (stream->handle[0]) {
6188 alClosePort(stream->handle[0]);
6189 stream->handle[0] = 0;
6191 if (stream->handle[1]) {
6192 alClosePort(stream->handle[1]);
6193 stream->handle[1] = 0;
6195 if (stream->userBuffer) {
6196 free(stream->userBuffer);
6197 stream->userBuffer = 0;
6199 sprintf(message, "RtAudio: ALSA error allocating buffer memory for device (%s).",
6200 devices[device].name);
6201 error(RtError::WARNING);
6205 void RtAudio :: closeStream(int streamId)
6207 // We don't want an exception to be thrown here because this
6208 // function is called by our class destructor. So, do our own
6210 if ( streams.find( streamId ) == streams.end() ) {
6211 sprintf(message, "RtAudio: invalid stream identifier!");
6212 error(RtError::WARNING);
6216 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) streams[streamId];
6218 if (stream->callbackInfo.usingCallback) {
6219 pthread_cancel(stream->callbackInfo.thread);
6220 pthread_join(stream->callbackInfo.thread, NULL);
6223 pthread_mutex_destroy(&stream->mutex);
6225 if (stream->handle[0])
6226 alClosePort(stream->handle[0]);
6228 if (stream->handle[1])
6229 alClosePort(stream->handle[1]);
6231 if (stream->userBuffer)
6232 free(stream->userBuffer);
6234 if (stream->deviceBuffer)
6235 free(stream->deviceBuffer);
6238 streams.erase(streamId);
6241 void RtAudio :: startStream(int streamId)
6243 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
6245 if (stream->state == STREAM_RUNNING)
6248 // The AL port is ready as soon as it is opened.
6249 stream->state = STREAM_RUNNING;
6252 void RtAudio :: stopStream(int streamId)
6254 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
6256 MUTEX_LOCK(&stream->mutex);
6258 if (stream->state == STREAM_STOPPED)
6262 int buffer_size = stream->bufferSize * stream->nBuffers;
6264 if (stream->mode == OUTPUT || stream->mode == DUPLEX)
6265 alZeroFrames(stream->handle[0], buffer_size);
6267 if (stream->mode == INPUT || stream->mode == DUPLEX) {
6268 result = alDiscardFrames(stream->handle[1], buffer_size);
6270 sprintf(message, "RtAudio: AL error draining stream device (%s): %s.",
6271 devices[stream->device[1]].name, alGetErrorString(oserror()));
6272 error(RtError::DRIVER_ERROR);
6275 stream->state = STREAM_STOPPED;
6278 MUTEX_UNLOCK(&stream->mutex);
6281 void RtAudio :: abortStream(int streamId)
6283 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
6285 MUTEX_LOCK(&stream->mutex);
6287 if (stream->state == STREAM_STOPPED)
6290 if (stream->mode == OUTPUT || stream->mode == DUPLEX) {
6292 int buffer_size = stream->bufferSize * stream->nBuffers;
6293 int result = alDiscardFrames(stream->handle[0], buffer_size);
6295 sprintf(message, "RtAudio: AL error aborting stream device (%s): %s.",
6296 devices[stream->device[0]].name, alGetErrorString(oserror()));
6297 error(RtError::DRIVER_ERROR);
6301 // There is no clear action to take on the input stream, since the
6302 // port will continue to run in any event.
6303 stream->state = STREAM_STOPPED;
6306 MUTEX_UNLOCK(&stream->mutex);
6309 int RtAudio :: streamWillBlock(int streamId)
6311 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
6313 MUTEX_LOCK(&stream->mutex);
6316 if (stream->state == STREAM_STOPPED)
6320 if (stream->mode == OUTPUT || stream->mode == DUPLEX) {
6321 err = alGetFillable(stream->handle[0]);
6323 sprintf(message, "RtAudio: AL error getting available frames for stream (%s): %s.",
6324 devices[stream->device[0]].name, alGetErrorString(oserror()));
6325 error(RtError::DRIVER_ERROR);
6331 if (stream->mode == INPUT || stream->mode == DUPLEX) {
6332 err = alGetFilled(stream->handle[1]);
6334 sprintf(message, "RtAudio: AL error getting available frames for stream (%s): %s.",
6335 devices[stream->device[1]].name, alGetErrorString(oserror()));
6336 error(RtError::DRIVER_ERROR);
6338 if (frames > err) frames = err;
6341 frames = stream->bufferSize - frames;
6342 if (frames < 0) frames = 0;
6345 MUTEX_UNLOCK(&stream->mutex);
6349 void RtAudio :: tickStream(int streamId)
6351 RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
6354 if (stream->state == STREAM_STOPPED) {
6355 if (stream->callbackInfo.usingCallback) usleep(50000); // sleep 50 milliseconds
6358 else if (stream->callbackInfo.usingCallback) {
6359 RTAUDIO_CALLBACK callback = (RTAUDIO_CALLBACK) stream->callbackInfo.callback;
6360 stopStream = callback(stream->userBuffer, stream->bufferSize, stream->callbackInfo.userData);
6363 MUTEX_LOCK(&stream->mutex);
6365 // The state might change while waiting on a mutex.
6366 if (stream->state == STREAM_STOPPED)
6371 RTAUDIO_FORMAT format;
6372 if (stream->mode == OUTPUT || stream->mode == DUPLEX) {
6374 // Setup parameters and do buffer conversion if necessary.
6375 if (stream->doConvertBuffer[0]) {
6376 convertStreamBuffer(stream, OUTPUT);
6377 buffer = stream->deviceBuffer;
6378 channels = stream->nDeviceChannels[0];
6379 format = stream->deviceFormat[0];
6382 buffer = stream->userBuffer;
6383 channels = stream->nUserChannels[0];
6384 format = stream->userFormat;
6387 // Do byte swapping if necessary.
6388 if (stream->doByteSwap[0])
6389 byteSwapBuffer(buffer, stream->bufferSize * channels, format);
6391 // Write interleaved samples to device.
6392 alWriteFrames(stream->handle[0], buffer, stream->bufferSize);
6395 if (stream->mode == INPUT || stream->mode == DUPLEX) {
6397 // Setup parameters.
6398 if (stream->doConvertBuffer[1]) {
6399 buffer = stream->deviceBuffer;
6400 channels = stream->nDeviceChannels[1];
6401 format = stream->deviceFormat[1];
6404 buffer = stream->userBuffer;
6405 channels = stream->nUserChannels[1];
6406 format = stream->userFormat;
6409 // Read interleaved samples from device.
6410 alReadFrames(stream->handle[1], buffer, stream->bufferSize);
6412 // Do byte swapping if necessary.
6413 if (stream->doByteSwap[1])
6414 byteSwapBuffer(buffer, stream->bufferSize * channels, format);
6416 // Do buffer conversion if necessary.
6417 if (stream->doConvertBuffer[1])
6418 convertStreamBuffer(stream, INPUT);
6422 MUTEX_UNLOCK(&stream->mutex);
6424 if (stream->callbackInfo.usingCallback && stopStream)
6425 this->stopStream(streamId);
6428 extern "C" void *callbackHandler(void *ptr)
6430 CALLBACK_INFO *info = (CALLBACK_INFO *) ptr;
6431 RtAudio *object = (RtAudio *) info->object;
6432 int stream = info->streamId;
6433 bool *usingCallback = &info->usingCallback;
6435 while ( *usingCallback ) {
6436 pthread_testcancel();
6438 object->tickStream(stream);
6440 catch (RtError &exception) {
6441 fprintf(stderr, "\nRtAudio: Callback thread error (%s) ... closing thread.\n\n",
6442 exception.getMessage());
6450 //******************** End of __IRIX_AL__ *********************//
6455 // *************************************************** //
6457 // Private common (OS-independent) RtAudio methods.
6459 // *************************************************** //
6461 // This method can be modified to control the behavior of error
6462 // message reporting and throwing.
6463 void RtAudio :: error(RtError::TYPE type)
6465 if (type == RtError::WARNING) {
6466 fprintf(stderr, "\n%s\n\n", message);
6468 else if (type == RtError::DEBUG_WARNING) {
6469 #if defined(__RTAUDIO_DEBUG__)
6470 fprintf(stderr, "\n%s\n\n", message);
6474 fprintf(stderr, "\n%s\n\n", message);
6475 throw RtError(message, type);
6479 void *RtAudio :: verifyStream(int streamId)
6481 // Verify the stream key.
6482 if ( streams.find( streamId ) == streams.end() ) {
6483 sprintf(message, "RtAudio: invalid stream identifier!");
6484 error(RtError::INVALID_STREAM);
6487 return streams[streamId];
6490 void RtAudio :: clearDeviceInfo(RTAUDIO_DEVICE *info)
6492 // Don't clear the name or DEVICE_ID fields here ... they are
6493 // typically set prior to a call of this function.
6494 info->probed = false;
6495 info->maxOutputChannels = 0;
6496 info->maxInputChannels = 0;
6497 info->maxDuplexChannels = 0;
6498 info->minOutputChannels = 0;
6499 info->minInputChannels = 0;
6500 info->minDuplexChannels = 0;
6501 info->hasDuplexSupport = false;
6502 info->nSampleRates = 0;
6503 for (int i=0; i<MAX_SAMPLE_RATES; i++)
6504 info->sampleRates[i] = 0;
6505 info->nativeFormats = 0;
6508 int RtAudio :: formatBytes(RTAUDIO_FORMAT format)
6510 if (format == RTAUDIO_SINT16)
6512 else if (format == RTAUDIO_SINT24 || format == RTAUDIO_SINT32 ||
6513 format == RTAUDIO_FLOAT32)
6515 else if (format == RTAUDIO_FLOAT64)
6517 else if (format == RTAUDIO_SINT8)
6520 sprintf(message,"RtAudio: undefined format in formatBytes().");
6521 error(RtError::WARNING);
6526 void RtAudio :: convertStreamBuffer(RTAUDIO_STREAM *stream, STREAM_MODE mode)
6528 // This method does format conversion, input/output channel compensation, and
6529 // data interleaving/deinterleaving. 24-bit integers are assumed to occupy
6530 // the upper three bytes of a 32-bit integer.
6532 int j, jump_in, jump_out, channels;
6533 RTAUDIO_FORMAT format_in, format_out;
6534 char *input, *output;
6536 if (mode == INPUT) { // convert device to user buffer
6537 input = stream->deviceBuffer;
6538 output = stream->userBuffer;
6539 jump_in = stream->nDeviceChannels[1];
6540 jump_out = stream->nUserChannels[1];
6541 format_in = stream->deviceFormat[1];
6542 format_out = stream->userFormat;
6544 else { // convert user to device buffer
6545 input = stream->userBuffer;
6546 output = stream->deviceBuffer;
6547 jump_in = stream->nUserChannels[0];
6548 jump_out = stream->nDeviceChannels[0];
6549 format_in = stream->userFormat;
6550 format_out = stream->deviceFormat[0];
6552 // clear our device buffer when in/out duplex device channels are different
6553 if ( stream->mode == DUPLEX &&
6554 stream->nDeviceChannels[0] != stream->nDeviceChannels[1] )
6555 memset(output, 0, stream->bufferSize * jump_out * formatBytes(format_out));
6558 channels = (jump_in < jump_out) ? jump_in : jump_out;
6560 // Set up the interleave/deinterleave offsets
6561 std::vector<int> offset_in(channels);
6562 std::vector<int> offset_out(channels);
6563 if (mode == INPUT && stream->deInterleave[1]) {
6564 for (int k=0; k<channels; k++) {
6565 offset_in[k] = k * stream->bufferSize;
6570 else if (mode == OUTPUT && stream->deInterleave[0]) {
6571 for (int k=0; k<channels; k++) {
6573 offset_out[k] = k * stream->bufferSize;
6578 for (int k=0; k<channels; k++) {
6584 if (format_out == RTAUDIO_FLOAT64) {
6586 FLOAT64 *out = (FLOAT64 *)output;
6588 if (format_in == RTAUDIO_SINT8) {
6589 signed char *in = (signed char *)input;
6590 scale = 1.0 / 128.0;
6591 for (int i=0; i<stream->bufferSize; i++) {
6592 for (j=0; j<channels; j++) {
6593 out[offset_out[j]] = (FLOAT64) in[offset_in[j]];
6594 out[offset_out[j]] *= scale;
6600 else if (format_in == RTAUDIO_SINT16) {
6601 INT16 *in = (INT16 *)input;
6602 scale = 1.0 / 32768.0;
6603 for (int i=0; i<stream->bufferSize; i++) {
6604 for (j=0; j<channels; j++) {
6605 out[offset_out[j]] = (FLOAT64) in[offset_in[j]];
6606 out[offset_out[j]] *= scale;
6612 else if (format_in == RTAUDIO_SINT24) {
6613 INT32 *in = (INT32 *)input;
6614 scale = 1.0 / 2147483648.0;
6615 for (int i=0; i<stream->bufferSize; i++) {
6616 for (j=0; j<channels; j++) {
6617 out[offset_out[j]] = (FLOAT64) (in[offset_in[j]] & 0xffffff00);
6618 out[offset_out[j]] *= scale;
6624 else if (format_in == RTAUDIO_SINT32) {
6625 INT32 *in = (INT32 *)input;
6626 scale = 1.0 / 2147483648.0;
6627 for (int i=0; i<stream->bufferSize; i++) {
6628 for (j=0; j<channels; j++) {
6629 out[offset_out[j]] = (FLOAT64) in[offset_in[j]];
6630 out[offset_out[j]] *= scale;
6636 else if (format_in == RTAUDIO_FLOAT32) {
6637 FLOAT32 *in = (FLOAT32 *)input;
6638 for (int i=0; i<stream->bufferSize; i++) {
6639 for (j=0; j<channels; j++) {
6640 out[offset_out[j]] = (FLOAT64) in[offset_in[j]];
6646 else if (format_in == RTAUDIO_FLOAT64) {
6647 // Channel compensation and/or (de)interleaving only.
6648 FLOAT64 *in = (FLOAT64 *)input;
6649 for (int i=0; i<stream->bufferSize; i++) {
6650 for (j=0; j<channels; j++) {
6651 out[offset_out[j]] = in[offset_in[j]];
6658 else if (format_out == RTAUDIO_FLOAT32) {
6660 FLOAT32 *out = (FLOAT32 *)output;
6662 if (format_in == RTAUDIO_SINT8) {
6663 signed char *in = (signed char *)input;
6664 scale = 1.0 / 128.0;
6665 for (int i=0; i<stream->bufferSize; i++) {
6666 for (j=0; j<channels; j++) {
6667 out[offset_out[j]] = (FLOAT32) in[offset_in[j]];
6668 out[offset_out[j]] *= scale;
6674 else if (format_in == RTAUDIO_SINT16) {
6675 INT16 *in = (INT16 *)input;
6676 scale = 1.0 / 32768.0;
6677 for (int i=0; i<stream->bufferSize; i++) {
6678 for (j=0; j<channels; j++) {
6679 out[offset_out[j]] = (FLOAT32) in[offset_in[j]];
6680 out[offset_out[j]] *= scale;
6686 else if (format_in == RTAUDIO_SINT24) {
6687 INT32 *in = (INT32 *)input;
6688 scale = 1.0 / 2147483648.0;
6689 for (int i=0; i<stream->bufferSize; i++) {
6690 for (j=0; j<channels; j++) {
6691 out[offset_out[j]] = (FLOAT32) (in[offset_in[j]] & 0xffffff00);
6692 out[offset_out[j]] *= scale;
6698 else if (format_in == RTAUDIO_SINT32) {
6699 INT32 *in = (INT32 *)input;
6700 scale = 1.0 / 2147483648.0;
6701 for (int i=0; i<stream->bufferSize; i++) {
6702 for (j=0; j<channels; j++) {
6703 out[offset_out[j]] = (FLOAT32) in[offset_in[j]];
6704 out[offset_out[j]] *= scale;
6710 else if (format_in == RTAUDIO_FLOAT32) {
6711 // Channel compensation and/or (de)interleaving only.
6712 FLOAT32 *in = (FLOAT32 *)input;
6713 for (int i=0; i<stream->bufferSize; i++) {
6714 for (j=0; j<channels; j++) {
6715 out[offset_out[j]] = in[offset_in[j]];
6721 else if (format_in == RTAUDIO_FLOAT64) {
6722 FLOAT64 *in = (FLOAT64 *)input;
6723 for (int i=0; i<stream->bufferSize; i++) {
6724 for (j=0; j<channels; j++) {
6725 out[offset_out[j]] = (FLOAT32) in[offset_in[j]];
6732 else if (format_out == RTAUDIO_SINT32) {
6733 INT32 *out = (INT32 *)output;
6734 if (format_in == RTAUDIO_SINT8) {
6735 signed char *in = (signed char *)input;
6736 for (int i=0; i<stream->bufferSize; i++) {
6737 for (j=0; j<channels; j++) {
6738 out[offset_out[j]] = (INT32) in[offset_in[j]];
6739 out[offset_out[j]] <<= 24;
6745 else if (format_in == RTAUDIO_SINT16) {
6746 INT16 *in = (INT16 *)input;
6747 for (int i=0; i<stream->bufferSize; i++) {
6748 for (j=0; j<channels; j++) {
6749 out[offset_out[j]] = (INT32) in[offset_in[j]];
6750 out[offset_out[j]] <<= 16;
6756 else if (format_in == RTAUDIO_SINT24) {
6757 INT32 *in = (INT32 *)input;
6758 for (int i=0; i<stream->bufferSize; i++) {
6759 for (j=0; j<channels; j++) {
6760 out[offset_out[j]] = (INT32) in[offset_in[j]];
6766 else if (format_in == RTAUDIO_SINT32) {
6767 // Channel compensation and/or (de)interleaving only.
6768 INT32 *in = (INT32 *)input;
6769 for (int i=0; i<stream->bufferSize; i++) {
6770 for (j=0; j<channels; j++) {
6771 out[offset_out[j]] = in[offset_in[j]];
6777 else if (format_in == RTAUDIO_FLOAT32) {
6778 FLOAT32 *in = (FLOAT32 *)input;
6779 for (int i=0; i<stream->bufferSize; i++) {
6780 for (j=0; j<channels; j++) {
6781 out[offset_out[j]] = (INT32) (in[offset_in[j]] * 2147483647.0);
6787 else if (format_in == RTAUDIO_FLOAT64) {
6788 FLOAT64 *in = (FLOAT64 *)input;
6789 for (int i=0; i<stream->bufferSize; i++) {
6790 for (j=0; j<channels; j++) {
6791 out[offset_out[j]] = (INT32) (in[offset_in[j]] * 2147483647.0);
6798 else if (format_out == RTAUDIO_SINT24) {
6799 INT32 *out = (INT32 *)output;
6800 if (format_in == RTAUDIO_SINT8) {
6801 signed char *in = (signed char *)input;
6802 for (int i=0; i<stream->bufferSize; i++) {
6803 for (j=0; j<channels; j++) {
6804 out[offset_out[j]] = (INT32) in[offset_in[j]];
6805 out[offset_out[j]] <<= 24;
6811 else if (format_in == RTAUDIO_SINT16) {
6812 INT16 *in = (INT16 *)input;
6813 for (int i=0; i<stream->bufferSize; i++) {
6814 for (j=0; j<channels; j++) {
6815 out[offset_out[j]] = (INT32) in[offset_in[j]];
6816 out[offset_out[j]] <<= 16;
6822 else if (format_in == RTAUDIO_SINT24) {
6823 // Channel compensation and/or (de)interleaving only.
6824 INT32 *in = (INT32 *)input;
6825 for (int i=0; i<stream->bufferSize; i++) {
6826 for (j=0; j<channels; j++) {
6827 out[offset_out[j]] = in[offset_in[j]];
6833 else if (format_in == RTAUDIO_SINT32) {
6834 INT32 *in = (INT32 *)input;
6835 for (int i=0; i<stream->bufferSize; i++) {
6836 for (j=0; j<channels; j++) {
6837 out[offset_out[j]] = (INT32) (in[offset_in[j]] & 0xffffff00);
6843 else if (format_in == RTAUDIO_FLOAT32) {
6844 FLOAT32 *in = (FLOAT32 *)input;
6845 for (int i=0; i<stream->bufferSize; i++) {
6846 for (j=0; j<channels; j++) {
6847 out[offset_out[j]] = (INT32) (in[offset_in[j]] * 2147483647.0);
6853 else if (format_in == RTAUDIO_FLOAT64) {
6854 FLOAT64 *in = (FLOAT64 *)input;
6855 for (int i=0; i<stream->bufferSize; i++) {
6856 for (j=0; j<channels; j++) {
6857 out[offset_out[j]] = (INT32) (in[offset_in[j]] * 2147483647.0);
6864 else if (format_out == RTAUDIO_SINT16) {
6865 INT16 *out = (INT16 *)output;
6866 if (format_in == RTAUDIO_SINT8) {
6867 signed char *in = (signed char *)input;
6868 for (int i=0; i<stream->bufferSize; i++) {
6869 for (j=0; j<channels; j++) {
6870 out[offset_out[j]] = (INT16) in[offset_in[j]];
6871 out[offset_out[j]] <<= 8;
6877 else if (format_in == RTAUDIO_SINT16) {
6878 // Channel compensation and/or (de)interleaving only.
6879 INT16 *in = (INT16 *)input;
6880 for (int i=0; i<stream->bufferSize; i++) {
6881 for (j=0; j<channels; j++) {
6882 out[offset_out[j]] = in[offset_in[j]];
6888 else if (format_in == RTAUDIO_SINT24) {
6889 INT32 *in = (INT32 *)input;
6890 for (int i=0; i<stream->bufferSize; i++) {
6891 for (j=0; j<channels; j++) {
6892 out[offset_out[j]] = (INT16) ((in[offset_in[j]] >> 16) & 0x0000ffff);
6898 else if (format_in == RTAUDIO_SINT32) {
6899 INT32 *in = (INT32 *)input;
6900 for (int i=0; i<stream->bufferSize; i++) {
6901 for (j=0; j<channels; j++) {
6902 out[offset_out[j]] = (INT16) ((in[offset_in[j]] >> 16) & 0x0000ffff);
6908 else if (format_in == RTAUDIO_FLOAT32) {
6909 FLOAT32 *in = (FLOAT32 *)input;
6910 for (int i=0; i<stream->bufferSize; i++) {
6911 for (j=0; j<channels; j++) {
6912 out[offset_out[j]] = (INT16) (in[offset_in[j]] * 32767.0);
6918 else if (format_in == RTAUDIO_FLOAT64) {
6919 FLOAT64 *in = (FLOAT64 *)input;
6920 for (int i=0; i<stream->bufferSize; i++) {
6921 for (j=0; j<channels; j++) {
6922 out[offset_out[j]] = (INT16) (in[offset_in[j]] * 32767.0);
6929 else if (format_out == RTAUDIO_SINT8) {
6930 signed char *out = (signed char *)output;
6931 if (format_in == RTAUDIO_SINT8) {
6932 // Channel compensation and/or (de)interleaving only.
6933 signed char *in = (signed char *)input;
6934 for (int i=0; i<stream->bufferSize; i++) {
6935 for (j=0; j<channels; j++) {
6936 out[offset_out[j]] = in[offset_in[j]];
6942 if (format_in == RTAUDIO_SINT16) {
6943 INT16 *in = (INT16 *)input;
6944 for (int i=0; i<stream->bufferSize; i++) {
6945 for (j=0; j<channels; j++) {
6946 out[offset_out[j]] = (signed char) ((in[offset_in[j]] >> 8) & 0x00ff);
6952 else if (format_in == RTAUDIO_SINT24) {
6953 INT32 *in = (INT32 *)input;
6954 for (int i=0; i<stream->bufferSize; i++) {
6955 for (j=0; j<channels; j++) {
6956 out[offset_out[j]] = (signed char) ((in[offset_in[j]] >> 24) & 0x000000ff);
6962 else if (format_in == RTAUDIO_SINT32) {
6963 INT32 *in = (INT32 *)input;
6964 for (int i=0; i<stream->bufferSize; i++) {
6965 for (j=0; j<channels; j++) {
6966 out[offset_out[j]] = (signed char) ((in[offset_in[j]] >> 24) & 0x000000ff);
6972 else if (format_in == RTAUDIO_FLOAT32) {
6973 FLOAT32 *in = (FLOAT32 *)input;
6974 for (int i=0; i<stream->bufferSize; i++) {
6975 for (j=0; j<channels; j++) {
6976 out[offset_out[j]] = (signed char) (in[offset_in[j]] * 127.0);
6982 else if (format_in == RTAUDIO_FLOAT64) {
6983 FLOAT64 *in = (FLOAT64 *)input;
6984 for (int i=0; i<stream->bufferSize; i++) {
6985 for (j=0; j<channels; j++) {
6986 out[offset_out[j]] = (signed char) (in[offset_in[j]] * 127.0);
6995 void RtAudio :: byteSwapBuffer(char *buffer, int samples, RTAUDIO_FORMAT format)
7001 if (format == RTAUDIO_SINT16) {
7002 for (int i=0; i<samples; i++) {
7003 // Swap 1st and 2nd bytes.
7008 // Increment 2 bytes.
7012 else if (format == RTAUDIO_SINT24 ||
7013 format == RTAUDIO_SINT32 ||
7014 format == RTAUDIO_FLOAT32) {
7015 for (int i=0; i<samples; i++) {
7016 // Swap 1st and 4th bytes.
7021 // Swap 2nd and 3rd bytes.
7027 // Increment 4 bytes.
7031 else if (format == RTAUDIO_FLOAT64) {
7032 for (int i=0; i<samples; i++) {
7033 // Swap 1st and 8th bytes
7038 // Swap 2nd and 7th bytes
7044 // Swap 3rd and 6th bytes
7050 // Swap 4th and 5th bytes
7056 // Increment 8 bytes.
7063 // *************************************************** //
7065 // RtError class definition.
7067 // *************************************************** //
7069 RtError :: RtError(const char *p, TYPE tipe)
7072 strncpy(error_message, p, 256);
7075 RtError :: ~RtError()
7079 void RtError :: printMessage()
7081 printf("\n%s\n\n", error_message);