CLAM-Development  1.4.0
RtAudio.cxx
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2004 MUSIC TECHNOLOGY GROUP (MTG)
3  * UNIVERSITAT POMPEU FABRA
4  *
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19  *
20  */
21 
22 /************************************************************************/
59 /************************************************************************/
60 
61 // RtAudio: Version 2.1.1, 24 October 2002
62 
63 #include "RtAudio.hxx"
64 #include <vector>
65 #include <cstdio>
66 #include <iostream>
67 
68 // Static variable definitions.
69 const unsigned int RtAudio :: SAMPLE_RATES[] = {
70  4000, 5512, 8000, 9600, 11025, 16000, 22050,
71  32000, 44100, 48000, 88200, 96000, 176400, 192000
72 };
79 
80 #if defined(__WINDOWS_DS__) || defined(__WINDOWS_ASIO__)
81  #define MUTEX_INITIALIZE(A) InitializeCriticalSection(A)
82  #define MUTEX_LOCK(A) EnterCriticalSection(A)
83  #define MUTEX_UNLOCK(A) LeaveCriticalSection(A)
84 #else // pthread API
85  #define MUTEX_INITIALIZE(A) pthread_mutex_init(A, NULL)
86  #define MUTEX_LOCK(A) pthread_mutex_lock(A)
87  #define MUTEX_UNLOCK(A) pthread_mutex_unlock(A)
88 #endif
89 
90 // *************************************************** //
91 //
92 // Public common (OS-independent) methods.
93 //
94 // *************************************************** //
95 
97 {
98  initialize();
99 
100  if (nDevices <= 0) {
101  sprintf(message, "RtAudio: no audio devices found!");
103  }
104 }
105 
106 RtAudio :: RtAudio(int *streamId,
107  int outputDevice, int outputChannels,
108  int inputDevice, int inputChannels,
109  RTAUDIO_FORMAT format, int sampleRate,
110  int *bufferSize, int numberOfBuffers)
111 {
112  initialize();
113 
114  if (nDevices <= 0) {
115  sprintf(message, "RtAudio: no audio devices found!");
117  }
118 
119  try {
120  *streamId = openStream(outputDevice, outputChannels, inputDevice, inputChannels,
121  format, sampleRate, bufferSize, numberOfBuffers);
122  }
123  catch (RtError &exception) {
124  // deallocate the RTAUDIO_DEVICE structures
125  if (devices) free(devices);
126  throw exception;
127  }
128 }
129 
131 {
132  // close any existing streams
133  while ( streams.size() )
134  closeStream( streams.begin()->first );
135 
136  // deallocate the RTAUDIO_DEVICE structures
137  if (devices) free(devices);
138 }
139 
140 int RtAudio :: openStream(int outputDevice, int outputChannels,
141  int inputDevice, int inputChannels,
142  RTAUDIO_FORMAT format, int sampleRate,
143  int *bufferSize, int numberOfBuffers)
144 {
145  static int streamKey = 0; // Unique stream identifier ... OK for multiple instances.
146 
147  if (outputChannels < 1 && inputChannels < 1) {
148  sprintf(message,"RtAudio: one or both 'channel' parameters must be greater than zero.");
150  }
151 
152  if ( formatBytes(format) == 0 ) {
153  sprintf(message,"RtAudio: 'format' parameter value is undefined.");
155  }
156 
157  if ( outputChannels > 0 ) {
158  if (outputDevice > nDevices || outputDevice < 0) {
159  sprintf(message,"RtAudio: 'outputDevice' parameter value (%d) is invalid.", outputDevice);
161  }
162  }
163 
164  if ( inputChannels > 0 ) {
165  if (inputDevice > nDevices || inputDevice < 0) {
166  sprintf(message,"RtAudio: 'inputDevice' parameter value (%d) is invalid.", inputDevice);
168  }
169  }
170 
171  // Allocate a new stream structure.
172  RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) calloc(1, sizeof(RTAUDIO_STREAM));
173  if (stream == NULL) {
174  sprintf(message, "RtAudio: memory allocation error!");
175  error(RtError::MEMORY_ERROR);
176  }
177  stream->mode = UNINITIALIZED;
178  MUTEX_INITIALIZE(&stream->mutex);
179 
180  bool result = FAILURE;
181  int device, defaultDevice = 0;
182  STREAM_MODE mode;
183  int channels;
184  if ( outputChannels > 0 ) {
185 
186  mode = OUTPUT;
187  channels = outputChannels;
188 
189  if ( outputDevice == 0 ) { // Try default device first.
190  defaultDevice = getDefaultOutputDevice();
191  device = defaultDevice;
192  }
193  else
194  device = outputDevice - 1;
195 
196  for (int i=-1; i<nDevices; i++) {
197  if (i >= 0 ) {
198  if ( i == defaultDevice ) continue;
199  device = i;
200  }
201  if (devices[device].probed == false) {
202  // If the device wasn't successfully probed before, try it
203  // again now.
204  clearDeviceInfo(&devices[device]);
205  probeDeviceInfo(&devices[device]);
206  }
207  if ( devices[device].probed )
208  result = probeDeviceOpen(device, stream, mode, channels, sampleRate,
209  format, bufferSize, numberOfBuffers);
210  if (result == SUCCESS) break;
211  if ( outputDevice > 0 ) break;
212  }
213  }
214 
215  if ( inputChannels > 0 && ( result == SUCCESS || outputChannels <= 0 ) ) {
216 
217  mode = INPUT;
218  channels = inputChannels;
219 
220  if ( inputDevice == 0 ) { // Try default device first.
221  defaultDevice = getDefaultInputDevice();
222  device = defaultDevice;
223  }
224  else
225  device = inputDevice - 1;
226 
227  for (int i=-1; i<nDevices; i++) {
228  if (i >= 0 ) {
229  if ( i == defaultDevice ) continue;
230  device = i;
231  }
232  if (devices[device].probed == false) {
233  // If the device wasn't successfully probed before, try it
234  // again now.
235  clearDeviceInfo(&devices[device]);
236  probeDeviceInfo(&devices[device]);
237  }
238  if ( devices[device].probed )
239  result = probeDeviceOpen(device, stream, mode, channels, sampleRate,
240  format, bufferSize, numberOfBuffers);
241  if (result == SUCCESS) break;
242  if ( outputDevice > 0 ) break;
243  }
244  }
245 
246  streams[++streamKey] = (void *) stream;
247  if ( result == SUCCESS )
248  return streamKey;
249 
250  // If we get here, all attempted probes failed. Close any opened
251  // devices and delete the allocated stream.
252  closeStream(streamKey);
253  if ( ( outputDevice == 0 && outputChannels > 0 )
254  || ( inputDevice == 0 && inputChannels > 0 ) )
255  sprintf(message,"RtAudio: no devices found for given parameters.");
256  else
257  sprintf(message,"RtAudio: unable to open specified device(s) with given stream parameters.");
259 
260  return -1;
261 }
262 
264 {
265  return nDevices;
266 }
267 
269 {
270  if (device > nDevices || device < 1) {
271  sprintf(message, "RtAudio: invalid device specifier (%d)!", device);
273  }
274 
275  int deviceIndex = device - 1;
276 
277  // If the device wasn't successfully probed before, try it now (or again).
278  if (devices[deviceIndex].probed == false) {
279  clearDeviceInfo(&devices[deviceIndex]);
280  probeDeviceInfo(&devices[deviceIndex]);
281  }
282 
283  // Clear the info structure.
284  memset(info, 0, sizeof(RTAUDIO_DEVICE));
285 
286  strncpy(info->name, devices[deviceIndex].name, 128);
287  info->probed = devices[deviceIndex].probed;
288  if ( info->probed == true ) {
289  info->maxOutputChannels = devices[deviceIndex].maxOutputChannels;
290  info->maxInputChannels = devices[deviceIndex].maxInputChannels;
291  info->maxDuplexChannels = devices[deviceIndex].maxDuplexChannels;
292  info->minOutputChannels = devices[deviceIndex].minOutputChannels;
293  info->minInputChannels = devices[deviceIndex].minInputChannels;
294  info->minDuplexChannels = devices[deviceIndex].minDuplexChannels;
295  info->hasDuplexSupport = devices[deviceIndex].hasDuplexSupport;
296  info->nSampleRates = devices[deviceIndex].nSampleRates;
297  if (info->nSampleRates == -1) {
298  info->sampleRates[0] = devices[deviceIndex].sampleRates[0];
299  info->sampleRates[1] = devices[deviceIndex].sampleRates[1];
300  }
301  else {
302  for (int i=0; i<info->nSampleRates; i++)
303  info->sampleRates[i] = devices[deviceIndex].sampleRates[i];
304  }
305  info->nativeFormats = devices[deviceIndex].nativeFormats;
306  if ( deviceIndex == getDefaultOutputDevice() ||
307  deviceIndex == getDefaultInputDevice() )
308  info->isDefault = true;
309  }
310 
311  return;
312 }
313 
314 char * const RtAudio :: getStreamBuffer(int streamId)
315 {
316  RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
317 
318  return stream->userBuffer;
319 }
320 
321 #if defined(__LINUX_ALSA__) || defined(__LINUX_OSS__) || defined(__IRIX_AL__)
322 
323 extern "C" void *callbackHandler(void * ptr);
324 
325 void RtAudio :: setStreamCallback(int streamId, RTAUDIO_CALLBACK callback, void *userData)
326 {
327  RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
328 
329  CALLBACK_INFO *info = (CALLBACK_INFO *) &stream->callbackInfo;
330  if ( info->usingCallback ) {
331  sprintf(message, "RtAudio: A callback is already set for this stream!");
332  error(RtError::WARNING);
333  return;
334  }
335 
336  info->callback = (void *) callback;
337  info->userData = userData;
338  info->usingCallback = true;
339  info->object = (void *) this;
340  info->streamId = streamId;
341 
342  int err = pthread_create(&info->thread, NULL, callbackHandler, &stream->callbackInfo);
343 
344  if (err) {
345  info->usingCallback = false;
346  sprintf(message, "RtAudio: error starting callback thread!");
347  error(RtError::THREAD_ERROR);
348  }
349 }
350 
351 void RtAudio :: cancelStreamCallback(int streamId)
352 {
353  RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
354 
355  if (stream->callbackInfo.usingCallback) {
356 
357  if (stream->state == STREAM_RUNNING)
358  stopStream( streamId );
359 
360  MUTEX_LOCK(&stream->mutex);
361 
362  stream->callbackInfo.usingCallback = false;
363  pthread_cancel(stream->callbackInfo.thread);
364  pthread_join(stream->callbackInfo.thread, NULL);
365  stream->callbackInfo.thread = 0;
366  stream->callbackInfo.callback = NULL;
367  stream->callbackInfo.userData = NULL;
368 
369  MUTEX_UNLOCK(&stream->mutex);
370  }
371 }
372 
373 #endif
374 
375 // *************************************************** //
376 //
377 // OS/API-specific methods.
378 //
379 // *************************************************** //
380 
381 #if defined(__MACOSX_CORE__)
382 
383 // The OS X CoreAudio API is designed to use a separate callback
384 // procedure for each of its audio devices. A single RtAudio duplex
385 // stream using two different devices is supported here, though it
386 // cannot be guaranteed to always behave correctly because we cannot
387 // synchronize these two callbacks. This same functionality can be
388 // achieved with better synchrony by opening two separate streams for
389 // the devices and using RtAudio blocking calls (i.e. tickStream()).
390 //
391 // The possibility of having multiple RtAudio streams accessing the
392 // same CoreAudio device is not currently supported. The problem
393 // involves the inability to install our callbackHandler function for
394 // the same device more than once. I experimented with a workaround
395 // for this, but it requires an additional buffer for mixing output
396 // data before filling the CoreAudio device buffer. In the end, I
397 // decided it wasn't worth supporting.
398 //
399 // Property listeners are currently not used. The issue is what could
400 // be done if a critical stream parameter (buffer size, sample rate,
401 // device disconnect) notification arrived. The listeners entail
402 // quite a bit of extra code and most likely, a user program wouldn't
403 // be prepared for the result anyway. Some initial listener code is
404 // commented out.
405 
406 void RtAudio :: initialize(void)
407 {
408  OSStatus err = noErr;
409  UInt32 dataSize;
410  AudioDeviceID *deviceList = NULL;
411  nDevices = 0;
412 
413  // Find out how many audio devices there are, if any.
414  err = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDevices, &dataSize, NULL);
415  if (err != noErr) {
416  sprintf(message, "RtAudio: OSX error getting device info!");
417  error(RtError::SYSTEM_ERROR);
418  }
419 
420  nDevices = dataSize / sizeof(AudioDeviceID);
421  if (nDevices == 0) return;
422 
423  // Allocate the RTAUDIO_DEVICE structures.
424  devices = (RTAUDIO_DEVICE *) calloc(nDevices, sizeof(RTAUDIO_DEVICE));
425  if (devices == NULL) {
426  sprintf(message, "RtAudio: memory allocation error!");
427  error(RtError::MEMORY_ERROR);
428  }
429 
430  // Make space for the devices we are about to get.
431  deviceList = (AudioDeviceID *) malloc( dataSize );
432  if (deviceList == NULL) {
433  sprintf(message, "RtAudio: memory allocation error!");
434  error(RtError::MEMORY_ERROR);
435  }
436 
437  // Get the array of AudioDeviceIDs.
438  err = AudioHardwareGetProperty(kAudioHardwarePropertyDevices, &dataSize, (void *) deviceList);
439  if (err != noErr) {
440  free(deviceList);
441  sprintf(message, "RtAudio: OSX error getting device properties!");
442  error(RtError::SYSTEM_ERROR);
443  }
444 
445  // Write device identifiers to device structures and then
446  // probe the device capabilities.
447  for (int i=0; i<nDevices; i++) {
448  devices[i].id[0] = deviceList[i];
449  //probeDeviceInfo(&devices[i]);
450  }
451 
452  free(deviceList);
453 }
454 
455 int RtAudio :: getDefaultInputDevice(void)
456 {
457  AudioDeviceID id;
458  UInt32 dataSize = sizeof( AudioDeviceID );
459 
460  OSStatus result = AudioHardwareGetProperty( kAudioHardwarePropertyDefaultInputDevice,
461  &dataSize, &id );
462 
463  if (result != noErr) {
464  sprintf( message, "RtAudio: OSX error getting default input device." );
465  error(RtError::WARNING);
466  return 0;
467  }
468 
469  for ( int i=0; i<nDevices; i++ ) {
470  if ( id == devices[i].id[0] ) return i;
471  }
472 
473  return 0;
474 }
475 
476 int RtAudio :: getDefaultOutputDevice(void)
477 {
478  AudioDeviceID id;
479  UInt32 dataSize = sizeof( AudioDeviceID );
480 
481  OSStatus result = AudioHardwareGetProperty( kAudioHardwarePropertyDefaultOutputDevice,
482  &dataSize, &id );
483 
484  if (result != noErr) {
485  sprintf( message, "RtAudio: OSX error getting default output device." );
486  error(RtError::WARNING);
487  return 0;
488  }
489 
490  for ( int i=0; i<nDevices; i++ ) {
491  if ( id == devices[i].id[0] ) return i;
492  }
493 
494  return 0;
495 }
496 
497 static bool deviceSupportsFormat( AudioDeviceID id, bool isInput,
498  AudioStreamBasicDescription *desc, bool isDuplex )
499 {
500  OSStatus result = noErr;
501  UInt32 dataSize = sizeof( AudioStreamBasicDescription );
502 
503  result = AudioDeviceGetProperty( id, 0, isInput,
504  kAudioDevicePropertyStreamFormatSupported,
505  &dataSize, desc );
506 
507  if (result == kAudioHardwareNoError) {
508  if ( isDuplex ) {
509  result = AudioDeviceGetProperty( id, 0, true,
510  kAudioDevicePropertyStreamFormatSupported,
511  &dataSize, desc );
512 
513 
514  if (result != kAudioHardwareNoError)
515  return false;
516  }
517  return true;
518  }
519 
520  return false;
521 }
522 
523 void RtAudio :: probeDeviceInfo(RTAUDIO_DEVICE *info)
524 {
525  OSStatus err = noErr;
526 
527  // Get the device manufacturer and name.
528  char name[256];
529  char fullname[512];
530  UInt32 dataSize = 256;
531  err = AudioDeviceGetProperty( info->id[0], 0, false,
532  kAudioDevicePropertyDeviceManufacturer,
533  &dataSize, name );
534  if (err != noErr) {
535  sprintf( message, "RtAudio: OSX error getting device manufacturer." );
536  error(RtError::DEBUG_WARNING);
537  return;
538  }
539  strncpy(fullname, name, 256);
540  strcat(fullname, ": " );
541 
542  dataSize = 256;
543  err = AudioDeviceGetProperty( info->id[0], 0, false,
544  kAudioDevicePropertyDeviceName,
545  &dataSize, name );
546  if (err != noErr) {
547  sprintf( message, "RtAudio: OSX error getting device name." );
548  error(RtError::DEBUG_WARNING);
549  return;
550  }
551  strncat(fullname, name, 254);
552  strncat(info->name, fullname, 128);
553 
554  // Get output channel information.
555  unsigned int i, minChannels, maxChannels, nStreams = 0;
556  AudioBufferList *bufferList = nil;
557  err = AudioDeviceGetPropertyInfo( info->id[0], 0, false,
558  kAudioDevicePropertyStreamConfiguration,
559  &dataSize, NULL );
560  if (err == noErr && dataSize > 0) {
561  bufferList = (AudioBufferList *) malloc( dataSize );
562  if (bufferList == NULL) {
563  sprintf(message, "RtAudio: memory allocation error!");
564  error(RtError::DEBUG_WARNING);
565  return;
566  }
567 
568  err = AudioDeviceGetProperty( info->id[0], 0, false,
569  kAudioDevicePropertyStreamConfiguration,
570  &dataSize, bufferList );
571  if (err == noErr) {
572  maxChannels = 0;
573  minChannels = 1000;
574  nStreams = bufferList->mNumberBuffers;
575  for ( i=0; i<nStreams; i++ ) {
576  maxChannels += bufferList->mBuffers[i].mNumberChannels;
577  if ( bufferList->mBuffers[i].mNumberChannels < minChannels )
578  minChannels = bufferList->mBuffers[i].mNumberChannels;
579  }
580  }
581  }
582  if (err != noErr || dataSize <= 0) {
583  sprintf( message, "RtAudio: OSX error getting output channels for device (%s).", info->name );
584  error(RtError::DEBUG_WARNING);
585  return;
586  }
587 
588  free (bufferList);
589  if ( nStreams ) {
590  if ( maxChannels > 0 )
591  info->maxOutputChannels = maxChannels;
592  if ( minChannels > 0 )
593  info->minOutputChannels = minChannels;
594  }
595 
596  // Get input channel information.
597  bufferList = nil;
598  err = AudioDeviceGetPropertyInfo( info->id[0], 0, true,
599  kAudioDevicePropertyStreamConfiguration,
600  &dataSize, NULL );
601  if (err == noErr && dataSize > 0) {
602  bufferList = (AudioBufferList *) malloc( dataSize );
603  if (bufferList == NULL) {
604  sprintf(message, "RtAudio: memory allocation error!");
605  error(RtError::DEBUG_WARNING);
606  return;
607  }
608  err = AudioDeviceGetProperty( info->id[0], 0, true,
609  kAudioDevicePropertyStreamConfiguration,
610  &dataSize, bufferList );
611  if (err == noErr) {
612  maxChannels = 0;
613  minChannels = 1000;
614  nStreams = bufferList->mNumberBuffers;
615  for ( i=0; i<nStreams; i++ ) {
616  if ( bufferList->mBuffers[i].mNumberChannels < minChannels )
617  minChannels = bufferList->mBuffers[i].mNumberChannels;
618  maxChannels += bufferList->mBuffers[i].mNumberChannels;
619  }
620  }
621  }
622  if (err != noErr || dataSize <= 0) {
623  sprintf( message, "RtAudio: OSX error getting input channels for device (%s).", info->name );
624  error(RtError::DEBUG_WARNING);
625  return;
626  }
627 
628  free (bufferList);
629  if ( nStreams ) {
630  if ( maxChannels > 0 )
631  info->maxInputChannels = maxChannels;
632  if ( minChannels > 0 )
633  info->minInputChannels = minChannels;
634  }
635 
636  // If device opens for both playback and capture, we determine the channels.
637  if (info->maxOutputChannels > 0 && info->maxInputChannels > 0) {
638  info->hasDuplexSupport = true;
639  info->maxDuplexChannels = (info->maxOutputChannels > info->maxInputChannels) ?
640  info->maxInputChannels : info->maxOutputChannels;
641  info->minDuplexChannels = (info->minOutputChannels > info->minInputChannels) ?
642  info->minInputChannels : info->minOutputChannels;
643  }
644 
645  // Probe the device sample rate and data format parameters. The
646  // core audio query mechanism is performed on a "stream"
647  // description, which can have a variable number of channels and
648  // apply to input or output only.
649 
650  // Create a stream description structure.
651  AudioStreamBasicDescription description;
652  dataSize = sizeof( AudioStreamBasicDescription );
653  memset(&description, 0, sizeof(AudioStreamBasicDescription));
654  bool isInput = false;
655  if ( info->maxOutputChannels == 0 ) isInput = true;
656  bool isDuplex = false;
657  if ( info->maxDuplexChannels > 0 ) isDuplex = true;
658 
659  // Determine the supported sample rates.
660  info->nSampleRates = 0;
661  for (i=0; i<MAX_SAMPLE_RATES; i++) {
662  description.mSampleRate = (double) SAMPLE_RATES[i];
663  if ( deviceSupportsFormat( info->id[0], isInput, &description, isDuplex ) )
664  info->sampleRates[info->nSampleRates++] = SAMPLE_RATES[i];
665  }
666 
667  if (info->nSampleRates == 0) {
668  sprintf( message, "RtAudio: No supported sample rates found for OSX device (%s).", info->name );
669  error(RtError::DEBUG_WARNING);
670  return;
671  }
672 
673  // Check for continuous sample rate support.
674  description.mSampleRate = kAudioStreamAnyRate;
675  if ( deviceSupportsFormat( info->id[0], isInput, &description, isDuplex ) ) {
676  info->sampleRates[1] = info->sampleRates[info->nSampleRates-1];
677  info->nSampleRates = -1;
678  }
679 
680  // Determine the supported data formats.
681  info->nativeFormats = 0;
682  description.mFormatID = kAudioFormatLinearPCM;
683  description.mBitsPerChannel = 8;
684  description.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsPacked | kLinearPCMFormatFlagIsBigEndian;
685  if ( deviceSupportsFormat( info->id[0], isInput, &description, isDuplex ) )
686  info->nativeFormats |= RTAUDIO_SINT8;
687  else {
688  description.mFormatFlags &= ~kLinearPCMFormatFlagIsBigEndian;
689  if ( deviceSupportsFormat( info->id[0], isInput, &description, isDuplex ) )
690  info->nativeFormats |= RTAUDIO_SINT8;
691  }
692 
693  description.mBitsPerChannel = 16;
694  description.mFormatFlags |= kLinearPCMFormatFlagIsBigEndian;
695  if ( deviceSupportsFormat( info->id[0], isInput, &description, isDuplex ) )
696  info->nativeFormats |= RTAUDIO_SINT16;
697  else {
698  description.mFormatFlags &= ~kLinearPCMFormatFlagIsBigEndian;
699  if ( deviceSupportsFormat( info->id[0], isInput, &description, isDuplex ) )
700  info->nativeFormats |= RTAUDIO_SINT16;
701  }
702 
703  description.mBitsPerChannel = 32;
704  description.mFormatFlags |= kLinearPCMFormatFlagIsBigEndian;
705  if ( deviceSupportsFormat( info->id[0], isInput, &description, isDuplex ) )
706  info->nativeFormats |= RTAUDIO_SINT32;
707  else {
708  description.mFormatFlags &= ~kLinearPCMFormatFlagIsBigEndian;
709  if ( deviceSupportsFormat( info->id[0], isInput, &description, isDuplex ) )
710  info->nativeFormats |= RTAUDIO_SINT32;
711  }
712 
713  description.mBitsPerChannel = 24;
714  description.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsAlignedHigh | kLinearPCMFormatFlagIsBigEndian;
715  if ( deviceSupportsFormat( info->id[0], isInput, &description, isDuplex ) )
716  info->nativeFormats |= RTAUDIO_SINT24;
717  else {
718  description.mFormatFlags &= ~kLinearPCMFormatFlagIsBigEndian;
719  if ( deviceSupportsFormat( info->id[0], isInput, &description, isDuplex ) )
720  info->nativeFormats |= RTAUDIO_SINT24;
721  }
722 
723  description.mBitsPerChannel = 32;
724  description.mFormatFlags = kLinearPCMFormatFlagIsFloat | kLinearPCMFormatFlagIsPacked | kLinearPCMFormatFlagIsBigEndian;
725  if ( deviceSupportsFormat( info->id[0], isInput, &description, isDuplex ) )
726  info->nativeFormats |= RTAUDIO_FLOAT32;
727  else {
728  description.mFormatFlags &= ~kLinearPCMFormatFlagIsBigEndian;
729  if ( deviceSupportsFormat( info->id[0], isInput, &description, isDuplex ) )
730  info->nativeFormats |= RTAUDIO_FLOAT32;
731  }
732 
733  description.mBitsPerChannel = 64;
734  description.mFormatFlags |= kLinearPCMFormatFlagIsBigEndian;
735  if ( deviceSupportsFormat( info->id[0], isInput, &description, isDuplex ) )
736  info->nativeFormats |= RTAUDIO_FLOAT64;
737  else {
738  description.mFormatFlags &= ~kLinearPCMFormatFlagIsBigEndian;
739  if ( deviceSupportsFormat( info->id[0], isInput, &description, isDuplex ) )
740  info->nativeFormats |= RTAUDIO_FLOAT64;
741  }
742 
743  // Check that we have at least one supported format.
744  if (info->nativeFormats == 0) {
745  sprintf(message, "RtAudio: OSX PCM device (%s) data format not supported by RtAudio.",
746  info->name);
747  error(RtError::DEBUG_WARNING);
748  return;
749  }
750 
751  info->probed = true;
752 }
753 
754 OSStatus callbackHandler(AudioDeviceID inDevice,
755  const AudioTimeStamp* inNow,
756  const AudioBufferList* inInputData,
757  const AudioTimeStamp* inInputTime,
758  AudioBufferList* outOutputData,
759  const AudioTimeStamp* inOutputTime,
760  void* infoPointer)
761 {
762  CALLBACK_INFO *info = (CALLBACK_INFO *) infoPointer;
763 
764  RtAudio *object = (RtAudio *) info->object;
765  try {
766  object->callbackEvent( info->streamId, inDevice, (void *)inInputData, (void *)outOutputData );
767  }
768  catch (RtError &exception) {
769  fprintf(stderr, "\nCallback handler error (%s)!\n\n", exception.getMessage());
770  return kAudioHardwareUnspecifiedError;
771  }
772 
773  return kAudioHardwareNoError;
774 }
775 
776 /*
777 OSStatus deviceListener(AudioDeviceID inDevice,
778  UInt32 channel,
779  Boolean isInput,
780  AudioDevicePropertyID propertyID,
781  void* infoPointer)
782 {
783  CALLBACK_INFO *info = (CALLBACK_INFO *) infoPointer;
784 
785  RtAudio *object = (RtAudio *) info->object;
786  try {
787  object->settingChange( info->streamId );
788  }
789  catch (RtError &exception) {
790  fprintf(stderr, "\nDevice listener error (%s)!\n\n", exception.getMessage());
791  return kAudioHardwareUnspecifiedError;
792  }
793 
794  return kAudioHardwareNoError;
795 }
796 */
797 
798 bool RtAudio :: probeDeviceOpen(int device, RTAUDIO_STREAM *stream,
799  STREAM_MODE mode, int channels,
800  int sampleRate, RTAUDIO_FORMAT format,
801  int *bufferSize, int numberOfBuffers)
802 {
803  // Check to make sure we don't already have a stream accessing this device.
804  RTAUDIO_STREAM *streamPtr;
805  std::map<int, void *>::const_iterator i;
806  for ( i=streams.begin(); i!=streams.end(); ++i ) {
807  streamPtr = (RTAUDIO_STREAM *) i->second;
808  if ( streamPtr->device[0] == device || streamPtr->device[1] == device ) {
809  sprintf(message, "RtAudio: no current OS X support for multiple streams accessing the same device!");
810  error(RtError::WARNING);
811  return FAILURE;
812  }
813  }
814 
815  // Setup for stream mode.
816  bool isInput = false;
817  AudioDeviceID id = devices[device].id[0];
818  if ( mode == INPUT ) isInput = true;
819 
820  // Search for a stream which contains the desired number of channels.
821  OSStatus err = noErr;
822  UInt32 dataSize;
823  unsigned int deviceChannels, nStreams;
824  UInt32 iChannel = 0, iStream = 0;
825  AudioBufferList *bufferList = nil;
826  err = AudioDeviceGetPropertyInfo( id, 0, isInput,
827  kAudioDevicePropertyStreamConfiguration,
828  &dataSize, NULL );
829 
830  if (err == noErr && dataSize > 0) {
831  bufferList = (AudioBufferList *) malloc( dataSize );
832  if (bufferList == NULL) {
833  sprintf(message, "RtAudio: memory allocation error!");
834  error(RtError::DEBUG_WARNING);
835  return FAILURE;
836  }
837  err = AudioDeviceGetProperty( id, 0, isInput,
838  kAudioDevicePropertyStreamConfiguration,
839  &dataSize, bufferList );
840 
841  if (err == noErr) {
842  stream->deInterleave[mode] = false;
843  nStreams = bufferList->mNumberBuffers;
844  for ( iStream=0; iStream<nStreams; iStream++ ) {
845  if ( bufferList->mBuffers[iStream].mNumberChannels >= (unsigned int) channels ) break;
846  iChannel += bufferList->mBuffers[iStream].mNumberChannels;
847  }
848  // If we didn't find a single stream above, see if we can meet
849  // the channel specification in mono mode (i.e. using separate
850  // non-interleaved buffers). This can only work if there are N
851  // consecutive one-channel streams, where N is the number of
852  // desired channels.
853  iChannel = 0;
854  if ( iStream >= nStreams && nStreams >= (unsigned int) channels ) {
855  int counter = 0;
856  for ( iStream=0; iStream<nStreams; iStream++ ) {
857  if ( bufferList->mBuffers[iStream].mNumberChannels == 1 )
858  counter++;
859  else
860  counter = 0;
861  if ( counter == channels ) {
862  iStream -= channels - 1;
863  iChannel -= channels - 1;
864  stream->deInterleave[mode] = true;
865  break;
866  }
867  iChannel += bufferList->mBuffers[iStream].mNumberChannels;
868  }
869  }
870  }
871  }
872  if (err != noErr || dataSize <= 0) {
873  if ( bufferList ) free( bufferList );
874  sprintf( message, "RtAudio: OSX error getting channels for device (%s).", devices[device].name );
875  error(RtError::DEBUG_WARNING);
876  return FAILURE;
877  }
878 
879  if (iStream >= nStreams) {
880  free (bufferList);
881  sprintf( message, "RtAudio: unable to find OSX audio stream on device (%s) for requested channels (%d).",
882  devices[device].name, channels );
883  error(RtError::DEBUG_WARNING);
884  return FAILURE;
885  }
886 
887  // This is ok even for mono mode ... it gets updated later.
888  deviceChannels = bufferList->mBuffers[iStream].mNumberChannels;
889  free (bufferList);
890 
891  // Determine the buffer size.
892  AudioValueRange bufferRange;
893  dataSize = sizeof(AudioValueRange);
894  err = AudioDeviceGetProperty( id, 0, isInput,
895  kAudioDevicePropertyBufferSizeRange,
896  &dataSize, &bufferRange);
897  if (err != noErr) {
898  sprintf( message, "RtAudio: OSX error getting buffer size range for device (%s).",
899  devices[device].name );
900  error(RtError::DEBUG_WARNING);
901  return FAILURE;
902  }
903 
904  long bufferBytes = *bufferSize * deviceChannels * formatBytes(RTAUDIO_FLOAT32);
905  if (bufferRange.mMinimum > bufferBytes) bufferBytes = (int) bufferRange.mMinimum;
906  else if (bufferRange.mMaximum < bufferBytes) bufferBytes = (int) bufferRange.mMaximum;
907 
908  // Set the buffer size. For mono mode, I'm assuming we only need to
909  // make this setting for the first channel.
910  UInt32 theSize = (UInt32) bufferBytes;
911  dataSize = sizeof( UInt32);
912  err = AudioDeviceSetProperty(id, NULL, 0, isInput,
913  kAudioDevicePropertyBufferSize,
914  dataSize, &theSize);
915  if (err != noErr) {
916  sprintf( message, "RtAudio: OSX error setting the buffer size for device (%s).",
917  devices[device].name );
918  error(RtError::DEBUG_WARNING);
919  return FAILURE;
920  }
921 
922  // If attempting to setup a duplex stream, the bufferSize parameter
923  // MUST be the same in both directions!
924  *bufferSize = bufferBytes / ( deviceChannels * formatBytes(RTAUDIO_FLOAT32) );
925  if ( stream->mode == OUTPUT && mode == INPUT && *bufferSize != stream->bufferSize ) {
926  sprintf( message, "RtAudio: OSX error setting buffer size for duplex stream on device (%s).",
927  devices[device].name );
928  error(RtError::DEBUG_WARNING);
929  return FAILURE;
930  }
931 
932  stream->bufferSize = *bufferSize;
933  stream->nBuffers = 1;
934 
935  // Set the stream format description. Do for each channel in mono mode.
936  AudioStreamBasicDescription description;
937  dataSize = sizeof( AudioStreamBasicDescription );
938  if ( stream->deInterleave[mode] ) nStreams = channels;
939  else nStreams = 1;
940  for ( unsigned int i=0; i<nStreams; i++, iChannel++ ) {
941 
942  err = AudioDeviceGetProperty( id, iChannel, isInput,
943  kAudioDevicePropertyStreamFormat,
944  &dataSize, &description );
945  if (err != noErr) {
946  sprintf( message, "RtAudio: OSX error getting stream format for device (%s).", devices[device].name );
947  error(RtError::DEBUG_WARNING);
948  return FAILURE;
949  }
950 
951  // Set the sample rate and data format id.
952  description.mSampleRate = (double) sampleRate;
953  description.mFormatID = kAudioFormatLinearPCM;
954  err = AudioDeviceSetProperty( id, NULL, iChannel, isInput,
955  kAudioDevicePropertyStreamFormat,
956  dataSize, &description );
957  if (err != noErr) {
958  sprintf( message, "RtAudio: OSX error setting sample rate or data format for device (%s).", devices[device].name );
959  error(RtError::DEBUG_WARNING);
960  return FAILURE;
961  }
962  }
963 
964  // Check whether we need byte-swapping (assuming OS X host is big-endian).
965  iChannel -= nStreams;
966  err = AudioDeviceGetProperty( id, iChannel, isInput,
967  kAudioDevicePropertyStreamFormat,
968  &dataSize, &description );
969  if (err != noErr) {
970  sprintf( message, "RtAudio: OSX error getting stream format for device (%s).", devices[device].name );
971  error(RtError::DEBUG_WARNING);
972  return FAILURE;
973  }
974 
975  stream->doByteSwap[mode] = false;
976  if ( !description.mFormatFlags & kLinearPCMFormatFlagIsBigEndian )
977  stream->doByteSwap[mode] = true;
978 
979  // From the CoreAudio documentation, PCM data must be supplied as
980  // 32-bit floats.
981  stream->userFormat = format;
982  stream->deviceFormat[mode] = RTAUDIO_FLOAT32;
983 
984  if ( stream->deInterleave[mode] )
985  stream->nDeviceChannels[mode] = channels;
986  else
987  stream->nDeviceChannels[mode] = description.mChannelsPerFrame;
988  stream->nUserChannels[mode] = channels;
989 
990  // Set handle and flags for buffer conversion.
991  stream->handle[mode] = iStream;
992  stream->doConvertBuffer[mode] = false;
993  if (stream->userFormat != stream->deviceFormat[mode])
994  stream->doConvertBuffer[mode] = true;
995  if (stream->nUserChannels[mode] < stream->nDeviceChannels[mode])
996  stream->doConvertBuffer[mode] = true;
997  if (stream->nUserChannels[mode] > 1 && stream->deInterleave[mode])
998  stream->doConvertBuffer[mode] = true;
999 
1000  // Allocate necessary internal buffers.
1001  if ( stream->nUserChannels[0] != stream->nUserChannels[1] ) {
1002 
1003  long buffer_bytes;
1004  if (stream->nUserChannels[0] >= stream->nUserChannels[1])
1005  buffer_bytes = stream->nUserChannels[0];
1006  else
1007  buffer_bytes = stream->nUserChannels[1];
1008 
1009  buffer_bytes *= *bufferSize * formatBytes(stream->userFormat);
1010  if (stream->userBuffer) free(stream->userBuffer);
1011  stream->userBuffer = (char *) calloc(buffer_bytes, 1);
1012  if (stream->userBuffer == NULL)
1013  goto memory_error;
1014  }
1015 
1016  if ( stream->deInterleave[mode] ) {
1017 
1018  long buffer_bytes;
1019  bool makeBuffer = true;
1020  if ( mode == OUTPUT )
1021  buffer_bytes = stream->nDeviceChannels[0] * formatBytes(stream->deviceFormat[0]);
1022  else { // mode == INPUT
1023  buffer_bytes = stream->nDeviceChannels[1] * formatBytes(stream->deviceFormat[1]);
1024  if ( stream->mode == OUTPUT && stream->deviceBuffer ) {
1025  long bytes_out = stream->nDeviceChannels[0] * formatBytes(stream->deviceFormat[0]);
1026  if ( buffer_bytes < bytes_out ) makeBuffer = false;
1027  }
1028  }
1029 
1030  if ( makeBuffer ) {
1031  buffer_bytes *= *bufferSize;
1032  if (stream->deviceBuffer) free(stream->deviceBuffer);
1033  stream->deviceBuffer = (char *) calloc(buffer_bytes, 1);
1034  if (stream->deviceBuffer == NULL)
1035  goto memory_error;
1036 
1037  // If not de-interleaving, we point stream->deviceBuffer to the
1038  // OS X supplied device buffer before doing any necessary data
1039  // conversions. This presents a problem if we have a duplex
1040  // stream using one device which needs de-interleaving and
1041  // another device which doesn't. So, save a pointer to our own
1042  // device buffer in the CALLBACK_INFO structure.
1043  stream->callbackInfo.buffers = stream->deviceBuffer;
1044  }
1045  }
1046 
1047  stream->sampleRate = sampleRate;
1048  stream->device[mode] = device;
1049  stream->state = STREAM_STOPPED;
1050  stream->callbackInfo.object = (void *) this;
1051  stream->callbackInfo.waitTime = (unsigned long) (200000.0 * stream->bufferSize / stream->sampleRate);
1052  stream->callbackInfo.device[mode] = id;
1053  if ( stream->mode == OUTPUT && mode == INPUT && stream->device[0] == device )
1054  // Only one callback procedure per device.
1055  stream->mode = DUPLEX;
1056  else {
1057  err = AudioDeviceAddIOProc( id, callbackHandler, (void *) &stream->callbackInfo );
1058  if (err != noErr) {
1059  sprintf( message, "RtAudio: OSX error setting callback for device (%s).", devices[device].name );
1060  error(RtError::DEBUG_WARNING);
1061  return FAILURE;
1062  }
1063  if ( stream->mode == OUTPUT && mode == INPUT )
1064  stream->mode = DUPLEX;
1065  else
1066  stream->mode = mode;
1067  }
1068 
1069  // If we wanted to use property listeners, they would be setup here.
1070 
1071  return SUCCESS;
1072 
1073  memory_error:
1074  if (stream->userBuffer) {
1075  free(stream->userBuffer);
1076  stream->userBuffer = 0;
1077  }
1078  sprintf(message, "RtAudio: OSX error allocating buffer memory (%s).", devices[device].name);
1079  error(RtError::WARNING);
1080  return FAILURE;
1081 }
1082 
1083 void RtAudio :: cancelStreamCallback(int streamId)
1084 {
1085  RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
1086 
1087  if (stream->callbackInfo.usingCallback) {
1088 
1089  if (stream->state == STREAM_RUNNING)
1090  stopStream( streamId );
1091 
1092  MUTEX_LOCK(&stream->mutex);
1093 
1094  stream->callbackInfo.usingCallback = false;
1095  stream->callbackInfo.userData = NULL;
1096  stream->state = STREAM_STOPPED;
1097  stream->callbackInfo.callback = NULL;
1098 
1099  MUTEX_UNLOCK(&stream->mutex);
1100  }
1101 }
1102 
1103 void RtAudio :: closeStream(int streamId)
1104 {
1105  // We don't want an exception to be thrown here because this
1106  // function is called by our class destructor. So, do our own
1107  // streamId check.
1108  if ( streams.find( streamId ) == streams.end() ) {
1109  sprintf(message, "RtAudio: invalid stream identifier!");
1110  error(RtError::WARNING);
1111  return;
1112  }
1113 
1114  RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) streams[streamId];
1115 
1116  AudioDeviceID id;
1117  if (stream->mode == OUTPUT || stream->mode == DUPLEX) {
1118  id = devices[stream->device[0]].id[0];
1119  if (stream->state == STREAM_RUNNING)
1120  AudioDeviceStop( id, callbackHandler );
1121  AudioDeviceRemoveIOProc( id, callbackHandler );
1122  }
1123 
1124  if (stream->mode == INPUT || ( stream->mode == DUPLEX && stream->device[0] != stream->device[1]) ) {
1125  id = devices[stream->device[1]].id[0];
1126  if (stream->state == STREAM_RUNNING)
1127  AudioDeviceStop( id, callbackHandler );
1128  AudioDeviceRemoveIOProc( id, callbackHandler );
1129  }
1130 
1131  pthread_mutex_destroy(&stream->mutex);
1132 
1133  if (stream->userBuffer)
1134  free(stream->userBuffer);
1135 
1136  if ( stream->deInterleave[0] || stream->deInterleave[1] )
1137  free(stream->callbackInfo.buffers);
1138 
1139  free(stream);
1140  streams.erase(streamId);
1141 }
1142 
1143 void RtAudio :: startStream(int streamId)
1144 {
1145  RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
1146 
1147  MUTEX_LOCK(&stream->mutex);
1148 
1149  if (stream->state == STREAM_RUNNING)
1150  goto unlock;
1151 
1152  OSStatus err;
1153  if (stream->mode == OUTPUT || stream->mode == DUPLEX) {
1154 
1155  err = AudioDeviceStart(devices[stream->device[0]].id[0], callbackHandler);
1156  if (err != noErr) {
1157  sprintf(message, "RtAudio: OSX error starting callback procedure on device (%s).",
1158  devices[stream->device[0]].name);
1159  MUTEX_UNLOCK(&stream->mutex);
1160  error(RtError::DRIVER_ERROR);
1161  }
1162  }
1163 
1164  if (stream->mode == INPUT || ( stream->mode == DUPLEX && stream->device[0] != stream->device[1]) ) {
1165 
1166  err = AudioDeviceStart(devices[stream->device[1]].id[0], callbackHandler);
1167  if (err != noErr) {
1168  sprintf(message, "RtAudio: OSX error starting input callback procedure on device (%s).",
1169  devices[stream->device[0]].name);
1170  MUTEX_UNLOCK(&stream->mutex);
1171  error(RtError::DRIVER_ERROR);
1172  }
1173  }
1174 
1175  stream->callbackInfo.streamId = streamId;
1176  stream->state = STREAM_RUNNING;
1177  stream->callbackInfo.blockTick = true;
1178  stream->callbackInfo.stopStream = false;
1179 
1180  unlock:
1181  MUTEX_UNLOCK(&stream->mutex);
1182 }
1183 
1184 void RtAudio :: stopStream(int streamId)
1185 {
1186  RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
1187 
1188  MUTEX_LOCK(&stream->mutex);
1189 
1190  if (stream->state == STREAM_STOPPED)
1191  goto unlock;
1192 
1193  OSStatus err;
1194  if (stream->mode == OUTPUT || stream->mode == DUPLEX) {
1195 
1196  err = AudioDeviceStop(devices[stream->device[0]].id[0], callbackHandler);
1197  if (err != noErr) {
1198  sprintf(message, "RtAudio: OSX error stopping callback procedure on device (%s).",
1199  devices[stream->device[0]].name);
1200  MUTEX_UNLOCK(&stream->mutex);
1201  error(RtError::DRIVER_ERROR);
1202  }
1203  }
1204 
1205  if (stream->mode == INPUT || ( stream->mode == DUPLEX && stream->device[0] != stream->device[1]) ) {
1206 
1207  err = AudioDeviceStop(devices[stream->device[1]].id[0], callbackHandler);
1208  if (err != noErr) {
1209  sprintf(message, "RtAudio: OSX error stopping input callback procedure on device (%s).",
1210  devices[stream->device[0]].name);
1211  MUTEX_UNLOCK(&stream->mutex);
1212  error(RtError::DRIVER_ERROR);
1213  }
1214  }
1215 
1216  stream->state = STREAM_STOPPED;
1217 
1218  unlock:
1219  MUTEX_UNLOCK(&stream->mutex);
1220 }
1221 
1222 void RtAudio :: abortStream(int streamId)
1223 {
1224  stopStream( streamId );
1225 }
1226 
1227 // I don't know how this function can be implemented.
1228 int RtAudio :: streamWillBlock(int streamId)
1229 {
1230  sprintf(message, "RtAudio: streamWillBlock() cannot be implemented for OS X.");
1231  error(RtError::WARNING);
1232  return 0;
1233 }
1234 
1235 void RtAudio :: tickStream(int streamId)
1236 {
1237  RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
1238 
1239  if (stream->state == STREAM_STOPPED)
1240  return;
1241 
1242  if (stream->callbackInfo.usingCallback) {
1243  sprintf(message, "RtAudio: tickStream() should not be used when a callback function is set!");
1244  error(RtError::WARNING);
1245  return;
1246  }
1247 
1248  // Block waiting here until the user data is processed in callbackEvent().
1249  while ( stream->callbackInfo.blockTick )
1250  usleep(stream->callbackInfo.waitTime);
1251 
1252  MUTEX_LOCK(&stream->mutex);
1253 
1254  stream->callbackInfo.blockTick = true;
1255 
1256  MUTEX_UNLOCK(&stream->mutex);
1257 }
1258 
1259 void RtAudio :: callbackEvent( int streamId, DEVICE_ID deviceId, void *inData, void *outData )
1260 {
1261  RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
1262 
1263  CALLBACK_INFO *info;
1264  AudioBufferList *inBufferList = (AudioBufferList *) inData;
1265  AudioBufferList *outBufferList = (AudioBufferList *) outData;
1266 
1267  if (stream->state == STREAM_STOPPED) return;
1268 
1269  info = (CALLBACK_INFO *) &stream->callbackInfo;
1270  if ( !info->usingCallback ) {
1271  // Block waiting here until we get new user data in tickStream().
1272  while ( !info->blockTick )
1273  usleep(info->waitTime);
1274  }
1275  else if ( info->stopStream ) {
1276  // Check if the stream should be stopped (via the previous user
1277  // callback return value). We stop the stream here, rather than
1278  // after the function call, so that output data can first be
1279  // processed.
1280  this->stopStream(info->streamId);
1281  return;
1282  }
1283 
1284  MUTEX_LOCK(&stream->mutex);
1285 
1286  // Invoke user callback first, to get fresh output data. Don't
1287  // invoke the user callback if duplex mode, the input/output devices
1288  // are different, and this function is called for the input device.
1289  if ( info->usingCallback && (stream->mode != DUPLEX || deviceId == info->device[0] ) ) {
1290  RTAUDIO_CALLBACK callback = (RTAUDIO_CALLBACK) info->callback;
1291  info->stopStream = callback(stream->userBuffer, stream->bufferSize, info->userData);
1292  }
1293 
1294  if ( stream->mode == OUTPUT || ( stream->mode == DUPLEX && deviceId == info->device[0] ) ) {
1295 
1296  if (stream->doConvertBuffer[0]) {
1297 
1298  if ( !stream->deInterleave[0] )
1299  stream->deviceBuffer = (char *) outBufferList->mBuffers[stream->handle[0]].mData;
1300  else
1301  stream->deviceBuffer = (char *) stream->callbackInfo.buffers;
1302 
1303  convertStreamBuffer(stream, OUTPUT);
1304  if ( stream->doByteSwap[0] )
1305  byteSwapBuffer(stream->deviceBuffer,
1306  stream->bufferSize * stream->nDeviceChannels[0],
1307  stream->deviceFormat[0]);
1308 
1309  if ( stream->deInterleave[0] ) {
1310  int bufferBytes = outBufferList->mBuffers[stream->handle[0]].mDataByteSize;
1311  for ( int i=0; i<stream->nDeviceChannels[0]; i++ ) {
1312  memcpy(outBufferList->mBuffers[stream->handle[0]+i].mData,
1313  &stream->deviceBuffer[i*bufferBytes], bufferBytes );
1314  }
1315  }
1316 
1317  }
1318  else {
1319  if (stream->doByteSwap[0])
1320  byteSwapBuffer(stream->userBuffer,
1321  stream->bufferSize * stream->nUserChannels[0],
1322  stream->userFormat);
1323 
1324  memcpy(outBufferList->mBuffers[stream->handle[0]].mData,
1325  stream->userBuffer,
1326  outBufferList->mBuffers[stream->handle[0]].mDataByteSize );
1327  }
1328  }
1329 
1330  if ( stream->mode == INPUT || ( stream->mode == DUPLEX && deviceId == info->device[1] ) ) {
1331 
1332  if (stream->doConvertBuffer[1]) {
1333 
1334  if ( stream->deInterleave[1] ) {
1335  stream->deviceBuffer = (char *) stream->callbackInfo.buffers;
1336  int bufferBytes = inBufferList->mBuffers[stream->handle[1]].mDataByteSize;
1337  for ( int i=0; i<stream->nDeviceChannels[1]; i++ ) {
1338  memcpy(&stream->deviceBuffer[i*bufferBytes],
1339  inBufferList->mBuffers[stream->handle[1]+i].mData, bufferBytes );
1340  }
1341  }
1342  else
1343  stream->deviceBuffer = (char *) inBufferList->mBuffers[stream->handle[1]].mData;
1344 
1345  if ( stream->doByteSwap[1] )
1346  byteSwapBuffer(stream->deviceBuffer,
1347  stream->bufferSize * stream->nDeviceChannels[1],
1348  stream->deviceFormat[1]);
1349  convertStreamBuffer(stream, INPUT);
1350 
1351  }
1352  else {
1353  memcpy(stream->userBuffer,
1354  inBufferList->mBuffers[stream->handle[1]].mData,
1355  inBufferList->mBuffers[stream->handle[1]].mDataByteSize );
1356 
1357  if (stream->doByteSwap[1])
1358  byteSwapBuffer(stream->userBuffer,
1359  stream->bufferSize * stream->nUserChannels[1],
1360  stream->userFormat);
1361  }
1362  }
1363 
1364  if ( !info->usingCallback && (stream->mode != DUPLEX || deviceId == info->device[1] ) )
1365  info->blockTick = false;
1366 
1367  MUTEX_UNLOCK(&stream->mutex);
1368 
1369 }
1370 
1371 void RtAudio :: setStreamCallback(int streamId, RTAUDIO_CALLBACK callback, void *userData)
1372 {
1373  RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
1374 
1375  stream->callbackInfo.callback = (void *) callback;
1376  stream->callbackInfo.userData = userData;
1377  stream->callbackInfo.usingCallback = true;
1378 }
1379 
1380 //******************** End of __MACOSX_CORE__ *********************//
1381 
1382 #elif defined(__LINUX_ALSA__)
1383 
1384 #define MAX_DEVICES 16
1385 
1386 void RtAudio :: initialize(void)
1387 {
1388  int card, result, device;
1389  char name[32];
1390  const char *cardId;
1391  char deviceNames[MAX_DEVICES][32];
1392  snd_ctl_t *handle;
1393  snd_ctl_card_info_t *info;
1394  snd_ctl_card_info_alloca(&info);
1395 
1396  // Count cards and devices
1397  nDevices = 0;
1398  card = -1;
1399  snd_card_next(&card);
1400  while ( card >= 0 ) {
1401  sprintf(name, "hw:%d", card);
1402  result = snd_ctl_open(&handle, name, 0);
1403  if (result < 0) {
1404  sprintf(message, "RtAudio: ALSA control open (%i): %s.", card, snd_strerror(result));
1405  error(RtError::DEBUG_WARNING);
1406  goto next_card;
1407  }
1408  result = snd_ctl_card_info(handle, info);
1409  if (result < 0) {
1410  sprintf(message, "RtAudio: ALSA control hardware info (%i): %s.", card, snd_strerror(result));
1411  error(RtError::DEBUG_WARNING);
1412  goto next_card;
1413  }
1414  cardId = snd_ctl_card_info_get_id(info);
1415  device = -1;
1416  while (1) {
1417  result = snd_ctl_pcm_next_device(handle, &device);
1418  if (result < 0) {
1419  sprintf(message, "RtAudio: ALSA control next device (%i): %s.", card, snd_strerror(result));
1420  error(RtError::DEBUG_WARNING);
1421  break;
1422  }
1423  if (device < 0)
1424  break;
1425  if ( strlen(cardId) )
1426  sprintf( deviceNames[nDevices++], "hw:%s,%d", cardId, device );
1427  else
1428  sprintf( deviceNames[nDevices++], "hw:%d,%d", card, device );
1429  if ( nDevices > MAX_DEVICES ) break;
1430  }
1431  if ( nDevices > MAX_DEVICES ) break;
1432  next_card:
1433  snd_ctl_close(handle);
1434  snd_card_next(&card);
1435  }
1436 
1437  if (nDevices == 0) return;
1438 
1439  // Allocate the RTAUDIO_DEVICE structures.
1440  devices = (RTAUDIO_DEVICE *) calloc(nDevices, sizeof(RTAUDIO_DEVICE));
1441  if (devices == NULL) {
1442  sprintf(message, "RtAudio: memory allocation error!");
1443  error(RtError::MEMORY_ERROR);
1444  }
1445 
1446  // Write device ascii identifiers to device structures and then
1447  // probe the device capabilities.
1448  for (int i=0; i<nDevices; i++) {
1449  strncpy(devices[i].name, deviceNames[i], 32);
1450  //probeDeviceInfo(&devices[i]);
1451  }
1452 }
1453 
1454 int RtAudio :: getDefaultInputDevice(void)
1455 {
1456  // No ALSA API functions for default devices.
1457  return 0;
1458 }
1459 
1460 int RtAudio :: getDefaultOutputDevice(void)
1461 {
1462  // No ALSA API functions for default devices.
1463  return 0;
1464 }
1465 
1466 void RtAudio :: probeDeviceInfo(RTAUDIO_DEVICE *info)
1467 {
1468  int err;
1469  int open_mode = SND_PCM_ASYNC;
1470  snd_pcm_t *handle;
1471  snd_ctl_t *chandle;
1472  snd_pcm_stream_t stream;
1473  snd_pcm_info_t *pcminfo;
1474  snd_pcm_info_alloca(&pcminfo);
1475  snd_pcm_hw_params_t *params;
1476  snd_pcm_hw_params_alloca(&params);
1477  char name[32];
1478  char *card;
1479 
1480  // Open the control interface for this card.
1481  strncpy( name, info->name, 32 );
1482  card = strtok(name, ",");
1483  err = snd_ctl_open(&chandle, card, 0);
1484  if (err < 0) {
1485  sprintf(message, "RtAudio: ALSA control open (%s): %s.", card, snd_strerror(err));
1486  error(RtError::DEBUG_WARNING);
1487  return;
1488  }
1489  unsigned int dev = (unsigned int) atoi( strtok(NULL, ",") );
1490 
1491  // First try for playback
1492  stream = SND_PCM_STREAM_PLAYBACK;
1493  snd_pcm_info_set_device(pcminfo, dev);
1494  snd_pcm_info_set_subdevice(pcminfo, 0);
1495  snd_pcm_info_set_stream(pcminfo, stream);
1496 
1497  if ((err = snd_ctl_pcm_info(chandle, pcminfo)) < 0) {
1498  if (err == -ENOENT) {
1499  sprintf(message, "RtAudio: ALSA pcm device (%s) doesn't handle output!", info->name);
1500  error(RtError::DEBUG_WARNING);
1501  }
1502  else {
1503  sprintf(message, "RtAudio: ALSA snd_ctl_pcm_info error for device (%s) output: %s",
1504  info->name, snd_strerror(err));
1505  error(RtError::DEBUG_WARNING);
1506  }
1507  goto capture_probe;
1508  }
1509 
1510  err = snd_pcm_open(&handle, info->name, stream, open_mode | SND_PCM_NONBLOCK );
1511  if (err < 0) {
1512  if ( err == EBUSY )
1513  sprintf(message, "RtAudio: ALSA pcm playback device (%s) is busy: %s.",
1514  info->name, snd_strerror(err));
1515  else
1516  sprintf(message, "RtAudio: ALSA pcm playback open (%s) error: %s.",
1517  info->name, snd_strerror(err));
1518  error(RtError::DEBUG_WARNING);
1519  goto capture_probe;
1520  }
1521 
1522  // We have an open device ... allocate the parameter structure.
1523  err = snd_pcm_hw_params_any(handle, params);
1524  if (err < 0) {
1525  snd_pcm_close(handle);
1526  sprintf(message, "RtAudio: ALSA hardware probe error (%s): %s.",
1527  info->name, snd_strerror(err));
1528  error(RtError::WARNING);
1529  goto capture_probe;
1530  }
1531 
1532  // Get output channel information.
1533  info->minOutputChannels = snd_pcm_hw_params_get_channels_min(params);
1534  info->maxOutputChannels = snd_pcm_hw_params_get_channels_max(params);
1535 
1536  snd_pcm_close(handle);
1537 
1538  capture_probe:
1539  // Now try for capture
1540  stream = SND_PCM_STREAM_CAPTURE;
1541  snd_pcm_info_set_stream(pcminfo, stream);
1542 
1543  err = snd_ctl_pcm_info(chandle, pcminfo);
1544  snd_ctl_close(chandle);
1545  if ( err < 0 ) {
1546  if (err == -ENOENT) {
1547  sprintf(message, "RtAudio: ALSA pcm device (%s) doesn't handle input!", info->name);
1548  error(RtError::DEBUG_WARNING);
1549  }
1550  else {
1551  sprintf(message, "RtAudio: ALSA snd_ctl_pcm_info error for device (%s) input: %s",
1552  info->name, snd_strerror(err));
1553  error(RtError::DEBUG_WARNING);
1554  }
1555  if (info->maxOutputChannels == 0)
1556  // didn't open for playback either ... device invalid
1557  return;
1558  goto probe_parameters;
1559  }
1560 
1561  err = snd_pcm_open(&handle, info->name, stream, open_mode | SND_PCM_NONBLOCK);
1562  if (err < 0) {
1563  if ( err == EBUSY )
1564  sprintf(message, "RtAudio: ALSA pcm capture device (%s) is busy: %s.",
1565  info->name, snd_strerror(err));
1566  else
1567  sprintf(message, "RtAudio: ALSA pcm capture open (%s) error: %s.",
1568  info->name, snd_strerror(err));
1569  error(RtError::DEBUG_WARNING);
1570  if (info->maxOutputChannels == 0)
1571  // didn't open for playback either ... device invalid
1572  return;
1573  goto probe_parameters;
1574  }
1575 
1576  // We have an open capture device ... allocate the parameter structure.
1577  err = snd_pcm_hw_params_any(handle, params);
1578  if (err < 0) {
1579  snd_pcm_close(handle);
1580  sprintf(message, "RtAudio: ALSA hardware probe error (%s): %s.",
1581  info->name, snd_strerror(err));
1582  error(RtError::WARNING);
1583  if (info->maxOutputChannels > 0)
1584  goto probe_parameters;
1585  else
1586  return;
1587  }
1588 
1589  // Get input channel information.
1590  info->minInputChannels = snd_pcm_hw_params_get_channels_min(params);
1591  info->maxInputChannels = snd_pcm_hw_params_get_channels_max(params);
1592 
1593  snd_pcm_close(handle);
1594 
1595  // If device opens for both playback and capture, we determine the channels.
1596  if (info->maxOutputChannels == 0 || info->maxInputChannels == 0)
1597  goto probe_parameters;
1598 
1599  info->hasDuplexSupport = true;
1600  info->maxDuplexChannels = (info->maxOutputChannels > info->maxInputChannels) ?
1601  info->maxInputChannels : info->maxOutputChannels;
1602  info->minDuplexChannels = (info->minOutputChannels > info->minInputChannels) ?
1603  info->minInputChannels : info->minOutputChannels;
1604 
1605  probe_parameters:
1606  // At this point, we just need to figure out the supported data
1607  // formats and sample rates. We'll proceed by opening the device in
1608  // the direction with the maximum number of channels, or playback if
1609  // they are equal. This might limit our sample rate options, but so
1610  // be it.
1611 
1612  if (info->maxOutputChannels >= info->maxInputChannels)
1613  stream = SND_PCM_STREAM_PLAYBACK;
1614  else
1615  stream = SND_PCM_STREAM_CAPTURE;
1616 
1617  err = snd_pcm_open(&handle, info->name, stream, open_mode);
1618  if (err < 0) {
1619  sprintf(message, "RtAudio: ALSA pcm (%s) won't reopen during probe: %s.",
1620  info->name, snd_strerror(err));
1621  error(RtError::WARNING);
1622  return;
1623  }
1624 
1625  // We have an open device ... allocate the parameter structure.
1626  err = snd_pcm_hw_params_any(handle, params);
1627  if (err < 0) {
1628  snd_pcm_close(handle);
1629  sprintf(message, "RtAudio: ALSA hardware reopen probe error (%s): %s.",
1630  info->name, snd_strerror(err));
1631  error(RtError::WARNING);
1632  return;
1633  }
1634 
1635  // Test a non-standard sample rate to see if continuous rate is supported.
1636  int dir = 0;
1637  if (snd_pcm_hw_params_test_rate(handle, params, 35500, dir) == 0) {
1638  // It appears that continuous sample rate support is available.
1639  info->nSampleRates = -1;
1640  info->sampleRates[0] = snd_pcm_hw_params_get_rate_min(params, &dir);
1641  info->sampleRates[1] = snd_pcm_hw_params_get_rate_max(params, &dir);
1642  }
1643  else {
1644  // No continuous rate support ... test our discrete set of sample rate values.
1645  info->nSampleRates = 0;
1646  for (int i=0; i<MAX_SAMPLE_RATES; i++) {
1647  if (snd_pcm_hw_params_test_rate(handle, params, SAMPLE_RATES[i], dir) == 0) {
1648  info->sampleRates[info->nSampleRates] = SAMPLE_RATES[i];
1649  info->nSampleRates++;
1650  }
1651  }
1652  if (info->nSampleRates == 0) {
1653  snd_pcm_close(handle);
1654  return;
1655  }
1656  }
1657 
1658  // Probe the supported data formats ... we don't care about endian-ness just yet
1659  snd_pcm_format_t format;
1660  info->nativeFormats = 0;
1661  format = SND_PCM_FORMAT_S8;
1662  if (snd_pcm_hw_params_test_format(handle, params, format) == 0)
1663  info->nativeFormats |= RTAUDIO_SINT8;
1664  format = SND_PCM_FORMAT_S16;
1665  if (snd_pcm_hw_params_test_format(handle, params, format) == 0)
1666  info->nativeFormats |= RTAUDIO_SINT16;
1667  format = SND_PCM_FORMAT_S24;
1668  if (snd_pcm_hw_params_test_format(handle, params, format) == 0)
1669  info->nativeFormats |= RTAUDIO_SINT24;
1670  format = SND_PCM_FORMAT_S32;
1671  if (snd_pcm_hw_params_test_format(handle, params, format) == 0)
1672  info->nativeFormats |= RTAUDIO_SINT32;
1673  format = SND_PCM_FORMAT_FLOAT;
1674  if (snd_pcm_hw_params_test_format(handle, params, format) == 0)
1675  info->nativeFormats |= RTAUDIO_FLOAT32;
1676  format = SND_PCM_FORMAT_FLOAT64;
1677  if (snd_pcm_hw_params_test_format(handle, params, format) == 0)
1678  info->nativeFormats |= RTAUDIO_FLOAT64;
1679 
1680  // Check that we have at least one supported format
1681  if (info->nativeFormats == 0) {
1682  snd_pcm_close(handle);
1683  sprintf(message, "RtAudio: ALSA PCM device (%s) data format not supported by RtAudio.",
1684  info->name);
1685  error(RtError::WARNING);
1686  return;
1687  }
1688 
1689  // That's all ... close the device and return
1690  snd_pcm_close(handle);
1691  info->probed = true;
1692  return;
1693 }
1694 
1695 bool RtAudio :: probeDeviceOpen(int device, RTAUDIO_STREAM *stream,
1696  STREAM_MODE mode, int channels,
1697  int sampleRate, RTAUDIO_FORMAT format,
1698  int *bufferSize, int numberOfBuffers)
1699 {
1700 #if defined(__RTAUDIO_DEBUG__)
1701  snd_output_t *out;
1702  snd_output_stdio_attach(&out, stderr, 0);
1703 #endif
1704 
1705  // I'm not using the "plug" interface ... too much inconsistent behavior.
1706  const char *name = devices[device].name;
1707 
1708  snd_pcm_stream_t alsa_stream;
1709  if (mode == OUTPUT)
1710  alsa_stream = SND_PCM_STREAM_PLAYBACK;
1711  else
1712  alsa_stream = SND_PCM_STREAM_CAPTURE;
1713 
1714  int err;
1715  snd_pcm_t *handle;
1716  int alsa_open_mode = SND_PCM_ASYNC;
1717  err = snd_pcm_open(&handle, name, alsa_stream, alsa_open_mode);
1718  if (err < 0) {
1719  sprintf(message,"RtAudio: ALSA pcm device (%s) won't open: %s.",
1720  name, snd_strerror(err));
1721  error(RtError::WARNING);
1722  return FAILURE;
1723  }
1724 
1725  // Fill the parameter structure.
1726  snd_pcm_hw_params_t *hw_params;
1727  snd_pcm_hw_params_alloca(&hw_params);
1728  err = snd_pcm_hw_params_any(handle, hw_params);
1729  if (err < 0) {
1730  snd_pcm_close(handle);
1731  sprintf(message, "RtAudio: ALSA error getting parameter handle (%s): %s.",
1732  name, snd_strerror(err));
1733  error(RtError::WARNING);
1734  return FAILURE;
1735  }
1736 
1737 #if defined(__RTAUDIO_DEBUG__)
1738  fprintf(stderr, "\nRtAudio: ALSA dump hardware params just after device open:\n\n");
1739  snd_pcm_hw_params_dump(hw_params, out);
1740 #endif
1741 
1742 
1743  // Set access ... try interleaved access first, then non-interleaved
1744  if ( !snd_pcm_hw_params_test_access( handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED) ) {
1745  err = snd_pcm_hw_params_set_access(handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED);
1746  }
1747  else if ( !snd_pcm_hw_params_test_access( handle, hw_params, SND_PCM_ACCESS_RW_NONINTERLEAVED) ) {
1748  err = snd_pcm_hw_params_set_access(handle, hw_params, SND_PCM_ACCESS_RW_NONINTERLEAVED);
1749  stream->deInterleave[mode] = true;
1750  }
1751  else {
1752  snd_pcm_close(handle);
1753  sprintf(message, "RtAudio: ALSA device (%s) access not supported by RtAudio.", name);
1754  error(RtError::WARNING);
1755  return FAILURE;
1756  }
1757 
1758  if (err < 0) {
1759  snd_pcm_close(handle);
1760  sprintf(message, "RtAudio: ALSA error setting access ( (%s): %s.", name, snd_strerror(err));
1761  error(RtError::WARNING);
1762  return FAILURE;
1763  }
1764 
1765  // Determine how to set the device format.
1766  stream->userFormat = format;
1767  snd_pcm_format_t device_format;
1768 
1769  if (format == RTAUDIO_SINT8)
1770  device_format = SND_PCM_FORMAT_S8;
1771  else if (format == RTAUDIO_SINT16)
1772  device_format = SND_PCM_FORMAT_S16;
1773  else if (format == RTAUDIO_SINT24)
1774  device_format = SND_PCM_FORMAT_S24;
1775  else if (format == RTAUDIO_SINT32)
1776  device_format = SND_PCM_FORMAT_S32;
1777  else if (format == RTAUDIO_FLOAT32)
1778  device_format = SND_PCM_FORMAT_FLOAT;
1779  else if (format == RTAUDIO_FLOAT64)
1780  device_format = SND_PCM_FORMAT_FLOAT64;
1781 
1782  if (snd_pcm_hw_params_test_format(handle, hw_params, device_format) == 0) {
1783  stream->deviceFormat[mode] = format;
1784  goto set_format;
1785  }
1786 
1787  // The user requested format is not natively supported by the device.
1788  device_format = SND_PCM_FORMAT_FLOAT64;
1789  if (snd_pcm_hw_params_test_format(handle, hw_params, device_format) == 0) {
1790  stream->deviceFormat[mode] = RTAUDIO_FLOAT64;
1791  goto set_format;
1792  }
1793 
1794  device_format = SND_PCM_FORMAT_FLOAT;
1795  if (snd_pcm_hw_params_test_format(handle, hw_params, device_format) == 0) {
1796  stream->deviceFormat[mode] = RTAUDIO_FLOAT32;
1797  goto set_format;
1798  }
1799 
1800  device_format = SND_PCM_FORMAT_S32;
1801  if (snd_pcm_hw_params_test_format(handle, hw_params, device_format) == 0) {
1802  stream->deviceFormat[mode] = RTAUDIO_SINT32;
1803  goto set_format;
1804  }
1805 
1806  device_format = SND_PCM_FORMAT_S24;
1807  if (snd_pcm_hw_params_test_format(handle, hw_params, device_format) == 0) {
1808  stream->deviceFormat[mode] = RTAUDIO_SINT24;
1809  goto set_format;
1810  }
1811 
1812  device_format = SND_PCM_FORMAT_S16;
1813  if (snd_pcm_hw_params_test_format(handle, hw_params, device_format) == 0) {
1814  stream->deviceFormat[mode] = RTAUDIO_SINT16;
1815  goto set_format;
1816  }
1817 
1818  device_format = SND_PCM_FORMAT_S8;
1819  if (snd_pcm_hw_params_test_format(handle, hw_params, device_format) == 0) {
1820  stream->deviceFormat[mode] = RTAUDIO_SINT8;
1821  goto set_format;
1822  }
1823 
1824  // If we get here, no supported format was found.
1825  sprintf(message,"RtAudio: ALSA pcm device (%s) data format not supported by RtAudio.", name);
1826  snd_pcm_close(handle);
1827  error(RtError::WARNING);
1828  return FAILURE;
1829 
1830  set_format:
1831  err = snd_pcm_hw_params_set_format(handle, hw_params, device_format);
1832  if (err < 0) {
1833  snd_pcm_close(handle);
1834  sprintf(message, "RtAudio: ALSA error setting format (%s): %s.",
1835  name, snd_strerror(err));
1836  error(RtError::WARNING);
1837  return FAILURE;
1838  }
1839 
1840  // Determine whether byte-swaping is necessary.
1841  stream->doByteSwap[mode] = false;
1842  if (device_format != SND_PCM_FORMAT_S8) {
1843  err = snd_pcm_format_cpu_endian(device_format);
1844  if (err == 0)
1845  stream->doByteSwap[mode] = true;
1846  else if (err < 0) {
1847  snd_pcm_close(handle);
1848  sprintf(message, "RtAudio: ALSA error getting format endian-ness (%s): %s.",
1849  name, snd_strerror(err));
1850  error(RtError::WARNING);
1851  return FAILURE;
1852  }
1853  }
1854 
1855  // Set the sample rate.
1856  err = snd_pcm_hw_params_set_rate(handle, hw_params, (unsigned int)sampleRate, 0);
1857  if (err < 0) {
1858  snd_pcm_close(handle);
1859  sprintf(message, "RtAudio: ALSA error setting sample rate (%d) on device (%s): %s.",
1860  sampleRate, name, snd_strerror(err));
1861  error(RtError::WARNING);
1862  return FAILURE;
1863  }
1864 
1865  // Determine the number of channels for this device. We support a possible
1866  // minimum device channel number > than the value requested by the user.
1867  stream->nUserChannels[mode] = channels;
1868  int device_channels = snd_pcm_hw_params_get_channels_max(hw_params);
1869  if (device_channels < channels) {
1870  snd_pcm_close(handle);
1871  sprintf(message, "RtAudio: channels (%d) not supported by device (%s).",
1872  channels, name);
1873  error(RtError::WARNING);
1874  return FAILURE;
1875  }
1876 
1877  device_channels = snd_pcm_hw_params_get_channels_min(hw_params);
1878  if (device_channels < channels) device_channels = channels;
1879  stream->nDeviceChannels[mode] = device_channels;
1880 
1881  // Set the device channels.
1882  err = snd_pcm_hw_params_set_channels(handle, hw_params, device_channels);
1883  if (err < 0) {
1884  snd_pcm_close(handle);
1885  sprintf(message, "RtAudio: ALSA error setting channels (%d) on device (%s): %s.",
1886  device_channels, name, snd_strerror(err));
1887  error(RtError::WARNING);
1888  return FAILURE;
1889  }
1890 
1891  // Set the buffer number, which in ALSA is referred to as the "period".
1892  int dir;
1893  int periods = numberOfBuffers;
1894  // Even though the hardware might allow 1 buffer, it won't work reliably.
1895  if (periods < 2) periods = 2;
1896  err = snd_pcm_hw_params_get_periods_min(hw_params, &dir);
1897  if (err > periods) periods = err;
1898  err = snd_pcm_hw_params_get_periods_max(hw_params, &dir);
1899  if (err < periods) periods = err;
1900 
1901  err = snd_pcm_hw_params_set_periods(handle, hw_params, periods, 0);
1902  if (err < 0) {
1903  snd_pcm_close(handle);
1904  sprintf(message, "RtAudio: ALSA error setting periods (%s): %s.",
1905  name, snd_strerror(err));
1906  error(RtError::WARNING);
1907  return FAILURE;
1908  }
1909 
1910  // Set the buffer (or period) size.
1911  err = snd_pcm_hw_params_get_period_size_min(hw_params, &dir);
1912  if (err > *bufferSize) *bufferSize = err;
1913 
1914  err = snd_pcm_hw_params_set_period_size(handle, hw_params, *bufferSize, 0);
1915  if (err < 0) {
1916  snd_pcm_close(handle);
1917  sprintf(message, "RtAudio: ALSA error setting period size (%s): %s.",
1918  name, snd_strerror(err));
1919  error(RtError::WARNING);
1920  return FAILURE;
1921  }
1922 
1923  // If attempting to setup a duplex stream, the bufferSize parameter
1924  // MUST be the same in both directions!
1925  if ( stream->mode == OUTPUT && mode == INPUT && *bufferSize != stream->bufferSize ) {
1926  sprintf( message, "RtAudio: ALSA error setting buffer size for duplex stream on device (%s).",
1927  name );
1928  error(RtError::DEBUG_WARNING);
1929  return FAILURE;
1930  }
1931 
1932  stream->bufferSize = *bufferSize;
1933 
1934  // Install the hardware configuration
1935  err = snd_pcm_hw_params(handle, hw_params);
1936  if (err < 0) {
1937  snd_pcm_close(handle);
1938  sprintf(message, "RtAudio: ALSA error installing hardware configuration (%s): %s.",
1939  name, snd_strerror(err));
1940  error(RtError::WARNING);
1941  return FAILURE;
1942  }
1943 
1944 #if defined(__RTAUDIO_DEBUG__)
1945  fprintf(stderr, "\nRtAudio: ALSA dump hardware params after installation:\n\n");
1946  snd_pcm_hw_params_dump(hw_params, out);
1947 #endif
1948 
1949  /*
1950  // Install the software configuration
1951  snd_pcm_sw_params_t *sw_params = NULL;
1952  snd_pcm_sw_params_alloca(&sw_params);
1953  snd_pcm_sw_params_current(handle, sw_params);
1954  err = snd_pcm_sw_params(handle, sw_params);
1955  if (err < 0) {
1956  snd_pcm_close(handle);
1957  sprintf(message, "RtAudio: ALSA error installing software configuration (%s): %s.",
1958  name, snd_strerror(err));
1959  error(RtError::WARNING);
1960  return FAILURE;
1961  }
1962  */
1963 
1964  // Set handle and flags for buffer conversion
1965  stream->handle[mode] = handle;
1966  stream->doConvertBuffer[mode] = false;
1967  if (stream->userFormat != stream->deviceFormat[mode])
1968  stream->doConvertBuffer[mode] = true;
1969  if (stream->nUserChannels[mode] < stream->nDeviceChannels[mode])
1970  stream->doConvertBuffer[mode] = true;
1971  if (stream->nUserChannels[mode] > 1 && stream->deInterleave[mode])
1972  stream->doConvertBuffer[mode] = true;
1973 
1974  // Allocate necessary internal buffers
1975  if ( stream->nUserChannels[0] != stream->nUserChannels[1] ) {
1976 
1977  long buffer_bytes;
1978  if (stream->nUserChannels[0] >= stream->nUserChannels[1])
1979  buffer_bytes = stream->nUserChannels[0];
1980  else
1981  buffer_bytes = stream->nUserChannels[1];
1982 
1983  buffer_bytes *= *bufferSize * formatBytes(stream->userFormat);
1984  if (stream->userBuffer) free(stream->userBuffer);
1985  stream->userBuffer = (char *) calloc(buffer_bytes, 1);
1986  if (stream->userBuffer == NULL)
1987  goto memory_error;
1988  }
1989 
1990  if ( stream->doConvertBuffer[mode] ) {
1991 
1992  long buffer_bytes;
1993  bool makeBuffer = true;
1994  if ( mode == OUTPUT )
1995  buffer_bytes = stream->nDeviceChannels[0] * formatBytes(stream->deviceFormat[0]);
1996  else { // mode == INPUT
1997  buffer_bytes = stream->nDeviceChannels[1] * formatBytes(stream->deviceFormat[1]);
1998  if ( stream->mode == OUTPUT && stream->deviceBuffer ) {
1999  long bytes_out = stream->nDeviceChannels[0] * formatBytes(stream->deviceFormat[0]);
2000  if ( buffer_bytes < bytes_out ) makeBuffer = false;
2001  }
2002  }
2003 
2004  if ( makeBuffer ) {
2005  buffer_bytes *= *bufferSize;
2006  if (stream->deviceBuffer) free(stream->deviceBuffer);
2007  stream->deviceBuffer = (char *) calloc(buffer_bytes, 1);
2008  if (stream->deviceBuffer == NULL)
2009  goto memory_error;
2010  }
2011  }
2012 
2013  stream->device[mode] = device;
2014  stream->state = STREAM_STOPPED;
2015  if ( stream->mode == OUTPUT && mode == INPUT )
2016  // We had already set up an output stream.
2017  stream->mode = DUPLEX;
2018  else
2019  stream->mode = mode;
2020  stream->nBuffers = periods;
2021  stream->sampleRate = sampleRate;
2022 
2023  return SUCCESS;
2024 
2025  memory_error:
2026  if (stream->handle[0]) {
2027  snd_pcm_close(stream->handle[0]);
2028  stream->handle[0] = 0;
2029  }
2030  if (stream->handle[1]) {
2031  snd_pcm_close(stream->handle[1]);
2032  stream->handle[1] = 0;
2033  }
2034  if (stream->userBuffer) {
2035  free(stream->userBuffer);
2036  stream->userBuffer = 0;
2037  }
2038  sprintf(message, "RtAudio: ALSA error allocating buffer memory (%s).", name);
2039  error(RtError::WARNING);
2040  return FAILURE;
2041 }
2042 
2043 void RtAudio :: closeStream(int streamId)
2044 {
2045  // We don't want an exception to be thrown here because this
2046  // function is called by our class destructor. So, do our own
2047  // streamId check.
2048  if ( streams.find( streamId ) == streams.end() ) {
2049  sprintf(message, "RtAudio: invalid stream identifier!");
2050  error(RtError::WARNING);
2051  return;
2052  }
2053 
2054  RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) streams[streamId];
2055 
2056  if (stream->callbackInfo.usingCallback) {
2057  pthread_cancel(stream->callbackInfo.thread);
2058  pthread_join(stream->callbackInfo.thread, NULL);
2059  }
2060 
2061  if (stream->state == STREAM_RUNNING) {
2062  if (stream->mode == OUTPUT || stream->mode == DUPLEX)
2063  snd_pcm_drop(stream->handle[0]);
2064  if (stream->mode == INPUT || stream->mode == DUPLEX)
2065  snd_pcm_drop(stream->handle[1]);
2066  }
2067 
2068  pthread_mutex_destroy(&stream->mutex);
2069 
2070  if (stream->handle[0])
2071  snd_pcm_close(stream->handle[0]);
2072 
2073  if (stream->handle[1])
2074  snd_pcm_close(stream->handle[1]);
2075 
2076  if (stream->userBuffer)
2077  free(stream->userBuffer);
2078 
2079  if (stream->deviceBuffer)
2080  free(stream->deviceBuffer);
2081 
2082  free(stream);
2083  streams.erase(streamId);
2084 }
2085 
2086 void RtAudio :: startStream(int streamId)
2087 {
2088  // This method calls snd_pcm_prepare if the device isn't already in that state.
2089 
2090  RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
2091 
2092  MUTEX_LOCK(&stream->mutex);
2093 
2094  if (stream->state == STREAM_RUNNING)
2095  goto unlock;
2096 
2097  int err;
2098  snd_pcm_state_t state;
2099  if (stream->mode == OUTPUT || stream->mode == DUPLEX) {
2100  state = snd_pcm_state(stream->handle[0]);
2101  if (state != SND_PCM_STATE_PREPARED) {
2102  err = snd_pcm_prepare(stream->handle[0]);
2103  if (err < 0) {
2104  sprintf(message, "RtAudio: ALSA error preparing pcm device (%s): %s.",
2105  devices[stream->device[0]].name, snd_strerror(err));
2106  MUTEX_UNLOCK(&stream->mutex);
2107  error(RtError::DRIVER_ERROR);
2108  }
2109  }
2110  }
2111 
2112  if (stream->mode == INPUT || stream->mode == DUPLEX) {
2113  state = snd_pcm_state(stream->handle[1]);
2114  if (state != SND_PCM_STATE_PREPARED) {
2115  err = snd_pcm_prepare(stream->handle[1]);
2116  if (err < 0) {
2117  sprintf(message, "RtAudio: ALSA error preparing pcm device (%s): %s.",
2118  devices[stream->device[1]].name, snd_strerror(err));
2119  MUTEX_UNLOCK(&stream->mutex);
2120  error(RtError::DRIVER_ERROR);
2121  }
2122  }
2123  }
2124  stream->state = STREAM_RUNNING;
2125 
2126  unlock:
2127  MUTEX_UNLOCK(&stream->mutex);
2128 }
2129 
2130 void RtAudio :: stopStream(int streamId)
2131 {
2132  RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
2133 
2134  MUTEX_LOCK(&stream->mutex);
2135 
2136  if (stream->state == STREAM_STOPPED)
2137  goto unlock;
2138 
2139  int err;
2140  if (stream->mode == OUTPUT || stream->mode == DUPLEX) {
2141  err = snd_pcm_drain(stream->handle[0]);
2142  if (err < 0) {
2143  sprintf(message, "RtAudio: ALSA error draining pcm device (%s): %s.",
2144  devices[stream->device[0]].name, snd_strerror(err));
2145  MUTEX_UNLOCK(&stream->mutex);
2146  error(RtError::DRIVER_ERROR);
2147  }
2148  }
2149 
2150  if (stream->mode == INPUT || stream->mode == DUPLEX) {
2151  err = snd_pcm_drain(stream->handle[1]);
2152  if (err < 0) {
2153  sprintf(message, "RtAudio: ALSA error draining pcm device (%s): %s.",
2154  devices[stream->device[1]].name, snd_strerror(err));
2155  MUTEX_UNLOCK(&stream->mutex);
2156  error(RtError::DRIVER_ERROR);
2157  }
2158  }
2159  stream->state = STREAM_STOPPED;
2160 
2161  unlock:
2162  MUTEX_UNLOCK(&stream->mutex);
2163 }
2164 
2165 void RtAudio :: abortStream(int streamId)
2166 {
2167  RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
2168 
2169  MUTEX_LOCK(&stream->mutex);
2170 
2171  if (stream->state == STREAM_STOPPED)
2172  goto unlock;
2173 
2174  int err;
2175  if (stream->mode == OUTPUT || stream->mode == DUPLEX) {
2176  err = snd_pcm_drop(stream->handle[0]);
2177  if (err < 0) {
2178  sprintf(message, "RtAudio: ALSA error draining pcm device (%s): %s.",
2179  devices[stream->device[0]].name, snd_strerror(err));
2180  MUTEX_UNLOCK(&stream->mutex);
2181  error(RtError::DRIVER_ERROR);
2182  }
2183  }
2184 
2185  if (stream->mode == INPUT || stream->mode == DUPLEX) {
2186  err = snd_pcm_drop(stream->handle[1]);
2187  if (err < 0) {
2188  sprintf(message, "RtAudio: ALSA error draining pcm device (%s): %s.",
2189  devices[stream->device[1]].name, snd_strerror(err));
2190  MUTEX_UNLOCK(&stream->mutex);
2191  error(RtError::DRIVER_ERROR);
2192  }
2193  }
2194  stream->state = STREAM_STOPPED;
2195 
2196  unlock:
2197  MUTEX_UNLOCK(&stream->mutex);
2198 }
2199 
2200 int RtAudio :: streamWillBlock(int streamId)
2201 {
2202  RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
2203 
2204  MUTEX_LOCK(&stream->mutex);
2205 
2206  int err = 0, frames = 0;
2207  if (stream->state == STREAM_STOPPED)
2208  goto unlock;
2209 
2210  if (stream->mode == OUTPUT || stream->mode == DUPLEX) {
2211  err = snd_pcm_avail_update(stream->handle[0]);
2212  if (err < 0) {
2213  sprintf(message, "RtAudio: ALSA error getting available frames for device (%s): %s.",
2214  devices[stream->device[0]].name, snd_strerror(err));
2215  MUTEX_UNLOCK(&stream->mutex);
2216  error(RtError::DRIVER_ERROR);
2217  }
2218  }
2219 
2220  frames = err;
2221 
2222  if (stream->mode == INPUT || stream->mode == DUPLEX) {
2223  err = snd_pcm_avail_update(stream->handle[1]);
2224  if (err < 0) {
2225  sprintf(message, "RtAudio: ALSA error getting available frames for device (%s): %s.",
2226  devices[stream->device[1]].name, snd_strerror(err));
2227  MUTEX_UNLOCK(&stream->mutex);
2228  error(RtError::DRIVER_ERROR);
2229  }
2230  if (frames > err) frames = err;
2231  }
2232 
2233  frames = stream->bufferSize - frames;
2234  if (frames < 0) frames = 0;
2235 
2236  unlock:
2237  MUTEX_UNLOCK(&stream->mutex);
2238  return frames;
2239 }
2240 
2241 void RtAudio :: tickStream(int streamId)
2242 {
2243  RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
2244 
2245  int stopStream = 0;
2246  if (stream->state == STREAM_STOPPED) {
2247  if (stream->callbackInfo.usingCallback) usleep(50000); // sleep 50 milliseconds
2248  return;
2249  }
2250  else if (stream->callbackInfo.usingCallback) {
2251  RTAUDIO_CALLBACK callback = (RTAUDIO_CALLBACK) stream->callbackInfo.callback;
2252  stopStream = callback(stream->userBuffer, stream->bufferSize, stream->callbackInfo.userData);
2253  }
2254 
2255  MUTEX_LOCK(&stream->mutex);
2256 
2257  // The state might change while waiting on a mutex.
2258  if (stream->state == STREAM_STOPPED)
2259  goto unlock;
2260 
2261  int err;
2262  char *buffer;
2263  int channels;
2264  RTAUDIO_FORMAT format;
2265  if (stream->mode == OUTPUT || stream->mode == DUPLEX) {
2266 
2267  // Setup parameters and do buffer conversion if necessary.
2268  if (stream->doConvertBuffer[0]) {
2269  convertStreamBuffer(stream, OUTPUT);
2270  buffer = stream->deviceBuffer;
2271  channels = stream->nDeviceChannels[0];
2272  format = stream->deviceFormat[0];
2273  }
2274  else {
2275  buffer = stream->userBuffer;
2276  channels = stream->nUserChannels[0];
2277  format = stream->userFormat;
2278  }
2279 
2280  // Do byte swapping if necessary.
2281  if (stream->doByteSwap[0])
2282  byteSwapBuffer(buffer, stream->bufferSize * channels, format);
2283 
2284  // Write samples to device in interleaved/non-interleaved format.
2285  if (stream->deInterleave[0]) {
2286  void *bufs[channels];
2287  size_t offset = stream->bufferSize * formatBytes(format);
2288  for (int i=0; i<channels; i++)
2289  bufs[i] = (void *) (buffer + (i * offset));
2290  err = snd_pcm_writen(stream->handle[0], bufs, stream->bufferSize);
2291  }
2292  else
2293  err = snd_pcm_writei(stream->handle[0], buffer, stream->bufferSize);
2294 
2295  if (err < stream->bufferSize) {
2296  // Either an error or underrun occured.
2297  if (err == -EPIPE) {
2298  snd_pcm_state_t state = snd_pcm_state(stream->handle[0]);
2299  if (state == SND_PCM_STATE_XRUN) {
2300  sprintf(message, "RtAudio: ALSA underrun detected.");
2301  error(RtError::WARNING);
2302  err = snd_pcm_prepare(stream->handle[0]);
2303  if (err < 0) {
2304  sprintf(message, "RtAudio: ALSA error preparing handle after underrun: %s.",
2305  snd_strerror(err));
2306  MUTEX_UNLOCK(&stream->mutex);
2307  error(RtError::DRIVER_ERROR);
2308  }
2309  }
2310  else {
2311  sprintf(message, "RtAudio: ALSA error, current state is %s.",
2312  snd_pcm_state_name(state));
2313  MUTEX_UNLOCK(&stream->mutex);
2314  error(RtError::DRIVER_ERROR);
2315  }
2316  goto unlock;
2317  }
2318  else {
2319  sprintf(message, "RtAudio: ALSA audio write error for device (%s): %s.",
2320  devices[stream->device[0]].name, snd_strerror(err));
2321  MUTEX_UNLOCK(&stream->mutex);
2322  error(RtError::DRIVER_ERROR);
2323  }
2324  }
2325  }
2326 
2327  if (stream->mode == INPUT || stream->mode == DUPLEX) {
2328 
2329  // Setup parameters.
2330  if (stream->doConvertBuffer[1]) {
2331  buffer = stream->deviceBuffer;
2332  channels = stream->nDeviceChannels[1];
2333  format = stream->deviceFormat[1];
2334  }
2335  else {
2336  buffer = stream->userBuffer;
2337  channels = stream->nUserChannels[1];
2338  format = stream->userFormat;
2339  }
2340 
2341  // Read samples from device in interleaved/non-interleaved format.
2342  if (stream->deInterleave[1]) {
2343  void *bufs[channels];
2344  size_t offset = stream->bufferSize * formatBytes(format);
2345  for (int i=0; i<channels; i++)
2346  bufs[i] = (void *) (buffer + (i * offset));
2347  err = snd_pcm_readn(stream->handle[1], bufs, stream->bufferSize);
2348  }
2349  else
2350  err = snd_pcm_readi(stream->handle[1], buffer, stream->bufferSize);
2351 
2352  if (err < stream->bufferSize) {
2353  // Either an error or underrun occured.
2354  if (err == -EPIPE) {
2355  snd_pcm_state_t state = snd_pcm_state(stream->handle[1]);
2356  if (state == SND_PCM_STATE_XRUN) {
2357  sprintf(message, "RtAudio: ALSA overrun detected.");
2358  error(RtError::WARNING);
2359  err = snd_pcm_prepare(stream->handle[1]);
2360  if (err < 0) {
2361  sprintf(message, "RtAudio: ALSA error preparing handle after overrun: %s.",
2362  snd_strerror(err));
2363  MUTEX_UNLOCK(&stream->mutex);
2364  error(RtError::DRIVER_ERROR);
2365  }
2366  }
2367  else {
2368  sprintf(message, "RtAudio: ALSA error, current state is %s.",
2369  snd_pcm_state_name(state));
2370  MUTEX_UNLOCK(&stream->mutex);
2371  error(RtError::DRIVER_ERROR);
2372  }
2373  goto unlock;
2374  }
2375  else {
2376  sprintf(message, "RtAudio: ALSA audio read error for device (%s): %s.",
2377  devices[stream->device[1]].name, snd_strerror(err));
2378  MUTEX_UNLOCK(&stream->mutex);
2379  error(RtError::DRIVER_ERROR);
2380  }
2381  }
2382 
2383  // Do byte swapping if necessary.
2384  if (stream->doByteSwap[1])
2385  byteSwapBuffer(buffer, stream->bufferSize * channels, format);
2386 
2387  // Do buffer conversion if necessary.
2388  if (stream->doConvertBuffer[1])
2389  convertStreamBuffer(stream, INPUT);
2390  }
2391 
2392  unlock:
2393  MUTEX_UNLOCK(&stream->mutex);
2394 
2395  if (stream->callbackInfo.usingCallback && stopStream)
2396  this->stopStream(streamId);
2397 }
2398 
2399 extern "C" void *callbackHandler(void *ptr)
2400 {
2401  CALLBACK_INFO *info = (CALLBACK_INFO *) ptr;
2402  RtAudio *object = (RtAudio *) info->object;
2403  int stream = info->streamId;
2404  bool *usingCallback = &info->usingCallback;
2405 
2406  while ( *usingCallback ) {
2407  pthread_testcancel();
2408  try {
2409  object->tickStream(stream);
2410  }
2411  catch (RtError &exception) {
2412  fprintf(stderr, "\nRtAudio: Callback thread error (%s) ... closing thread.\n\n",
2413  exception.getMessage());
2414  break;
2415  }
2416  }
2417 
2418  return 0;
2419 }
2420 
2421 //******************** End of __LINUX_ALSA__ *********************//
2422 
2423 #elif defined(__LINUX_OSS__)
2424 
2425 #include <sys/stat.h>
2426 #include <sys/types.h>
2427 #include <sys/ioctl.h>
2428 #include <unistd.h>
2429 #include <fcntl.h>
2430 #include <sys/soundcard.h>
2431 #include <errno.h>
2432 #include <math.h>
2433 
2434 #define DAC_NAME "/dev/dsp"
2435 #define MAX_DEVICES 16
2436 #define MAX_CHANNELS 16
2437 
2438 void RtAudio :: initialize(void)
2439 {
2440  // Count cards and devices
2441  nDevices = 0;
2442 
2443  // We check /dev/dsp before probing devices. /dev/dsp is supposed to
2444  // be a link to the "default" audio device, of the form /dev/dsp0,
2445  // /dev/dsp1, etc... However, I've seen many cases where /dev/dsp was a
2446  // real device, so we need to check for that. Also, sometimes the
2447  // link is to /dev/dspx and other times just dspx. I'm not sure how
2448  // the latter works, but it does.
2449  char device_name[16];
2450  struct stat dspstat;
2451  int dsplink = -1;
2452  int i = 0;
2453  if (lstat(DAC_NAME, &dspstat) == 0) {
2454  if (S_ISLNK(dspstat.st_mode)) {
2455  i = readlink(DAC_NAME, device_name, sizeof(device_name));
2456  if (i > 0) {
2457  device_name[i] = '\0';
2458  if (i > 8) { // check for "/dev/dspx"
2459  if (!strncmp(DAC_NAME, device_name, 8))
2460  dsplink = atoi(&device_name[8]);
2461  }
2462  else if (i > 3) { // check for "dspx"
2463  if (!strncmp("dsp", device_name, 3))
2464  dsplink = atoi(&device_name[3]);
2465  }
2466  }
2467  else {
2468  sprintf(message, "RtAudio: cannot read value of symbolic link %s.", DAC_NAME);
2469  error(RtError::SYSTEM_ERROR);
2470  }
2471  }
2472  }
2473  else {
2474  sprintf(message, "RtAudio: cannot stat %s.", DAC_NAME);
2475  error(RtError::SYSTEM_ERROR);
2476  }
2477 
2478  // The OSS API doesn't provide a routine for determining the number
2479  // of devices. Thus, we'll just pursue a brute force method. The
2480  // idea is to start with /dev/dsp(0) and continue with higher device
2481  // numbers until we reach MAX_DSP_DEVICES. This should tell us how
2482  // many devices we have ... it is not a fullproof scheme, but hopefully
2483  // it will work most of the time.
2484 
2485  int fd = 0;
2486  char names[MAX_DEVICES][16];
2487  for (i=-1; i<MAX_DEVICES; i++) {
2488 
2489  // Probe /dev/dsp first, since it is supposed to be the default device.
2490  if (i == -1)
2491  sprintf(device_name, "%s", DAC_NAME);
2492  else if (i == dsplink)
2493  continue; // We've aready probed this device via /dev/dsp link ... try next device.
2494  else
2495  sprintf(device_name, "%s%d", DAC_NAME, i);
2496 
2497  // First try to open the device for playback, then record mode.
2498  fd = open(device_name, O_WRONLY | O_NONBLOCK);
2499  if (fd == -1) {
2500  // Open device for playback failed ... either busy or doesn't exist.
2501  if (errno != EBUSY && errno != EAGAIN) {
2502  // Try to open for capture
2503  fd = open(device_name, O_RDONLY | O_NONBLOCK);
2504  if (fd == -1) {
2505  // Open device for record failed.
2506  if (errno != EBUSY && errno != EAGAIN)
2507  continue;
2508  else {
2509  sprintf(message, "RtAudio: OSS record device (%s) is busy.", device_name);
2510  error(RtError::WARNING);
2511  // still count it for now
2512  }
2513  }
2514  }
2515  else {
2516  sprintf(message, "RtAudio: OSS playback device (%s) is busy.", device_name);
2517  error(RtError::WARNING);
2518  // still count it for now
2519  }
2520  }
2521 
2522  if (fd >= 0) close(fd);
2523  strncpy(names[nDevices], device_name, 16);
2524  nDevices++;
2525  }
2526 
2527  if (nDevices == 0) return;
2528 
2529  // Allocate the RTAUDIO_DEVICE structures.
2530  devices = (RTAUDIO_DEVICE *) calloc(nDevices, sizeof(RTAUDIO_DEVICE));
2531  if (devices == NULL) {
2532  sprintf(message, "RtAudio: memory allocation error!");
2533  error(RtError::MEMORY_ERROR);
2534  }
2535 
2536  // Write device ascii identifiers to device control structure and then probe capabilities.
2537  for (i=0; i<nDevices; i++) {
2538  strncpy(devices[i].name, names[i], 16);
2539  //probeDeviceInfo(&devices[i]);
2540  }
2541 
2542  return;
2543 }
2544 
2545 int RtAudio :: getDefaultInputDevice(void)
2546 {
2547  // No OSS API functions for default devices.
2548  return 0;
2549 }
2550 
2551 int RtAudio :: getDefaultOutputDevice(void)
2552 {
2553  // No OSS API functions for default devices.
2554  return 0;
2555 }
2556 
2557 void RtAudio :: probeDeviceInfo(RTAUDIO_DEVICE *info)
2558 {
2559  int i, fd, channels, mask;
2560 
2561  // The OSS API doesn't provide a means for probing the capabilities
2562  // of devices. Thus, we'll just pursue a brute force method.
2563 
2564  // First try for playback
2565  fd = open(info->name, O_WRONLY | O_NONBLOCK);
2566  if (fd == -1) {
2567  // Open device failed ... either busy or doesn't exist
2568  if (errno == EBUSY || errno == EAGAIN)
2569  sprintf(message, "RtAudio: OSS playback device (%s) is busy and cannot be probed.",
2570  info->name);
2571  else
2572  sprintf(message, "RtAudio: OSS playback device (%s) open error.", info->name);
2573  error(RtError::DEBUG_WARNING);
2574  goto capture_probe;
2575  }
2576 
2577  // We have an open device ... see how many channels it can handle
2578  for (i=MAX_CHANNELS; i>0; i--) {
2579  channels = i;
2580  if (ioctl(fd, SNDCTL_DSP_CHANNELS, &channels) == -1) {
2581  // This would normally indicate some sort of hardware error, but under ALSA's
2582  // OSS emulation, it sometimes indicates an invalid channel value. Further,
2583  // the returned channel value is not changed. So, we'll ignore the possible
2584  // hardware error.
2585  continue; // try next channel number
2586  }
2587  // Check to see whether the device supports the requested number of channels
2588  if (channels != i ) continue; // try next channel number
2589  // If here, we found the largest working channel value
2590  break;
2591  }
2592  info->maxOutputChannels = i;
2593 
2594  // Now find the minimum number of channels it can handle
2595  for (i=1; i<=info->maxOutputChannels; i++) {
2596  channels = i;
2597  if (ioctl(fd, SNDCTL_DSP_CHANNELS, &channels) == -1 || channels != i)
2598  continue; // try next channel number
2599  // If here, we found the smallest working channel value
2600  break;
2601  }
2602  info->minOutputChannels = i;
2603  close(fd);
2604 
2605  capture_probe:
2606  // Now try for capture
2607  fd = open(info->name, O_RDONLY | O_NONBLOCK);
2608  if (fd == -1) {
2609  // Open device for capture failed ... either busy or doesn't exist
2610  if (errno == EBUSY || errno == EAGAIN)
2611  sprintf(message, "RtAudio: OSS capture device (%s) is busy and cannot be probed.",
2612  info->name);
2613  else
2614  sprintf(message, "RtAudio: OSS capture device (%s) open error.", info->name);
2615  error(RtError::DEBUG_WARNING);
2616  if (info->maxOutputChannels == 0)
2617  // didn't open for playback either ... device invalid
2618  return;
2619  goto probe_parameters;
2620  }
2621 
2622  // We have the device open for capture ... see how many channels it can handle
2623  for (i=MAX_CHANNELS; i>0; i--) {
2624  channels = i;
2625  if (ioctl(fd, SNDCTL_DSP_CHANNELS, &channels) == -1 || channels != i) {
2626  continue; // as above
2627  }
2628  // If here, we found a working channel value
2629  break;
2630  }
2631  info->maxInputChannels = i;
2632 
2633  // Now find the minimum number of channels it can handle
2634  for (i=1; i<=info->maxInputChannels; i++) {
2635  channels = i;
2636  if (ioctl(fd, SNDCTL_DSP_CHANNELS, &channels) == -1 || channels != i)
2637  continue; // try next channel number
2638  // If here, we found the smallest working channel value
2639  break;
2640  }
2641  info->minInputChannels = i;
2642  close(fd);
2643 
2644  if (info->maxOutputChannels == 0 && info->maxInputChannels == 0) {
2645  sprintf(message, "RtAudio: OSS device (%s) reports zero channels for input and output.",
2646  info->name);
2647  error(RtError::DEBUG_WARNING);
2648  return;
2649  }
2650 
2651  // If device opens for both playback and capture, we determine the channels.
2652  if (info->maxOutputChannels == 0 || info->maxInputChannels == 0)
2653  goto probe_parameters;
2654 
2655  fd = open(info->name, O_RDWR | O_NONBLOCK);
2656  if (fd == -1)
2657  goto probe_parameters;
2658 
2659  ioctl(fd, SNDCTL_DSP_SETDUPLEX, 0);
2660  ioctl(fd, SNDCTL_DSP_GETCAPS, &mask);
2661  if (mask & DSP_CAP_DUPLEX) {
2662  info->hasDuplexSupport = true;
2663  // We have the device open for duplex ... see how many channels it can handle
2664  for (i=MAX_CHANNELS; i>0; i--) {
2665  channels = i;
2666  if (ioctl(fd, SNDCTL_DSP_CHANNELS, &channels) == -1 || channels != i)
2667  continue; // as above
2668  // If here, we found a working channel value
2669  break;
2670  }
2671  info->maxDuplexChannels = i;
2672 
2673  // Now find the minimum number of channels it can handle
2674  for (i=1; i<=info->maxDuplexChannels; i++) {
2675  channels = i;
2676  if (ioctl(fd, SNDCTL_DSP_CHANNELS, &channels) == -1 || channels != i)
2677  continue; // try next channel number
2678  // If here, we found the smallest working channel value
2679  break;
2680  }
2681  info->minDuplexChannels = i;
2682  }
2683  close(fd);
2684 
2685  probe_parameters:
2686  // At this point, we need to figure out the supported data formats
2687  // and sample rates. We'll proceed by openning the device in the
2688  // direction with the maximum number of channels, or playback if
2689  // they are equal. This might limit our sample rate options, but so
2690  // be it.
2691 
2692  if (info->maxOutputChannels >= info->maxInputChannels) {
2693  fd = open(info->name, O_WRONLY | O_NONBLOCK);
2694  channels = info->maxOutputChannels;
2695  }
2696  else {
2697  fd = open(info->name, O_RDONLY | O_NONBLOCK);
2698  channels = info->maxInputChannels;
2699  }
2700 
2701  if (fd == -1) {
2702  // We've got some sort of conflict ... abort
2703  sprintf(message, "RtAudio: OSS device (%s) won't reopen during probe.",
2704  info->name);
2705  error(RtError::DEBUG_WARNING);
2706  return;
2707  }
2708 
2709  // We have an open device ... set to maximum channels.
2710  i = channels;
2711  if (ioctl(fd, SNDCTL_DSP_CHANNELS, &channels) == -1 || channels != i) {
2712  // We've got some sort of conflict ... abort
2713  close(fd);
2714  sprintf(message, "RtAudio: OSS device (%s) won't revert to previous channel setting.",
2715  info->name);
2716  error(RtError::DEBUG_WARNING);
2717  return;
2718  }
2719 
2720  if (ioctl(fd, SNDCTL_DSP_GETFMTS, &mask) == -1) {
2721  close(fd);
2722  sprintf(message, "RtAudio: OSS device (%s) can't get supported audio formats.",
2723  info->name);
2724  error(RtError::DEBUG_WARNING);
2725  return;
2726  }
2727 
2728  // Probe the supported data formats ... we don't care about endian-ness just yet.
2729  int format;
2730  info->nativeFormats = 0;
2731 #if defined (AFMT_S32_BE)
2732  // This format does not seem to be in the 2.4 kernel version of OSS soundcard.h
2733  if (mask & AFMT_S32_BE) {
2734  format = AFMT_S32_BE;
2735  info->nativeFormats |= RTAUDIO_SINT32;
2736  }
2737 #endif
2738 #if defined (AFMT_S32_LE)
2739  /* This format is not in the 2.4.4 kernel version of OSS soundcard.h */
2740  if (mask & AFMT_S32_LE) {
2741  format = AFMT_S32_LE;
2742  info->nativeFormats |= RTAUDIO_SINT32;
2743  }
2744 #endif
2745  if (mask & AFMT_S8) {
2746  format = AFMT_S8;
2747  info->nativeFormats |= RTAUDIO_SINT8;
2748  }
2749  if (mask & AFMT_S16_BE) {
2750  format = AFMT_S16_BE;
2751  info->nativeFormats |= RTAUDIO_SINT16;
2752  }
2753  if (mask & AFMT_S16_LE) {
2754  format = AFMT_S16_LE;
2755  info->nativeFormats |= RTAUDIO_SINT16;
2756  }
2757 
2758  // Check that we have at least one supported format
2759  if (info->nativeFormats == 0) {
2760  close(fd);
2761  sprintf(message, "RtAudio: OSS device (%s) data format not supported by RtAudio.",
2762  info->name);
2763  error(RtError::DEBUG_WARNING);
2764  return;
2765  }
2766 
2767  // Set the format
2768  i = format;
2769  if (ioctl(fd, SNDCTL_DSP_SETFMT, &format) == -1 || format != i) {
2770  close(fd);
2771  sprintf(message, "RtAudio: OSS device (%s) error setting data format.",
2772  info->name);
2773  error(RtError::DEBUG_WARNING);
2774  return;
2775  }
2776 
2777  // Probe the supported sample rates ... first get lower limit
2778  int speed = 1;
2779  if (ioctl(fd, SNDCTL_DSP_SPEED, &speed) == -1) {
2780  // If we get here, we're probably using an ALSA driver with OSS-emulation,
2781  // which doesn't conform to the OSS specification. In this case,
2782  // we'll probe our predefined list of sample rates for working values.
2783  info->nSampleRates = 0;
2784  for (i=0; i<MAX_SAMPLE_RATES; i++) {
2785  speed = SAMPLE_RATES[i];
2786  if (ioctl(fd, SNDCTL_DSP_SPEED, &speed) != -1) {
2787  info->sampleRates[info->nSampleRates] = SAMPLE_RATES[i];
2788  info->nSampleRates++;
2789  }
2790  }
2791  if (info->nSampleRates == 0) {
2792  close(fd);
2793  return;
2794  }
2795  goto finished;
2796  }
2797  info->sampleRates[0] = speed;
2798 
2799  // Now get upper limit
2800  speed = 1000000;
2801  if (ioctl(fd, SNDCTL_DSP_SPEED, &speed) == -1) {
2802  close(fd);
2803  sprintf(message, "RtAudio: OSS device (%s) error setting sample rate.",
2804  info->name);
2805  error(RtError::DEBUG_WARNING);
2806  return;
2807  }
2808  info->sampleRates[1] = speed;
2809  info->nSampleRates = -1;
2810 
2811  finished: // That's all ... close the device and return
2812  close(fd);
2813  info->probed = true;
2814  return;
2815 }
2816 
2817 bool RtAudio :: probeDeviceOpen(int device, RTAUDIO_STREAM *stream,
2818  STREAM_MODE mode, int channels,
2819  int sampleRate, RTAUDIO_FORMAT format,
2820  int *bufferSize, int numberOfBuffers)
2821 {
2822  int buffers, buffer_bytes, device_channels, device_format;
2823  int srate, temp, fd;
2824 
2825  const char *name = devices[device].name;
2826 
2827  if (mode == OUTPUT)
2828  fd = open(name, O_WRONLY | O_NONBLOCK);
2829  else { // mode == INPUT
2830  if (stream->mode == OUTPUT && stream->device[0] == device) {
2831  // We just set the same device for playback ... close and reopen for duplex (OSS only).
2832  close(stream->handle[0]);
2833  stream->handle[0] = 0;
2834  // First check that the number previously set channels is the same.
2835  if (stream->nUserChannels[0] != channels) {
2836  sprintf(message, "RtAudio: input/output channels must be equal for OSS duplex device (%s).", name);
2837  goto error;
2838  }
2839  fd = open(name, O_RDWR | O_NONBLOCK);
2840  }
2841  else
2842  fd = open(name, O_RDONLY | O_NONBLOCK);
2843  }
2844 
2845  if (fd == -1) {
2846  if (errno == EBUSY || errno == EAGAIN)
2847  sprintf(message, "RtAudio: OSS device (%s) is busy and cannot be opened.",
2848  name);
2849  else
2850  sprintf(message, "RtAudio: OSS device (%s) cannot be opened.", name);
2851  goto error;
2852  }
2853 
2854  // Now reopen in blocking mode.
2855  close(fd);
2856  if (mode == OUTPUT)
2857  fd = open(name, O_WRONLY | O_SYNC);
2858  else { // mode == INPUT
2859  if (stream->mode == OUTPUT && stream->device[0] == device)
2860  fd = open(name, O_RDWR | O_SYNC);
2861  else
2862  fd = open(name, O_RDONLY | O_SYNC);
2863  }
2864 
2865  if (fd == -1) {
2866  sprintf(message, "RtAudio: OSS device (%s) cannot be opened.", name);
2867  goto error;
2868  }
2869 
2870  // Get the sample format mask
2871  int mask;
2872  if (ioctl(fd, SNDCTL_DSP_GETFMTS, &mask) == -1) {
2873  close(fd);
2874  sprintf(message, "RtAudio: OSS device (%s) can't get supported audio formats.",
2875  name);
2876  goto error;
2877  }
2878 
2879  // Determine how to set the device format.
2880  stream->userFormat = format;
2881  device_format = -1;
2882  stream->doByteSwap[mode] = false;
2883  if (format == RTAUDIO_SINT8) {
2884  if (mask & AFMT_S8) {
2885  device_format = AFMT_S8;
2886  stream->deviceFormat[mode] = RTAUDIO_SINT8;
2887  }
2888  }
2889  else if (format == RTAUDIO_SINT16) {
2890  if (mask & AFMT_S16_NE) {
2891  device_format = AFMT_S16_NE;
2892  stream->deviceFormat[mode] = RTAUDIO_SINT16;
2893  }
2894 #if BYTE_ORDER == LITTLE_ENDIAN
2895  else if (mask & AFMT_S16_BE) {
2896  device_format = AFMT_S16_BE;
2897  stream->deviceFormat[mode] = RTAUDIO_SINT16;
2898  stream->doByteSwap[mode] = true;
2899  }
2900 #else
2901  else if (mask & AFMT_S16_LE) {
2902  device_format = AFMT_S16_LE;
2903  stream->deviceFormat[mode] = RTAUDIO_SINT16;
2904  stream->doByteSwap[mode] = true;
2905  }
2906 #endif
2907  }
2908 #if defined (AFMT_S32_NE) && defined (AFMT_S32_LE) && defined (AFMT_S32_BE)
2909  else if (format == RTAUDIO_SINT32) {
2910  if (mask & AFMT_S32_NE) {
2911  device_format = AFMT_S32_NE;
2912  stream->deviceFormat[mode] = RTAUDIO_SINT32;
2913  }
2914 #if BYTE_ORDER == LITTLE_ENDIAN
2915  else if (mask & AFMT_S32_BE) {
2916  device_format = AFMT_S32_BE;
2917  stream->deviceFormat[mode] = RTAUDIO_SINT32;
2918  stream->doByteSwap[mode] = true;
2919  }
2920 #else
2921  else if (mask & AFMT_S32_LE) {
2922  device_format = AFMT_S32_LE;
2923  stream->deviceFormat[mode] = RTAUDIO_SINT32;
2924  stream->doByteSwap[mode] = true;
2925  }
2926 #endif
2927  }
2928 #endif
2929 
2930  if (device_format == -1) {
2931  // The user requested format is not natively supported by the device.
2932  if (mask & AFMT_S16_NE) {
2933  device_format = AFMT_S16_NE;
2934  stream->deviceFormat[mode] = RTAUDIO_SINT16;
2935  }
2936 #if BYTE_ORDER == LITTLE_ENDIAN
2937  else if (mask & AFMT_S16_BE) {
2938  device_format = AFMT_S16_BE;
2939  stream->deviceFormat[mode] = RTAUDIO_SINT16;
2940  stream->doByteSwap[mode] = true;
2941  }
2942 #else
2943  else if (mask & AFMT_S16_LE) {
2944  device_format = AFMT_S16_LE;
2945  stream->deviceFormat[mode] = RTAUDIO_SINT16;
2946  stream->doByteSwap[mode] = true;
2947  }
2948 #endif
2949 #if defined (AFMT_S32_NE) && defined (AFMT_S32_LE) && defined (AFMT_S32_BE)
2950  else if (mask & AFMT_S32_NE) {
2951  device_format = AFMT_S32_NE;
2952  stream->deviceFormat[mode] = RTAUDIO_SINT32;
2953  }
2954 #if BYTE_ORDER == LITTLE_ENDIAN
2955  else if (mask & AFMT_S32_BE) {
2956  device_format = AFMT_S32_BE;
2957  stream->deviceFormat[mode] = RTAUDIO_SINT32;
2958  stream->doByteSwap[mode] = true;
2959  }
2960 #else
2961  else if (mask & AFMT_S32_LE) {
2962  device_format = AFMT_S32_LE;
2963  stream->deviceFormat[mode] = RTAUDIO_SINT32;
2964  stream->doByteSwap[mode] = true;
2965  }
2966 #endif
2967 #endif
2968  else if (mask & AFMT_S8) {
2969  device_format = AFMT_S8;
2970  stream->deviceFormat[mode] = RTAUDIO_SINT8;
2971  }
2972  }
2973 
2974  if (stream->deviceFormat[mode] == 0) {
2975  // This really shouldn't happen ...
2976  close(fd);
2977  sprintf(message, "RtAudio: OSS device (%s) data format not supported by RtAudio.",
2978  name);
2979  goto error;
2980  }
2981 
2982  // Determine the number of channels for this device. Note that the
2983  // channel value requested by the user might be < min_X_Channels.
2984  stream->nUserChannels[mode] = channels;
2985  device_channels = channels;
2986  if (mode == OUTPUT) {
2987  if (channels < devices[device].minOutputChannels)
2988  device_channels = devices[device].minOutputChannels;
2989  }
2990  else { // mode == INPUT
2991  if (stream->mode == OUTPUT && stream->device[0] == device) {
2992  // We're doing duplex setup here.
2993  if (channels < devices[device].minDuplexChannels)
2994  device_channels = devices[device].minDuplexChannels;
2995  }
2996  else {
2997  if (channels < devices[device].minInputChannels)
2998  device_channels = devices[device].minInputChannels;
2999  }
3000  }
3001  stream->nDeviceChannels[mode] = device_channels;
3002 
3003  // Attempt to set the buffer size. According to OSS, the minimum
3004  // number of buffers is two. The supposed minimum buffer size is 16
3005  // bytes, so that will be our lower bound. The argument to this
3006  // call is in the form 0xMMMMSSSS (hex), where the buffer size (in
3007  // bytes) is given as 2^SSSS and the number of buffers as 2^MMMM.
3008  // We'll check the actual value used near the end of the setup
3009  // procedure.
3010  buffer_bytes = *bufferSize * formatBytes(stream->deviceFormat[mode]) * device_channels;
3011  if (buffer_bytes < 16) buffer_bytes = 16;
3012  buffers = numberOfBuffers;
3013  if (buffers < 2) buffers = 2;
3014  temp = ((int) buffers << 16) + (int)(log10((double)buffer_bytes)/log10(2.0));
3015  if (ioctl(fd, SNDCTL_DSP_SETFRAGMENT, &temp)) {
3016  close(fd);
3017  sprintf(message, "RtAudio: OSS error setting fragment size for device (%s).",
3018  name);
3019  goto error;
3020  }
3021  stream->nBuffers = buffers;
3022 
3023  // Set the data format.
3024  temp = device_format;
3025  if (ioctl(fd, SNDCTL_DSP_SETFMT, &device_format) == -1 || device_format != temp) {
3026  close(fd);
3027  sprintf(message, "RtAudio: OSS error setting data format for device (%s).",
3028  name);
3029  goto error;
3030  }
3031 
3032  // Set the number of channels.
3033  temp = device_channels;
3034  if (ioctl(fd, SNDCTL_DSP_CHANNELS, &device_channels) == -1 || device_channels != temp) {
3035  close(fd);
3036  sprintf(message, "RtAudio: OSS error setting %d channels on device (%s).",
3037  temp, name);
3038  goto error;
3039  }
3040 
3041  // Set the sample rate.
3042  srate = sampleRate;
3043  temp = srate;
3044  if (ioctl(fd, SNDCTL_DSP_SPEED, &srate) == -1) {
3045  close(fd);
3046  sprintf(message, "RtAudio: OSS error setting sample rate = %d on device (%s).",
3047  temp, name);
3048  goto error;
3049  }
3050 
3051  // Verify the sample rate setup worked.
3052  if (abs(srate - temp) > 100) {
3053  close(fd);
3054  sprintf(message, "RtAudio: OSS error ... audio device (%s) doesn't support sample rate of %d.",
3055  name, temp);
3056  goto error;
3057  }
3058  stream->sampleRate = sampleRate;
3059 
3060  if (ioctl(fd, SNDCTL_DSP_GETBLKSIZE, &buffer_bytes) == -1) {
3061  close(fd);
3062  sprintf(message, "RtAudio: OSS error getting buffer size for device (%s).",
3063  name);
3064  goto error;
3065  }
3066 
3067  // Save buffer size (in sample frames).
3068  *bufferSize = buffer_bytes / (formatBytes(stream->deviceFormat[mode]) * device_channels);
3069  stream->bufferSize = *bufferSize;
3070 
3071  if (mode == INPUT && stream->mode == OUTPUT &&
3072  stream->device[0] == device) {
3073  // We're doing duplex setup here.
3074  stream->deviceFormat[0] = stream->deviceFormat[1];
3075  stream->nDeviceChannels[0] = device_channels;
3076  }
3077 
3078  // Set flags for buffer conversion
3079  stream->doConvertBuffer[mode] = false;
3080  if (stream->userFormat != stream->deviceFormat[mode])
3081  stream->doConvertBuffer[mode] = true;
3082  if (stream->nUserChannels[mode] < stream->nDeviceChannels[mode])
3083  stream->doConvertBuffer[mode] = true;
3084 
3085  // Allocate necessary internal buffers
3086  if ( stream->nUserChannels[0] != stream->nUserChannels[1] ) {
3087 
3088  long buffer_bytes;
3089  if (stream->nUserChannels[0] >= stream->nUserChannels[1])
3090  buffer_bytes = stream->nUserChannels[0];
3091  else
3092  buffer_bytes = stream->nUserChannels[1];
3093 
3094  buffer_bytes *= *bufferSize * formatBytes(stream->userFormat);
3095  if (stream->userBuffer) free(stream->userBuffer);
3096  stream->userBuffer = (char *) calloc(buffer_bytes, 1);
3097  if (stream->userBuffer == NULL) {
3098  close(fd);
3099  sprintf(message, "RtAudio: OSS error allocating user buffer memory (%s).",
3100  name);
3101  goto error;
3102  }
3103  }
3104 
3105  if ( stream->doConvertBuffer[mode] ) {
3106 
3107  long buffer_bytes;
3108  bool makeBuffer = true;
3109  if ( mode == OUTPUT )
3110  buffer_bytes = stream->nDeviceChannels[0] * formatBytes(stream->deviceFormat[0]);
3111  else { // mode == INPUT
3112  buffer_bytes = stream->nDeviceChannels[1] * formatBytes(stream->deviceFormat[1]);
3113  if ( stream->mode == OUTPUT && stream->deviceBuffer ) {
3114  long bytes_out = stream->nDeviceChannels[0] * formatBytes(stream->deviceFormat[0]);
3115  if ( buffer_bytes < bytes_out ) makeBuffer = false;
3116  }
3117  }
3118 
3119  if ( makeBuffer ) {
3120  buffer_bytes *= *bufferSize;
3121  if (stream->deviceBuffer) free(stream->deviceBuffer);
3122  stream->deviceBuffer = (char *) calloc(buffer_bytes, 1);
3123  if (stream->deviceBuffer == NULL) {
3124  close(fd);
3125  free(stream->userBuffer);
3126  sprintf(message, "RtAudio: OSS error allocating device buffer memory (%s).",
3127  name);
3128  goto error;
3129  }
3130  }
3131  }
3132 
3133  stream->device[mode] = device;
3134  stream->handle[mode] = fd;
3135  stream->state = STREAM_STOPPED;
3136  if ( stream->mode == OUTPUT && mode == INPUT ) {
3137  stream->mode = DUPLEX;
3138  if (stream->device[0] == device)
3139  stream->handle[0] = fd;
3140  }
3141  else
3142  stream->mode = mode;
3143 
3144  return SUCCESS;
3145 
3146  error:
3147  if (stream->handle[0]) {
3148  close(stream->handle[0]);
3149  stream->handle[0] = 0;
3150  }
3151  error(RtError::WARNING);
3152  return FAILURE;
3153 }
3154 
3155 void RtAudio :: closeStream(int streamId)
3156 {
3157  // We don't want an exception to be thrown here because this
3158  // function is called by our class destructor. So, do our own
3159  // streamId check.
3160  if ( streams.find( streamId ) == streams.end() ) {
3161  sprintf(message, "RtAudio: invalid stream identifier!");
3162  error(RtError::WARNING);
3163  return;
3164  }
3165 
3166  RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) streams[streamId];
3167 
3168  if (stream->callbackInfo.usingCallback) {
3169  pthread_cancel(stream->callbackInfo.thread);
3170  pthread_join(stream->callbackInfo.thread, NULL);
3171  }
3172 
3173  if (stream->state == STREAM_RUNNING) {
3174  if (stream->mode == OUTPUT || stream->mode == DUPLEX)
3175  ioctl(stream->handle[0], SNDCTL_DSP_RESET, 0);
3176  if (stream->mode == INPUT || stream->mode == DUPLEX)
3177  ioctl(stream->handle[1], SNDCTL_DSP_RESET, 0);
3178  }
3179 
3180  pthread_mutex_destroy(&stream->mutex);
3181 
3182  if (stream->handle[0])
3183  close(stream->handle[0]);
3184 
3185  if (stream->handle[1])
3186  close(stream->handle[1]);
3187 
3188  if (stream->userBuffer)
3189  free(stream->userBuffer);
3190 
3191  if (stream->deviceBuffer)
3192  free(stream->deviceBuffer);
3193 
3194  free(stream);
3195  streams.erase(streamId);
3196 }
3197 
3198 void RtAudio :: startStream(int streamId)
3199 {
3200  RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
3201 
3202  MUTEX_LOCK(&stream->mutex);
3203 
3204  stream->state = STREAM_RUNNING;
3205 
3206  // No need to do anything else here ... OSS automatically starts
3207  // when fed samples.
3208 
3209  MUTEX_UNLOCK(&stream->mutex);
3210 }
3211 
3212 void RtAudio :: stopStream(int streamId)
3213 {
3214  RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
3215 
3216  MUTEX_LOCK(&stream->mutex);
3217 
3218  if (stream->state == STREAM_STOPPED)
3219  goto unlock;
3220 
3221  int err;
3222  if (stream->mode == OUTPUT || stream->mode == DUPLEX) {
3223  err = ioctl(stream->handle[0], SNDCTL_DSP_SYNC, 0);
3224  if (err < -1) {
3225  sprintf(message, "RtAudio: OSS error stopping device (%s).",
3226  devices[stream->device[0]].name);
3227  error(RtError::DRIVER_ERROR);
3228  }
3229  }
3230  else {
3231  err = ioctl(stream->handle[1], SNDCTL_DSP_SYNC, 0);
3232  if (err < -1) {
3233  sprintf(message, "RtAudio: OSS error stopping device (%s).",
3234  devices[stream->device[1]].name);
3235  error(RtError::DRIVER_ERROR);
3236  }
3237  }
3238  stream->state = STREAM_STOPPED;
3239 
3240  unlock:
3241  MUTEX_UNLOCK(&stream->mutex);
3242 }
3243 
3244 void RtAudio :: abortStream(int streamId)
3245 {
3246  RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
3247 
3248  MUTEX_LOCK(&stream->mutex);
3249 
3250  if (stream->state == STREAM_STOPPED)
3251  goto unlock;
3252 
3253  int err;
3254  if (stream->mode == OUTPUT || stream->mode == DUPLEX) {
3255  err = ioctl(stream->handle[0], SNDCTL_DSP_RESET, 0);
3256  if (err < -1) {
3257  sprintf(message, "RtAudio: OSS error aborting device (%s).",
3258  devices[stream->device[0]].name);
3259  error(RtError::DRIVER_ERROR);
3260  }
3261  }
3262  else {
3263  err = ioctl(stream->handle[1], SNDCTL_DSP_RESET, 0);
3264  if (err < -1) {
3265  sprintf(message, "RtAudio: OSS error aborting device (%s).",
3266  devices[stream->device[1]].name);
3267  error(RtError::DRIVER_ERROR);
3268  }
3269  }
3270  stream->state = STREAM_STOPPED;
3271 
3272  unlock:
3273  MUTEX_UNLOCK(&stream->mutex);
3274 }
3275 
3276 int RtAudio :: streamWillBlock(int streamId)
3277 {
3278  RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
3279 
3280  MUTEX_LOCK(&stream->mutex);
3281 
3282  int bytes = 0, channels = 0, frames = 0;
3283  if (stream->state == STREAM_STOPPED)
3284  goto unlock;
3285 
3286  audio_buf_info info;
3287  if (stream->mode == OUTPUT || stream->mode == DUPLEX) {
3288  ioctl(stream->handle[0], SNDCTL_DSP_GETOSPACE, &info);
3289  bytes = info.bytes;
3290  channels = stream->nDeviceChannels[0];
3291  }
3292 
3293  if (stream->mode == INPUT || stream->mode == DUPLEX) {
3294  ioctl(stream->handle[1], SNDCTL_DSP_GETISPACE, &info);
3295  if (stream->mode == DUPLEX ) {
3296  bytes = (bytes < info.bytes) ? bytes : info.bytes;
3297  channels = stream->nDeviceChannels[0];
3298  }
3299  else {
3300  bytes = info.bytes;
3301  channels = stream->nDeviceChannels[1];
3302  }
3303  }
3304 
3305  frames = (int) (bytes / (channels * formatBytes(stream->deviceFormat[0])));
3306  frames -= stream->bufferSize;
3307  if (frames < 0) frames = 0;
3308 
3309  unlock:
3310  MUTEX_UNLOCK(&stream->mutex);
3311  return frames;
3312 }
3313 
3314 void RtAudio :: tickStream(int streamId)
3315 {
3316  RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
3317 
3318  int stopStream = 0;
3319  if (stream->state == STREAM_STOPPED) {
3320  if (stream->callbackInfo.usingCallback) usleep(50000); // sleep 50 milliseconds
3321  return;
3322  }
3323  else if (stream->callbackInfo.usingCallback) {
3324  RTAUDIO_CALLBACK callback = (RTAUDIO_CALLBACK) stream->callbackInfo.callback;
3325  stopStream = callback(stream->userBuffer, stream->bufferSize, stream->callbackInfo.userData);
3326  }
3327 
3328  MUTEX_LOCK(&stream->mutex);
3329 
3330  // The state might change while waiting on a mutex.
3331  if (stream->state == STREAM_STOPPED)
3332  goto unlock;
3333 
3334  int result;
3335  char *buffer;
3336  int samples;
3337  RTAUDIO_FORMAT format;
3338  if (stream->mode == OUTPUT || stream->mode == DUPLEX) {
3339 
3340  // Setup parameters and do buffer conversion if necessary.
3341  if (stream->doConvertBuffer[0]) {
3342  convertStreamBuffer(stream, OUTPUT);
3343  buffer = stream->deviceBuffer;
3344  samples = stream->bufferSize * stream->nDeviceChannels[0];
3345  format = stream->deviceFormat[0];
3346  }
3347  else {
3348  buffer = stream->userBuffer;
3349  samples = stream->bufferSize * stream->nUserChannels[0];
3350  format = stream->userFormat;
3351  }
3352 
3353  // Do byte swapping if necessary.
3354  if (stream->doByteSwap[0])
3355  byteSwapBuffer(buffer, samples, format);
3356 
3357  // Write samples to device.
3358  result = write(stream->handle[0], buffer, samples * formatBytes(format));
3359 
3360  if (result == -1) {
3361  // This could be an underrun, but the basic OSS API doesn't provide a means for determining that.
3362  sprintf(message, "RtAudio: OSS audio write error for device (%s).",
3363  devices[stream->device[0]].name);
3364  error(RtError::DRIVER_ERROR);
3365  }
3366  }
3367 
3368  if (stream->mode == INPUT || stream->mode == DUPLEX) {
3369 
3370  // Setup parameters.
3371  if (stream->doConvertBuffer[1]) {
3372  buffer = stream->deviceBuffer;
3373  samples = stream->bufferSize * stream->nDeviceChannels[1];
3374  format = stream->deviceFormat[1];
3375  }
3376  else {
3377  buffer = stream->userBuffer;
3378  samples = stream->bufferSize * stream->nUserChannels[1];
3379  format = stream->userFormat;
3380  }
3381 
3382  // Read samples from device.
3383  result = read(stream->handle[1], buffer, samples * formatBytes(format));
3384 
3385  if (result == -1) {
3386  // This could be an overrun, but the basic OSS API doesn't provide a means for determining that.
3387  sprintf(message, "RtAudio: OSS audio read error for device (%s).",
3388  devices[stream->device[1]].name);
3389  error(RtError::DRIVER_ERROR);
3390  }
3391 
3392  // Do byte swapping if necessary.
3393  if (stream->doByteSwap[1])
3394  byteSwapBuffer(buffer, samples, format);
3395 
3396  // Do buffer conversion if necessary.
3397  if (stream->doConvertBuffer[1])
3398  convertStreamBuffer(stream, INPUT);
3399  }
3400 
3401  unlock:
3402  MUTEX_UNLOCK(&stream->mutex);
3403 
3404  if (stream->callbackInfo.usingCallback && stopStream)
3405  this->stopStream(streamId);
3406 }
3407 
3408 extern "C" void *callbackHandler(void *ptr)
3409 {
3410  CALLBACK_INFO *info = (CALLBACK_INFO *) ptr;
3411  RtAudio *object = (RtAudio *) info->object;
3412  int stream = info->streamId;
3413  bool *usingCallback = &info->usingCallback;
3414 
3415  while ( *usingCallback ) {
3416  pthread_testcancel();
3417  try {
3418  object->tickStream(stream);
3419  }
3420  catch (RtError &exception) {
3421  fprintf(stderr, "\nRtAudio: Callback thread error (%s) ... closing thread.\n\n",
3422  exception.getMessage());
3423  break;
3424  }
3425  }
3426 
3427  return 0;
3428 }
3429 
3430 
3431 //******************** End of __LINUX_OSS__ *********************//
3432 
3433 #elif defined(__WINDOWS_ASIO__) // ASIO API on Windows
3434 
3435 // The ASIO API is designed around a callback scheme, so this
3436 // implementation is similar to that used for OS X CoreAudio. The
3437 // primary constraint with ASIO is that it only allows access to a
3438 // single driver at a time. Thus, it is not possible to have more
3439 // than one simultaneous RtAudio stream.
3440 //
3441 // This implementation also requires a number of external ASIO files
3442 // and a few global variables. The ASIO callback scheme does not
3443 // allow for the passing of user data, so we must create a global
3444 // pointer to our callbackInfo structure.
3445 
3446 #include "asio/asiosys.h"
3447 #include "asio/asio.h"
3448 #include "asio/asiodrivers.h"
3449 #include <math.h>
3450 
3451 AsioDrivers drivers;
3452 ASIOCallbacks asioCallbacks;
3453 CALLBACK_INFO *asioCallbackInfo;
3454 ASIODriverInfo driverInfo;
3455 
3456 void RtAudio :: initialize(void)
3457 {
3458  nDevices = drivers.asioGetNumDev();
3459  if (nDevices <= 0) return;
3460 
3461  // Allocate the RTAUDIO_DEVICE structures.
3462  devices = (RTAUDIO_DEVICE *) calloc(nDevices, sizeof(RTAUDIO_DEVICE));
3463  if (devices == NULL) {
3464  sprintf(message, "RtAudio: memory allocation error!");
3465  error(RtError::MEMORY_ERROR);
3466  }
3467 
3468  // Write device driver names to device structures and then probe the
3469  // device capabilities.
3470  for (int i=0; i<nDevices; i++) {
3471  if ( drivers.asioGetDriverName( i, devices[i].name, 128 ) == 0 )
3472  //probeDeviceInfo(&devices[i]);
3473  ;
3474  else {
3475  sprintf(message, "RtAudio: error getting ASIO driver name for device index %d!", i);
3476  error(RtError::WARNING);
3477  }
3478  }
3479 
3480  drivers.removeCurrentDriver();
3481  driverInfo.asioVersion = 2;
3482  // See note in DirectSound implementation about GetDesktopWindow().
3483  driverInfo.sysRef = GetForegroundWindow();
3484 }
3485 
3486 int RtAudio :: getDefaultInputDevice(void)
3487 {
3488  return 0;
3489 }
3490 
3491 int RtAudio :: getDefaultOutputDevice(void)
3492 {
3493  return 0;
3494 }
3495 
3496 void RtAudio :: probeDeviceInfo(RTAUDIO_DEVICE *info)
3497 {
3498  // Don't probe if a stream is already open.
3499  if ( streams.size() > 0 ) {
3500  sprintf(message, "RtAudio: unable to probe ASIO driver while a stream is open.");
3501  error(RtError::DEBUG_WARNING);
3502  return;
3503  }
3504 
3505  if ( !drivers.loadDriver( info->name ) ) {
3506  sprintf(message, "RtAudio: ASIO error loading driver (%s).", info->name);
3507  error(RtError::DEBUG_WARNING);
3508  return;
3509  }
3510 
3511  ASIOError result = ASIOInit( &driverInfo );
3512  if ( result != ASE_OK ) {
3513  char details[32];
3514  if ( result == ASE_HWMalfunction )
3515  sprintf(details, "hardware malfunction");
3516  else if ( result == ASE_NoMemory )
3517  sprintf(details, "no memory");
3518  else if ( result == ASE_NotPresent )
3519  sprintf(details, "driver/hardware not present");
3520  else
3521  sprintf(details, "unspecified");
3522  sprintf(message, "RtAudio: ASIO error (%s) initializing driver (%s).", details, info->name);
3523  error(RtError::DEBUG_WARNING);
3524  return;
3525  }
3526 
3527  // Determine the device channel information.
3528  long inputChannels, outputChannels;
3529  result = ASIOGetChannels( &inputChannels, &outputChannels );
3530  if ( result != ASE_OK ) {
3531  drivers.removeCurrentDriver();
3532  sprintf(message, "RtAudio: ASIO error getting input/output channel count (%s).", info->name);
3533  error(RtError::DEBUG_WARNING);
3534  return;
3535  }
3536 
3537  info->maxOutputChannels = outputChannels;
3538  if ( outputChannels > 0 ) info->minOutputChannels = 1;
3539 
3540  info->maxInputChannels = inputChannels;
3541  if ( inputChannels > 0 ) info->minInputChannels = 1;
3542 
3543  // If device opens for both playback and capture, we determine the channels.
3544  if (info->maxOutputChannels > 0 && info->maxInputChannels > 0) {
3545  info->hasDuplexSupport = true;
3546  info->maxDuplexChannels = (info->maxOutputChannels > info->maxInputChannels) ?
3547  info->maxInputChannels : info->maxOutputChannels;
3548  info->minDuplexChannels = (info->minOutputChannels > info->minInputChannels) ?
3549  info->minInputChannels : info->minOutputChannels;
3550  }
3551 
3552  // Determine the supported sample rates.
3553  info->nSampleRates = 0;
3554  for (int i=0; i<MAX_SAMPLE_RATES; i++) {
3555  result = ASIOCanSampleRate( (ASIOSampleRate) SAMPLE_RATES[i] );
3556  if ( result == ASE_OK )
3557  info->sampleRates[info->nSampleRates++] = SAMPLE_RATES[i];
3558  }
3559 
3560  if (info->nSampleRates == 0) {
3561  drivers.removeCurrentDriver();
3562  sprintf( message, "RtAudio: No supported sample rates found for ASIO driver (%s).", info->name );
3563  error(RtError::DEBUG_WARNING);
3564  return;
3565  }
3566 
3567  // Determine supported data types ... just check first channel and assume rest are the same.
3568  ASIOChannelInfo channelInfo;
3569  channelInfo.channel = 0;
3570  channelInfo.isInput = true;
3571  if ( info->maxInputChannels <= 0 ) channelInfo.isInput = false;
3572  result = ASIOGetChannelInfo( &channelInfo );
3573  if ( result != ASE_OK ) {
3574  drivers.removeCurrentDriver();
3575  sprintf(message, "RtAudio: ASIO error getting driver (%s) channel information.", info->name);
3576  error(RtError::DEBUG_WARNING);
3577  return;
3578  }
3579 
3580  if ( channelInfo.type == ASIOSTInt16MSB || channelInfo.type == ASIOSTInt16LSB )
3581  info->nativeFormats |= RTAUDIO_SINT16;
3582  else if ( channelInfo.type == ASIOSTInt32MSB || channelInfo.type == ASIOSTInt32LSB )
3583  info->nativeFormats |= RTAUDIO_SINT32;
3584  else if ( channelInfo.type == ASIOSTFloat32MSB || channelInfo.type == ASIOSTFloat32LSB )
3585  info->nativeFormats |= RTAUDIO_FLOAT32;
3586  else if ( channelInfo.type == ASIOSTFloat64MSB || channelInfo.type == ASIOSTFloat64LSB )
3587  info->nativeFormats |= RTAUDIO_FLOAT64;
3588 
3589  // Check that we have at least one supported format.
3590  if (info->nativeFormats == 0) {
3591  drivers.removeCurrentDriver();
3592  sprintf(message, "RtAudio: ASIO driver (%s) data format not supported by RtAudio.",
3593  info->name);
3594  error(RtError::DEBUG_WARNING);
3595  return;
3596  }
3597 
3598  info->probed = true;
3599  drivers.removeCurrentDriver();
3600 }
3601 
3602 void bufferSwitch(long index, ASIOBool processNow)
3603 {
3604  RtAudio *object = (RtAudio *) asioCallbackInfo->object;
3605  try {
3606  object->callbackEvent( asioCallbackInfo->streamId, index, (void *)NULL, (void *)NULL );
3607  }
3608  catch (RtError &exception) {
3609  fprintf(stderr, "\nCallback handler error (%s)!\n\n", exception.getMessage());
3610  return;
3611  }
3612 
3613  return;
3614 }
3615 
3616 void sampleRateChanged(ASIOSampleRate sRate)
3617 {
3618  // The ASIO documentation says that this usually only happens during
3619  // external sync. Audio processing is not stopped by the driver,
3620  // actual sample rate might not have even changed, maybe only the
3621  // sample rate status of an AES/EBU or S/PDIF digital input at the
3622  // audio device.
3623 
3624  RtAudio *object = (RtAudio *) asioCallbackInfo->object;
3625  try {
3626  object->stopStream( asioCallbackInfo->streamId );
3627  }
3628  catch (RtError &exception) {
3629  fprintf(stderr, "\nRtAudio: sampleRateChanged() error (%s)!\n\n", exception.getMessage());
3630  return;
3631  }
3632 
3633  fprintf(stderr, "\nRtAudio: ASIO driver reports sample rate changed to %d ... stream stopped!!!", (int) sRate);
3634 }
3635 
3636 long asioMessages(long selector, long value, void* message, double* opt)
3637 {
3638  long ret = 0;
3639  switch(selector) {
3640  case kAsioSelectorSupported:
3641  if(value == kAsioResetRequest
3642  || value == kAsioEngineVersion
3643  || value == kAsioResyncRequest
3644  || value == kAsioLatenciesChanged
3645  // The following three were added for ASIO 2.0, you don't
3646  // necessarily have to support them.
3647  || value == kAsioSupportsTimeInfo
3648  || value == kAsioSupportsTimeCode
3649  || value == kAsioSupportsInputMonitor)
3650  ret = 1L;
3651  break;
3652  case kAsioResetRequest:
3653  // Defer the task and perform the reset of the driver during the
3654  // next "safe" situation. You cannot reset the driver right now,
3655  // as this code is called from the driver. Reset the driver is
3656  // done by completely destruct is. I.e. ASIOStop(),
3657  // ASIODisposeBuffers(), Destruction Afterwards you initialize the
3658  // driver again.
3659  fprintf(stderr, "\nRtAudio: ASIO driver reset requested!!!");
3660  ret = 1L;
3661  break;
3662  case kAsioResyncRequest:
3663  // This informs the application that the driver encountered some
3664  // non-fatal data loss. It is used for synchronization purposes
3665  // of different media. Added mainly to work around the Win16Mutex
3666  // problems in Windows 95/98 with the Windows Multimedia system,
3667  // which could lose data because the Mutex was held too long by
3668  // another thread. However a driver can issue it in other
3669  // situations, too.
3670  fprintf(stderr, "\nRtAudio: ASIO driver resync requested!!!");
3671  ret = 1L;
3672  break;
3673  case kAsioLatenciesChanged:
3674  // This will inform the host application that the drivers were
3675  // latencies changed. Beware, it this does not mean that the
3676  // buffer sizes have changed! You might need to update internal
3677  // delay data.
3678  fprintf(stderr, "\nRtAudio: ASIO driver latency may have changed!!!");
3679  ret = 1L;
3680  break;
3681  case kAsioEngineVersion:
3682  // Return the supported ASIO version of the host application. If
3683  // a host application does not implement this selector, ASIO 1.0
3684  // is assumed by the driver.
3685  ret = 2L;
3686  break;
3687  case kAsioSupportsTimeInfo:
3688  // Informs the driver whether the
3689  // asioCallbacks.bufferSwitchTimeInfo() callback is supported.
3690  // For compatibility with ASIO 1.0 drivers the host application
3691  // should always support the "old" bufferSwitch method, too.
3692  ret = 0;
3693  break;
3694  case kAsioSupportsTimeCode:
3695  // Informs the driver wether application is interested in time
3696  // code info. If an application does not need to know about time
3697  // code, the driver has less work to do.
3698  ret = 0;
3699  break;
3700  }
3701  return ret;
3702 }
3703 
3704 bool RtAudio :: probeDeviceOpen(int device, RTAUDIO_STREAM *stream,
3705  STREAM_MODE mode, int channels,
3706  int sampleRate, RTAUDIO_FORMAT format,
3707  int *bufferSize, int numberOfBuffers)
3708 {
3709  // Don't attempt to load another driver if a stream is already open.
3710  if ( streams.size() > 0 ) {
3711  sprintf(message, "RtAudio: unable to load ASIO driver while a stream is open.");
3712  error(RtError::WARNING);
3713  return FAILURE;
3714  }
3715 
3716  // For ASIO, a duplex stream MUST use the same driver.
3717  if ( mode == INPUT && stream->mode == OUTPUT && stream->device[0] != device ) {
3718  sprintf(message, "RtAudio: ASIO duplex stream must use the same device for input and output.");
3719  error(RtError::WARNING);
3720  return FAILURE;
3721  }
3722 
3723  // Only load the driver once for duplex stream.
3724  ASIOError result;
3725  if ( mode != INPUT || stream->mode != OUTPUT ) {
3726  if ( !drivers.loadDriver( devices[device].name ) ) {
3727  sprintf(message, "RtAudio: ASIO error loading driver (%s).", devices[device].name);
3728  error(RtError::DEBUG_WARNING);
3729  return FAILURE;
3730  }
3731 
3732  result = ASIOInit( &driverInfo );
3733  if ( result != ASE_OK ) {
3734  char details[32];
3735  if ( result == ASE_HWMalfunction )
3736  sprintf(details, "hardware malfunction");
3737  else if ( result == ASE_NoMemory )
3738  sprintf(details, "no memory");
3739  else if ( result == ASE_NotPresent )
3740  sprintf(details, "driver/hardware not present");
3741  else
3742  sprintf(details, "unspecified");
3743  sprintf(message, "RtAudio: ASIO error (%s) initializing driver (%s).", details, devices[device].name);
3744  error(RtError::DEBUG_WARNING);
3745  return FAILURE;
3746  }
3747  }
3748 
3749  // Check the device channel count.
3750  long inputChannels, outputChannels;
3751  result = ASIOGetChannels( &inputChannels, &outputChannels );
3752  if ( result != ASE_OK ) {
3753  drivers.removeCurrentDriver();
3754  sprintf(message, "RtAudio: ASIO error getting input/output channel count (%s).",
3755  devices[device].name);
3756  error(RtError::DEBUG_WARNING);
3757  return FAILURE;
3758  }
3759 
3760  if ( ( mode == OUTPUT && channels > outputChannels) ||
3761  ( mode == INPUT && channels > inputChannels) ) {
3762  drivers.removeCurrentDriver();
3763  sprintf(message, "RtAudio: ASIO driver (%s) does not support requested channel count (%d).",
3764  devices[device].name, channels);
3765  error(RtError::DEBUG_WARNING);
3766  return FAILURE;
3767  }
3768  stream->nDeviceChannels[mode] = channels;
3769  stream->nUserChannels[mode] = channels;
3770 
3771  // Verify the sample rate is supported.
3772  result = ASIOCanSampleRate( (ASIOSampleRate) sampleRate );
3773  if ( result != ASE_OK ) {
3774  drivers.removeCurrentDriver();
3775  sprintf(message, "RtAudio: ASIO driver (%s) does not support requested sample rate (%d).",
3776  devices[device].name, sampleRate);
3777  error(RtError::DEBUG_WARNING);
3778  return FAILURE;
3779  }
3780 
3781  // Set the sample rate.
3782  result = ASIOSetSampleRate( (ASIOSampleRate) sampleRate );
3783  if ( result != ASE_OK ) {
3784  drivers.removeCurrentDriver();
3785  sprintf(message, "RtAudio: ASIO driver (%s) error setting sample rate (%d).",
3786  devices[device].name, sampleRate);
3787  error(RtError::DEBUG_WARNING);
3788  return FAILURE;
3789  }
3790 
3791  // Determine the driver data type.
3792  ASIOChannelInfo channelInfo;
3793  channelInfo.channel = 0;
3794  if ( mode == OUTPUT ) channelInfo.isInput = false;
3795  else channelInfo.isInput = true;
3796  result = ASIOGetChannelInfo( &channelInfo );
3797  if ( result != ASE_OK ) {
3798  drivers.removeCurrentDriver();
3799  sprintf(message, "RtAudio: ASIO driver (%s) error getting data format.",
3800  devices[device].name);
3801  error(RtError::DEBUG_WARNING);
3802  return FAILURE;
3803  }
3804 
3805  // Assuming WINDOWS host is always little-endian.
3806  stream->doByteSwap[mode] = false;
3807  stream->userFormat = format;
3808  stream->deviceFormat[mode] = 0;
3809  if ( channelInfo.type == ASIOSTInt16MSB || channelInfo.type == ASIOSTInt16LSB ) {
3810  stream->deviceFormat[mode] = RTAUDIO_SINT16;
3811  if ( channelInfo.type == ASIOSTInt16MSB ) stream->doByteSwap[mode] = true;
3812  }
3813  else if ( channelInfo.type == ASIOSTInt32MSB || channelInfo.type == ASIOSTInt32LSB ) {
3814  stream->deviceFormat[mode] = RTAUDIO_SINT32;
3815  if ( channelInfo.type == ASIOSTInt32MSB ) stream->doByteSwap[mode] = true;
3816  }
3817  else if ( channelInfo.type == ASIOSTFloat32MSB || channelInfo.type == ASIOSTFloat32LSB ) {
3818  stream->deviceFormat[mode] = RTAUDIO_FLOAT32;
3819  if ( channelInfo.type == ASIOSTFloat32MSB ) stream->doByteSwap[mode] = true;
3820  }
3821  else if ( channelInfo.type == ASIOSTFloat64MSB || channelInfo.type == ASIOSTFloat64LSB ) {
3822  stream->deviceFormat[mode] = RTAUDIO_FLOAT64;
3823  if ( channelInfo.type == ASIOSTFloat64MSB ) stream->doByteSwap[mode] = true;
3824  }
3825 
3826  if ( stream->deviceFormat[mode] == 0 ) {
3827  drivers.removeCurrentDriver();
3828  sprintf(message, "RtAudio: ASIO driver (%s) data format not supported by RtAudio.",
3829  devices[device].name);
3830  error(RtError::DEBUG_WARNING);
3831  return FAILURE;
3832  }
3833 
3834  // Set the buffer size. For a duplex stream, this will end up
3835  // setting the buffer size based on the input constraints, which
3836  // should be ok.
3837  long minSize, maxSize, preferSize, granularity;
3838  result = ASIOGetBufferSize( &minSize, &maxSize, &preferSize, &granularity );
3839  if ( result != ASE_OK ) {
3840  drivers.removeCurrentDriver();
3841  sprintf(message, "RtAudio: ASIO driver (%s) error getting buffer size.",
3842  devices[device].name);
3843  error(RtError::DEBUG_WARNING);
3844  return FAILURE;
3845  }
3846 
3847  if ( *bufferSize < minSize ) *bufferSize = minSize;
3848  else if ( *bufferSize > maxSize ) *bufferSize = maxSize;
3849  else if ( granularity == -1 ) {
3850  // Make sure bufferSize is a power of two.
3851  double power = log10( *bufferSize ) / log10( 2.0 );
3852  *bufferSize = pow( 2.0, floor(power+0.5) );
3853  if ( *bufferSize < minSize ) *bufferSize = minSize;
3854  else if ( *bufferSize > maxSize ) *bufferSize = maxSize;
3855  else *bufferSize = preferSize;
3856  }
3857 
3858  if ( mode == INPUT && stream->mode == OUTPUT && stream->bufferSize != *bufferSize )
3859  cout << "possible input/output buffersize discrepancy" << endl;
3860 
3861  stream->bufferSize = *bufferSize;
3862  stream->nBuffers = 2;
3863 
3864  // ASIO always uses deinterleaved channels.
3865  stream->deInterleave[mode] = true;
3866 
3867  // Create the ASIO internal buffers. Since RtAudio sets up input
3868  // and output separately, we'll have to dispose of previously
3869  // created output buffers for a duplex stream.
3870  if ( mode == INPUT && stream->mode == OUTPUT ) {
3871  free(stream->callbackInfo.buffers);
3872  result = ASIODisposeBuffers();
3873  if ( result != ASE_OK ) {
3874  drivers.removeCurrentDriver();
3875  sprintf(message, "RtAudio: ASIO driver (%s) error disposing previously allocated buffers.",
3876  devices[device].name);
3877  error(RtError::DEBUG_WARNING);
3878  return FAILURE;
3879  }
3880  }
3881 
3882  // Allocate, initialize, and save the bufferInfos in our stream callbackInfo structure.
3883  int i, nChannels = stream->nDeviceChannels[0] + stream->nDeviceChannels[1];
3884  stream->callbackInfo.buffers = 0;
3885  ASIOBufferInfo *bufferInfos = (ASIOBufferInfo *) malloc( nChannels * sizeof(ASIOBufferInfo) );
3886  stream->callbackInfo.buffers = (void *) bufferInfos;
3887  ASIOBufferInfo *infos = bufferInfos;
3888  for ( i=0; i<stream->nDeviceChannels[1]; i++, infos++ ) {
3889  infos->isInput = ASIOTrue;
3890  infos->channelNum = i;
3891  infos->buffers[0] = infos->buffers[1] = 0;
3892  }
3893 
3894  for ( i=0; i<stream->nDeviceChannels[0]; i++, infos++ ) {
3895  infos->isInput = ASIOFalse;
3896  infos->channelNum = i;
3897  infos->buffers[0] = infos->buffers[1] = 0;
3898  }
3899 
3900  // Set up the ASIO callback structure and create the ASIO data buffers.
3901  asioCallbacks.bufferSwitch = &bufferSwitch;
3902  asioCallbacks.sampleRateDidChange = &sampleRateChanged;
3903  asioCallbacks.asioMessage = &asioMessages;
3904  asioCallbacks.bufferSwitchTimeInfo = NULL;
3905  result = ASIOCreateBuffers( bufferInfos, nChannels, stream->bufferSize, &asioCallbacks);
3906  if ( result != ASE_OK ) {
3907  drivers.removeCurrentDriver();
3908  sprintf(message, "RtAudio: ASIO driver (%s) error creating buffers.",
3909  devices[device].name);
3910  error(RtError::DEBUG_WARNING);
3911  return FAILURE;
3912  }
3913 
3914  // Set flags for buffer conversion.
3915  stream->doConvertBuffer[mode] = false;
3916  if (stream->userFormat != stream->deviceFormat[mode])
3917  stream->doConvertBuffer[mode] = true;
3918  if (stream->nUserChannels[mode] < stream->nDeviceChannels[mode])
3919  stream->doConvertBuffer[mode] = true;
3920  if (stream->nUserChannels[mode] > 1 && stream->deInterleave[mode])
3921  stream->doConvertBuffer[mode] = true;
3922 
3923  // Allocate necessary internal buffers
3924  if ( stream->nUserChannels[0] != stream->nUserChannels[1] ) {
3925 
3926  long buffer_bytes;
3927  if (stream->nUserChannels[0] >= stream->nUserChannels[1])
3928  buffer_bytes = stream->nUserChannels[0];
3929  else
3930  buffer_bytes = stream->nUserChannels[1];
3931 
3932  buffer_bytes *= *bufferSize * formatBytes(stream->userFormat);
3933  if (stream->userBuffer) free(stream->userBuffer);
3934  stream->userBuffer = (char *) calloc(buffer_bytes, 1);
3935  if (stream->userBuffer == NULL)
3936  goto memory_error;
3937  }
3938 
3939  if ( stream->doConvertBuffer[mode] ) {
3940 
3941  long buffer_bytes;
3942  bool makeBuffer = true;
3943  if ( mode == OUTPUT )
3944  buffer_bytes = stream->nDeviceChannels[0] * formatBytes(stream->deviceFormat[0]);
3945  else { // mode == INPUT
3946  buffer_bytes = stream->nDeviceChannels[1] * formatBytes(stream->deviceFormat[1]);
3947  if ( stream->mode == OUTPUT && stream->deviceBuffer ) {
3948  long bytes_out = stream->nDeviceChannels[0] * formatBytes(stream->deviceFormat[0]);
3949  if ( buffer_bytes < bytes_out ) makeBuffer = false;
3950  }
3951  }
3952 
3953  if ( makeBuffer ) {
3954  buffer_bytes *= *bufferSize;
3955  if (stream->deviceBuffer) free(stream->deviceBuffer);
3956  stream->deviceBuffer = (char *) calloc(buffer_bytes, 1);
3957  if (stream->deviceBuffer == NULL)
3958  goto memory_error;
3959  }
3960  }
3961 
3962  stream->device[mode] = device;
3963  stream->state = STREAM_STOPPED;
3964  if ( stream->mode == OUTPUT && mode == INPUT )
3965  // We had already set up an output stream.
3966  stream->mode = DUPLEX;
3967  else
3968  stream->mode = mode;
3969  stream->sampleRate = sampleRate;
3970  asioCallbackInfo = &stream->callbackInfo;
3971  stream->callbackInfo.object = (void *) this;
3972  stream->callbackInfo.waitTime = (unsigned long) (200.0 * stream->bufferSize / stream->sampleRate);
3973 
3974  return SUCCESS;
3975 
3976  memory_error:
3977  ASIODisposeBuffers();
3978  drivers.removeCurrentDriver();
3979 
3980  if (stream->callbackInfo.buffers)
3981  free(stream->callbackInfo.buffers);
3982  stream->callbackInfo.buffers = 0;
3983 
3984  if (stream->userBuffer) {
3985  free(stream->userBuffer);
3986  stream->userBuffer = 0;
3987  }
3988  sprintf(message, "RtAudio: error allocating buffer memory (%s).",
3989  devices[device].name);
3990  error(RtError::WARNING);
3991  return FAILURE;
3992 }
3993 
3994 void RtAudio :: cancelStreamCallback(int streamId)
3995 {
3996  RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
3997 
3998  if (stream->callbackInfo.usingCallback) {
3999 
4000  if (stream->state == STREAM_RUNNING)
4001  stopStream( streamId );
4002 
4003  MUTEX_LOCK(&stream->mutex);
4004 
4005  stream->callbackInfo.usingCallback = false;
4006  stream->callbackInfo.userData = NULL;
4007  stream->state = STREAM_STOPPED;
4008  stream->callbackInfo.callback = NULL;
4009 
4010  MUTEX_UNLOCK(&stream->mutex);
4011  }
4012 }
4013 
4014 void RtAudio :: closeStream(int streamId)
4015 {
4016  // We don't want an exception to be thrown here because this
4017  // function is called by our class destructor. So, do our own
4018  // streamId check.
4019  if ( streams.find( streamId ) == streams.end() ) {
4020  sprintf(message, "RtAudio: invalid stream identifier!");
4021  error(RtError::WARNING);
4022  return;
4023  }
4024 
4025  RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) streams[streamId];
4026 
4027  if (stream->state == STREAM_RUNNING)
4028  ASIOStop();
4029 
4030  ASIODisposeBuffers();
4031  //ASIOExit();
4032  drivers.removeCurrentDriver();
4033 
4034  DeleteCriticalSection(&stream->mutex);
4035 
4036  if (stream->callbackInfo.buffers)
4037  free(stream->callbackInfo.buffers);
4038 
4039  if (stream->userBuffer)
4040  free(stream->userBuffer);
4041 
4042  if (stream->deviceBuffer)
4043  free(stream->deviceBuffer);
4044 
4045  free(stream);
4046  streams.erase(streamId);
4047 }
4048 
4049 void RtAudio :: startStream(int streamId)
4050 {
4051  RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
4052 
4053  MUTEX_LOCK(&stream->mutex);
4054 
4055  if (stream->state == STREAM_RUNNING) {
4056  MUTEX_UNLOCK(&stream->mutex);
4057  return;
4058  }
4059 
4060  stream->callbackInfo.blockTick = true;
4061  stream->callbackInfo.stopStream = false;
4062  stream->callbackInfo.streamId = streamId;
4063  ASIOError result = ASIOStart();
4064  if ( result != ASE_OK ) {
4065  sprintf(message, "RtAudio: ASIO error starting device (%s).",
4066  devices[stream->device[0]].name);
4067  MUTEX_UNLOCK(&stream->mutex);
4068  error(RtError::DRIVER_ERROR);
4069  }
4070  stream->state = STREAM_RUNNING;
4071 
4072  MUTEX_UNLOCK(&stream->mutex);
4073 }
4074 
4075 void RtAudio :: stopStream(int streamId)
4076 {
4077  RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
4078 
4079  MUTEX_LOCK(&stream->mutex);
4080 
4081  if (stream->state == STREAM_STOPPED) {
4082  MUTEX_UNLOCK(&stream->mutex);
4083  return;
4084  }
4085 
4086  ASIOError result = ASIOStop();
4087  if ( result != ASE_OK ) {
4088  sprintf(message, "RtAudio: ASIO error stopping device (%s).",
4089  devices[stream->device[0]].name);
4090  MUTEX_UNLOCK(&stream->mutex);
4091  error(RtError::DRIVER_ERROR);
4092  }
4093  stream->state = STREAM_STOPPED;
4094 
4095  MUTEX_UNLOCK(&stream->mutex);
4096 }
4097 
4098 void RtAudio :: abortStream(int streamId)
4099 {
4100  stopStream( streamId );
4101 }
4102 
4103 // I don't know how this function can be implemented.
4104 int RtAudio :: streamWillBlock(int streamId)
4105 {
4106  sprintf(message, "RtAudio: streamWillBlock() cannot be implemented for ASIO.");
4107  error(RtError::WARNING);
4108  return 0;
4109 }
4110 
4111 void RtAudio :: tickStream(int streamId)
4112 {
4113  RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
4114 
4115  if (stream->state == STREAM_STOPPED)
4116  return;
4117 
4118  if (stream->callbackInfo.usingCallback) {
4119  sprintf(message, "RtAudio: tickStream() should not be used when a callback function is set!");
4120  error(RtError::WARNING);
4121  return;
4122  }
4123 
4124  // Block waiting here until the user data is processed in callbackEvent().
4125  while ( stream->callbackInfo.blockTick )
4126  Sleep(stream->callbackInfo.waitTime);
4127 
4128  MUTEX_LOCK(&stream->mutex);
4129 
4130  stream->callbackInfo.blockTick = true;
4131 
4132  MUTEX_UNLOCK(&stream->mutex);
4133 }
4134 
4135 void RtAudio :: callbackEvent(int streamId, int bufferIndex, void *inData, void *outData)
4136 {
4137  RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
4138 
4139  CALLBACK_INFO *info = asioCallbackInfo;
4140  if ( !info->usingCallback ) {
4141  // Block waiting here until we get new user data in tickStream().
4142  while ( !info->blockTick )
4143  Sleep(info->waitTime);
4144  }
4145  else if ( info->stopStream ) {
4146  // Check if the stream should be stopped (via the previous user
4147  // callback return value). We stop the stream here, rather than
4148  // after the function call, so that output data can first be
4149  // processed.
4150  this->stopStream(asioCallbackInfo->streamId);
4151  return;
4152  }
4153 
4154  MUTEX_LOCK(&stream->mutex);
4155 
4156  // Invoke user callback first, to get fresh output data.
4157  if ( info->usingCallback ) {
4158  RTAUDIO_CALLBACK callback = (RTAUDIO_CALLBACK) info->callback;
4159  if ( callback(stream->userBuffer, stream->bufferSize, info->userData) )
4160  info->stopStream = true;
4161  }
4162 
4163  int nChannels = stream->nDeviceChannels[0] + stream->nDeviceChannels[1];
4164  int bufferBytes;
4165  ASIOBufferInfo *bufferInfos = (ASIOBufferInfo *) info->buffers;
4166  if ( stream->mode == OUTPUT || stream->mode == DUPLEX ) {
4167 
4168  bufferBytes = stream->bufferSize * formatBytes(stream->deviceFormat[0]);
4169  if (stream->doConvertBuffer[0]) {
4170 
4171  convertStreamBuffer(stream, OUTPUT);
4172  if ( stream->doByteSwap[0] )
4173  byteSwapBuffer(stream->deviceBuffer,
4174  stream->bufferSize * stream->nDeviceChannels[0],
4175  stream->deviceFormat[0]);
4176 
4177  // Always de-interleave ASIO output data.
4178  for ( int i=0; i<stream->nDeviceChannels[0]; i++, bufferInfos++ ) {
4179  memcpy(bufferInfos->buffers[bufferIndex],
4180  &stream->deviceBuffer[i*bufferBytes], bufferBytes );
4181  }
4182  }
4183  else { // single channel only
4184 
4185  if (stream->doByteSwap[0])
4186  byteSwapBuffer(stream->userBuffer,
4187  stream->bufferSize * stream->nUserChannels[0],
4188  stream->userFormat);
4189 
4190  memcpy(bufferInfos->buffers[bufferIndex], stream->userBuffer, bufferBytes );
4191  }
4192  }
4193 
4194  if ( stream->mode == INPUT || stream->mode == DUPLEX ) {
4195 
4196  bufferBytes = stream->bufferSize * formatBytes(stream->deviceFormat[1]);
4197  if (stream->doConvertBuffer[1]) {
4198 
4199  // Always interleave ASIO input data.
4200  for ( int i=0; i<stream->nDeviceChannels[1]; i++, bufferInfos++ )
4201  memcpy(&stream->deviceBuffer[i*bufferBytes], bufferInfos->buffers[bufferIndex], bufferBytes );
4202 
4203  if ( stream->doByteSwap[1] )
4204  byteSwapBuffer(stream->deviceBuffer,
4205  stream->bufferSize * stream->nDeviceChannels[1],
4206  stream->deviceFormat[1]);
4207  convertStreamBuffer(stream, INPUT);
4208 
4209  }
4210  else { // single channel only
4211  memcpy(stream->userBuffer, bufferInfos->buffers[bufferIndex], bufferBytes );
4212 
4213  if (stream->doByteSwap[1])
4214  byteSwapBuffer(stream->userBuffer,
4215  stream->bufferSize * stream->nUserChannels[1],
4216  stream->userFormat);
4217  }
4218  }
4219 
4220  if ( !info->usingCallback )
4221  info->blockTick = false;
4222 
4223  MUTEX_UNLOCK(&stream->mutex);
4224 }
4225 
4226 void RtAudio :: setStreamCallback(int streamId, RTAUDIO_CALLBACK callback, void *userData)
4227 {
4228  RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
4229 
4230  stream->callbackInfo.callback = (void *) callback;
4231  stream->callbackInfo.userData = userData;
4232  stream->callbackInfo.usingCallback = true;
4233 }
4234 
4235 //******************** End of __WINDOWS_ASIO__ *********************//
4236 
4237 #elif defined(__WINDOWS_DS__) // Windows DirectSound API
4238 
4239 #include <dsound.h>
4240 
4241 // Declarations for utility functions, callbacks, and structures
4242 // specific to the DirectSound implementation.
4243 static bool CALLBACK deviceCountCallback(LPGUID lpguid,
4244  LPCSTR lpcstrDescription,
4245  LPCSTR lpcstrModule,
4246  LPVOID lpContext);
4247 
4248 static bool CALLBACK deviceInfoCallback(LPGUID lpguid,
4249  LPCSTR lpcstrDescription,
4250  LPCSTR lpcstrModule,
4251  LPVOID lpContext);
4252 
4253 static bool CALLBACK defaultDeviceCallback(LPGUID lpguid,
4254  LPCSTR lpcstrDescription,
4255  LPCSTR lpcstrModule,
4256  LPVOID lpContext);
4257 
4258 static bool CALLBACK deviceIdCallback(LPGUID lpguid,
4259  LPCSTR lpcstrDescription,
4260  LPCSTR lpcstrModule,
4261  LPVOID lpContext);
4262 
4263 static char* getErrorString(int code);
4264 
4265 struct enum_info {
4266  char name[64];
4267  LPGUID id;
4268  bool isInput;
4269  bool isValid;
4270 };
4271 
4272 int RtAudio :: getDefaultInputDevice(void)
4273 {
4274  enum_info info;
4275  info.name[0] = '\0';
4276 
4277  // Enumerate through devices to find the default output.
4278  HRESULT result = DirectSoundCaptureEnumerate((LPDSENUMCALLBACK)defaultDeviceCallback, &info);
4279  if ( FAILED(result) ) {
4280  sprintf(message, "RtAudio: Error performing default input device enumeration: %s.",
4281  getErrorString(result));
4282  error(RtError::WARNING);
4283  return 0;
4284  }
4285 
4286  for ( int i=0; i<nDevices; i++ )
4287  if ( strncmp( devices[i].name, info.name, 64 ) == 0 ) return i;
4288 
4289  return 0;
4290 }
4291 
4292 int RtAudio :: getDefaultOutputDevice(void)
4293 {
4294  enum_info info;
4295  info.name[0] = '\0';
4296 
4297  // Enumerate through devices to find the default output.
4298  HRESULT result = DirectSoundEnumerate((LPDSENUMCALLBACK)defaultDeviceCallback, &info);
4299  if ( FAILED(result) ) {
4300  sprintf(message, "RtAudio: Error performing default output device enumeration: %s.",
4301  getErrorString(result));
4302  error(RtError::WARNING);
4303  return 0;
4304  }
4305 
4306  for ( int i=0; i<nDevices; i++ )
4307  if ( strncmp(devices[i].name, info.name, 64 ) == 0 ) return i;
4308 
4309  return 0;
4310 }
4311 
4312 void RtAudio :: initialize(void)
4313 {
4314  int i, ins = 0, outs = 0, count = 0;
4315  HRESULT result;
4316  nDevices = 0;
4317 
4318  // Count DirectSound devices.
4319  result = DirectSoundEnumerate((LPDSENUMCALLBACK)deviceCountCallback, &outs);
4320  if ( FAILED(result) ) {
4321  sprintf(message, "RtAudio: Unable to enumerate through sound playback devices: %s.",
4322  getErrorString(result));
4323  error(RtError::DRIVER_ERROR);
4324  }
4325 
4326  // Count DirectSoundCapture devices.
4327  result = DirectSoundCaptureEnumerate((LPDSENUMCALLBACK)deviceCountCallback, &ins);
4328  if ( FAILED(result) ) {
4329  sprintf(message, "RtAudio: Unable to enumerate through sound capture devices: %s.",
4330  getErrorString(result));
4331  error(RtError::DRIVER_ERROR);
4332  }
4333 
4334  count = ins + outs;
4335  if (count == 0) return;
4336 
4337  std::vector<enum_info> info(count);
4338  for (i=0; i<count; i++) {
4339  info[i].name[0] = '\0';
4340  if (i < outs) info[i].isInput = false;
4341  else info[i].isInput = true;
4342  }
4343 
4344  // Get playback device info and check capabilities.
4345  result = DirectSoundEnumerate((LPDSENUMCALLBACK)deviceInfoCallback, &info[0]);
4346  if ( FAILED(result) ) {
4347  sprintf(message, "RtAudio: Unable to enumerate through sound playback devices: %s.",
4348  getErrorString(result));
4349  error(RtError::DRIVER_ERROR);
4350  }
4351 
4352  // Get capture device info and check capabilities.
4353  result = DirectSoundCaptureEnumerate((LPDSENUMCALLBACK)deviceInfoCallback, &info[0]);
4354  if ( FAILED(result) ) {
4355  sprintf(message, "RtAudio: Unable to enumerate through sound capture devices: %s.",
4356  getErrorString(result));
4357  error(RtError::DRIVER_ERROR);
4358  }
4359 
4360  // Parse the devices and check validity. Devices are considered
4361  // invalid if they cannot be opened, they report < 1 supported
4362  // channels, or they report no supported data (capture only).
4363  for (i=0; i<count; i++)
4364  if ( info[i].isValid ) nDevices++;
4365 
4366  if (nDevices == 0) return;
4367 
4368  // Allocate the RTAUDIO_DEVICE structures.
4369  devices = (RTAUDIO_DEVICE *) calloc(nDevices, sizeof(RTAUDIO_DEVICE));
4370  if (devices == NULL) {
4371  sprintf(message, "RtAudio: memory allocation error!");
4372  error(RtError::MEMORY_ERROR);
4373  }
4374 
4375  // Copy the names to our devices structures.
4376  int index = 0;
4377  for (i=0; i<count; i++) {
4378  if ( info[i].isValid )
4379  strncpy(devices[index++].name, info[i].name, 64);
4380  }
4381 
4382  //for (i=0;i<nDevices; i++)
4383  //probeDeviceInfo(&devices[i]);
4384 
4385  return;
4386 }
4387 
4388 void RtAudio :: probeDeviceInfo(RTAUDIO_DEVICE *info)
4389 {
4390  enum_info dsinfo;
4391  strncpy( dsinfo.name, info->name, 64 );
4392  dsinfo.isValid = false;
4393 
4394  // Enumerate through input devices to find the id (if it exists).
4395  HRESULT result = DirectSoundCaptureEnumerate((LPDSENUMCALLBACK)deviceIdCallback, &dsinfo);
4396  if ( FAILED(result) ) {
4397  sprintf(message, "RtAudio: Error performing input device id enumeration: %s.",
4398  getErrorString(result));
4399  error(RtError::WARNING);
4400  return;
4401  }
4402 
4403  // Do capture probe first.
4404  if ( dsinfo.isValid == false )
4405  goto playback_probe;
4406 
4407  LPDIRECTSOUNDCAPTURE input;
4408  result = DirectSoundCaptureCreate( dsinfo.id, &input, NULL );
4409  if ( FAILED(result) ) {
4410  sprintf(message, "RtAudio: Could not create DirectSound capture object (%s): %s.",
4411  info->name, getErrorString(result));
4412  error(RtError::WARNING);
4413  goto playback_probe;
4414  }
4415 
4416  DSCCAPS in_caps;
4417  in_caps.dwSize = sizeof(in_caps);
4418  result = input->GetCaps( &in_caps );
4419  if ( FAILED(result) ) {
4420  input->Release();
4421  sprintf(message, "RtAudio: Could not get DirectSound capture capabilities (%s): %s.",
4422  info->name, getErrorString(result));
4423  error(RtError::WARNING);
4424  goto playback_probe;
4425  }
4426 
4427  // Get input channel information.
4428  info->minInputChannels = 1;
4429  info->maxInputChannels = in_caps.dwChannels;
4430 
4431  // Get sample rate and format information.
4432  if( in_caps.dwChannels == 2 ) {
4433  if( in_caps.dwFormats & WAVE_FORMAT_1S16 ) info->nativeFormats |= RTAUDIO_SINT16;
4434  if( in_caps.dwFormats & WAVE_FORMAT_2S16 ) info->nativeFormats |= RTAUDIO_SINT16;
4435  if( in_caps.dwFormats & WAVE_FORMAT_4S16 ) info->nativeFormats |= RTAUDIO_SINT16;
4436  if( in_caps.dwFormats & WAVE_FORMAT_1S08 ) info->nativeFormats |= RTAUDIO_SINT8;
4437  if( in_caps.dwFormats & WAVE_FORMAT_2S08 ) info->nativeFormats |= RTAUDIO_SINT8;
4438  if( in_caps.dwFormats & WAVE_FORMAT_4S08 ) info->nativeFormats |= RTAUDIO_SINT8;
4439 
4440  if ( info->nativeFormats & RTAUDIO_SINT16 ) {
4441  if( in_caps.dwFormats & WAVE_FORMAT_1S16 ) info->sampleRates[info->nSampleRates++] = 11025;
4442  if( in_caps.dwFormats & WAVE_FORMAT_2S16 ) info->sampleRates[info->nSampleRates++] = 22050;
4443  if( in_caps.dwFormats & WAVE_FORMAT_4S16 ) info->sampleRates[info->nSampleRates++] = 44100;
4444  }
4445  else if ( info->nativeFormats & RTAUDIO_SINT8 ) {
4446  if( in_caps.dwFormats & WAVE_FORMAT_1S08 ) info->sampleRates[info->nSampleRates++] = 11025;
4447  if( in_caps.dwFormats & WAVE_FORMAT_2S08 ) info->sampleRates[info->nSampleRates++] = 22050;
4448  if( in_caps.dwFormats & WAVE_FORMAT_4S08 ) info->sampleRates[info->nSampleRates++] = 44100;
4449  }
4450  }
4451  else if ( in_caps.dwChannels == 1 ) {
4452  if( in_caps.dwFormats & WAVE_FORMAT_1M16 ) info->nativeFormats |= RTAUDIO_SINT16;
4453  if( in_caps.dwFormats & WAVE_FORMAT_2M16 ) info->nativeFormats |= RTAUDIO_SINT16;
4454  if( in_caps.dwFormats & WAVE_FORMAT_4M16 ) info->nativeFormats |= RTAUDIO_SINT16;
4455  if( in_caps.dwFormats & WAVE_FORMAT_1M08 ) info->nativeFormats |= RTAUDIO_SINT8;
4456  if( in_caps.dwFormats & WAVE_FORMAT_2M08 ) info->nativeFormats |= RTAUDIO_SINT8;
4457  if( in_caps.dwFormats & WAVE_FORMAT_4M08 ) info->nativeFormats |= RTAUDIO_SINT8;
4458 
4459  if ( info->nativeFormats & RTAUDIO_SINT16 ) {
4460  if( in_caps.dwFormats & WAVE_FORMAT_1M16 ) info->sampleRates[info->nSampleRates++] = 11025;
4461  if( in_caps.dwFormats & WAVE_FORMAT_2M16 ) info->sampleRates[info->nSampleRates++] = 22050;
4462  if( in_caps.dwFormats & WAVE_FORMAT_4M16 ) info->sampleRates[info->nSampleRates++] = 44100;
4463  }
4464  else if ( info->nativeFormats & RTAUDIO_SINT8 ) {
4465  if( in_caps.dwFormats & WAVE_FORMAT_1M08 ) info->sampleRates[info->nSampleRates++] = 11025;
4466  if( in_caps.dwFormats & WAVE_FORMAT_2M08 ) info->sampleRates[info->nSampleRates++] = 22050;
4467  if( in_caps.dwFormats & WAVE_FORMAT_4M08 ) info->sampleRates[info->nSampleRates++] = 44100;
4468  }
4469  }
4470  else info->minInputChannels = 0; // technically, this would be an error
4471 
4472  input->Release();
4473 
4474  playback_probe:
4475 
4476  dsinfo.isValid = false;
4477 
4478  // Enumerate through output devices to find the id (if it exists).
4479  result = DirectSoundEnumerate((LPDSENUMCALLBACK)deviceIdCallback, &dsinfo);
4480  if ( FAILED(result) ) {
4481  sprintf(message, "RtAudio: Error performing output device id enumeration: %s.",
4482  getErrorString(result));
4483  error(RtError::WARNING);
4484  return;
4485  }
4486 
4487  // Now do playback probe.
4488  if ( dsinfo.isValid == false )
4489  goto check_parameters;
4490 
4491  LPDIRECTSOUND output;
4492  DSCAPS out_caps;
4493  result = DirectSoundCreate( dsinfo.id, &output, NULL );
4494  if ( FAILED(result) ) {
4495  sprintf(message, "RtAudio: Could not create DirectSound playback object (%s): %s.",
4496  info->name, getErrorString(result));
4497  error(RtError::WARNING);
4498  goto check_parameters;
4499  }
4500 
4501  out_caps.dwSize = sizeof(out_caps);
4502  result = output->GetCaps( &out_caps );
4503  if ( FAILED(result) ) {
4504  output->Release();
4505  sprintf(message, "RtAudio: Could not get DirectSound playback capabilities (%s): %s.",
4506  info->name, getErrorString(result));
4507  error(RtError::WARNING);
4508  goto check_parameters;
4509  }
4510 
4511  // Get output channel information.
4512  info->minOutputChannels = 1;
4513  info->maxOutputChannels = ( out_caps.dwFlags & DSCAPS_PRIMARYSTEREO ) ? 2 : 1;
4514 
4515  // Get sample rate information. Use capture device rate information
4516  // if it exists.
4517  if ( info->nSampleRates == 0 ) {
4518  info->sampleRates[0] = (int) out_caps.dwMinSecondarySampleRate;
4519  info->sampleRates[1] = (int) out_caps.dwMaxSecondarySampleRate;
4520  if ( out_caps.dwFlags & DSCAPS_CONTINUOUSRATE )
4521  info->nSampleRates = -1;
4522  else if ( out_caps.dwMinSecondarySampleRate == out_caps.dwMaxSecondarySampleRate ) {
4523  if ( out_caps.dwMinSecondarySampleRate == 0 ) {
4524  // This is a bogus driver report ... fake the range and cross
4525  // your fingers.
4526  info->sampleRates[0] = 11025;
4527  info->sampleRates[1] = 48000;
4528  info->nSampleRates = -1; /* continuous range */
4529  sprintf(message, "RtAudio: bogus sample rates reported by DirectSound driver ... using defaults (%s).",
4530  info->name);
4531  error(RtError::DEBUG_WARNING);
4532  }
4533  else {
4534  info->nSampleRates = 1;
4535  }
4536  }
4537  else if ( (out_caps.dwMinSecondarySampleRate < 1000.0) &&
4538  (out_caps.dwMaxSecondarySampleRate > 50000.0) ) {
4539  // This is a bogus driver report ... support for only two
4540  // distant rates. We'll assume this is a range.
4541  info->nSampleRates = -1;
4542  sprintf(message, "RtAudio: bogus sample rates reported by DirectSound driver ... using range (%s).",
4543  info->name);
4544  error(RtError::WARNING);
4545  }
4546  else info->nSampleRates = 2;
4547  }
4548  else {
4549  // Check input rates against output rate range
4550  for ( int i=info->nSampleRates-1; i>=0; i-- ) {
4551  if ( info->sampleRates[i] <= out_caps.dwMaxSecondarySampleRate )
4552  break;
4553  info->nSampleRates--;
4554  }
4555  while ( info->sampleRates[0] < out_caps.dwMinSecondarySampleRate ) {
4556  info->nSampleRates--;
4557  for ( int i=0; i<info->nSampleRates; i++)
4558  info->sampleRates[i] = info->sampleRates[i+1];
4559  if ( info->nSampleRates <= 0 ) break;
4560  }
4561  }
4562 
4563  // Get format information.
4564  if ( out_caps.dwFlags & DSCAPS_PRIMARY16BIT ) info->nativeFormats |= RTAUDIO_SINT16;
4565  if ( out_caps.dwFlags & DSCAPS_PRIMARY8BIT ) info->nativeFormats |= RTAUDIO_SINT8;
4566 
4567  output->Release();
4568 
4569  check_parameters:
4570  if ( info->maxInputChannels == 0 && info->maxOutputChannels == 0 )
4571  return;
4572  if ( info->nSampleRates == 0 || info->nativeFormats == 0 )
4573  return;
4574 
4575  // Determine duplex status.
4576  if (info->maxInputChannels < info->maxOutputChannels)
4577  info->maxDuplexChannels = info->maxInputChannels;
4578  else
4579  info->maxDuplexChannels = info->maxOutputChannels;
4580  if (info->minInputChannels < info->minOutputChannels)
4581  info->minDuplexChannels = info->minInputChannels;
4582  else
4583  info->minDuplexChannels = info->minOutputChannels;
4584 
4585  if ( info->maxDuplexChannels > 0 ) info->hasDuplexSupport = true;
4586  else info->hasDuplexSupport = false;
4587 
4588  info->probed = true;
4589 
4590  return;
4591 }
4592 
4593 bool RtAudio :: probeDeviceOpen(int device, RTAUDIO_STREAM *stream,
4594  STREAM_MODE mode, int channels,
4595  int sampleRate, RTAUDIO_FORMAT format,
4596  int *bufferSize, int numberOfBuffers)
4597 {
4598  HRESULT result;
4599  HWND hWnd = GetForegroundWindow();
4600  // According to a note in PortAudio, using GetDesktopWindow()
4601  // instead of GetForegroundWindow() is supposed to avoid problems
4602  // that occur when the application's window is not the foreground
4603  // window. Also, if the application window closes before the
4604  // DirectSound buffer, DirectSound can crash. However, for console
4605  // applications, no sound was produced when using GetDesktopWindow().
4606  long buffer_size;
4607  LPVOID audioPtr;
4608  DWORD dataLen;
4609  int nBuffers;
4610 
4611  // Check the numberOfBuffers parameter and limit the lowest value to
4612  // two. This is a judgement call and a value of two is probably too
4613  // low for capture, but it should work for playback.
4614  if (numberOfBuffers < 2)
4615  nBuffers = 2;
4616  else
4617  nBuffers = numberOfBuffers;
4618 
4619  // Define the wave format structure (16-bit PCM, srate, channels)
4620  WAVEFORMATEX waveFormat;
4621  ZeroMemory(&waveFormat, sizeof(WAVEFORMATEX));
4622  waveFormat.wFormatTag = WAVE_FORMAT_PCM;
4623  waveFormat.nChannels = channels;
4624  waveFormat.nSamplesPerSec = (unsigned long) sampleRate;
4625 
4626  // Determine the data format.
4627  if ( devices[device].nativeFormats ) { // 8-bit and/or 16-bit support
4628  if ( format == RTAUDIO_SINT8 ) {
4629  if ( devices[device].nativeFormats & RTAUDIO_SINT8 )
4630  waveFormat.wBitsPerSample = 8;
4631  else
4632  waveFormat.wBitsPerSample = 16;
4633  }
4634  else {
4635  if ( devices[device].nativeFormats & RTAUDIO_SINT16 )
4636  waveFormat.wBitsPerSample = 16;
4637  else
4638  waveFormat.wBitsPerSample = 8;
4639  }
4640  }
4641  else {
4642  sprintf(message, "RtAudio: no reported data formats for DirectSound device (%s).",
4643  devices[device].name);
4644  error(RtError::DEBUG_WARNING);
4645  return FAILURE;
4646  }
4647 
4648  waveFormat.nBlockAlign = waveFormat.nChannels * waveFormat.wBitsPerSample / 8;
4649  waveFormat.nAvgBytesPerSec = waveFormat.nSamplesPerSec * waveFormat.nBlockAlign;
4650 
4651  enum_info dsinfo;
4652  strncpy( dsinfo.name, devices[device].name, 64 );
4653  dsinfo.isValid = false;
4654  if ( mode == OUTPUT ) {
4655 
4656  if ( devices[device].maxOutputChannels < channels )
4657  return FAILURE;
4658 
4659  // Enumerate through output devices to find the id (if it exists).
4660  result = DirectSoundEnumerate((LPDSENUMCALLBACK)deviceIdCallback, &dsinfo);
4661  if ( FAILED(result) ) {
4662  sprintf(message, "RtAudio: Error performing output device id enumeration: %s.",
4663  getErrorString(result));
4664  error(RtError::DEBUG_WARNING);
4665  return FAILURE;
4666  }
4667 
4668  if ( dsinfo.isValid == false ) {
4669  sprintf(message, "RtAudio: DS output device (%s) id not found!", devices[device].name);
4670  error(RtError::DEBUG_WARNING);
4671  return FAILURE;
4672  }
4673 
4674  LPGUID id = dsinfo.id;
4675  LPDIRECTSOUND object;
4676  LPDIRECTSOUNDBUFFER buffer;
4677  DSBUFFERDESC bufferDescription;
4678 
4679  result = DirectSoundCreate( id, &object, NULL );
4680  if ( FAILED(result) ) {
4681  sprintf(message, "RtAudio: Could not create DirectSound playback object (%s): %s.",
4682  devices[device].name, getErrorString(result));
4683  error(RtError::DEBUG_WARNING);
4684  return FAILURE;
4685  }
4686 
4687  // Set cooperative level to DSSCL_EXCLUSIVE
4688  result = object->SetCooperativeLevel(hWnd, DSSCL_EXCLUSIVE);
4689  if ( FAILED(result) ) {
4690  object->Release();
4691  sprintf(message, "RtAudio: Unable to set DirectSound cooperative level (%s): %s.",
4692  devices[device].name, getErrorString(result));
4693  error(RtError::WARNING);
4694  return FAILURE;
4695  }
4696 
4697  // Even though we will write to the secondary buffer, we need to
4698  // access the primary buffer to set the correct output format.
4699  // The default is 8-bit, 22 kHz!
4700  // Setup the DS primary buffer description.
4701  ZeroMemory(&bufferDescription, sizeof(DSBUFFERDESC));
4702  bufferDescription.dwSize = sizeof(DSBUFFERDESC);
4703  bufferDescription.dwFlags = DSBCAPS_PRIMARYBUFFER;
4704  // Obtain the primary buffer
4705  result = object->CreateSoundBuffer(&bufferDescription, &buffer, NULL);
4706  if ( FAILED(result) ) {
4707  object->Release();
4708  sprintf(message, "RtAudio: Unable to access DS primary buffer (%s): %s.",
4709  devices[device].name, getErrorString(result));
4710  error(RtError::WARNING);
4711  return FAILURE;
4712  }
4713 
4714  // Set the primary DS buffer sound format.
4715  result = buffer->SetFormat(&waveFormat);
4716  if ( FAILED(result) ) {
4717  object->Release();
4718  sprintf(message, "RtAudio: Unable to set DS primary buffer format (%s): %s.",
4719  devices[device].name, getErrorString(result));
4720  error(RtError::WARNING);
4721  return FAILURE;
4722  }
4723 
4724  // Setup the secondary DS buffer description.
4725  buffer_size = channels * *bufferSize * nBuffers * waveFormat.wBitsPerSample / 8;
4726  ZeroMemory(&bufferDescription, sizeof(DSBUFFERDESC));
4727  bufferDescription.dwSize = sizeof(DSBUFFERDESC);
4728  bufferDescription.dwFlags = ( DSBCAPS_STICKYFOCUS |
4729  DSBCAPS_GETCURRENTPOSITION2 |
4730  DSBCAPS_LOCHARDWARE ); // Force hardware mixing
4731  bufferDescription.dwBufferBytes = buffer_size;
4732  bufferDescription.lpwfxFormat = &waveFormat;
4733 
4734  // Try to create the secondary DS buffer. If that doesn't work,
4735  // try to use software mixing. Otherwise, there's a problem.
4736  result = object->CreateSoundBuffer(&bufferDescription, &buffer, NULL);
4737  if ( FAILED(result) ) {
4738  bufferDescription.dwFlags = ( DSBCAPS_STICKYFOCUS |
4739  DSBCAPS_GETCURRENTPOSITION2 |
4740  DSBCAPS_LOCSOFTWARE ); // Force software mixing
4741  result = object->CreateSoundBuffer(&bufferDescription, &buffer, NULL);
4742  if ( FAILED(result) ) {
4743  object->Release();
4744  sprintf(message, "RtAudio: Unable to create secondary DS buffer (%s): %s.",
4745  devices[device].name, getErrorString(result));
4746  error(RtError::WARNING);
4747  return FAILURE;
4748  }
4749  }
4750 
4751  // Get the buffer size ... might be different from what we specified.
4752  DSBCAPS dsbcaps;
4753  dsbcaps.dwSize = sizeof(DSBCAPS);
4754  buffer->GetCaps(&dsbcaps);
4755  buffer_size = dsbcaps.dwBufferBytes;
4756 
4757  // Lock the DS buffer
4758  result = buffer->Lock(0, buffer_size, &audioPtr, &dataLen, NULL, NULL, 0);
4759  if ( FAILED(result) ) {
4760  object->Release();
4761  sprintf(message, "RtAudio: Unable to lock DS buffer (%s): %s.",
4762  devices[device].name, getErrorString(result));
4763  error(RtError::WARNING);
4764  return FAILURE;
4765  }
4766 
4767  // Zero the DS buffer
4768  ZeroMemory(audioPtr, dataLen);
4769 
4770  // Unlock the DS buffer
4771  result = buffer->Unlock(audioPtr, dataLen, NULL, 0);
4772  if ( FAILED(result) ) {
4773  object->Release();
4774  sprintf(message, "RtAudio: Unable to unlock DS buffer(%s): %s.",
4775  devices[device].name, getErrorString(result));
4776  error(RtError::WARNING);
4777  return FAILURE;
4778  }
4779 
4780  stream->handle[0].object = (void *) object;
4781  stream->handle[0].buffer = (void *) buffer;
4782  stream->nDeviceChannels[0] = channels;
4783  }
4784 
4785  if ( mode == INPUT ) {
4786 
4787  if ( devices[device].maxInputChannels < channels )
4788  return FAILURE;
4789 
4790  // Enumerate through input devices to find the id (if it exists).
4791  result = DirectSoundCaptureEnumerate((LPDSENUMCALLBACK)deviceIdCallback, &dsinfo);
4792  if ( FAILED(result) ) {
4793  sprintf(message, "RtAudio: Error performing input device id enumeration: %s.",
4794  getErrorString(result));
4795  error(RtError::DEBUG_WARNING);
4796  return FAILURE;
4797  }
4798 
4799  if ( dsinfo.isValid == false ) {
4800  sprintf(message, "RtAudio: DS input device (%s) id not found!", devices[device].name);
4801  error(RtError::DEBUG_WARNING);
4802  return FAILURE;
4803  }
4804 
4805  LPGUID id = dsinfo.id;
4806  LPDIRECTSOUNDCAPTURE object;
4807  LPDIRECTSOUNDCAPTUREBUFFER buffer;
4808  DSCBUFFERDESC bufferDescription;
4809 
4810  result = DirectSoundCaptureCreate( id, &object, NULL );
4811  if ( FAILED(result) ) {
4812  sprintf(message, "RtAudio: Could not create DirectSound capture object (%s): %s.",
4813  devices[device].name, getErrorString(result));
4814  error(RtError::WARNING);
4815  return FAILURE;
4816  }
4817 
4818  // Setup the secondary DS buffer description.
4819  buffer_size = channels * *bufferSize * nBuffers * waveFormat.wBitsPerSample / 8;
4820  ZeroMemory(&bufferDescription, sizeof(DSCBUFFERDESC));
4821  bufferDescription.dwSize = sizeof(DSCBUFFERDESC);
4822  bufferDescription.dwFlags = 0;
4823  bufferDescription.dwReserved = 0;
4824  bufferDescription.dwBufferBytes = buffer_size;
4825  bufferDescription.lpwfxFormat = &waveFormat;
4826 
4827  // Create the capture buffer.
4828  result = object->CreateCaptureBuffer(&bufferDescription, &buffer, NULL);
4829  if ( FAILED(result) ) {
4830  object->Release();
4831  sprintf(message, "RtAudio: Unable to create DS capture buffer (%s): %s.",
4832  devices[device].name, getErrorString(result));
4833  error(RtError::WARNING);
4834  return FAILURE;
4835  }
4836 
4837  // Lock the capture buffer
4838  result = buffer->Lock(0, buffer_size, &audioPtr, &dataLen, NULL, NULL, 0);
4839  if ( FAILED(result) ) {
4840  object->Release();
4841  sprintf(message, "RtAudio: Unable to lock DS capture buffer (%s): %s.",
4842  devices[device].name, getErrorString(result));
4843  error(RtError::WARNING);
4844  return FAILURE;
4845  }
4846 
4847  // Zero the buffer
4848  ZeroMemory(audioPtr, dataLen);
4849 
4850  // Unlock the buffer
4851  result = buffer->Unlock(audioPtr, dataLen, NULL, 0);
4852  if ( FAILED(result) ) {
4853  object->Release();
4854  sprintf(message, "RtAudio: Unable to unlock DS capture buffer (%s): %s.",
4855  devices[device].name, getErrorString(result));
4856  error(RtError::WARNING);
4857  return FAILURE;
4858  }
4859 
4860  stream->handle[1].object = (void *) object;
4861  stream->handle[1].buffer = (void *) buffer;
4862  stream->nDeviceChannels[1] = channels;
4863  }
4864 
4865  stream->userFormat = format;
4866  if ( waveFormat.wBitsPerSample == 8 )
4867  stream->deviceFormat[mode] = RTAUDIO_SINT8;
4868  else
4869  stream->deviceFormat[mode] = RTAUDIO_SINT16;
4870  stream->nUserChannels[mode] = channels;
4871  *bufferSize = buffer_size / (channels * nBuffers * waveFormat.wBitsPerSample / 8);
4872  stream->bufferSize = *bufferSize;
4873 
4874  // Set flags for buffer conversion
4875  stream->doConvertBuffer[mode] = false;
4876  if (stream->userFormat != stream->deviceFormat[mode])
4877  stream->doConvertBuffer[mode] = true;
4878  if (stream->nUserChannels[mode] < stream->nDeviceChannels[mode])
4879  stream->doConvertBuffer[mode] = true;
4880 
4881  // Allocate necessary internal buffers
4882  if ( stream->nUserChannels[0] != stream->nUserChannels[1] ) {
4883 
4884  long buffer_bytes;
4885  if (stream->nUserChannels[0] >= stream->nUserChannels[1])
4886  buffer_bytes = stream->nUserChannels[0];
4887  else
4888  buffer_bytes = stream->nUserChannels[1];
4889 
4890  buffer_bytes *= *bufferSize * formatBytes(stream->userFormat);
4891  if (stream->userBuffer) free(stream->userBuffer);
4892  stream->userBuffer = (char *) calloc(buffer_bytes, 1);
4893  if (stream->userBuffer == NULL)
4894  goto memory_error;
4895  }
4896 
4897  if ( stream->doConvertBuffer[mode] ) {
4898 
4899  long buffer_bytes;
4900  bool makeBuffer = true;
4901  if ( mode == OUTPUT )
4902  buffer_bytes = stream->nDeviceChannels[0] * formatBytes(stream->deviceFormat[0]);
4903  else { // mode == INPUT
4904  buffer_bytes = stream->nDeviceChannels[1] * formatBytes(stream->deviceFormat[1]);
4905  if ( stream->mode == OUTPUT && stream->deviceBuffer ) {
4906  long bytes_out = stream->nDeviceChannels[0] * formatBytes(stream->deviceFormat[0]);
4907  if ( buffer_bytes < bytes_out ) makeBuffer = false;
4908  }
4909  }
4910 
4911  if ( makeBuffer ) {
4912  buffer_bytes *= *bufferSize;
4913  if (stream->deviceBuffer) free(stream->deviceBuffer);
4914  stream->deviceBuffer = (char *) calloc(buffer_bytes, 1);
4915  if (stream->deviceBuffer == NULL)
4916  goto memory_error;
4917  }
4918  }
4919 
4920  stream->device[mode] = device;
4921  stream->state = STREAM_STOPPED;
4922  if ( stream->mode == OUTPUT && mode == INPUT )
4923  // We had already set up an output stream.
4924  stream->mode = DUPLEX;
4925  else
4926  stream->mode = mode;
4927  stream->nBuffers = nBuffers;
4928  stream->sampleRate = sampleRate;
4929 
4930  return SUCCESS;
4931 
4932  memory_error:
4933  if (stream->handle[0].object) {
4934  LPDIRECTSOUND object = (LPDIRECTSOUND) stream->handle[0].object;
4935  LPDIRECTSOUNDBUFFER buffer = (LPDIRECTSOUNDBUFFER) stream->handle[0].buffer;
4936  if (buffer) {
4937  buffer->Release();
4938  stream->handle[0].buffer = NULL;
4939  }
4940  object->Release();
4941  stream->handle[0].object = NULL;
4942  }
4943  if (stream->handle[1].object) {
4944  LPDIRECTSOUNDCAPTURE object = (LPDIRECTSOUNDCAPTURE) stream->handle[1].object;
4945  LPDIRECTSOUNDCAPTUREBUFFER buffer = (LPDIRECTSOUNDCAPTUREBUFFER) stream->handle[1].buffer;
4946  if (buffer) {
4947  buffer->Release();
4948  stream->handle[1].buffer = NULL;
4949  }
4950  object->Release();
4951  stream->handle[1].object = NULL;
4952  }
4953  if (stream->userBuffer) {
4954  free(stream->userBuffer);
4955  stream->userBuffer = 0;
4956  }
4957  sprintf(message, "RtAudio: error allocating buffer memory (%s).",
4958  devices[device].name);
4959  error(RtError::WARNING);
4960  return FAILURE;
4961 }
4962 
4963 void RtAudio :: cancelStreamCallback(int streamId)
4964 {
4965  RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
4966 
4967  if (stream->callbackInfo.usingCallback) {
4968 
4969  if (stream->state == STREAM_RUNNING)
4970  stopStream( streamId );
4971 
4972  MUTEX_LOCK(&stream->mutex);
4973 
4974  stream->callbackInfo.usingCallback = false;
4975  WaitForSingleObject( (HANDLE)stream->callbackInfo.thread, INFINITE );
4976  CloseHandle( (HANDLE)stream->callbackInfo.thread );
4977  stream->callbackInfo.thread = 0;
4978  stream->callbackInfo.callback = NULL;
4979  stream->callbackInfo.userData = NULL;
4980 
4981  MUTEX_UNLOCK(&stream->mutex);
4982  }
4983 }
4984 
4985 void RtAudio :: closeStream(int streamId)
4986 {
4987  // We don't want an exception to be thrown here because this
4988  // function is called by our class destructor. So, do our own
4989  // streamId check.
4990  if ( streams.find( streamId ) == streams.end() ) {
4991  sprintf(message, "RtAudio: invalid stream identifier!");
4992  error(RtError::WARNING);
4993  return;
4994  }
4995 
4996  RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) streams[streamId];
4997 
4998  if (stream->callbackInfo.usingCallback) {
4999  stream->callbackInfo.usingCallback = false;
5000  WaitForSingleObject( (HANDLE)stream->callbackInfo.thread, INFINITE );
5001  CloseHandle( (HANDLE)stream->callbackInfo.thread );
5002  }
5003 
5004  DeleteCriticalSection(&stream->mutex);
5005 
5006  if (stream->handle[0].object) {
5007  LPDIRECTSOUND object = (LPDIRECTSOUND) stream->handle[0].object;
5008  LPDIRECTSOUNDBUFFER buffer = (LPDIRECTSOUNDBUFFER) stream->handle[0].buffer;
5009  if (buffer) {
5010  buffer->Stop();
5011  buffer->Release();
5012  }
5013  object->Release();
5014  }
5015 
5016  if (stream->handle[1].object) {
5017  LPDIRECTSOUNDCAPTURE object = (LPDIRECTSOUNDCAPTURE) stream->handle[1].object;
5018  LPDIRECTSOUNDCAPTUREBUFFER buffer = (LPDIRECTSOUNDCAPTUREBUFFER) stream->handle[1].buffer;
5019  if (buffer) {
5020  buffer->Stop();
5021  buffer->Release();
5022  }
5023  object->Release();
5024  }
5025 
5026  if (stream->userBuffer)
5027  free(stream->userBuffer);
5028 
5029  if (stream->deviceBuffer)
5030  free(stream->deviceBuffer);
5031 
5032  free(stream);
5033  streams.erase(streamId);
5034 }
5035 
5036 void RtAudio :: startStream(int streamId)
5037 {
5038  RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
5039 
5040  MUTEX_LOCK(&stream->mutex);
5041 
5042  if (stream->state == STREAM_RUNNING)
5043  goto unlock;
5044 
5045  HRESULT result;
5046  if (stream->mode == OUTPUT || stream->mode == DUPLEX) {
5047  LPDIRECTSOUNDBUFFER buffer = (LPDIRECTSOUNDBUFFER) stream->handle[0].buffer;
5048  result = buffer->Play(0, 0, DSBPLAY_LOOPING );
5049  if ( FAILED(result) ) {
5050  sprintf(message, "RtAudio: Unable to start DS buffer (%s): %s.",
5051  devices[stream->device[0]].name, getErrorString(result));
5052  error(RtError::DRIVER_ERROR);
5053  }
5054  }
5055 
5056  if (stream->mode == INPUT || stream->mode == DUPLEX) {
5057  LPDIRECTSOUNDCAPTUREBUFFER buffer = (LPDIRECTSOUNDCAPTUREBUFFER) stream->handle[1].buffer;
5058  result = buffer->Start(DSCBSTART_LOOPING );
5059  if ( FAILED(result) ) {
5060  sprintf(message, "RtAudio: Unable to start DS capture buffer (%s): %s.",
5061  devices[stream->device[1]].name, getErrorString(result));
5062  error(RtError::DRIVER_ERROR);
5063  }
5064  }
5065  stream->state = STREAM_RUNNING;
5066 
5067  unlock:
5068  MUTEX_UNLOCK(&stream->mutex);
5069 }
5070 
5071 void RtAudio :: stopStream(int streamId)
5072 {
5073  RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
5074 
5075  MUTEX_LOCK(&stream->mutex);
5076 
5077  if (stream->state == STREAM_STOPPED) {
5078  MUTEX_UNLOCK(&stream->mutex);
5079  return;
5080  }
5081 
5082  // There is no specific DirectSound API call to "drain" a buffer
5083  // before stopping. We can hack this for playback by writing zeroes
5084  // for another bufferSize * nBuffers frames. For capture, the
5085  // concept is less clear so we'll repeat what we do in the
5086  // abortStream() case.
5087  HRESULT result;
5088  DWORD dsBufferSize;
5089  LPVOID buffer1 = NULL;
5090  LPVOID buffer2 = NULL;
5091  DWORD bufferSize1 = 0;
5092  DWORD bufferSize2 = 0;
5093  if (stream->mode == OUTPUT || stream->mode == DUPLEX) {
5094 
5095  DWORD currentPos, safePos;
5096  long buffer_bytes = stream->bufferSize * stream->nDeviceChannels[0];
5097  buffer_bytes *= formatBytes(stream->deviceFormat[0]);
5098 
5099  LPDIRECTSOUNDBUFFER dsBuffer = (LPDIRECTSOUNDBUFFER) stream->handle[0].buffer;
5100  UINT nextWritePos = stream->handle[0].bufferPointer;
5101  dsBufferSize = buffer_bytes * stream->nBuffers;
5102 
5103  // Write zeroes for nBuffer counts.
5104  for (int i=0; i<stream->nBuffers; i++) {
5105 
5106  // Find out where the read and "safe write" pointers are.
5107  result = dsBuffer->GetCurrentPosition(&currentPos, &safePos);
5108  if ( FAILED(result) ) {
5109  sprintf(message, "RtAudio: Unable to get current DS position (%s): %s.",
5110  devices[stream->device[0]].name, getErrorString(result));
5111  error(RtError::DRIVER_ERROR);
5112  }
5113 
5114  if ( currentPos < nextWritePos ) currentPos += dsBufferSize; // unwrap offset
5115  DWORD endWrite = nextWritePos + buffer_bytes;
5116 
5117  // Check whether the entire write region is behind the play pointer.
5118  while ( currentPos < endWrite ) {
5119  float millis = (endWrite - currentPos) * 900.0;
5120  millis /= ( formatBytes(stream->deviceFormat[0]) * stream->sampleRate);
5121  if ( millis < 1.0 ) millis = 1.0;
5122  Sleep( (DWORD) millis );
5123 
5124  // Wake up, find out where we are now
5125  result = dsBuffer->GetCurrentPosition( &currentPos, &safePos );
5126  if ( FAILED(result) ) {
5127  sprintf(message, "RtAudio: Unable to get current DS position (%s): %s.",
5128  devices[stream->device[0]].name, getErrorString(result));
5129  error(RtError::DRIVER_ERROR);
5130  }
5131  if ( currentPos < nextWritePos ) currentPos += dsBufferSize; // unwrap offset
5132  }
5133 
5134  // Lock free space in the buffer
5135  result = dsBuffer->Lock (nextWritePos, buffer_bytes, &buffer1,
5136  &bufferSize1, &buffer2, &bufferSize2, 0);
5137  if ( FAILED(result) ) {
5138  sprintf(message, "RtAudio: Unable to lock DS buffer during playback (%s): %s.",
5139  devices[stream->device[0]].name, getErrorString(result));
5140  error(RtError::DRIVER_ERROR);
5141  }
5142 
5143  // Zero the free space
5144  ZeroMemory(buffer1, bufferSize1);
5145  if (buffer2 != NULL) ZeroMemory(buffer2, bufferSize2);
5146 
5147  // Update our buffer offset and unlock sound buffer
5148  dsBuffer->Unlock (buffer1, bufferSize1, buffer2, bufferSize2);
5149  if ( FAILED(result) ) {
5150  sprintf(message, "RtAudio: Unable to unlock DS buffer during playback (%s): %s.",
5151  devices[stream->device[0]].name, getErrorString(result));
5152  error(RtError::DRIVER_ERROR);
5153  }
5154  nextWritePos = (nextWritePos + bufferSize1 + bufferSize2) % dsBufferSize;
5155  stream->handle[0].bufferPointer = nextWritePos;
5156  }
5157 
5158  // If we play again, start at the beginning of the buffer.
5159  stream->handle[0].bufferPointer = 0;
5160  }
5161 
5162  if (stream->mode == INPUT || stream->mode == DUPLEX) {
5163  LPDIRECTSOUNDCAPTUREBUFFER buffer = (LPDIRECTSOUNDCAPTUREBUFFER) stream->handle[1].buffer;
5164  buffer1 = NULL;
5165  bufferSize1 = 0;
5166 
5167  result = buffer->Stop();
5168  if ( FAILED(result) ) {
5169  sprintf(message, "RtAudio: Unable to stop DS capture buffer (%s): %s",
5170  devices[stream->device[1]].name, getErrorString(result));
5171  error(RtError::DRIVER_ERROR);
5172  }
5173 
5174  dsBufferSize = stream->bufferSize * stream->nDeviceChannels[1];
5175  dsBufferSize *= formatBytes(stream->deviceFormat[1]) * stream->nBuffers;
5176 
5177  // Lock the buffer and clear it so that if we start to play again,
5178  // we won't have old data playing.
5179  result = buffer->Lock(0, dsBufferSize, &buffer1, &bufferSize1, NULL, NULL, 0);
5180  if ( FAILED(result) ) {
5181  sprintf(message, "RtAudio: Unable to lock DS capture buffer (%s): %s.",
5182  devices[stream->device[1]].name, getErrorString(result));
5183  error(RtError::DRIVER_ERROR);
5184  }
5185 
5186  // Zero the DS buffer
5187  ZeroMemory(buffer1, bufferSize1);
5188 
5189  // Unlock the DS buffer
5190  result = buffer->Unlock(buffer1, bufferSize1, NULL, 0);
5191  if ( FAILED(result) ) {
5192  sprintf(message, "RtAudio: Unable to unlock DS capture buffer (%s): %s.",
5193  devices[stream->device[1]].name, getErrorString(result));
5194  error(RtError::DRIVER_ERROR);
5195  }
5196 
5197  // If we start recording again, we must begin at beginning of buffer.
5198  stream->handle[1].bufferPointer = 0;
5199  }
5200  stream->state = STREAM_STOPPED;
5201 
5202  MUTEX_UNLOCK(&stream->mutex);
5203 }
5204 
5205 void RtAudio :: abortStream(int streamId)
5206 {
5207  RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
5208 
5209  MUTEX_LOCK(&stream->mutex);
5210 
5211  if (stream->state == STREAM_STOPPED)
5212  goto unlock;
5213 
5214  HRESULT result;
5215  long dsBufferSize;
5216  LPVOID audioPtr;
5217  DWORD dataLen;
5218  if (stream->mode == OUTPUT || stream->mode == DUPLEX) {
5219  LPDIRECTSOUNDBUFFER buffer = (LPDIRECTSOUNDBUFFER) stream->handle[0].buffer;
5220  result = buffer->Stop();
5221  if ( FAILED(result) ) {
5222  sprintf(message, "RtAudio: Unable to stop DS buffer (%s): %s",
5223  devices[stream->device[0]].name, getErrorString(result));
5224  error(RtError::DRIVER_ERROR);
5225  }
5226 
5227  dsBufferSize = stream->bufferSize * stream->nDeviceChannels[0];
5228  dsBufferSize *= formatBytes(stream->deviceFormat[0]) * stream->nBuffers;
5229 
5230  // Lock the buffer and clear it so that if we start to play again,
5231  // we won't have old data playing.
5232  result = buffer->Lock(0, dsBufferSize, &audioPtr, &dataLen, NULL, NULL, 0);
5233  if ( FAILED(result) ) {
5234  sprintf(message, "RtAudio: Unable to lock DS buffer (%s): %s.",
5235  devices[stream->device[0]].name, getErrorString(result));
5236  error(RtError::DRIVER_ERROR);
5237  }
5238 
5239  // Zero the DS buffer
5240  ZeroMemory(audioPtr, dataLen);
5241 
5242  // Unlock the DS buffer
5243  result = buffer->Unlock(audioPtr, dataLen, NULL, 0);
5244  if ( FAILED(result) ) {
5245  sprintf(message, "RtAudio: Unable to unlock DS buffer (%s): %s.",
5246  devices[stream->device[0]].name, getErrorString(result));
5247  error(RtError::DRIVER_ERROR);
5248  }
5249 
5250  // If we start playing again, we must begin at beginning of buffer.
5251  stream->handle[0].bufferPointer = 0;
5252  }
5253 
5254  if (stream->mode == INPUT || stream->mode == DUPLEX) {
5255  LPDIRECTSOUNDCAPTUREBUFFER buffer = (LPDIRECTSOUNDCAPTUREBUFFER) stream->handle[1].buffer;
5256  audioPtr = NULL;
5257  dataLen = 0;
5258 
5259  result = buffer->Stop();
5260  if ( FAILED(result) ) {
5261  sprintf(message, "RtAudio: Unable to stop DS capture buffer (%s): %s",
5262  devices[stream->device[1]].name, getErrorString(result));
5263  error(RtError::DRIVER_ERROR);
5264  }
5265 
5266  dsBufferSize = stream->bufferSize * stream->nDeviceChannels[1];
5267  dsBufferSize *= formatBytes(stream->deviceFormat[1]) * stream->nBuffers;
5268 
5269  // Lock the buffer and clear it so that if we start to play again,
5270  // we won't have old data playing.
5271  result = buffer->Lock(0, dsBufferSize, &audioPtr, &dataLen, NULL, NULL, 0);
5272  if ( FAILED(result) ) {
5273  sprintf(message, "RtAudio: Unable to lock DS capture buffer (%s): %s.",
5274  devices[stream->device[1]].name, getErrorString(result));
5275  error(RtError::DRIVER_ERROR);
5276  }
5277 
5278  // Zero the DS buffer
5279  ZeroMemory(audioPtr, dataLen);
5280 
5281  // Unlock the DS buffer
5282  result = buffer->Unlock(audioPtr, dataLen, NULL, 0);
5283  if ( FAILED(result) ) {
5284  sprintf(message, "RtAudio: Unable to unlock DS capture buffer (%s): %s.",
5285  devices[stream->device[1]].name, getErrorString(result));
5286  error(RtError::DRIVER_ERROR);
5287  }
5288 
5289  // If we start recording again, we must begin at beginning of buffer.
5290  stream->handle[1].bufferPointer = 0;
5291  }
5292  stream->state = STREAM_STOPPED;
5293 
5294  unlock:
5295  MUTEX_UNLOCK(&stream->mutex);
5296 }
5297 
5298 int RtAudio :: streamWillBlock(int streamId)
5299 {
5300  RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
5301 
5302  MUTEX_LOCK(&stream->mutex);
5303 
5304  int channels;
5305  int frames = 0;
5306  if (stream->state == STREAM_STOPPED)
5307  goto unlock;
5308 
5309  HRESULT result;
5310  DWORD currentPos, safePos;
5311  channels = 1;
5312  if (stream->mode == OUTPUT || stream->mode == DUPLEX) {
5313 
5314  LPDIRECTSOUNDBUFFER dsBuffer = (LPDIRECTSOUNDBUFFER) stream->handle[0].buffer;
5315  UINT nextWritePos = stream->handle[0].bufferPointer;
5316  channels = stream->nDeviceChannels[0];
5317  DWORD dsBufferSize = stream->bufferSize * channels;
5318  dsBufferSize *= formatBytes(stream->deviceFormat[0]) * stream->nBuffers;
5319 
5320  // Find out where the read and "safe write" pointers are.
5321  result = dsBuffer->GetCurrentPosition(&currentPos, &safePos);
5322  if ( FAILED(result) ) {
5323  sprintf(message, "RtAudio: Unable to get current DS position (%s): %s.",
5324  devices[stream->device[0]].name, getErrorString(result));
5325  error(RtError::DRIVER_ERROR);
5326  }
5327 
5328  if ( currentPos < nextWritePos ) currentPos += dsBufferSize; // unwrap offset
5329  frames = currentPos - nextWritePos;
5330  frames /= channels * formatBytes(stream->deviceFormat[0]);
5331  }
5332 
5333  if (stream->mode == INPUT || stream->mode == DUPLEX) {
5334 
5335  LPDIRECTSOUNDCAPTUREBUFFER dsBuffer = (LPDIRECTSOUNDCAPTUREBUFFER) stream->handle[1].buffer;
5336  UINT nextReadPos = stream->handle[1].bufferPointer;
5337  channels = stream->nDeviceChannels[1];
5338  DWORD dsBufferSize = stream->bufferSize * channels;
5339  dsBufferSize *= formatBytes(stream->deviceFormat[1]) * stream->nBuffers;
5340 
5341  // Find out where the write and "safe read" pointers are.
5342  result = dsBuffer->GetCurrentPosition(&currentPos, &safePos);
5343  if ( FAILED(result) ) {
5344  sprintf(message, "RtAudio: Unable to get current DS capture position (%s): %s.",
5345  devices[stream->device[1]].name, getErrorString(result));
5346  error(RtError::DRIVER_ERROR);
5347  }
5348 
5349  if ( safePos < nextReadPos ) safePos += dsBufferSize; // unwrap offset
5350 
5351  if (stream->mode == DUPLEX ) {
5352  // Take largest value of the two.
5353  int temp = safePos - nextReadPos;
5354  temp /= channels * formatBytes(stream->deviceFormat[1]);
5355  frames = ( temp > frames ) ? temp : frames;
5356  }
5357  else {
5358  frames = safePos - nextReadPos;
5359  frames /= channels * formatBytes(stream->deviceFormat[1]);
5360  }
5361  }
5362 
5363  frames = stream->bufferSize - frames;
5364  if (frames < 0) frames = 0;
5365 
5366  unlock:
5367  MUTEX_UNLOCK(&stream->mutex);
5368  return frames;
5369 }
5370 
5371 void RtAudio :: tickStream(int streamId)
5372 {
5373  RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
5374 
5375  int stopStream = 0;
5376  if (stream->state == STREAM_STOPPED) {
5377  if (stream->callbackInfo.usingCallback) Sleep(50); // sleep 50 milliseconds
5378  return;
5379  }
5380  else if (stream->callbackInfo.usingCallback) {
5381  RTAUDIO_CALLBACK callback = (RTAUDIO_CALLBACK) stream->callbackInfo.callback;
5382  stopStream = callback(stream->userBuffer, stream->bufferSize, stream->callbackInfo.userData);
5383  }
5384 
5385  MUTEX_LOCK(&stream->mutex);
5386 
5387  // The state might change while waiting on a mutex.
5388  if (stream->state == STREAM_STOPPED) {
5389  MUTEX_UNLOCK(&stream->mutex);
5390  return;
5391  }
5392 
5393  HRESULT result;
5394  DWORD currentPos, safePos;
5395  LPVOID buffer1 = NULL;
5396  LPVOID buffer2 = NULL;
5397  DWORD bufferSize1 = 0;
5398  DWORD bufferSize2 = 0;
5399  char *buffer;
5400  long buffer_bytes;
5401  if (stream->mode == OUTPUT || stream->mode == DUPLEX) {
5402 
5403  // Setup parameters and do buffer conversion if necessary.
5404  if (stream->doConvertBuffer[0]) {
5405  convertStreamBuffer(stream, OUTPUT);
5406  buffer = stream->deviceBuffer;
5407  buffer_bytes = stream->bufferSize * stream->nDeviceChannels[0];
5408  buffer_bytes *= formatBytes(stream->deviceFormat[0]);
5409  }
5410  else {
5411  buffer = stream->userBuffer;
5412  buffer_bytes = stream->bufferSize * stream->nUserChannels[0];
5413  buffer_bytes *= formatBytes(stream->userFormat);
5414  }
5415 
5416  // No byte swapping necessary in DirectSound implementation.
5417 
5418  LPDIRECTSOUNDBUFFER dsBuffer = (LPDIRECTSOUNDBUFFER) stream->handle[0].buffer;
5419  UINT nextWritePos = stream->handle[0].bufferPointer;
5420  DWORD dsBufferSize = buffer_bytes * stream->nBuffers;
5421 
5422  // Find out where the read and "safe write" pointers are.
5423  result = dsBuffer->GetCurrentPosition(&currentPos, &safePos);
5424  if ( FAILED(result) ) {
5425  sprintf(message, "RtAudio: Unable to get current DS position (%s): %s.",
5426  devices[stream->device[0]].name, getErrorString(result));
5427  error(RtError::DRIVER_ERROR);
5428  }
5429 
5430  if ( currentPos < nextWritePos ) currentPos += dsBufferSize; // unwrap offset
5431  DWORD endWrite = nextWritePos + buffer_bytes;
5432 
5433  // Check whether the entire write region is behind the play pointer.
5434  while ( currentPos < endWrite ) {
5435  // If we are here, then we must wait until the play pointer gets
5436  // beyond the write region. The approach here is to use the
5437  // Sleep() function to suspend operation until safePos catches
5438  // up. Calculate number of milliseconds to wait as:
5439  // time = distance * (milliseconds/second) * fudgefactor /
5440  // ((bytes/sample) * (samples/second))
5441  // A "fudgefactor" less than 1 is used because it was found
5442  // that sleeping too long was MUCH worse than sleeping for
5443  // several shorter periods.
5444  float millis = (endWrite - currentPos) * 900.0;
5445  millis /= ( formatBytes(stream->deviceFormat[0]) * stream->sampleRate);
5446  if ( millis < 1.0 ) millis = 1.0;
5447  Sleep( (DWORD) millis );
5448 
5449  // Wake up, find out where we are now
5450  result = dsBuffer->GetCurrentPosition( &currentPos, &safePos );
5451  if ( FAILED(result) ) {
5452  sprintf(message, "RtAudio: Unable to get current DS position (%s): %s.",
5453  devices[stream->device[0]].name, getErrorString(result));
5454  error(RtError::DRIVER_ERROR);
5455  }
5456  if ( currentPos < nextWritePos ) currentPos += dsBufferSize; // unwrap offset
5457  }
5458 
5459  // Lock free space in the buffer
5460  result = dsBuffer->Lock (nextWritePos, buffer_bytes, &buffer1,
5461  &bufferSize1, &buffer2, &bufferSize2, 0);
5462  if ( FAILED(result) ) {
5463  sprintf(message, "RtAudio: Unable to lock DS buffer during playback (%s): %s.",
5464  devices[stream->device[0]].name, getErrorString(result));
5465  error(RtError::DRIVER_ERROR);
5466  }
5467 
5468  // Copy our buffer into the DS buffer
5469  CopyMemory(buffer1, buffer, bufferSize1);
5470  if (buffer2 != NULL) CopyMemory(buffer2, buffer+bufferSize1, bufferSize2);
5471 
5472  // Update our buffer offset and unlock sound buffer
5473  dsBuffer->Unlock (buffer1, bufferSize1, buffer2, bufferSize2);
5474  if ( FAILED(result) ) {
5475  sprintf(message, "RtAudio: Unable to unlock DS buffer during playback (%s): %s.",
5476  devices[stream->device[0]].name, getErrorString(result));
5477  error(RtError::DRIVER_ERROR);
5478  }
5479  nextWritePos = (nextWritePos + bufferSize1 + bufferSize2) % dsBufferSize;
5480  stream->handle[0].bufferPointer = nextWritePos;
5481  }
5482 
5483  if (stream->mode == INPUT || stream->mode == DUPLEX) {
5484 
5485  // Setup parameters.
5486  if (stream->doConvertBuffer[1]) {
5487  buffer = stream->deviceBuffer;
5488  buffer_bytes = stream->bufferSize * stream->nDeviceChannels[1];
5489  buffer_bytes *= formatBytes(stream->deviceFormat[1]);
5490  }
5491  else {
5492  buffer = stream->userBuffer;
5493  buffer_bytes = stream->bufferSize * stream->nUserChannels[1];
5494  buffer_bytes *= formatBytes(stream->userFormat);
5495  }
5496 
5497  LPDIRECTSOUNDCAPTUREBUFFER dsBuffer = (LPDIRECTSOUNDCAPTUREBUFFER) stream->handle[1].buffer;
5498  UINT nextReadPos = stream->handle[1].bufferPointer;
5499  DWORD dsBufferSize = buffer_bytes * stream->nBuffers;
5500 
5501  // Find out where the write and "safe read" pointers are.
5502  result = dsBuffer->GetCurrentPosition(&currentPos, &safePos);
5503  if ( FAILED(result) ) {
5504  sprintf(message, "RtAudio: Unable to get current DS capture position (%s): %s.",
5505  devices[stream->device[1]].name, getErrorString(result));
5506  error(RtError::DRIVER_ERROR);
5507  }
5508 
5509  if ( safePos < nextReadPos ) safePos += dsBufferSize; // unwrap offset
5510  DWORD endRead = nextReadPos + buffer_bytes;
5511 
5512  // Check whether the entire write region is behind the play pointer.
5513  while ( safePos < endRead ) {
5514  // See comments for playback.
5515  float millis = (endRead - safePos) * 900.0;
5516  millis /= ( formatBytes(stream->deviceFormat[1]) * stream->sampleRate);
5517  if ( millis < 1.0 ) millis = 1.0;
5518  Sleep( (DWORD) millis );
5519 
5520  // Wake up, find out where we are now
5521  result = dsBuffer->GetCurrentPosition( &currentPos, &safePos );
5522  if ( FAILED(result) ) {
5523  sprintf(message, "RtAudio: Unable to get current DS capture position (%s): %s.",
5524  devices[stream->device[1]].name, getErrorString(result));
5525  error(RtError::DRIVER_ERROR);
5526  }
5527 
5528  if ( safePos < nextReadPos ) safePos += dsBufferSize; // unwrap offset
5529  }
5530 
5531  // Lock free space in the buffer
5532  result = dsBuffer->Lock (nextReadPos, buffer_bytes, &buffer1,
5533  &bufferSize1, &buffer2, &bufferSize2, 0);
5534  if ( FAILED(result) ) {
5535  sprintf(message, "RtAudio: Unable to lock DS buffer during capture (%s): %s.",
5536  devices[stream->device[1]].name, getErrorString(result));
5537  error(RtError::DRIVER_ERROR);
5538  }
5539 
5540  // Copy our buffer into the DS buffer
5541  CopyMemory(buffer, buffer1, bufferSize1);
5542  if (buffer2 != NULL) CopyMemory(buffer+bufferSize1, buffer2, bufferSize2);
5543 
5544  // Update our buffer offset and unlock sound buffer
5545  nextReadPos = (nextReadPos + bufferSize1 + bufferSize2) % dsBufferSize;
5546  dsBuffer->Unlock (buffer1, bufferSize1, buffer2, bufferSize2);
5547  if ( FAILED(result) ) {
5548  sprintf(message, "RtAudio: Unable to unlock DS buffer during capture (%s): %s.",
5549  devices[stream->device[1]].name, getErrorString(result));
5550  error(RtError::DRIVER_ERROR);
5551  }
5552  stream->handle[1].bufferPointer = nextReadPos;
5553 
5554  // No byte swapping necessary in DirectSound implementation.
5555 
5556  // Do buffer conversion if necessary.
5557  if (stream->doConvertBuffer[1])
5558  convertStreamBuffer(stream, INPUT);
5559  }
5560 
5561  MUTEX_UNLOCK(&stream->mutex);
5562 
5563  if (stream->callbackInfo.usingCallback && stopStream)
5564  this->stopStream(streamId);
5565 }
5566 
5567 // Definitions for utility functions and callbacks
5568 // specific to the DirectSound implementation.
5569 
5570 extern "C" unsigned __stdcall callbackHandler(void *ptr)
5571 {
5572  CALLBACK_INFO *info = (CALLBACK_INFO *) ptr;
5573  RtAudio *object = (RtAudio *) info->object;
5574  int stream = info->streamId;
5575  bool *usingCallback = &info->usingCallback;
5576 
5577  while ( *usingCallback ) {
5578  try {
5579  object->tickStream(stream);
5580  }
5581  catch (RtError &exception) {
5582  fprintf(stderr, "\nRtAudio: Callback thread error (%s) ... closing thread.\n\n",
5583  exception.getMessage());
5584  break;
5585  }
5586  }
5587 
5588  _endthreadex( 0 );
5589  return 0;
5590 }
5591 
5592 void RtAudio :: setStreamCallback(int streamId, RTAUDIO_CALLBACK callback, void *userData)
5593 {
5594  RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
5595 
5596  CALLBACK_INFO *info = (CALLBACK_INFO *) &stream->callbackInfo;
5597  if ( info->usingCallback ) {
5598  sprintf(message, "RtAudio: A callback is already set for this stream!");
5599  error(RtError::WARNING);
5600  return;
5601  }
5602 
5603  info->callback = (void *) callback;
5604  info->userData = userData;
5605  info->usingCallback = true;
5606  info->object = (void *) this;
5607  info->streamId = streamId;
5608 
5609  unsigned thread_id;
5610  info->thread = _beginthreadex(NULL, 0, &callbackHandler,
5611  &stream->callbackInfo, 0, &thread_id);
5612  if (info->thread == 0) {
5613  info->usingCallback = false;
5614  sprintf(message, "RtAudio: error starting callback thread!");
5615  error(RtError::THREAD_ERROR);
5616  }
5617 
5618  // When spawning multiple threads in quick succession, it appears to be
5619  // necessary to wait a bit for each to initialize ... another windoism!
5620  Sleep(1);
5621 }
5622 
5623 static bool CALLBACK deviceCountCallback(LPGUID lpguid,
5624  LPCSTR lpcstrDescription,
5625  LPCSTR lpcstrModule,
5626  LPVOID lpContext)
5627 {
5628  int *pointer = ((int *) lpContext);
5629  (*pointer)++;
5630 
5631  return true;
5632 }
5633 
5634 static bool CALLBACK deviceInfoCallback(LPGUID lpguid,
5635  LPCSTR lpcstrDescription,
5636  LPCSTR lpcstrModule,
5637  LPVOID lpContext)
5638 {
5639  enum_info *info = ((enum_info *) lpContext);
5640  while (strlen(info->name) > 0) info++;
5641 
5642  strncpy(info->name, lpcstrDescription, 64);
5643  info->id = lpguid;
5644 
5645  HRESULT hr;
5646  info->isValid = false;
5647  if (info->isInput == true) {
5648  DSCCAPS caps;
5649  LPDIRECTSOUNDCAPTURE object;
5650 
5651  hr = DirectSoundCaptureCreate( lpguid, &object, NULL );
5652  if( hr != DS_OK ) return true;
5653 
5654  caps.dwSize = sizeof(caps);
5655  hr = object->GetCaps( &caps );
5656  if( hr == DS_OK ) {
5657  if (caps.dwChannels > 0 && caps.dwFormats > 0)
5658  info->isValid = true;
5659  }
5660  object->Release();
5661  }
5662  else {
5663  DSCAPS caps;
5664  LPDIRECTSOUND object;
5665  hr = DirectSoundCreate( lpguid, &object, NULL );
5666  if( hr != DS_OK ) return true;
5667 
5668  caps.dwSize = sizeof(caps);
5669  hr = object->GetCaps( &caps );
5670  if( hr == DS_OK ) {
5671  if ( caps.dwFlags & DSCAPS_PRIMARYMONO || caps.dwFlags & DSCAPS_PRIMARYSTEREO )
5672  info->isValid = true;
5673  }
5674  object->Release();
5675  }
5676 
5677  return true;
5678 }
5679 
5680 static bool CALLBACK defaultDeviceCallback(LPGUID lpguid,
5681  LPCSTR lpcstrDescription,
5682  LPCSTR lpcstrModule,
5683  LPVOID lpContext)
5684 {
5685  enum_info *info = ((enum_info *) lpContext);
5686 
5687  if ( lpguid == NULL ) {
5688  strncpy(info->name, lpcstrDescription, 64);
5689  return false;
5690  }
5691 
5692  return true;
5693 }
5694 
5695 static bool CALLBACK deviceIdCallback(LPGUID lpguid,
5696  LPCSTR lpcstrDescription,
5697  LPCSTR lpcstrModule,
5698  LPVOID lpContext)
5699 {
5700  enum_info *info = ((enum_info *) lpContext);
5701 
5702  if ( strncmp( info->name, lpcstrDescription, 64 ) == 0 ) {
5703  info->id = lpguid;
5704  info->isValid = true;
5705  return false;
5706  }
5707 
5708  return true;
5709 }
5710 
5711 static char* getErrorString(int code)
5712 {
5713  switch (code) {
5714 
5715  case DSERR_ALLOCATED:
5716  return "Direct Sound already allocated";
5717 
5718  case DSERR_CONTROLUNAVAIL:
5719  return "Direct Sound control unavailable";
5720 
5721  case DSERR_INVALIDPARAM:
5722  return "Direct Sound invalid parameter";
5723 
5724  case DSERR_INVALIDCALL:
5725  return "Direct Sound invalid call";
5726 
5727  case DSERR_GENERIC:
5728  return "Direct Sound generic error";
5729 
5730  case DSERR_PRIOLEVELNEEDED:
5731  return "Direct Sound Priority level needed";
5732 
5733  case DSERR_OUTOFMEMORY:
5734  return "Direct Sound out of memory";
5735 
5736  case DSERR_BADFORMAT:
5737  return "Direct Sound bad format";
5738 
5739  case DSERR_UNSUPPORTED:
5740  return "Direct Sound unsupported error";
5741 
5742  case DSERR_NODRIVER:
5743  return "Direct Sound no driver error";
5744 
5745  case DSERR_ALREADYINITIALIZED:
5746  return "Direct Sound already initialized";
5747 
5748  case DSERR_NOAGGREGATION:
5749  return "Direct Sound no aggregation";
5750 
5751  case DSERR_BUFFERLOST:
5752  return "Direct Sound buffer lost";
5753 
5754  case DSERR_OTHERAPPHASPRIO:
5755  return "Direct Sound other app has priority";
5756 
5757  case DSERR_UNINITIALIZED:
5758  return "Direct Sound uninitialized";
5759 
5760  default:
5761  return "Direct Sound unknown error";
5762  }
5763 }
5764 
5765 //******************** End of __WINDOWS_DS__ *********************//
5766 
5767 #elif defined(__IRIX_AL__) // SGI's AL API for IRIX
5768 
5769 #include <unistd.h>
5770 #include <errno.h>
5771 
5772 void RtAudio :: initialize(void)
5773 {
5774  // Count cards and devices
5775  nDevices = 0;
5776 
5777  // Determine the total number of input and output devices.
5778  nDevices = alQueryValues(AL_SYSTEM, AL_DEVICES, 0, 0, 0, 0);
5779  if (nDevices < 0) {
5780  sprintf(message, "RtAudio: AL error counting devices: %s.",
5781  alGetErrorString(oserror()));
5782  error(RtError::DRIVER_ERROR);
5783  }
5784 
5785  if (nDevices <= 0) return;
5786 
5787  ALvalue *vls = (ALvalue *) new ALvalue[nDevices];
5788 
5789  // Allocate the RTAUDIO_DEVICE structures.
5790  devices = (RTAUDIO_DEVICE *) calloc(nDevices, sizeof(RTAUDIO_DEVICE));
5791  if (devices == NULL) {
5792  sprintf(message, "RtAudio: memory allocation error!");
5793  error(RtError::MEMORY_ERROR);
5794  }
5795 
5796  // Write device ascii identifiers and resource ids to device info
5797  // structure.
5798  char name[32];
5799  int outs, ins, i;
5800  ALpv pvs[1];
5801  pvs[0].param = AL_NAME;
5802  pvs[0].value.ptr = name;
5803  pvs[0].sizeIn = 32;
5804 
5805  outs = alQueryValues(AL_SYSTEM, AL_DEFAULT_OUTPUT, vls, nDevices, 0, 0);
5806  if (outs < 0) {
5807  sprintf(message, "RtAudio: AL error getting output devices: %s.",
5808  alGetErrorString(oserror()));
5809  error(RtError::DRIVER_ERROR);
5810  }
5811 
5812  for (i=0; i<outs; i++) {
5813  if (alGetParams(vls[i].i, pvs, 1) < 0) {
5814  sprintf(message, "RtAudio: AL error querying output devices: %s.",
5815  alGetErrorString(oserror()));
5816  error(RtError::DRIVER_ERROR);
5817  }
5818  strncpy(devices[i].name, name, 32);
5819  devices[i].id[0] = vls[i].i;
5820  }
5821 
5822  ins = alQueryValues(AL_SYSTEM, AL_DEFAULT_INPUT, &vls[outs], nDevices-outs, 0, 0);
5823  if (ins < 0) {
5824  sprintf(message, "RtAudio: AL error getting input devices: %s.",
5825  alGetErrorString(oserror()));
5826  error(RtError::DRIVER_ERROR);
5827  }
5828 
5829  for (i=outs; i<ins+outs; i++) {
5830  if (alGetParams(vls[i].i, pvs, 1) < 0) {
5831  sprintf(message, "RtAudio: AL error querying input devices: %s.",
5832  alGetErrorString(oserror()));
5833  error(RtError::DRIVER_ERROR);
5834  }
5835  strncpy(devices[i].name, name, 32);
5836  devices[i].id[1] = vls[i].i;
5837  }
5838 
5839  delete [] vls;
5840 
5841  return;
5842 }
5843 
5844 int RtAudio :: getDefaultInputDevice(void)
5845 {
5846  ALvalue value;
5847  int result = alQueryValues(AL_SYSTEM, AL_DEFAULT_INPUT, &value, 1, 0, 0);
5848  if (result < 0) {
5849  sprintf(message, "RtAudio: AL error getting default input device id: %s.",
5850  alGetErrorString(oserror()));
5851  error(RtError::WARNING);
5852  }
5853  else {
5854  for ( int i=0; i<nDevices; i++ )
5855  if ( devices[i].id[1] == value.i ) return i;
5856  }
5857 
5858  return 0;
5859 }
5860 
5861 int RtAudio :: getDefaultOutputDevice(void)
5862 {
5863  ALvalue value;
5864  int result = alQueryValues(AL_SYSTEM, AL_DEFAULT_OUTPUT, &value, 1, 0, 0);
5865  if (result < 0) {
5866  sprintf(message, "RtAudio: AL error getting default output device id: %s.",
5867  alGetErrorString(oserror()));
5868  error(RtError::WARNING);
5869  }
5870  else {
5871  for ( int i=0; i<nDevices; i++ )
5872  if ( devices[i].id[0] == value.i ) return i;
5873  }
5874 
5875  return 0;
5876 }
5877 
5878 void RtAudio :: probeDeviceInfo(RTAUDIO_DEVICE *info)
5879 {
5880  int resource, result, i;
5881  ALvalue value;
5882  ALparamInfo pinfo;
5883 
5884  // Get output resource ID if it exists.
5885  resource = info->id[0];
5886  if (resource > 0) {
5887 
5888  // Probe output device parameters.
5889  result = alQueryValues(resource, AL_CHANNELS, &value, 1, 0, 0);
5890  if (result < 0) {
5891  sprintf(message, "RtAudio: AL error getting device (%s) channels: %s.",
5892  info->name, alGetErrorString(oserror()));
5893  error(RtError::WARNING);
5894  }
5895  else {
5896  info->maxOutputChannels = value.i;
5897  info->minOutputChannels = 1;
5898  }
5899 
5900  result = alGetParamInfo(resource, AL_RATE, &pinfo);
5901  if (result < 0) {
5902  sprintf(message, "RtAudio: AL error getting device (%s) rates: %s.",
5903  info->name, alGetErrorString(oserror()));
5904  error(RtError::WARNING);
5905  }
5906  else {
5907  info->nSampleRates = 0;
5908  for (i=0; i<MAX_SAMPLE_RATES; i++) {
5909  if ( SAMPLE_RATES[i] >= pinfo.min.i && SAMPLE_RATES[i] <= pinfo.max.i ) {
5910  info->sampleRates[info->nSampleRates] = SAMPLE_RATES[i];
5911  info->nSampleRates++;
5912  }
5913  }
5914  }
5915 
5916  // The AL library supports all our formats, except 24-bit and 32-bit ints.
5917  info->nativeFormats = (RTAUDIO_FORMAT) 51;
5918  }
5919 
5920  // Now get input resource ID if it exists.
5921  resource = info->id[1];
5922  if (resource > 0) {
5923 
5924  // Probe input device parameters.
5925  result = alQueryValues(resource, AL_CHANNELS, &value, 1, 0, 0);
5926  if (result < 0) {
5927  sprintf(message, "RtAudio: AL error getting device (%s) channels: %s.",
5928  info->name, alGetErrorString(oserror()));
5929  error(RtError::WARNING);
5930  }
5931  else {
5932  info->maxInputChannels = value.i;
5933  info->minInputChannels = 1;
5934  }
5935 
5936  result = alGetParamInfo(resource, AL_RATE, &pinfo);
5937  if (result < 0) {
5938  sprintf(message, "RtAudio: AL error getting device (%s) rates: %s.",
5939  info->name, alGetErrorString(oserror()));
5940  error(RtError::WARNING);
5941  }
5942  else {
5943  // In the case of the default device, these values will
5944  // overwrite the rates determined for the output device. Since
5945  // the input device is most likely to be more limited than the
5946  // output device, this is ok.
5947  info->nSampleRates = 0;
5948  for (i=0; i<MAX_SAMPLE_RATES; i++) {
5949  if ( SAMPLE_RATES[i] >= pinfo.min.i && SAMPLE_RATES[i] <= pinfo.max.i ) {
5950  info->sampleRates[info->nSampleRates] = SAMPLE_RATES[i];
5951  info->nSampleRates++;
5952  }
5953  }
5954  }
5955 
5956  // The AL library supports all our formats, except 24-bit and 32-bit ints.
5957  info->nativeFormats = (RTAUDIO_FORMAT) 51;
5958  }
5959 
5960  if ( info->maxInputChannels == 0 && info->maxOutputChannels == 0 )
5961  return;
5962  if ( info->nSampleRates == 0 )
5963  return;
5964 
5965  // Determine duplex status.
5966  if (info->maxInputChannels < info->maxOutputChannels)
5967  info->maxDuplexChannels = info->maxInputChannels;
5968  else
5969  info->maxDuplexChannels = info->maxOutputChannels;
5970  if (info->minInputChannels < info->minOutputChannels)
5971  info->minDuplexChannels = info->minInputChannels;
5972  else
5973  info->minDuplexChannels = info->minOutputChannels;
5974 
5975  if ( info->maxDuplexChannels > 0 ) info->hasDuplexSupport = true;
5976  else info->hasDuplexSupport = false;
5977 
5978  info->probed = true;
5979 
5980  return;
5981 }
5982 
5983 bool RtAudio :: probeDeviceOpen(int device, RTAUDIO_STREAM *stream,
5984  STREAM_MODE mode, int channels,
5985  int sampleRate, RTAUDIO_FORMAT format,
5986  int *bufferSize, int numberOfBuffers)
5987 {
5988  int result, resource, nBuffers;
5989  ALconfig al_config;
5990  ALport port;
5991  ALpv pvs[2];
5992 
5993  // Get a new ALconfig structure.
5994  al_config = alNewConfig();
5995  if ( !al_config ) {
5996  sprintf(message,"RtAudio: can't get AL config: %s.",
5997  alGetErrorString(oserror()));
5998  error(RtError::WARNING);
5999  return FAILURE;
6000  }
6001 
6002  // Set the channels.
6003  result = alSetChannels(al_config, channels);
6004  if ( result < 0 ) {
6005  sprintf(message,"RtAudio: can't set %d channels in AL config: %s.",
6006  channels, alGetErrorString(oserror()));
6007  error(RtError::WARNING);
6008  return FAILURE;
6009  }
6010 
6011  // Attempt to set the queue size. The al API doesn't provide a
6012  // means for querying the minimum/maximum buffer size of a device,
6013  // so if the specified size doesn't work, take whatever the
6014  // al_config structure returns.
6015  if ( numberOfBuffers < 1 )
6016  nBuffers = 1;
6017  else
6018  nBuffers = numberOfBuffers;
6019  long buffer_size = *bufferSize * nBuffers;
6020  result = alSetQueueSize(al_config, buffer_size); // in sample frames
6021  if ( result < 0 ) {
6022  // Get the buffer size specified by the al_config and try that.
6023  buffer_size = alGetQueueSize(al_config);
6024  result = alSetQueueSize(al_config, buffer_size);
6025  if ( result < 0 ) {
6026  sprintf(message,"RtAudio: can't set buffer size (%ld) in AL config: %s.",
6027  buffer_size, alGetErrorString(oserror()));
6028  error(RtError::WARNING);
6029  return FAILURE;
6030  }
6031  *bufferSize = buffer_size / nBuffers;
6032  }
6033 
6034  // Set the data format.
6035  stream->userFormat = format;
6036  stream->deviceFormat[mode] = format;
6037  if (format == RTAUDIO_SINT8) {
6038  result = alSetSampFmt(al_config, AL_SAMPFMT_TWOSCOMP);
6039  result = alSetWidth(al_config, AL_SAMPLE_8);
6040  }
6041  else if (format == RTAUDIO_SINT16) {
6042  result = alSetSampFmt(al_config, AL_SAMPFMT_TWOSCOMP);
6043  result = alSetWidth(al_config, AL_SAMPLE_16);
6044  }
6045  else if (format == RTAUDIO_SINT24) {
6046  // Our 24-bit format assumes the upper 3 bytes of a 4 byte word.
6047  // The AL library uses the lower 3 bytes, so we'll need to do our
6048  // own conversion.
6049  result = alSetSampFmt(al_config, AL_SAMPFMT_FLOAT);
6050  stream->deviceFormat[mode] = RTAUDIO_FLOAT32;
6051  }
6052  else if (format == RTAUDIO_SINT32) {
6053  // The AL library doesn't seem to support the 32-bit integer
6054  // format, so we'll need to do our own conversion.
6055  result = alSetSampFmt(al_config, AL_SAMPFMT_FLOAT);
6056  stream->deviceFormat[mode] = RTAUDIO_FLOAT32;
6057  }
6058  else if (format == RTAUDIO_FLOAT32)
6059  result = alSetSampFmt(al_config, AL_SAMPFMT_FLOAT);
6060  else if (format == RTAUDIO_FLOAT64)
6061  result = alSetSampFmt(al_config, AL_SAMPFMT_DOUBLE);
6062 
6063  if ( result == -1 ) {
6064  sprintf(message,"RtAudio: AL error setting sample format in AL config: %s.",
6065  alGetErrorString(oserror()));
6066  error(RtError::WARNING);
6067  return FAILURE;
6068  }
6069 
6070  if (mode == OUTPUT) {
6071 
6072  // Set our device.
6073  if (device == 0)
6074  resource = AL_DEFAULT_OUTPUT;
6075  else
6076  resource = devices[device].id[0];
6077  result = alSetDevice(al_config, resource);
6078  if ( result == -1 ) {
6079  sprintf(message,"RtAudio: AL error setting device (%s) in AL config: %s.",
6080  devices[device].name, alGetErrorString(oserror()));
6081  error(RtError::WARNING);
6082  return FAILURE;
6083  }
6084 
6085  // Open the port.
6086  port = alOpenPort("RtAudio Output Port", "w", al_config);
6087  if( !port ) {
6088  sprintf(message,"RtAudio: AL error opening output port: %s.",
6089  alGetErrorString(oserror()));
6090  error(RtError::WARNING);
6091  return FAILURE;
6092  }
6093 
6094  // Set the sample rate
6095  pvs[0].param = AL_MASTER_CLOCK;
6096  pvs[0].value.i = AL_CRYSTAL_MCLK_TYPE;
6097  pvs[1].param = AL_RATE;
6098  pvs[1].value.ll = alDoubleToFixed((double)sampleRate);
6099  result = alSetParams(resource, pvs, 2);
6100  if ( result < 0 ) {
6101  alClosePort(port);
6102  sprintf(message,"RtAudio: AL error setting sample rate (%d) for device (%s): %s.",
6103  sampleRate, devices[device].name, alGetErrorString(oserror()));
6104  error(RtError::WARNING);
6105  return FAILURE;
6106  }
6107  }
6108  else { // mode == INPUT
6109 
6110  // Set our device.
6111  if (device == 0)
6112  resource = AL_DEFAULT_INPUT;
6113  else
6114  resource = devices[device].id[1];
6115  result = alSetDevice(al_config, resource);
6116  if ( result == -1 ) {
6117  sprintf(message,"RtAudio: AL error setting device (%s) in AL config: %s.",
6118  devices[device].name, alGetErrorString(oserror()));
6119  error(RtError::WARNING);
6120  return FAILURE;
6121  }
6122 
6123  // Open the port.
6124  port = alOpenPort("RtAudio Output Port", "r", al_config);
6125  if( !port ) {
6126  sprintf(message,"RtAudio: AL error opening input port: %s.",
6127  alGetErrorString(oserror()));
6128  error(RtError::WARNING);
6129  return FAILURE;
6130  }
6131 
6132  // Set the sample rate
6133  pvs[0].param = AL_MASTER_CLOCK;
6134  pvs[0].value.i = AL_CRYSTAL_MCLK_TYPE;
6135  pvs[1].param = AL_RATE;
6136  pvs[1].value.ll = alDoubleToFixed((double)sampleRate);
6137  result = alSetParams(resource, pvs, 2);
6138  if ( result < 0 ) {
6139  alClosePort(port);
6140  sprintf(message,"RtAudio: AL error setting sample rate (%d) for device (%s): %s.",
6141  sampleRate, devices[device].name, alGetErrorString(oserror()));
6142  error(RtError::WARNING);
6143  return FAILURE;
6144  }
6145  }
6146 
6147  alFreeConfig(al_config);
6148 
6149  stream->nUserChannels[mode] = channels;
6150  stream->nDeviceChannels[mode] = channels;
6151 
6152  // Set handle and flags for buffer conversion
6153  stream->handle[mode] = port;
6154  stream->doConvertBuffer[mode] = false;
6155  if (stream->userFormat != stream->deviceFormat[mode])
6156  stream->doConvertBuffer[mode] = true;
6157 
6158  // Allocate necessary internal buffers
6159  if ( stream->nUserChannels[0] != stream->nUserChannels[1] ) {
6160 
6161  long buffer_bytes;
6162  if (stream->nUserChannels[0] >= stream->nUserChannels[1])
6163  buffer_bytes = stream->nUserChannels[0];
6164  else
6165  buffer_bytes = stream->nUserChannels[1];
6166 
6167  buffer_bytes *= *bufferSize * formatBytes(stream->userFormat);
6168  if (stream->userBuffer) free(stream->userBuffer);
6169  stream->userBuffer = (char *) calloc(buffer_bytes, 1);
6170  if (stream->userBuffer == NULL)
6171  goto memory_error;
6172  }
6173 
6174  if ( stream->doConvertBuffer[mode] ) {
6175 
6176  long buffer_bytes;
6177  bool makeBuffer = true;
6178  if ( mode == OUTPUT )
6179  buffer_bytes = stream->nDeviceChannels[0] * formatBytes(stream->deviceFormat[0]);
6180  else { // mode == INPUT
6181  buffer_bytes = stream->nDeviceChannels[1] * formatBytes(stream->deviceFormat[1]);
6182  if ( stream->mode == OUTPUT && stream->deviceBuffer ) {
6183  long bytes_out = stream->nDeviceChannels[0] * formatBytes(stream->deviceFormat[0]);
6184  if ( buffer_bytes < bytes_out ) makeBuffer = false;
6185  }
6186  }
6187 
6188  if ( makeBuffer ) {
6189  buffer_bytes *= *bufferSize;
6190  if (stream->deviceBuffer) free(stream->deviceBuffer);
6191  stream->deviceBuffer = (char *) calloc(buffer_bytes, 1);
6192  if (stream->deviceBuffer == NULL)
6193  goto memory_error;
6194  }
6195  }
6196 
6197  stream->device[mode] = device;
6198  stream->state = STREAM_STOPPED;
6199  if ( stream->mode == OUTPUT && mode == INPUT )
6200  // We had already set up an output stream.
6201  stream->mode = DUPLEX;
6202  else
6203  stream->mode = mode;
6204  stream->nBuffers = nBuffers;
6205  stream->bufferSize = *bufferSize;
6206  stream->sampleRate = sampleRate;
6207 
6208  return SUCCESS;
6209 
6210  memory_error:
6211  if (stream->handle[0]) {
6212  alClosePort(stream->handle[0]);
6213  stream->handle[0] = 0;
6214  }
6215  if (stream->handle[1]) {
6216  alClosePort(stream->handle[1]);
6217  stream->handle[1] = 0;
6218  }
6219  if (stream->userBuffer) {
6220  free(stream->userBuffer);
6221  stream->userBuffer = 0;
6222  }
6223  sprintf(message, "RtAudio: ALSA error allocating buffer memory for device (%s).",
6224  devices[device].name);
6225  error(RtError::WARNING);
6226  return FAILURE;
6227 }
6228 
6229 void RtAudio :: closeStream(int streamId)
6230 {
6231  // We don't want an exception to be thrown here because this
6232  // function is called by our class destructor. So, do our own
6233  // streamId check.
6234  if ( streams.find( streamId ) == streams.end() ) {
6235  sprintf(message, "RtAudio: invalid stream identifier!");
6236  error(RtError::WARNING);
6237  return;
6238  }
6239 
6240  RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) streams[streamId];
6241 
6242  if (stream->callbackInfo.usingCallback) {
6243  pthread_cancel(stream->callbackInfo.thread);
6244  pthread_join(stream->callbackInfo.thread, NULL);
6245  }
6246 
6247  pthread_mutex_destroy(&stream->mutex);
6248 
6249  if (stream->handle[0])
6250  alClosePort(stream->handle[0]);
6251 
6252  if (stream->handle[1])
6253  alClosePort(stream->handle[1]);
6254 
6255  if (stream->userBuffer)
6256  free(stream->userBuffer);
6257 
6258  if (stream->deviceBuffer)
6259  free(stream->deviceBuffer);
6260 
6261  free(stream);
6262  streams.erase(streamId);
6263 }
6264 
6265 void RtAudio :: startStream(int streamId)
6266 {
6267  RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
6268 
6269  if (stream->state == STREAM_RUNNING)
6270  return;
6271 
6272  // The AL port is ready as soon as it is opened.
6273  stream->state = STREAM_RUNNING;
6274 }
6275 
6276 void RtAudio :: stopStream(int streamId)
6277 {
6278  RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
6279 
6280  MUTEX_LOCK(&stream->mutex);
6281 
6282  if (stream->state == STREAM_STOPPED)
6283  goto unlock;
6284 
6285  int result;
6286  int buffer_size = stream->bufferSize * stream->nBuffers;
6287 
6288  if (stream->mode == OUTPUT || stream->mode == DUPLEX)
6289  alZeroFrames(stream->handle[0], buffer_size);
6290 
6291  if (stream->mode == INPUT || stream->mode == DUPLEX) {
6292  result = alDiscardFrames(stream->handle[1], buffer_size);
6293  if (result == -1) {
6294  sprintf(message, "RtAudio: AL error draining stream device (%s): %s.",
6295  devices[stream->device[1]].name, alGetErrorString(oserror()));
6296  error(RtError::DRIVER_ERROR);
6297  }
6298  }
6299  stream->state = STREAM_STOPPED;
6300 
6301  unlock:
6302  MUTEX_UNLOCK(&stream->mutex);
6303 }
6304 
6305 void RtAudio :: abortStream(int streamId)
6306 {
6307  RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
6308 
6309  MUTEX_LOCK(&stream->mutex);
6310 
6311  if (stream->state == STREAM_STOPPED)
6312  goto unlock;
6313 
6314  if (stream->mode == OUTPUT || stream->mode == DUPLEX) {
6315 
6316  int buffer_size = stream->bufferSize * stream->nBuffers;
6317  int result = alDiscardFrames(stream->handle[0], buffer_size);
6318  if (result == -1) {
6319  sprintf(message, "RtAudio: AL error aborting stream device (%s): %s.",
6320  devices[stream->device[0]].name, alGetErrorString(oserror()));
6321  error(RtError::DRIVER_ERROR);
6322  }
6323  }
6324 
6325  // There is no clear action to take on the input stream, since the
6326  // port will continue to run in any event.
6327  stream->state = STREAM_STOPPED;
6328 
6329  unlock:
6330  MUTEX_UNLOCK(&stream->mutex);
6331 }
6332 
6333 int RtAudio :: streamWillBlock(int streamId)
6334 {
6335  RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
6336 
6337  MUTEX_LOCK(&stream->mutex);
6338 
6339  int frames = 0;
6340  if (stream->state == STREAM_STOPPED)
6341  goto unlock;
6342 
6343  int err = 0;
6344  if (stream->mode == OUTPUT || stream->mode == DUPLEX) {
6345  err = alGetFillable(stream->handle[0]);
6346  if (err < 0) {
6347  sprintf(message, "RtAudio: AL error getting available frames for stream (%s): %s.",
6348  devices[stream->device[0]].name, alGetErrorString(oserror()));
6349  error(RtError::DRIVER_ERROR);
6350  }
6351  }
6352 
6353  frames = err;
6354 
6355  if (stream->mode == INPUT || stream->mode == DUPLEX) {
6356  err = alGetFilled(stream->handle[1]);
6357  if (err < 0) {
6358  sprintf(message, "RtAudio: AL error getting available frames for stream (%s): %s.",
6359  devices[stream->device[1]].name, alGetErrorString(oserror()));
6360  error(RtError::DRIVER_ERROR);
6361  }
6362  if (frames > err) frames = err;
6363  }
6364 
6365  frames = stream->bufferSize - frames;
6366  if (frames < 0) frames = 0;
6367 
6368  unlock:
6369  MUTEX_UNLOCK(&stream->mutex);
6370  return frames;
6371 }
6372 
6373 void RtAudio :: tickStream(int streamId)
6374 {
6375  RTAUDIO_STREAM *stream = (RTAUDIO_STREAM *) verifyStream(streamId);
6376 
6377  int stopStream = 0;
6378  if (stream->state == STREAM_STOPPED) {
6379  if (stream->callbackInfo.usingCallback) usleep(50000); // sleep 50 milliseconds
6380  return;
6381  }
6382  else if (stream->callbackInfo.usingCallback) {
6383  RTAUDIO_CALLBACK callback = (RTAUDIO_CALLBACK) stream->callbackInfo.callback;
6384  stopStream = callback(stream->userBuffer, stream->bufferSize, stream->callbackInfo.userData);
6385  }
6386 
6387  MUTEX_LOCK(&stream->mutex);
6388 
6389  // The state might change while waiting on a mutex.
6390  if (stream->state == STREAM_STOPPED)
6391  goto unlock;
6392 
6393  char *buffer;
6394  int channels;
6395  RTAUDIO_FORMAT format;
6396  if (stream->mode == OUTPUT || stream->mode == DUPLEX) {
6397 
6398  // Setup parameters and do buffer conversion if necessary.
6399  if (stream->doConvertBuffer[0]) {
6400  convertStreamBuffer(stream, OUTPUT);
6401  buffer = stream->deviceBuffer;
6402  channels = stream->nDeviceChannels[0];
6403  format = stream->deviceFormat[0];
6404  }
6405  else {
6406  buffer = stream->userBuffer;
6407  channels = stream->nUserChannels[0];
6408  format = stream->userFormat;
6409  }
6410 
6411  // Do byte swapping if necessary.
6412  if (stream->doByteSwap[0])
6413  byteSwapBuffer(buffer, stream->bufferSize * channels, format);
6414 
6415  // Write interleaved samples to device.
6416  alWriteFrames(stream->handle[0], buffer, stream->bufferSize);
6417  }
6418 
6419  if (stream->mode == INPUT || stream->mode == DUPLEX) {
6420 
6421  // Setup parameters.
6422  if (stream->doConvertBuffer[1]) {
6423  buffer = stream->deviceBuffer;
6424  channels = stream->nDeviceChannels[1];
6425  format = stream->deviceFormat[1];
6426  }
6427  else {
6428  buffer = stream->userBuffer;
6429  channels = stream->nUserChannels[1];
6430  format = stream->userFormat;
6431  }
6432 
6433  // Read interleaved samples from device.
6434  alReadFrames(stream->handle[1], buffer, stream->bufferSize);
6435 
6436  // Do byte swapping if necessary.
6437  if (stream->doByteSwap[1])
6438  byteSwapBuffer(buffer, stream->bufferSize * channels, format);
6439 
6440  // Do buffer conversion if necessary.
6441  if (stream->doConvertBuffer[1])
6442  convertStreamBuffer(stream, INPUT);
6443  }
6444 
6445  unlock:
6446  MUTEX_UNLOCK(&stream->mutex);
6447 
6448  if (stream->callbackInfo.usingCallback && stopStream)
6449  this->stopStream(streamId);
6450 }
6451 
6452 extern "C" void *callbackHandler(void *ptr)
6453 {
6454  CALLBACK_INFO *info = (CALLBACK_INFO *) ptr;
6455  RtAudio *object = (RtAudio *) info->object;
6456  int stream = info->streamId;
6457  bool *usingCallback = &info->usingCallback;
6458 
6459  while ( *usingCallback ) {
6460  pthread_testcancel();
6461  try {
6462  object->tickStream(stream);
6463  }
6464  catch (RtError &exception) {
6465  fprintf(stderr, "\nRtAudio: Callback thread error (%s) ... closing thread.\n\n",
6466  exception.getMessage());
6467  break;
6468  }
6469  }
6470 
6471  return 0;
6472 }
6473 
6474 //******************** End of __IRIX_AL__ *********************//
6475 
6476 #endif
6477 
6478 
6479 // *************************************************** //
6480 //
6481 // Private common (OS-independent) RtAudio methods.
6482 //
6483 // *************************************************** //
6484 
6485 // This method can be modified to control the behavior of error
6486 // message reporting and throwing.
6487 void RtAudio :: error(RtError::TYPE type)
6488 {
6489  if (type == RtError::WARNING) {
6490  fprintf(stderr, "\n%s\n\n", message);
6491  }
6492  else if (type == RtError::DEBUG_WARNING) {
6493 #if defined(__RTAUDIO_DEBUG__)
6494  fprintf(stderr, "\n%s\n\n", message);
6495 #endif
6496  }
6497  else {
6498  fprintf(stderr, "\n%s\n\n", message);
6499  throw RtError(message, type);
6500  }
6501 }
6502 
6503 void *RtAudio :: verifyStream(int streamId)
6504 {
6505  // Verify the stream key.
6506  if ( streams.find( streamId ) == streams.end() ) {
6507  sprintf(message, "RtAudio: invalid stream identifier!");
6508  error(RtError::INVALID_STREAM);
6509  }
6510 
6511  return streams[streamId];
6512 }
6513 
6514 void RtAudio :: clearDeviceInfo(RTAUDIO_DEVICE *info)
6515 {
6516  // Don't clear the name or DEVICE_ID fields here ... they are
6517  // typically set prior to a call of this function.
6518  info->probed = false;
6519  info->maxOutputChannels = 0;
6520  info->maxInputChannels = 0;
6521  info->maxDuplexChannels = 0;
6522  info->minOutputChannels = 0;
6523  info->minInputChannels = 0;
6524  info->minDuplexChannels = 0;
6525  info->hasDuplexSupport = false;
6526  info->nSampleRates = 0;
6527  for (int i=0; i<MAX_SAMPLE_RATES; i++)
6528  info->sampleRates[i] = 0;
6529  info->nativeFormats = 0;
6530 }
6531 
6532 int RtAudio :: formatBytes(RTAUDIO_FORMAT format)
6533 {
6534  if (format == RTAUDIO_SINT16)
6535  return 2;
6536  else if (format == RTAUDIO_SINT24 || format == RTAUDIO_SINT32 ||
6537  format == RTAUDIO_FLOAT32)
6538  return 4;
6539  else if (format == RTAUDIO_FLOAT64)
6540  return 8;
6541  else if (format == RTAUDIO_SINT8)
6542  return 1;
6543 
6544  sprintf(message,"RtAudio: undefined format in formatBytes().");
6545  error(RtError::WARNING);
6546 
6547  return 0;
6548 }
6549 
6550 void RtAudio :: convertStreamBuffer(RTAUDIO_STREAM *stream, STREAM_MODE mode)
6551 {
6552  // This method does format conversion, input/output channel compensation, and
6553  // data interleaving/deinterleaving. 24-bit integers are assumed to occupy
6554  // the upper three bytes of a 32-bit integer.
6555 
6556  int j, jump_in, jump_out, channels;
6557  RTAUDIO_FORMAT format_in, format_out;
6558  char *input, *output;
6559 
6560  if (mode == INPUT) { // convert device to user buffer
6561  input = stream->deviceBuffer;
6562  output = stream->userBuffer;
6563  jump_in = stream->nDeviceChannels[1];
6564  jump_out = stream->nUserChannels[1];
6565  format_in = stream->deviceFormat[1];
6566  format_out = stream->userFormat;
6567  }
6568  else { // convert user to device buffer
6569  input = stream->userBuffer;
6570  output = stream->deviceBuffer;
6571  jump_in = stream->nUserChannels[0];
6572  jump_out = stream->nDeviceChannels[0];
6573  format_in = stream->userFormat;
6574  format_out = stream->deviceFormat[0];
6575 
6576  // clear our device buffer when in/out duplex device channels are different
6577  if ( stream->mode == DUPLEX &&
6578  stream->nDeviceChannels[0] != stream->nDeviceChannels[1] )
6579  memset(output, 0, stream->bufferSize * jump_out * formatBytes(format_out));
6580  }
6581 
6582  channels = (jump_in < jump_out) ? jump_in : jump_out;
6583 
6584  // Set up the interleave/deinterleave offsets
6585  std::vector<int> offset_in(channels);
6586  std::vector<int> offset_out(channels);
6587  if (mode == INPUT && stream->deInterleave[1]) {
6588  for (int k=0; k<channels; k++) {
6589  offset_in[k] = k * stream->bufferSize;
6590  offset_out[k] = k;
6591  jump_in = 1;
6592  }
6593  }
6594  else if (mode == OUTPUT && stream->deInterleave[0]) {
6595  for (int k=0; k<channels; k++) {
6596  offset_in[k] = k;
6597  offset_out[k] = k * stream->bufferSize;
6598  jump_out = 1;
6599  }
6600  }
6601  else {
6602  for (int k=0; k<channels; k++) {
6603  offset_in[k] = k;
6604  offset_out[k] = k;
6605  }
6606  }
6607 
6608  if (format_out == RTAUDIO_FLOAT64) {
6609  FLOAT64 scale;
6610  FLOAT64 *out = (FLOAT64 *)output;
6611 
6612  if (format_in == RTAUDIO_SINT8) {
6613  signed char *in = (signed char *)input;
6614  scale = 1.0 / 128.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]];
6618  out[offset_out[j]] *= scale;
6619  }
6620  in += jump_in;
6621  out += jump_out;
6622  }
6623  }
6624  else if (format_in == RTAUDIO_SINT16) {
6625  INT16 *in = (INT16 *)input;
6626  scale = 1.0 / 32768.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;
6631  }
6632  in += jump_in;
6633  out += jump_out;
6634  }
6635  }
6636  else if (format_in == RTAUDIO_SINT24) {
6637  INT32 *in = (INT32 *)input;
6638  scale = 1.0 / 2147483648.0;
6639  for (int i=0; i<stream->bufferSize; i++) {
6640  for (j=0; j<channels; j++) {
6641  out[offset_out[j]] = (FLOAT64) (in[offset_in[j]] & 0xffffff00);
6642  out[offset_out[j]] *= scale;
6643  }
6644  in += jump_in;
6645  out += jump_out;
6646  }
6647  }
6648  else if (format_in == RTAUDIO_SINT32) {
6649  INT32 *in = (INT32 *)input;
6650  scale = 1.0 / 2147483648.0;
6651  for (int i=0; i<stream->bufferSize; i++) {
6652  for (j=0; j<channels; j++) {
6653  out[offset_out[j]] = (FLOAT64) in[offset_in[j]];
6654  out[offset_out[j]] *= scale;
6655  }
6656  in += jump_in;
6657  out += jump_out;
6658  }
6659  }
6660  else if (format_in == RTAUDIO_FLOAT32) {
6661  FLOAT32 *in = (FLOAT32 *)input;
6662  for (int i=0; i<stream->bufferSize; i++) {
6663  for (j=0; j<channels; j++) {
6664  out[offset_out[j]] = (FLOAT64) in[offset_in[j]];
6665  }
6666  in += jump_in;
6667  out += jump_out;
6668  }
6669  }
6670  else if (format_in == RTAUDIO_FLOAT64) {
6671  // Channel compensation and/or (de)interleaving only.
6672  FLOAT64 *in = (FLOAT64 *)input;
6673  for (int i=0; i<stream->bufferSize; i++) {
6674  for (j=0; j<channels; j++) {
6675  out[offset_out[j]] = in[offset_in[j]];
6676  }
6677  in += jump_in;
6678  out += jump_out;
6679  }
6680  }
6681  }
6682  else if (format_out == RTAUDIO_FLOAT32) {
6683  FLOAT32 scale;
6684  FLOAT32 *out = (FLOAT32 *)output;
6685 
6686  if (format_in == RTAUDIO_SINT8) {
6687  signed char *in = (signed char *)input;
6688  scale = 1.0 / 128.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]];
6692  out[offset_out[j]] *= scale;
6693  }
6694  in += jump_in;
6695  out += jump_out;
6696  }
6697  }
6698  else if (format_in == RTAUDIO_SINT16) {
6699  INT16 *in = (INT16 *)input;
6700  scale = 1.0 / 32768.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;
6705  }
6706  in += jump_in;
6707  out += jump_out;
6708  }
6709  }
6710  else if (format_in == RTAUDIO_SINT24) {
6711  INT32 *in = (INT32 *)input;
6712  scale = 1.0 / 2147483648.0;
6713  for (int i=0; i<stream->bufferSize; i++) {
6714  for (j=0; j<channels; j++) {
6715  out[offset_out[j]] = (FLOAT32) (in[offset_in[j]] & 0xffffff00);
6716  out[offset_out[j]] *= scale;
6717  }
6718  in += jump_in;
6719  out += jump_out;
6720  }
6721  }
6722  else if (format_in == RTAUDIO_SINT32) {
6723  INT32 *in = (INT32 *)input;
6724  scale = 1.0 / 2147483648.0;
6725  for (int i=0; i<stream->bufferSize; i++) {
6726  for (j=0; j<channels; j++) {
6727  out[offset_out[j]] = (FLOAT32) in[offset_in[j]];
6728  out[offset_out[j]] *= scale;
6729  }
6730  in += jump_in;
6731  out += jump_out;
6732  }
6733  }
6734  else if (format_in == RTAUDIO_FLOAT32) {
6735  // Channel compensation and/or (de)interleaving only.
6736  FLOAT32 *in = (FLOAT32 *)input;
6737  for (int i=0; i<stream->bufferSize; i++) {
6738  for (j=0; j<channels; j++) {
6739  out[offset_out[j]] = in[offset_in[j]];
6740  }
6741  in += jump_in;
6742  out += jump_out;
6743  }
6744  }
6745  else if (format_in == RTAUDIO_FLOAT64) {
6746  FLOAT64 *in = (FLOAT64 *)input;
6747  for (int i=0; i<stream->bufferSize; i++) {
6748  for (j=0; j<channels; j++) {
6749  out[offset_out[j]] = (FLOAT32) in[offset_in[j]];
6750  }
6751  in += jump_in;
6752  out += jump_out;
6753  }
6754  }
6755  }
6756  else if (format_out == RTAUDIO_SINT32) {
6757  INT32 *out = (INT32 *)output;
6758  if (format_in == RTAUDIO_SINT8) {
6759  signed char *in = (signed char *)input;
6760  for (int i=0; i<stream->bufferSize; i++) {
6761  for (j=0; j<channels; j++) {
6762  out[offset_out[j]] = (INT32) in[offset_in[j]];
6763  out[offset_out[j]] <<= 24;
6764  }
6765  in += jump_in;
6766  out += jump_out;
6767  }
6768  }
6769  else if (format_in == RTAUDIO_SINT16) {
6770  INT16 *in = (INT16 *)input;
6771  for (int i=0; i<stream->bufferSize; i++) {
6772  for (j=0; j<channels; j++) {
6773  out[offset_out[j]] = (INT32) in[offset_in[j]];
6774  out[offset_out[j]] <<= 16;
6775  }
6776  in += jump_in;
6777  out += jump_out;
6778  }
6779  }
6780  else if (format_in == RTAUDIO_SINT24) {
6781  INT32 *in = (INT32 *)input;
6782  for (int i=0; i<stream->bufferSize; i++) {
6783  for (j=0; j<channels; j++) {
6784  out[offset_out[j]] = (INT32) in[offset_in[j]];
6785  }
6786  in += jump_in;
6787  out += jump_out;
6788  }
6789  }
6790  else if (format_in == RTAUDIO_SINT32) {
6791  // Channel compensation and/or (de)interleaving only.
6792  INT32 *in = (INT32 *)input;
6793  for (int i=0; i<stream->bufferSize; i++) {
6794  for (j=0; j<channels; j++) {
6795  out[offset_out[j]] = in[offset_in[j]];
6796  }
6797  in += jump_in;
6798  out += jump_out;
6799  }
6800  }
6801  else if (format_in == RTAUDIO_FLOAT32) {
6802  FLOAT32 *in = (FLOAT32 *)input;
6803  for (int i=0; i<stream->bufferSize; i++) {
6804  for (j=0; j<channels; j++) {
6805  out[offset_out[j]] = (INT32) (in[offset_in[j]] * 2147483647.0);
6806  }
6807  in += jump_in;
6808  out += jump_out;
6809  }
6810  }
6811  else if (format_in == RTAUDIO_FLOAT64) {
6812  FLOAT64 *in = (FLOAT64 *)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]] * 2147483647.0);
6816  }
6817  in += jump_in;
6818  out += jump_out;
6819  }
6820  }
6821  }
6822  else if (format_out == RTAUDIO_SINT24) {
6823  INT32 *out = (INT32 *)output;
6824  if (format_in == RTAUDIO_SINT8) {
6825  signed char *in = (signed char *)input;
6826  for (int i=0; i<stream->bufferSize; i++) {
6827  for (j=0; j<channels; j++) {
6828  out[offset_out[j]] = (INT32) in[offset_in[j]];
6829  out[offset_out[j]] <<= 24;
6830  }
6831  in += jump_in;
6832  out += jump_out;
6833  }
6834  }
6835  else if (format_in == RTAUDIO_SINT16) {
6836  INT16 *in = (INT16 *)input;
6837  for (int i=0; i<stream->bufferSize; i++) {
6838  for (j=0; j<channels; j++) {
6839  out[offset_out[j]] = (INT32) in[offset_in[j]];
6840  out[offset_out[j]] <<= 16;
6841  }
6842  in += jump_in;
6843  out += jump_out;
6844  }
6845  }
6846  else if (format_in == RTAUDIO_SINT24) {
6847  // Channel compensation and/or (de)interleaving only.
6848  INT32 *in = (INT32 *)input;
6849  for (int i=0; i<stream->bufferSize; i++) {
6850  for (j=0; j<channels; j++) {
6851  out[offset_out[j]] = in[offset_in[j]];
6852  }
6853  in += jump_in;
6854  out += jump_out;
6855  }
6856  }
6857  else if (format_in == RTAUDIO_SINT32) {
6858  INT32 *in = (INT32 *)input;
6859  for (int i=0; i<stream->bufferSize; i++) {
6860  for (j=0; j<channels; j++) {
6861  out[offset_out[j]] = (INT32) (in[offset_in[j]] & 0xffffff00);
6862  }
6863  in += jump_in;
6864  out += jump_out;
6865  }
6866  }
6867  else if (format_in == RTAUDIO_FLOAT32) {
6868  FLOAT32 *in = (FLOAT32 *)input;
6869  for (int i=0; i<stream->bufferSize; i++) {
6870  for (j=0; j<channels; j++) {
6871  out[offset_out[j]] = (INT32) (in[offset_in[j]] * 2147483647.0);
6872  }
6873  in += jump_in;
6874  out += jump_out;
6875  }
6876  }
6877  else if (format_in == RTAUDIO_FLOAT64) {
6878  FLOAT64 *in = (FLOAT64 *)input;
6879  for (int i=0; i<stream->bufferSize; i++) {
6880  for (j=0; j<channels; j++) {
6881  out[offset_out[j]] = (INT32) (in[offset_in[j]] * 2147483647.0);
6882  }
6883  in += jump_in;
6884  out += jump_out;
6885  }
6886  }
6887  }
6888  else if (format_out == RTAUDIO_SINT16) {
6889  INT16 *out = (INT16 *)output;
6890  if (format_in == RTAUDIO_SINT8) {
6891  signed char *in = (signed char *)input;
6892  for (int i=0; i<stream->bufferSize; i++) {
6893  for (j=0; j<channels; j++) {
6894  out[offset_out[j]] = (INT16) in[offset_in[j]];
6895  out[offset_out[j]] <<= 8;
6896  }
6897  in += jump_in;
6898  out += jump_out;
6899  }
6900  }
6901  else if (format_in == RTAUDIO_SINT16) {
6902  // Channel compensation and/or (de)interleaving only.
6903  INT16 *in = (INT16 *)input;
6904  for (int i=0; i<stream->bufferSize; i++) {
6905  for (j=0; j<channels; j++) {
6906  out[offset_out[j]] = in[offset_in[j]];
6907  }
6908  in += jump_in;
6909  out += jump_out;
6910  }
6911  }
6912  else if (format_in == RTAUDIO_SINT24) {
6913  INT32 *in = (INT32 *)input;
6914  for (int i=0; i<stream->bufferSize; i++) {
6915  for (j=0; j<channels; j++) {
6916  out[offset_out[j]] = (INT16) ((in[offset_in[j]] >> 16) & 0x0000ffff);
6917  }
6918  in += jump_in;
6919  out += jump_out;
6920  }
6921  }
6922  else if (format_in == RTAUDIO_SINT32) {
6923  INT32 *in = (INT32 *)input;
6924  for (int i=0; i<stream->bufferSize; i++) {
6925  for (j=0; j<channels; j++) {
6926  out[offset_out[j]] = (INT16) ((in[offset_in[j]] >> 16) & 0x0000ffff);
6927  }
6928  in += jump_in;
6929  out += jump_out;
6930  }
6931  }
6932  else if (format_in == RTAUDIO_FLOAT32) {
6933  FLOAT32 *in = (FLOAT32 *)input;
6934  for (int i=0; i<stream->bufferSize; i++) {
6935  for (j=0; j<channels; j++) {
6936  out[offset_out[j]] = (INT16) (in[offset_in[j]] * 32767.0);
6937  }
6938  in += jump_in;
6939  out += jump_out;
6940  }
6941  }
6942  else if (format_in == RTAUDIO_FLOAT64) {
6943  FLOAT64 *in = (FLOAT64 *)input;
6944  for (int i=0; i<stream->bufferSize; i++) {
6945  for (j=0; j<channels; j++) {
6946  out[offset_out[j]] = (INT16) (in[offset_in[j]] * 32767.0);
6947  }
6948  in += jump_in;
6949  out += jump_out;
6950  }
6951  }
6952  }
6953  else if (format_out == RTAUDIO_SINT8) {
6954  signed char *out = (signed char *)output;
6955  if (format_in == RTAUDIO_SINT8) {
6956  // Channel compensation and/or (de)interleaving only.
6957  signed char *in = (signed char *)input;
6958  for (int i=0; i<stream->bufferSize; i++) {
6959  for (j=0; j<channels; j++) {
6960  out[offset_out[j]] = in[offset_in[j]];
6961  }
6962  in += jump_in;
6963  out += jump_out;
6964  }
6965  }
6966  if (format_in == RTAUDIO_SINT16) {
6967  INT16 *in = (INT16 *)input;
6968  for (int i=0; i<stream->bufferSize; i++) {
6969  for (j=0; j<channels; j++) {
6970  out[offset_out[j]] = (signed char) ((in[offset_in[j]] >> 8) & 0x00ff);
6971  }
6972  in += jump_in;
6973  out += jump_out;
6974  }
6975  }
6976  else if (format_in == RTAUDIO_SINT24) {
6977  INT32 *in = (INT32 *)input;
6978  for (int i=0; i<stream->bufferSize; i++) {
6979  for (j=0; j<channels; j++) {
6980  out[offset_out[j]] = (signed char) ((in[offset_in[j]] >> 24) & 0x000000ff);
6981  }
6982  in += jump_in;
6983  out += jump_out;
6984  }
6985  }
6986  else if (format_in == RTAUDIO_SINT32) {
6987  INT32 *in = (INT32 *)input;
6988  for (int i=0; i<stream->bufferSize; i++) {
6989  for (j=0; j<channels; j++) {
6990  out[offset_out[j]] = (signed char) ((in[offset_in[j]] >> 24) & 0x000000ff);
6991  }
6992  in += jump_in;
6993  out += jump_out;
6994  }
6995  }
6996  else if (format_in == RTAUDIO_FLOAT32) {
6997  FLOAT32 *in = (FLOAT32 *)input;
6998  for (int i=0; i<stream->bufferSize; i++) {
6999  for (j=0; j<channels; j++) {
7000  out[offset_out[j]] = (signed char) (in[offset_in[j]] * 127.0);
7001  }
7002  in += jump_in;
7003  out += jump_out;
7004  }
7005  }
7006  else if (format_in == RTAUDIO_FLOAT64) {
7007  FLOAT64 *in = (FLOAT64 *)input;
7008  for (int i=0; i<stream->bufferSize; i++) {
7009  for (j=0; j<channels; j++) {
7010  out[offset_out[j]] = (signed char) (in[offset_in[j]] * 127.0);
7011  }
7012  in += jump_in;
7013  out += jump_out;
7014  }
7015  }
7016  }
7017 }
7018 
7019 void RtAudio :: byteSwapBuffer(char *buffer, int samples, RTAUDIO_FORMAT format)
7020 {
7021  register char val;
7022  register char *ptr;
7023 
7024  ptr = buffer;
7025  if (format == RTAUDIO_SINT16) {
7026  for (int i=0; i<samples; i++) {
7027  // Swap 1st and 2nd bytes.
7028  val = *(ptr);
7029  *(ptr) = *(ptr+1);
7030  *(ptr+1) = val;
7031 
7032  // Increment 2 bytes.
7033  ptr += 2;
7034  }
7035  }
7036  else if (format == RTAUDIO_SINT24 ||
7037  format == RTAUDIO_SINT32 ||
7038  format == RTAUDIO_FLOAT32) {
7039  for (int i=0; i<samples; i++) {
7040  // Swap 1st and 4th bytes.
7041  val = *(ptr);
7042  *(ptr) = *(ptr+3);
7043  *(ptr+3) = val;
7044 
7045  // Swap 2nd and 3rd bytes.
7046  ptr += 1;
7047  val = *(ptr);
7048  *(ptr) = *(ptr+1);
7049  *(ptr+1) = val;
7050 
7051  // Increment 4 bytes.
7052  ptr += 4;
7053  }
7054  }
7055  else if (format == RTAUDIO_FLOAT64) {
7056  for (int i=0; i<samples; i++) {
7057  // Swap 1st and 8th bytes
7058  val = *(ptr);
7059  *(ptr) = *(ptr+7);
7060  *(ptr+7) = val;
7061 
7062  // Swap 2nd and 7th bytes
7063  ptr += 1;
7064  val = *(ptr);
7065  *(ptr) = *(ptr+5);
7066  *(ptr+5) = val;
7067 
7068  // Swap 3rd and 6th bytes
7069  ptr += 1;
7070  val = *(ptr);
7071  *(ptr) = *(ptr+3);
7072  *(ptr+3) = val;
7073 
7074  // Swap 4th and 5th bytes
7075  ptr += 1;
7076  val = *(ptr);
7077  *(ptr) = *(ptr+1);
7078  *(ptr+1) = val;
7079 
7080  // Increment 8 bytes.
7081  ptr += 8;
7082  }
7083  }
7084 }
7085 
7086 
7087 // *************************************************** //
7088 //
7089 // RtError class definition.
7090 //
7091 // *************************************************** //
7092 
7093 RtError :: RtError(const char *p, TYPE tipe)
7094 {
7095  type = tipe;
7096  strncpy(error_message, p, 256);
7097 }
7098 
7100 {
7101 }
7102 
7104 {
7105  printf("\n%s\n\n", error_message);
7106 }
7107