usrp: Check return value in fusb_libusb1 _reap()
[debian/gnuradio] / gr-audio-osx / src / audio_osx_source.cc
1 /* -*- c++ -*- */
2 /*
3  * Copyright 2006 Free Software Foundation, Inc.
4  * 
5  * This file is part of GNU Radio.
6  *
7  * GNU Radio is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 3, or (at your option)
10  * any later version.
11  * 
12  * GNU Radio is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  * 
17  * You should have received a copy of the GNU General Public License
18  * along with GNU Radio; see the file COPYING.  If not, write to
19  * the Free Software Foundation, Inc., 51 Franklin Street,
20  * Boston, MA 02110-1301, USA.
21  */
22
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26
27 #define _USE_OMNI_THREADS_
28
29 #include <audio_osx_source.h>
30 #include <gr_io_signature.h>
31 #include <stdexcept>
32 #include <audio_osx.h>
33
34 #define _OSX_AU_DEBUG_ 0
35 #define _OSX_DO_LISTENERS_ 0
36
37 void PrintStreamDesc (AudioStreamBasicDescription *inDesc)
38 {
39   if (inDesc == NULL) {
40     std::cerr << "PrintStreamDesc: Can't print a NULL desc!" << std::endl;
41     return;
42   }
43
44   std::cerr << "  Sample Rate        : " << inDesc->mSampleRate << std::endl;
45   char format_id[4];
46   strncpy (format_id, (char*)(&inDesc->mFormatID), 4);
47   std::cerr << "  Format ID          : " << format_id << std::endl;
48   std::cerr << "  Format Flags       : " << inDesc->mFormatFlags << std::endl;
49   std::cerr << "  Bytes per Packet   : " << inDesc->mBytesPerPacket << std::endl;
50   std::cerr << "  Frames per Packet  : " << inDesc->mFramesPerPacket << std::endl;
51   std::cerr << "  Bytes per Frame    : " << inDesc->mBytesPerFrame << std::endl;
52   std::cerr << "  Channels per Frame : " << inDesc->mChannelsPerFrame << std::endl;
53   std::cerr << "  Bits per Channel   : " << inDesc->mBitsPerChannel << std::endl;
54 }
55
56 // FIXME these should query some kind of user preference
57
58 audio_osx_source::audio_osx_source (int sample_rate,
59                                     const std::string device_name,
60                                     bool do_block,
61                                     int channel_config,
62                                     int max_sample_count)
63   : gr_sync_block ("audio_osx_source",
64                    gr_make_io_signature (0, 0, 0),
65                    gr_make_io_signature (0, 0, 0)),
66     d_deviceSampleRate (0.0), d_outputSampleRate (0.0),
67     d_channel_config (0),
68     d_inputBufferSizeFrames (0), d_inputBufferSizeBytes (0),
69     d_outputBufferSizeFrames (0), d_outputBufferSizeBytes (0),
70     d_deviceBufferSizeFrames (0), d_deviceBufferSizeBytes (0),
71     d_leadSizeFrames (0), d_leadSizeBytes (0),
72     d_trailSizeFrames (0), d_trailSizeBytes (0),
73     d_extraBufferSizeFrames (0), d_extraBufferSizeBytes (0),
74     d_queueSampleCount (0), d_max_sample_count (0),
75     d_n_AvailableInputFrames (0), d_n_ActualInputFrames (0),
76     d_n_user_channels (0), d_n_max_channels (0), d_n_deviceChannels (0),
77     d_do_block (do_block), d_passThrough (false),
78     d_internal (0), d_cond_data (0),
79     d_buffers (0),
80     d_InputAU (0), d_InputBuffer (0), d_OutputBuffer (0),
81     d_AudioConverter (0)
82 {
83   if (sample_rate <= 0) {
84     std::cerr << "Invalid Sample Rate: " << sample_rate << std::endl;
85     throw std::invalid_argument ("audio_osx_source::audio_osx_source");
86   } else
87     d_outputSampleRate = (Float64) sample_rate;
88
89   if (channel_config <= 0 & channel_config != -1) {
90     std::cerr << "Invalid Channel Config: " << channel_config << std::endl;
91     throw std::invalid_argument ("audio_osx_source::audio_osx_source");
92   } else if (channel_config == -1) {
93 // no user input; try "device name" instead
94     int l_n_channels = (int) strtol (device_name.data(), (char **)NULL, 10);
95     if (l_n_channels == 0 & errno) {
96       std::cerr << "Error Converting Device Name: " << errno << std::endl;
97       throw std::invalid_argument ("audio_osx_source::audio_osx_source");
98     }
99     if (l_n_channels <= 0)
100       channel_config = 2;
101     else
102       channel_config = l_n_channels;
103   }
104
105   d_channel_config = channel_config;
106
107 // check that the max # of samples to store is valid
108
109   if (max_sample_count == -1)
110     max_sample_count = sample_rate;
111   else if (max_sample_count <= 0) {
112     std::cerr << "Invalid Max Sample Count: " << max_sample_count << std::endl;
113     throw std::invalid_argument ("audio_osx_source::audio_osx_source");
114   }
115
116   d_max_sample_count = max_sample_count;
117
118 #if _OSX_AU_DEBUG_
119   std::cerr << "source(): max # samples = " << d_max_sample_count << std::endl;
120 #endif
121
122   OSStatus err = noErr;
123
124 // create the default AudioUnit for input
125
126 // Open the default input unit
127 #ifndef GR_USE_OLD_AUDIO_UNIT
128   AudioComponentDescription InputDesc;
129 #else
130   ComponentDescription InputDesc;
131 #endif
132   
133
134   InputDesc.componentType = kAudioUnitType_Output;
135   InputDesc.componentSubType = kAudioUnitSubType_HALOutput;
136   InputDesc.componentManufacturer = kAudioUnitManufacturer_Apple;
137   InputDesc.componentFlags = 0;
138   InputDesc.componentFlagsMask = 0;
139
140 #ifndef GR_USE_OLD_AUDIO_UNIT
141   AudioComponent comp = AudioComponentFindNext (NULL, &InputDesc);
142 #else
143   Component comp = FindNextComponent (NULL, &InputDesc);
144 #endif
145   
146   if (comp == NULL) {
147 #ifndef GR_USE_OLD_AUDIO_UNIT
148     std::cerr << "AudioComponentFindNext Error" << std::endl;
149 #else
150     std::cerr << "FindNextComponent Error" << std::endl;
151 #endif
152     throw std::runtime_error ("audio_osx_source::audio_osx_source");
153   }
154
155 #ifndef GR_USE_OLD_AUDIO_UNIT
156   err = AudioComponentInstanceNew (comp, &d_InputAU);
157   CheckErrorAndThrow (err, "AudioComponentInstanceNew",
158                       "audio_osx_source::audio_osx_source");
159 #else
160   err = OpenAComponent (comp, &d_InputAU);
161   CheckErrorAndThrow (err, "OpenAComponent",
162                       "audio_osx_source::audio_osx_source");
163 #endif
164   
165
166   UInt32 enableIO;
167
168 // must enable the AUHAL for input and disable output 
169 // before setting the AUHAL's current device
170
171 // Enable input on the AUHAL
172   enableIO = 1;
173   err = AudioUnitSetProperty (d_InputAU,
174                               kAudioOutputUnitProperty_EnableIO,
175                               kAudioUnitScope_Input,
176                               1, // input element
177                               &enableIO,
178                               sizeof (UInt32));
179   CheckErrorAndThrow (err, "AudioUnitSetProperty Input Enable",
180                       "audio_osx_source::audio_osx_source");
181
182 // Disable output on the AUHAL
183   enableIO = 0;
184   err = AudioUnitSetProperty (d_InputAU,
185                               kAudioOutputUnitProperty_EnableIO,
186                               kAudioUnitScope_Output,
187                               0, // output element
188                               &enableIO,
189                               sizeof (UInt32));
190   CheckErrorAndThrow (err, "AudioUnitSetProperty Output Disable",
191                       "audio_osx_source::audio_osx_source");
192
193 // set the default input device for our input AU
194
195   SetDefaultInputDeviceAsCurrent ();
196
197 #if _OSX_DO_LISTENERS_
198 // set up a listener if default hardware input device changes
199
200   err = AudioHardwareAddPropertyListener
201     (kAudioHardwarePropertyDefaultInputDevice,
202      (AudioHardwarePropertyListenerProc) HardwareListener,
203      this);
204
205   CheckErrorAndThrow (err, "AudioHardwareAddPropertyListener",
206                       "audio_osx_source::audio_osx_source");
207
208 // Add a listener for any changes in the input AU's output stream
209 // the function "UnitListener" will be called if the stream format
210 // changes for whatever reason
211
212   err = AudioUnitAddPropertyListener
213     (d_InputAU,
214      kAudioUnitProperty_StreamFormat,
215      (AudioUnitPropertyListenerProc) UnitListener,
216      this);
217   CheckErrorAndThrow (err, "Adding Unit Property Listener",
218                       "audio_osx_source::audio_osx_source");
219 #endif
220
221 // Now find out if it actually can do input.
222
223   UInt32 hasInput = 0;
224   UInt32 dataSize = sizeof (hasInput);
225   err = AudioUnitGetProperty (d_InputAU,
226                               kAudioOutputUnitProperty_HasIO,
227                               kAudioUnitScope_Input,
228                               1,
229                               &hasInput,
230                               &dataSize);
231   CheckErrorAndThrow (err, "AudioUnitGetProperty HasIO",
232                       "audio_osx_source::audio_osx_source");
233   if (hasInput == 0) {
234     std::cerr << "Selected Audio Device does not support Input." << std::endl;
235     throw std::runtime_error ("audio_osx_source::audio_osx_source");
236   }
237
238 // Set up a callback function to retrieve input from the Audio Device
239
240   AURenderCallbackStruct AUCallBack;
241
242   AUCallBack.inputProc = (AURenderCallback)(audio_osx_source::AUInputCallback);
243   AUCallBack.inputProcRefCon = this;
244
245   err = AudioUnitSetProperty (d_InputAU,
246                               kAudioOutputUnitProperty_SetInputCallback,
247                               kAudioUnitScope_Global,
248                               0,
249                               &AUCallBack,
250                               sizeof (AURenderCallbackStruct));
251   CheckErrorAndThrow (err, "AudioUnitSetProperty Input Callback",
252                       "audio_osx_source::audio_osx_source");
253
254   UInt32 propertySize;
255   AudioStreamBasicDescription asbd_device, asbd_client, asbd_user;
256
257 // asbd_device: ASBD of the device that is creating the input data stream
258 // asbd_client: ASBD of the client size (output) of the hardware device
259 // asbd_user:   ASBD of the user's arguments
260
261 // Get the Stream Format (device side)
262
263   propertySize = sizeof (asbd_device);
264   err = AudioUnitGetProperty (d_InputAU,
265                               kAudioUnitProperty_StreamFormat,
266                               kAudioUnitScope_Input,
267                               1,
268                               &asbd_device,
269                               &propertySize);
270   CheckErrorAndThrow (err, "AudioUnitGetProperty Device Input Stream Format",
271                       "audio_osx_source::audio_osx_source");
272
273 #if _OSX_AU_DEBUG_
274   std::cerr << std::endl << "---- Device Stream Format ----" << std::endl;
275   PrintStreamDesc (&asbd_device);
276 #endif
277
278 // Get the Stream Format (client side)
279   propertySize = sizeof (asbd_client);
280   err = AudioUnitGetProperty (d_InputAU,
281                               kAudioUnitProperty_StreamFormat,
282                               kAudioUnitScope_Output,
283                               1,
284                               &asbd_client,
285                               &propertySize);
286   CheckErrorAndThrow (err, "AudioUnitGetProperty Device Ouput Stream Format",
287                       "audio_osx_source::audio_osx_source");
288
289 #if _OSX_AU_DEBUG_
290   std::cerr << std::endl << "---- Client Stream Format ----" << std::endl;
291   PrintStreamDesc (&asbd_client);
292 #endif
293
294 // Set the format of all the AUs to the input/output devices channel count
295
296 // get the max number of input (& thus output) channels supported by
297 // this device
298   d_n_max_channels = asbd_client.mChannelsPerFrame;
299
300 // create the output io signature;
301 // no input siganture to set (source is hardware)
302   set_output_signature (gr_make_io_signature (1,
303                                               d_n_max_channels,
304                                               sizeof (float)));
305
306 // allocate the output circular buffer(s), one per channel
307   d_buffers = (circular_buffer<float>**) new
308     circular_buffer<float>* [d_n_max_channels];
309   UInt32 n_alloc = (UInt32) ceil ((double) d_max_sample_count);
310   for (UInt32 n = 0; n < d_n_max_channels; n++) {
311     d_buffers[n] = new circular_buffer<float> (n_alloc, false, false);
312   }
313
314   d_deviceSampleRate = asbd_device.mSampleRate;
315   d_n_deviceChannels = asbd_device.mChannelsPerFrame;
316
317 // create an ASBD for the user's wants
318
319   asbd_user.mSampleRate = d_outputSampleRate;
320   asbd_user.mFormatID = kAudioFormatLinearPCM;
321   asbd_user.mFormatFlags = (kLinearPCMFormatFlagIsFloat |
322                             GR_PCM_ENDIANNESS |
323                             kLinearPCMFormatFlagIsPacked |
324                             kAudioFormatFlagIsNonInterleaved);
325   asbd_user.mBytesPerPacket = 4;
326   asbd_user.mFramesPerPacket = 1;
327   asbd_user.mBytesPerFrame = 4;
328   asbd_user.mChannelsPerFrame = d_n_max_channels;
329   asbd_user.mBitsPerChannel = 32;
330
331   if (d_deviceSampleRate == d_outputSampleRate) {
332 // no need to do conversion if asbd_client matches user wants
333     d_passThrough = true;
334     d_leadSizeFrames = d_trailSizeFrames = 0L;
335   } else {
336     d_passThrough = false;
337 // Create the audio converter
338
339     err = AudioConverterNew (&asbd_client, &asbd_user, &d_AudioConverter);
340     CheckErrorAndThrow (err, "AudioConverterNew",
341                         "audio_osx_source::audio_osx_source");
342
343 // Set the audio converter sample rate quality to "max" ...
344 // requires more samples, but should sound nicer
345
346     UInt32 ACQuality = kAudioConverterQuality_Max;
347     propertySize = sizeof (ACQuality);
348     err = AudioConverterSetProperty (d_AudioConverter,
349                                      kAudioConverterSampleRateConverterQuality,
350                                      propertySize,
351                                      &ACQuality);
352     CheckErrorAndThrow (err, "AudioConverterSetProperty "
353                         "SampleRateConverterQuality",
354                         "audio_osx_source::audio_osx_source");
355
356 // set the audio converter's prime method to "pre",
357 // which uses both leading and trailing frames
358 // from the "current input".  All of this is handled
359 // internally by the AudioConverter; we just supply
360 // the frames for conversion.
361
362 //   UInt32 ACPrimeMethod = kConverterPrimeMethod_None;
363     UInt32 ACPrimeMethod = kConverterPrimeMethod_Pre;
364     propertySize = sizeof (ACPrimeMethod);
365     err = AudioConverterSetProperty (d_AudioConverter, 
366                                      kAudioConverterPrimeMethod,
367                                      propertySize,
368                                      &ACPrimeMethod);
369     CheckErrorAndThrow (err, "AudioConverterSetProperty PrimeMethod",
370                         "audio_osx_source::audio_osx_source");
371
372 // Get the size of the I/O buffer(s) to allow for pre-allocated buffers
373       
374 // lead frame info (trail frame info is ignored)
375
376     AudioConverterPrimeInfo ACPrimeInfo = {0, 0};
377     propertySize = sizeof (ACPrimeInfo);
378     err = AudioConverterGetProperty (d_AudioConverter, 
379                                      kAudioConverterPrimeInfo,
380                                      &propertySize,
381                                      &ACPrimeInfo);
382     CheckErrorAndThrow (err, "AudioConverterGetProperty PrimeInfo",
383                         "audio_osx_source::audio_osx_source");
384
385     switch (ACPrimeMethod) {
386     case (kConverterPrimeMethod_None):
387       d_leadSizeFrames =
388         d_trailSizeFrames = 0L;
389       break;
390     case (kConverterPrimeMethod_Normal):
391       d_leadSizeFrames = 0L;
392       d_trailSizeFrames = ACPrimeInfo.trailingFrames;
393       break;
394     default:
395       d_leadSizeFrames = ACPrimeInfo.leadingFrames;
396       d_trailSizeFrames = ACPrimeInfo.trailingFrames;
397     }
398   }
399   d_leadSizeBytes = d_leadSizeFrames * sizeof (Float32);
400   d_trailSizeBytes = d_trailSizeFrames * sizeof (Float32);
401
402   propertySize = sizeof (d_deviceBufferSizeFrames);
403   err = AudioUnitGetProperty (d_InputAU,
404                               kAudioDevicePropertyBufferFrameSize,
405                               kAudioUnitScope_Global,
406                               0,
407                               &d_deviceBufferSizeFrames,
408                               &propertySize);
409   CheckErrorAndThrow (err, "AudioUnitGetProperty Buffer Frame Size",
410                       "audio_osx_source::audio_osx_source");
411
412   d_deviceBufferSizeBytes = d_deviceBufferSizeFrames * sizeof (Float32);
413   d_inputBufferSizeBytes = d_deviceBufferSizeBytes + d_leadSizeBytes;
414   d_inputBufferSizeFrames = d_deviceBufferSizeFrames + d_leadSizeFrames;
415
416 // outBufSizeBytes = floor (inBufSizeBytes * rate_out / rate_in)
417 // since this is rarely exact, we need another buffer to hold
418 // "extra" samples not processed at any given sampling period
419 // this buffer must be at least 4 floats in size, but generally
420 // follows the rule that
421 // extraBufSize =  ceil (rate_in / rate_out)*sizeof(float)
422
423   d_extraBufferSizeFrames = ((UInt32) ceil (d_deviceSampleRate
424                                             / d_outputSampleRate)
425                              * sizeof (float));
426   if (d_extraBufferSizeFrames < 4)
427     d_extraBufferSizeFrames = 4;
428   d_extraBufferSizeBytes = d_extraBufferSizeFrames * sizeof (float);
429
430   d_outputBufferSizeFrames = (UInt32) ceil (((Float64) d_inputBufferSizeFrames)
431                                             * d_outputSampleRate
432                                             / d_deviceSampleRate);
433   d_outputBufferSizeBytes = d_outputBufferSizeFrames * sizeof (float);
434   d_inputBufferSizeFrames += d_extraBufferSizeFrames;
435
436 // pre-alloc all buffers
437
438   AllocAudioBufferList (&d_InputBuffer, d_n_deviceChannels,
439                         d_inputBufferSizeBytes);
440   if (d_passThrough == false) {
441     AllocAudioBufferList (&d_OutputBuffer, d_n_max_channels,
442                           d_outputBufferSizeBytes);
443   } else {
444     d_OutputBuffer = d_InputBuffer;
445   }
446
447 // create the stuff to regulate I/O
448
449   d_cond_data = new mld_condition ();
450   if (d_cond_data == NULL)
451     CheckErrorAndThrow (errno, "new mld_condition (data)",
452                         "audio_osx_source::audio_osx_source");
453   d_internal = d_cond_data->mutex ();
454
455 // initialize the AU for input
456
457   err = AudioUnitInitialize (d_InputAU);
458   CheckErrorAndThrow (err, "AudioUnitInitialize",
459                       "audio_osx_source::audio_osx_source");
460
461 #if _OSX_AU_DEBUG_
462   std::cerr << "audio_osx_source Parameters:" << std::endl;
463   std::cerr << "  Device Sample Rate is " << d_deviceSampleRate << std::endl;
464   std::cerr << "  User Sample Rate is " << d_outputSampleRate << std::endl;
465   std::cerr << "  Max Sample Count is " << d_max_sample_count << std::endl;
466   std::cerr << "  # Device Channels is " << d_n_deviceChannels << std::endl;
467   std::cerr << "  # Max Channels is " << d_n_max_channels << std::endl;
468   std::cerr << "  Device Buffer Size is Frames = " << d_deviceBufferSizeFrames << std::endl;
469   std::cerr << "  Lead Size is Frames = " << d_leadSizeFrames << std::endl;
470   std::cerr << "  Trail Size is Frames = " << d_trailSizeFrames << std::endl;
471   std::cerr << "  Input Buffer Size is Frames = " << d_inputBufferSizeFrames << std::endl;
472   std::cerr << "  Output Buffer Size is Frames = " << d_outputBufferSizeFrames << std::endl;
473 #endif
474 }
475
476 void
477 audio_osx_source::AllocAudioBufferList (AudioBufferList** t_ABL,
478                                         UInt32 n_channels,
479                                         UInt32 bufferSizeBytes)
480 {
481   FreeAudioBufferList (t_ABL);
482   UInt32 propertySize = (offsetof (AudioBufferList, mBuffers[0]) +
483                          (sizeof (AudioBuffer) * n_channels));
484   *t_ABL = (AudioBufferList*) calloc (1, propertySize);
485   (*t_ABL)->mNumberBuffers = n_channels;
486
487   int counter = n_channels;
488
489   while (--counter >= 0) {
490     (*t_ABL)->mBuffers[counter].mNumberChannels = 1;
491     (*t_ABL)->mBuffers[counter].mDataByteSize = bufferSizeBytes;
492     (*t_ABL)->mBuffers[counter].mData = calloc (1, bufferSizeBytes);
493   }
494 }
495
496 void
497 audio_osx_source::FreeAudioBufferList (AudioBufferList** t_ABL)
498 {
499 // free pre-allocated audio buffer, if it exists
500   if (*t_ABL != NULL) {
501     int counter = (*t_ABL)->mNumberBuffers;
502     while (--counter >= 0)
503       free ((*t_ABL)->mBuffers[counter].mData);
504     free (*t_ABL);
505     (*t_ABL) = 0;
506   }
507 }
508
509 bool audio_osx_source::IsRunning ()
510 {
511   UInt32 AURunning = 0, AUSize = sizeof (UInt32);
512
513   OSStatus err = AudioUnitGetProperty (d_InputAU,
514                                        kAudioOutputUnitProperty_IsRunning,
515                                        kAudioUnitScope_Global,
516                                        0,
517                                        &AURunning,
518                                        &AUSize);
519   CheckErrorAndThrow (err, "AudioUnitGetProperty IsRunning",
520                       "audio_osx_source::IsRunning");
521
522   return (AURunning);
523 }
524
525 bool audio_osx_source::start ()
526 {
527   if (! IsRunning ()) {
528     OSStatus err = AudioOutputUnitStart (d_InputAU);
529     CheckErrorAndThrow (err, "AudioOutputUnitStart",
530                         "audio_osx_source::start");
531   }
532
533   return (true);
534 }
535
536 bool audio_osx_source::stop ()
537 {
538   if (IsRunning ()) {
539     OSStatus err = AudioOutputUnitStop (d_InputAU);
540     CheckErrorAndThrow (err, "AudioOutputUnitStart",
541                         "audio_osx_source::stop");
542     for (UInt32 n = 0; n < d_n_user_channels; n++) {
543       d_buffers[n]->abort ();
544     }
545   }
546
547   return (true);
548 }
549
550 audio_osx_source::~audio_osx_source ()
551 {
552   OSStatus err = noErr;
553
554 // stop the AudioUnit
555   stop();
556
557 #if _OSX_DO_LISTENERS_
558 // remove the listeners
559
560   err = AudioUnitRemovePropertyListener
561     (d_InputAU,
562      kAudioUnitProperty_StreamFormat,
563      (AudioUnitPropertyListenerProc) UnitListener);
564   CheckError (err, "~audio_osx_source: AudioUnitRemovePropertyListener");
565
566   err = AudioHardwareRemovePropertyListener
567     (kAudioHardwarePropertyDefaultInputDevice,
568      (AudioHardwarePropertyListenerProc) HardwareListener);
569   CheckError (err, "~audio_osx_source: AudioHardwareRemovePropertyListener");
570 #endif
571
572 // free pre-allocated audio buffers
573   FreeAudioBufferList (&d_InputBuffer);
574
575   if (d_passThrough == false) {
576     err = AudioConverterDispose (d_AudioConverter);
577     CheckError (err, "~audio_osx_source: AudioConverterDispose");
578     FreeAudioBufferList (&d_OutputBuffer);
579   }
580
581 // remove the audio unit
582   err = AudioUnitUninitialize (d_InputAU);
583   CheckError (err, "~audio_osx_source: AudioUnitUninitialize");
584
585 #ifndef GR_USE_OLD_AUDIO_UNIT
586   err = AudioComponentInstanceDispose (d_InputAU);
587   CheckError (err, "~audio_osx_source: AudioComponentInstanceDispose");
588 #else
589   err = CloseComponent (d_InputAU);
590   CheckError (err, "~audio_osx_source: CloseComponent");
591 #endif
592
593 // empty and delete the queues
594   for (UInt32 n = 0; n < d_n_max_channels; n++) {
595     delete d_buffers[n];
596     d_buffers[n] = 0;
597   }
598   delete [] d_buffers;
599   d_buffers = 0;
600
601 // close and delete the control stuff
602   delete d_cond_data;
603 }
604
605 audio_osx_source_sptr
606 audio_osx_make_source (int sampling_freq,
607                        const std::string device_name,
608                        bool do_block,
609                        int channel_config,
610                        int max_sample_count)
611 {
612   return audio_osx_source_sptr (new audio_osx_source (sampling_freq,
613                                                       device_name,
614                                                       do_block,
615                                                       channel_config,
616                                                       max_sample_count));
617 }
618
619 bool
620 audio_osx_source::check_topology (int ninputs, int noutputs)
621 {
622 // check # inputs to make sure it's valid
623   if (ninputs != 0) {
624     std::cerr << "audio_osx_source::check_topology(): number of input "
625               << "streams provided (" << ninputs
626               << ") should be 0." << std::endl;
627     throw std::runtime_error ("audio_osx_source::check_topology()");
628   }
629
630 // check # outputs to make sure it's valid
631   if ((noutputs < 1) | (noutputs > (int) d_n_max_channels)) {
632     std::cerr << "audio_osx_source::check_topology(): number of output "
633               << "streams provided (" << noutputs << ") should be in [1,"
634               << d_n_max_channels << "] for the selected audio device."
635               << std::endl;
636     throw std::runtime_error ("audio_osx_source::check_topology()");
637   }
638
639 // save the actual number of output (user) channels
640   d_n_user_channels = noutputs;
641
642 #if _OSX_AU_DEBUG_
643   std::cerr << "chk_topo: Actual # user output channels = "
644             << noutputs << std::endl;
645 #endif
646
647   return (true);
648 }
649
650 int
651 audio_osx_source::work
652 (int noutput_items,
653  gr_vector_const_void_star &input_items,
654  gr_vector_void_star &output_items)
655 {
656   // acquire control to do processing here only
657   d_internal->lock ();
658
659 #if _OSX_AU_DEBUG_
660   std::cerr << "work1: SC = " << d_queueSampleCount
661             << ", #OI = " << noutput_items
662             << ", #Chan = " << output_items.size() << std::endl;
663 #endif
664
665   // set the actual # of output items to the 'desired' amount then
666   // verify that data is available; if not enough data is available,
667   // either wait until it is (is "do_block" is true), return (0) is no
668   // data is available and "do_block" is false, or process the actual
669   // amount of available data.
670
671   UInt32 actual_noutput_items = noutput_items;
672
673   if (d_queueSampleCount < actual_noutput_items) {
674     if (d_queueSampleCount == 0) {
675       // no data; do_block decides what to do
676       if (d_do_block == true) {
677         while (d_queueSampleCount == 0) {
678           // release control so-as to allow data to be retrieved;
679           // block until there is data to return
680           d_cond_data->wait ();
681           // the condition's signal() was called; acquire control to
682           // keep thread safe
683         }
684       } else {
685         // no data & not blocking; return nothing
686         // release control so-as to allow data to be retrieved
687         d_internal->unlock ();
688         return (0);
689       }
690     }
691     // use the actual amount of available data
692     actual_noutput_items = d_queueSampleCount;
693   }
694
695   // number of channels
696   int l_counter = (int) output_items.size();
697
698   // copy the items from the circular buffer(s) to 'work's output buffers
699   // verify that the number copied out is as expected.
700
701   while (--l_counter >= 0) {
702     size_t t_n_output_items = actual_noutput_items;
703     d_buffers[l_counter]->dequeue ((float*) output_items[l_counter],
704                                    &t_n_output_items);
705     if (t_n_output_items != actual_noutput_items) {
706       std::cerr << "audio_osx_source::work(): ERROR: number of "
707                 << "available items changing unexpectedly; expecting "
708                 << actual_noutput_items << ", got "
709                 << t_n_output_items << "." << std::endl;
710       throw std::runtime_error ("audio_osx_source::work()");
711     }
712   }
713
714   // subtract the actual number of items removed from the buffer(s)
715   // from the local accounting of the number of available samples
716
717   d_queueSampleCount -= actual_noutput_items;
718
719 #if _OSX_AU_DEBUG_
720   std::cerr << "work2: SC = " << d_queueSampleCount
721             << ", act#OI = " << actual_noutput_items << std::endl;
722 #endif
723
724   // release control to allow for other processing parts to run
725
726   d_internal->unlock ();
727
728 #if _OSX_AU_DEBUG_
729   std::cerr << "work3: Returning." << std::endl;
730 #endif
731
732   return (actual_noutput_items);
733 }
734
735 OSStatus
736 audio_osx_source::ConverterCallback
737 (AudioConverterRef inAudioConverter,
738  UInt32* ioNumberDataPackets,
739  AudioBufferList* ioData,
740  AudioStreamPacketDescription** ioASPD,
741  void* inUserData)
742 {
743   // take current device buffers and copy them to the tail of the
744   // input buffers the lead buffer is already there in the first
745   // d_leadSizeFrames slots
746
747   audio_osx_source* This = static_cast<audio_osx_source*>(inUserData);
748   AudioBufferList* l_inputABL = This->d_InputBuffer;
749   UInt32 totalInputBufferSizeBytes = ((*ioNumberDataPackets) * sizeof (float));
750   int counter = This->d_n_deviceChannels;
751   ioData->mNumberBuffers = This->d_n_deviceChannels;
752   This->d_n_ActualInputFrames = (*ioNumberDataPackets);
753
754 #if _OSX_AU_DEBUG_
755   std::cerr << "cc1: io#DP = " << (*ioNumberDataPackets)
756             << ", TIBSB = " << totalInputBufferSizeBytes
757             << ", #C = " << counter << std::endl;
758 #endif
759
760   while (--counter >= 0)  {
761     AudioBuffer* l_ioD_AB = &(ioData->mBuffers[counter]);
762     l_ioD_AB->mNumberChannels = 1;
763     l_ioD_AB->mData = (float*)(l_inputABL->mBuffers[counter].mData);
764     l_ioD_AB->mDataByteSize = totalInputBufferSizeBytes;
765   }
766
767 #if _OSX_AU_DEBUG_
768   std::cerr << "cc2: Returning." << std::endl;
769 #endif
770
771   return (noErr);
772 }
773
774 OSStatus
775 audio_osx_source::AUInputCallback (void* inRefCon,
776                                    AudioUnitRenderActionFlags* ioActionFlags,
777                                    const AudioTimeStamp* inTimeStamp,
778                                    UInt32 inBusNumber,
779                                    UInt32 inNumberFrames,
780                                    AudioBufferList* ioData)
781 {
782   OSStatus err = noErr;
783   audio_osx_source* This = static_cast<audio_osx_source*>(inRefCon);
784
785   This->d_internal->lock ();
786
787 #if _OSX_AU_DEBUG_
788   std::cerr << "cb0: in#F = " << inNumberFrames
789             << ", inBN = " << inBusNumber
790             << ", SC = " << This->d_queueSampleCount << std::endl;
791 #endif
792
793 // Get the new audio data from the input device
794
795   err = AudioUnitRender (This->d_InputAU,
796                          ioActionFlags,
797                          inTimeStamp,
798                          1, //inBusNumber,
799                          inNumberFrames,
800                          This->d_InputBuffer);
801   CheckErrorAndThrow (err, "AudioUnitRender",
802                       "audio_osx_source::AUInputCallback");
803
804   UInt32 AvailableInputFrames = inNumberFrames;
805   This->d_n_AvailableInputFrames = inNumberFrames;
806
807 // get the number of actual output frames,
808 // either via converting the buffer or not
809
810   UInt32 ActualOutputFrames;
811
812   if (This->d_passThrough == true) {
813     ActualOutputFrames = AvailableInputFrames;
814   } else {
815     UInt32 AvailableInputBytes = AvailableInputFrames * sizeof (float);
816     UInt32 AvailableOutputBytes = AvailableInputBytes;
817     UInt32 AvailableOutputFrames = AvailableOutputBytes / sizeof (float);
818     UInt32 propertySize = sizeof (AvailableOutputBytes);
819     err = AudioConverterGetProperty (This->d_AudioConverter,
820                    kAudioConverterPropertyCalculateOutputBufferSize,
821                                      &propertySize,
822                                      &AvailableOutputBytes);
823     CheckErrorAndThrow (err, "AudioConverterGetProperty CalculateOutputBufferSize", "audio_osx_source::audio_osx_source");
824
825     AvailableOutputFrames = AvailableOutputBytes / sizeof (float);
826
827 #if 0
828 // when decimating too much, the output sounds warbly due to
829 // fluctuating # of output frames
830 // This should not be a surprise, but there's probably some
831 // clever programming that could lessed the effect ...
832 // like finding the "ideal" # of output frames, and keeping
833 // that number constant no matter the # of input frames
834     UInt32 l_InputBytes = AvailableOutputBytes;
835     propertySize = sizeof (AvailableOutputBytes);
836     err = AudioConverterGetProperty (This->d_AudioConverter,
837                      kAudioConverterPropertyCalculateInputBufferSize,
838                                      &propertySize,
839                                      &l_InputBytes);
840     CheckErrorAndThrow (err, "AudioConverterGetProperty CalculateInputBufferSize", "audio_osx_source::audio_osx_source");
841
842     if (l_InputBytes < AvailableInputBytes) {
843 // OK to zero pad the input a little
844       AvailableOutputFrames += 1;
845       AvailableOutputBytes = AvailableOutputFrames * sizeof (float);
846     }
847 #endif
848
849 #if _OSX_AU_DEBUG_
850     std::cerr << "cb1:  avail: #IF = " << AvailableInputFrames
851               << ", #OF = " << AvailableOutputFrames << std::endl;
852 #endif
853     ActualOutputFrames = AvailableOutputFrames;
854
855 // convert the data to the correct rate
856 // on input, ActualOutputFrames is the number of available output frames
857
858     err = AudioConverterFillComplexBuffer (This->d_AudioConverter,
859            (AudioConverterComplexInputDataProc)(This->ConverterCallback),
860                                            inRefCon,
861                                            &ActualOutputFrames,
862                                            This->d_OutputBuffer,
863                                            NULL);
864     CheckErrorAndThrow (err, "AudioConverterFillComplexBuffer",
865                         "audio_osx_source::AUInputCallback");
866
867 // on output, ActualOutputFrames is the actual number of output frames
868
869 #if _OSX_AU_DEBUG_
870     std::cerr << "cb2: actual: #IF = " << This->d_n_ActualInputFrames
871               << ", #OF = " << AvailableOutputFrames << std::endl;
872     if (This->d_n_ActualInputFrames != AvailableInputFrames)
873       std::cerr << "cb2.1: avail#IF = " << AvailableInputFrames
874                 << ", actual#IF = " << This->d_n_ActualInputFrames << std::endl;
875 #endif
876   }
877
878 // add the output frames to the buffers' queue, checking for overflow
879
880   int l_counter = This->d_n_user_channels;
881   int res = 0;
882
883   while (--l_counter >= 0) {
884     float* inBuffer = (float*) This->d_OutputBuffer->mBuffers[l_counter].mData;
885
886 #if _OSX_AU_DEBUG_
887     std::cerr << "cb3: enqueuing audio data." << std::endl;
888 #endif
889
890     int l_res = This->d_buffers[l_counter]->enqueue (inBuffer, ActualOutputFrames);
891     if (l_res == -1)
892       res = -1;
893   }
894
895   if (res == -1) {
896 // data coming in too fast
897 // drop oldest buffer
898     fputs ("aO", stderr);
899     fflush (stderr);
900 // set the local number of samples available to the max
901     This->d_queueSampleCount = This->d_buffers[0]->buffer_length_items ();
902   } else {
903 // keep up the local sample count
904     This->d_queueSampleCount += ActualOutputFrames;
905   }
906
907 #if _OSX_AU_DEBUG_
908   std::cerr << "cb4: #OI = " << ActualOutputFrames
909             << ", #Cnt = " << This->d_queueSampleCount
910             << ", mSC = " << This->d_max_sample_count << std::endl;
911 #endif
912
913 // signal that data is available, if appropraite
914   This->d_cond_data->signal ();
915
916 #if _OSX_AU_DEBUG_
917   std::cerr << "cb5: releasing internal mutex." << std::endl;
918 #endif
919
920 // release control to allow for other processing parts to run
921   This->d_internal->unlock ();
922
923 #if _OSX_AU_DEBUG_
924   std::cerr << "cb6: returning." << std::endl;
925 #endif
926
927   return (err);
928 }
929
930 void
931 audio_osx_source::SetDefaultInputDeviceAsCurrent
932 ()
933 {
934 // set the default input device
935   AudioDeviceID deviceID;
936   UInt32 dataSize = sizeof (AudioDeviceID);
937   AudioHardwareGetProperty (kAudioHardwarePropertyDefaultInputDevice,
938                             &dataSize,
939                             &deviceID);
940   OSStatus err = AudioUnitSetProperty (d_InputAU,
941                                        kAudioOutputUnitProperty_CurrentDevice,
942                                        kAudioUnitScope_Global,
943                                        0,
944                                        &deviceID,
945                                        sizeof (AudioDeviceID));
946   CheckErrorAndThrow (err, "AudioUnitSetProperty Current Device",
947                       "audio_osx_source::SetDefaultInputDeviceAsCurrent");
948 }
949
950 #if _OSX_DO_LISTENERS_
951 OSStatus
952 audio_osx_source::HardwareListener
953 (AudioHardwarePropertyID inPropertyID, 
954  void *inClientData)
955 {
956   OSStatus err = noErr;
957   audio_osx_source* This = static_cast<audio_osx_source*>(inClientData);
958
959   std::cerr << "a_o_s::HardwareListener" << std::endl;
960
961 // set the new default hardware input device for use by our AU
962
963   This->SetDefaultInputDeviceAsCurrent ();
964
965 // reset the converter to tell it that the stream has changed
966
967   err = AudioConverterReset (This->d_AudioConverter);
968   CheckErrorAndThrow (err, "AudioConverterReset",
969                       "audio_osx_source::UnitListener");
970
971   return (err);
972 }
973
974 OSStatus
975 audio_osx_source::UnitListener
976 (void *inRefCon,
977  AudioUnit ci,
978  AudioUnitPropertyID inID,
979  AudioUnitScope inScope,
980  AudioUnitElement inElement)
981 {
982   OSStatus err = noErr;
983   audio_osx_source* This = static_cast<audio_osx_source*>(inRefCon);
984   AudioStreamBasicDescription asbd;                     
985
986   std::cerr << "a_o_s::UnitListener" << std::endl;
987
988 // get the converter's input ASBD (for printing)
989
990   UInt32 propertySize = sizeof (asbd);
991   err = AudioConverterGetProperty (This->d_AudioConverter,
992                                    kAudioConverterCurrentInputStreamDescription,
993                                    &propertySize,
994                                    &asbd);
995   CheckErrorAndThrow (err, "AudioConverterGetProperty "
996                       "CurrentInputStreamDescription",
997                       "audio_osx_source::UnitListener");
998
999   std::cerr << "UnitListener: Input Source changed." << std::endl
1000             << "Old Source Output Info:" << std::endl;
1001   PrintStreamDesc (&asbd);
1002
1003 // get the new input unit's output ASBD
1004
1005   propertySize = sizeof (asbd);
1006   err = AudioUnitGetProperty (This->d_InputAU,
1007                               kAudioUnitProperty_StreamFormat,
1008                               kAudioUnitScope_Output, 1,
1009                               &asbd, &propertySize);
1010   CheckErrorAndThrow (err, "AudioUnitGetProperty StreamFormat",
1011                       "audio_osx_source::UnitListener");
1012
1013   std::cerr << "New Source Output Info:" << std::endl;
1014   PrintStreamDesc (&asbd);
1015
1016 // set the converter's input ASBD to this
1017
1018   err = AudioConverterSetProperty (This->d_AudioConverter,
1019                                    kAudioConverterCurrentInputStreamDescription,
1020                                    propertySize,
1021                                    &asbd);
1022   CheckErrorAndThrow (err, "AudioConverterSetProperty "
1023                       "CurrentInputStreamDescription",
1024                       "audio_osx_source::UnitListener");
1025
1026 // reset the converter to tell it that the stream has changed
1027
1028   err = AudioConverterReset (This->d_AudioConverter);
1029   CheckErrorAndThrow (err, "AudioConverterReset",
1030                       "audio_osx_source::UnitListener");
1031
1032   return (err);
1033 }
1034 #endif