1 /* -*- c++ -*- */
2 /*
3 * Copyright 2006-2011,2013-2014 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 #include "../audio_registry.h"
28 #include "osx_source.h"
29
30 #include <gnuradio/io_signature.h>
31 #include <gnuradio/prefs.h>
32 #include <stdexcept>
33
34 namespace gr {
35 namespace audio {
36
37 source::sptr
osx_source_fcn(int sampling_rate,const std::string & device_name,bool ok_to_block)38 osx_source_fcn(int sampling_rate, const std::string& device_name, bool ok_to_block)
39 {
40 return source::sptr(new osx_source(sampling_rate, device_name, ok_to_block));
41 }
42
default_device_name()43 static std::string default_device_name()
44 {
45 return prefs::singleton()->get_string(
46 "audio_osx", "default_input_device", "built-in");
47 }
48
osx_source(int sample_rate,const std::string & device_name,bool ok_to_block)49 osx_source::osx_source(int sample_rate, const std::string& device_name, bool ok_to_block)
50 : sync_block(
51 "audio_osx_source", io_signature::make(0, 0, 0), io_signature::make(0, 0, 0)),
52 d_device_sample_rate(0.0),
53 d_output_sample_rate(0.0),
54 d_input_buffer_size_frames(0),
55 d_input_buffer_size_bytes(0),
56 d_output_buffer_size_frames(0),
57 d_output_buffer_size_bytes(0),
58 d_device_buffer_size_frames(0),
59 d_device_buffer_size_bytes(0),
60 d_lead_size_frames(0),
61 d_lead_size_bytes(0),
62 d_trail_size_frames(0),
63 d_trail_size_bytes(0),
64 d_extra_buffer_size_frames(0),
65 d_extra_buffer_size_bytes(0),
66 d_queue_sample_count(0),
67 d_buffer_sample_count(0),
68 d_n_available_input_frames(0),
69 d_n_actual_input_frames(0),
70 d_n_user_channels(0),
71 d_n_dev_channels(0),
72 d_ok_to_block(ok_to_block),
73 d_pass_through(false),
74 d_waiting_for_data(false),
75 d_do_reset(false),
76 d_hardware_changed(false),
77 d_using_default_device(false),
78 d_desired_name(device_name.empty() ? default_device_name() : device_name),
79 d_input_ad_id(0),
80 d_input_au(0),
81 d_input_buffer(0),
82 d_output_buffer(0),
83 d_audio_converter(0)
84 {
85 // set the desired output sample rate
86
87 if (sample_rate <= 0) {
88 GR_LOG_ERROR(d_logger, boost::format("Invalid Sample Rate: %d") % sample_rate);
89 throw std::invalid_argument("audio_osx_source");
90 } else {
91 d_output_sample_rate = (Float64)sample_rate;
92 }
93
94 // set up for audio input using the stored desired parameters
95
96 setup();
97 }
98
setup()99 void osx_source::setup()
100 {
101 OSStatus err = noErr;
102
103 // set the default input audio device id to "unknown"
104
105 d_input_ad_id = kAudioDeviceUnknown;
106
107 // try to find the input audio device, if specified
108
109 std::vector<AudioDeviceID> all_ad_ids;
110 std::vector<std::string> all_names;
111
112 osx::find_audio_devices(d_desired_name, true, &all_ad_ids, &all_names);
113
114 // check number of device(s) returned
115
116 if (d_desired_name.length() != 0) {
117 if (all_ad_ids.size() == 1) {
118
119 // exactly 1 match was found; see if it was partial
120
121 if (all_names[0].compare(d_desired_name) != 0) {
122
123 // yes: log the full device name
124 GR_LOG_INFO(d_logger,
125 boost::format("Using input audio device '%s'.") %
126 all_names[0]);
127 }
128
129 // store info on this device
130
131 d_input_ad_id = all_ad_ids[0];
132 d_selected_name = all_names[0];
133
134 } else {
135
136 // either 0 or more than 1 device was found; get all input
137 // device names, print those, and error out.
138
139 osx::find_audio_devices("", true, NULL, &all_names);
140
141 std::string err_str("\n\nA unique input audio device name "
142 "matching the string '");
143 err_str += d_desired_name;
144 err_str += "' was not found.\n\n";
145 err_str += "The current known input audio device name";
146 err_str += ((all_names.size() > 1) ? "s are" : " is");
147 err_str += ":\n";
148 for (UInt32 nn = 0; nn < all_names.size(); ++nn) {
149 err_str += " " + all_names[nn] + "\n";
150 }
151 GR_LOG_ERROR(d_logger, boost::format(err_str));
152 throw std::runtime_error("audio_osx_source::setup");
153 }
154 }
155
156 // if no input audio device id was found or no specific device
157 // name was provided, use the default input audio device id as
158 // set in System Preferences.
159
160 if (d_input_ad_id == kAudioDeviceUnknown) {
161
162 UInt32 prop_size = (UInt32)sizeof(AudioDeviceID);
163 AudioObjectPropertyAddress ao_address = {
164 kAudioHardwarePropertyDefaultInputDevice,
165 kAudioObjectPropertyScopeGlobal,
166 kAudioObjectPropertyElementMaster
167 };
168
169 err = AudioObjectGetPropertyData(
170 kAudioObjectSystemObject, &ao_address, 0, NULL, &prop_size, &d_input_ad_id);
171 check_error_and_throw(err,
172 "Getting the default input audio device ID failed",
173 "audio_osx_source::setup");
174
175 {
176 // retrieve the device name; max name length is 64 characters.
177
178 UInt32 prop_size = 65;
179 char c_name_buf[prop_size];
180 memset((void*)c_name_buf, 0, (size_t)prop_size);
181 --prop_size;
182
183 AudioObjectPropertyAddress ao_address = { kAudioDevicePropertyDeviceName,
184 kAudioDevicePropertyScopeInput,
185 0 };
186
187 if ((err = AudioObjectGetPropertyData(d_input_ad_id,
188 &ao_address,
189 0,
190 NULL,
191 &prop_size,
192 (void*)c_name_buf)) != noErr) {
193
194 check_error(err, "Unable to retrieve input audio device name");
195
196 } else {
197
198 GR_LOG_INFO(d_logger,
199 boost::format("\n\nUsing input audio device '%s'.\n ... "
200 "which is the current default input audio"
201 " device.\n Changing the default input"
202 " audio device in the System Preferences"
203 " will \n result in changing it here, too "
204 "(with an internal reconfiguration).\n") %
205 std::string(c_name_buf));
206 }
207
208 d_selected_name = c_name_buf;
209 }
210
211 d_using_default_device = true;
212 }
213
214 // retrieve the total number of channels for the selected input
215 // audio device
216
217 osx::get_num_channels_for_audio_device_id(d_input_ad_id, &d_n_dev_channels, NULL);
218
219 // set the block output signature, if not already set
220 // (d_n_user_channels is set in check_topology, which is called
221 // before the flow-graph is running)
222
223 if (d_n_user_channels == 0) {
224 set_output_signature(io_signature::make(1, d_n_dev_channels, sizeof(float)));
225 }
226
227 // set the interim buffer size; to work with the GR scheduler,
228 // must be at least 16kB. Pick 50 kB since that's plenty yet
229 // not very much.
230
231 d_buffer_sample_count =
232 (d_output_sample_rate < 50000.0 ? 50000 : (UInt32)d_output_sample_rate);
233
234 #if _OSX_AU_DEBUG_
235 std::cerr << "source(): max # samples = " << d_buffer_sample_count << std::endl;
236 #endif
237
238 // create the default AudioUnit for input
239
240 // Open the default input unit
241
242 #ifndef GR_USE_OLD_AUDIO_UNIT
243 AudioComponentDescription desc;
244 #else
245 ComponentDescription desc;
246 #endif
247
248 desc.componentType = kAudioUnitType_Output;
249 desc.componentSubType = kAudioUnitSubType_HALOutput;
250 desc.componentManufacturer = kAudioUnitManufacturer_Apple;
251 desc.componentFlags = 0;
252 desc.componentFlagsMask = 0;
253
254 #ifndef GR_USE_OLD_AUDIO_UNIT
255
256 AudioComponent comp = AudioComponentFindNext(NULL, &desc);
257 if (!comp) {
258 GR_LOG_FATAL(d_logger, boost::format("AudioComponentFindNext Failed"));
259 throw std::runtime_error("audio_osx_source::setup");
260 }
261 err = AudioComponentInstanceNew(comp, &d_input_au);
262 check_error_and_throw(
263 err, "AudioComponentInstanceNew Failed", "audio_osx_source::setup");
264
265 #else
266
267 Component comp = FindNextComponent(NULL, &desc);
268 if (!comp) {
269 GR_LOG_FATAL(d_logger, boost::format("FindNextComponent Failed"));
270 throw std::runtime_error("audio_osx_source::setup");
271 }
272 err = OpenAComponent(comp, &d_input_au);
273 check_error_and_throw(err, "OpenAComponent Failed", "audio_osx_source::setup");
274
275 #endif
276
277 // must enable the AUHAL for input and disable output
278 // before setting the AUHAL's current device
279
280 // Enable input on the AUHAL
281
282 UInt32 enable_io = 1;
283 err = AudioUnitSetProperty(d_input_au,
284 kAudioOutputUnitProperty_EnableIO,
285 kAudioUnitScope_Input,
286 1, // input element
287 &enable_io,
288 sizeof(enable_io));
289 check_error_and_throw(
290 err, "AudioUnitSetProperty Input Enable", "audio_osx_source::setup");
291
292 // Disable output on the AUHAL
293
294 enable_io = 0;
295 err = AudioUnitSetProperty(d_input_au,
296 kAudioOutputUnitProperty_EnableIO,
297 kAudioUnitScope_Output,
298 0, // output element
299 &enable_io,
300 sizeof(enable_io));
301 check_error_and_throw(
302 err, "AudioUnitSetProperty Output Disable", "audio_osx_source::setup");
303
304 // set the selected device ID as the current input device
305
306 err = AudioUnitSetProperty(d_input_au,
307 kAudioOutputUnitProperty_CurrentDevice,
308 kAudioUnitScope_Global,
309 0,
310 &d_input_ad_id,
311 sizeof(d_input_ad_id));
312 check_error_and_throw(err,
313 "Setting selected input device as current failed",
314 "audio_osx_source::setup");
315
316 // Set up a callback function to retrieve input from the Audio Device
317
318 AURenderCallbackStruct au_callback = { reinterpret_cast<AURenderCallback>(
319 &osx_source::au_input_callback),
320 reinterpret_cast<void*>(this) };
321 UInt32 prop_size = (UInt32)sizeof(au_callback);
322
323 err = AudioUnitSetProperty(d_input_au,
324 kAudioOutputUnitProperty_SetInputCallback,
325 kAudioUnitScope_Global,
326 0,
327 &au_callback,
328 prop_size);
329 check_error_and_throw(err, "Set Input Callback", "audio_osx_source::setup");
330
331 // Get the Stream Format (device side; cannot generally be changed)
332
333 prop_size = (UInt32)sizeof(d_asbd_device);
334 memset((void*)(&d_asbd_device), 0, (size_t)prop_size);
335 err = AudioUnitGetProperty(d_input_au,
336 kAudioUnitProperty_StreamFormat,
337 kAudioUnitScope_Input,
338 1,
339 &d_asbd_device,
340 &prop_size);
341 check_error_and_throw(
342 err, "Get Device Input Stream Format (before) failed", "audio_osx_source::setup");
343
344 #if _OSX_AU_DEBUG_
345 std::cerr << std::endl
346 << "---- Device Stream Format (before) ----" << std::endl
347 << d_asbd_device << std::endl
348 << std::endl;
349 #endif
350
351 // try to set the device (input) side of the audio device to the
352 // sample rate of this source. This will likely fail, and
353 // that's OK; just ignore the error since we can accomplish
354 // audio input in other ways.
355
356 prop_size = (UInt32)sizeof(d_asbd_device);
357 d_asbd_device.mSampleRate = d_output_sample_rate;
358 err = AudioUnitSetProperty(d_input_au,
359 kAudioUnitProperty_StreamFormat,
360 kAudioUnitScope_Input,
361 1,
362 &d_asbd_device,
363 prop_size);
364 #if _OSX_AU_DEBUG_
365 check_error(err, "Set Device Input Stream Format failed (expected)");
366 #endif
367
368 memset((void*)(&d_asbd_device), 0, (size_t)prop_size);
369 err = AudioUnitGetProperty(d_input_au,
370 kAudioUnitProperty_StreamFormat,
371 kAudioUnitScope_Input,
372 1,
373 &d_asbd_device,
374 &prop_size);
375 check_error_and_throw(
376 err, "Get Device Input Stream Format (after) failed", "audio_osx_source::setup");
377
378 #if _OSX_AU_DEBUG_
379 std::cerr << std::endl
380 << "---- Device Stream Format (after) ----" << std::endl
381 << d_asbd_device << std::endl
382 << std::endl;
383 #endif
384
385 d_device_sample_rate = d_asbd_device.mSampleRate;
386
387 // Get the Stream Format (client side; might be changeable)
388
389 prop_size = (UInt32)sizeof(d_asbd_client);
390 memset((void*)(&d_asbd_client), 0, (size_t)prop_size);
391 err = AudioUnitGetProperty(d_input_au,
392 kAudioUnitProperty_StreamFormat,
393 kAudioUnitScope_Output,
394 1,
395 &d_asbd_client,
396 &prop_size);
397 check_error_and_throw(err,
398 "Get Device Output Stream Format (before) failed",
399 "audio_osx_source::setup");
400
401 #if _OSX_AU_DEBUG_
402 std::cerr << "---- Client Stream Format (Before) ----" << std::endl
403 << d_asbd_client << std::endl
404 << std::endl;
405 #endif
406
407 // Set the format of all the AUs to the
408 // input/output devices channel count
409
410 d_asbd_client.mFormatID = kAudioFormatLinearPCM;
411 d_asbd_client.mFormatFlags = (kAudioFormatFlagIsFloat | kAudioFormatFlagIsPacked |
412 kAudioFormatFlagIsNonInterleaved);
413 if ((d_asbd_client.mFormatID == kAudioFormatLinearPCM) && (d_n_dev_channels == 1)) {
414 d_asbd_client.mFormatFlags &= ~kLinearPCMFormatFlagIsNonInterleaved;
415 }
416 d_asbd_client.mBytesPerFrame = (UInt32)sizeof(float);
417 d_asbd_client.mFramesPerPacket = 1;
418 d_asbd_client.mBitsPerChannel = d_asbd_client.mBytesPerFrame * 8;
419 d_asbd_client.mChannelsPerFrame = d_n_dev_channels;
420 d_asbd_client.mBytesPerPacket = d_asbd_client.mBytesPerFrame;
421
422 // according to Apple docs [see, e.g., Apple Technical Note
423 // TN2091 "Device input using the HAL Output Audio Unit"], the
424 // device input and output sample rate must be the same; do
425 // sample rate conversion elsewhere.
426
427 d_asbd_client.mSampleRate = d_asbd_device.mSampleRate;
428 err = AudioUnitSetProperty(d_input_au,
429 kAudioUnitProperty_StreamFormat,
430 kAudioUnitScope_Output,
431 1,
432 &d_asbd_client,
433 prop_size);
434 check_error_and_throw(
435 err, "Set Device Output Stream Format failed", "audio_osx_source::setup");
436
437 // Get the Stream Format (client side), again
438
439 prop_size = (UInt32)sizeof(d_asbd_client);
440 memset((void*)(&d_asbd_client), 0, (size_t)prop_size);
441 err = AudioUnitGetProperty(d_input_au,
442 kAudioUnitProperty_StreamFormat,
443 kAudioUnitScope_Output,
444 1,
445 &d_asbd_client,
446 &prop_size);
447 check_error_and_throw(
448 err, "Get Device Output Stream Format (after) failed", "audio_osx_source::setup");
449
450 #if _OSX_AU_DEBUG_
451 std::cerr << "---- Client Stream Format (After) ----" << std::endl
452 << d_asbd_client << std::endl
453 << std::endl;
454 #endif
455
456 d_pass_through = (d_asbd_client.mSampleRate == d_output_sample_rate);
457
458 if (d_pass_through) {
459
460 // no need to do conversion if d_asbd_client matches user wants
461 d_lead_size_frames = d_trail_size_frames = 0L;
462
463 } else {
464
465 // create an ASBD for the user's wants
466
467 memset((void*)(&d_asbd_user), 0, sizeof(d_asbd_user));
468 d_asbd_user.mSampleRate = d_output_sample_rate;
469 d_asbd_user.mFormatID = kAudioFormatLinearPCM;
470 d_asbd_user.mFormatFlags =
471 (kLinearPCMFormatFlagIsFloat | GR_PCM_ENDIANNESS |
472 kLinearPCMFormatFlagIsPacked | kAudioFormatFlagIsNonInterleaved);
473 d_asbd_user.mBytesPerPacket = (UInt32)sizeof(float);
474 d_asbd_user.mFramesPerPacket = 1;
475 d_asbd_user.mBytesPerFrame = d_asbd_user.mBytesPerPacket;
476 d_asbd_user.mChannelsPerFrame = d_n_dev_channels;
477 d_asbd_user.mBitsPerChannel = d_asbd_user.mBytesPerPacket * 8;
478
479 // Create the audio converter
480
481 err = AudioConverterNew(&d_asbd_client, &d_asbd_user, &d_audio_converter);
482 check_error_and_throw(err, "AudioConverterNew failed", "audio_osx_source::setup");
483
484 // Set the audio converter sample rate quality to "max" ...
485 // requires more samples, but should sound nicer
486
487 UInt32 ac_quality = kAudioConverterQuality_Max;
488 prop_size = (UInt32)sizeof(ac_quality);
489 err = AudioConverterSetProperty(d_audio_converter,
490 kAudioConverterSampleRateConverterQuality,
491 prop_size,
492 &ac_quality);
493 check_error_and_throw(
494 err, "Set Sample Rate Converter Quality failed", "audio_osx_source::setup");
495
496 // set the audio converter's prime method to "pre",
497 // which uses both leading and trailing frames
498 // from the "current input". All of this is handled
499 // internally by the AudioConverter; we just supply
500 // the frames for conversion.
501
502 UInt32 ac_prime_method = kConverterPrimeMethod_Pre;
503 prop_size = (UInt32)sizeof(ac_prime_method);
504 err = AudioConverterSetProperty(
505 d_audio_converter, kAudioConverterPrimeMethod, prop_size, &ac_prime_method);
506 check_error_and_throw(err, "Set Prime Method failed", "audio_osx_source::setup");
507
508 // Get the size of the priming I/O buffer space to allow for
509 // pre-allocated buffers
510
511 AudioConverterPrimeInfo ac_prime_info = { 0, 0 };
512 prop_size = (UInt32)sizeof(ac_prime_info);
513 err = AudioConverterGetProperty(
514 d_audio_converter, kAudioConverterPrimeInfo, &prop_size, &ac_prime_info);
515 check_error_and_throw(err, "Get Prime Info failed", "audio_osx_source::setup");
516
517 d_lead_size_frames = ac_prime_info.leadingFrames;
518 d_trail_size_frames = ac_prime_info.trailingFrames;
519 }
520
521 d_lead_size_bytes = d_lead_size_frames * sizeof(float);
522 d_trail_size_bytes = d_trail_size_frames * sizeof(float);
523
524 prop_size = (UInt32)sizeof(d_device_buffer_size_frames);
525 err = AudioUnitGetProperty(d_input_au,
526 kAudioDevicePropertyBufferFrameSize,
527 kAudioUnitScope_Global,
528 0,
529 &d_device_buffer_size_frames,
530 &prop_size);
531 check_error_and_throw(err, "Get Buffer Frame Size failed", "audio_osx_source::setup");
532
533 d_device_buffer_size_bytes = (d_device_buffer_size_frames * sizeof(float));
534 d_input_buffer_size_bytes = (d_device_buffer_size_bytes + d_lead_size_bytes);
535 d_input_buffer_size_frames = (d_device_buffer_size_frames + d_lead_size_frames);
536
537 // outBufSizeBytes = floor (inBufSizeBytes * rate_out / rate_in)
538 // since this is rarely exact, we need another buffer to hold
539 // "extra" samples not processed at any given sampling period
540 // this buffer must be at least 4 floats in size, but generally
541 // follows the rule that
542 // extraBufSize = ceil (rate_in / rate_out)*sizeof(float)
543
544 d_extra_buffer_size_frames =
545 ((UInt32)ceil(d_device_sample_rate / d_output_sample_rate) * sizeof(float));
546 if (d_extra_buffer_size_frames < 4)
547 d_extra_buffer_size_frames = 4;
548 d_extra_buffer_size_bytes = d_extra_buffer_size_frames * sizeof(float);
549
550 d_output_buffer_size_frames =
551 (UInt32)ceil(((Float64)d_input_buffer_size_frames) * d_output_sample_rate /
552 d_device_sample_rate);
553 d_output_buffer_size_bytes = d_output_buffer_size_frames * sizeof(float);
554 d_input_buffer_size_frames += d_extra_buffer_size_frames;
555
556 // pre-alloc all CoreAudio buffers
557
558 alloc_audio_buffer_list(&d_input_buffer, d_n_dev_channels, d_input_buffer_size_bytes);
559 if (!d_pass_through) {
560 alloc_audio_buffer_list(
561 &d_output_buffer, d_n_dev_channels, d_output_buffer_size_bytes);
562 } else {
563 d_output_buffer = d_input_buffer;
564 }
565
566 // allocate the output circular buffer(s), one per device
567 // channel (the user may select fewer channels; those buffers
568 // just won't get used).
569
570 d_buffers.resize(d_n_dev_channels);
571 for (UInt32 nn = 0; nn < d_n_dev_channels; ++nn) {
572 d_buffers[nn] = new circular_buffer<float>(d_buffer_sample_count, false, false);
573 }
574
575 // clear the RunLoop (whatever that is); needed, for some
576 // reason, before a listener will work.
577
578 {
579 CFRunLoopRef the_run_loop = NULL;
580 AudioObjectPropertyAddress property = { kAudioHardwarePropertyRunLoop,
581 kAudioObjectPropertyScopeGlobal,
582 kAudioObjectPropertyElementMaster };
583 prop_size = (UInt32)sizeof(the_run_loop);
584 err = AudioObjectSetPropertyData(
585 kAudioObjectSystemObject, &property, 0, NULL, prop_size, &the_run_loop);
586 check_error(err,
587 "Clearing RunLoop failed; "
588 "Audio Input Device Listener might not work.");
589 }
590
591 // set up listeners
592
593 #ifndef GR_USE_OLD_AUDIO_UNIT
594
595 // 10.4 and newer
596
597 {
598
599 // set up a listener if hardware changes (at all)
600
601 AudioObjectPropertyAddress property = { kAudioHardwarePropertyDevices,
602 kAudioObjectPropertyScopeGlobal,
603 kAudioObjectPropertyElementMaster };
604
605 err = AudioObjectAddPropertyListener(
606 kAudioObjectSystemObject,
607 &property,
608 reinterpret_cast<AudioObjectPropertyListenerProc>(
609 &osx_source::hardware_listener),
610 reinterpret_cast<void*>(this));
611 check_error(err, "Adding Audio Hardware Listener failed");
612 }
613
614 if (d_using_default_device) {
615
616 // set up a listener if default hardware input device changes
617
618 AudioObjectPropertyAddress property = { kAudioHardwarePropertyDefaultInputDevice,
619 kAudioObjectPropertyScopeGlobal,
620 kAudioObjectPropertyElementMaster };
621
622 err = AudioObjectAddPropertyListener(
623 kAudioObjectSystemObject,
624 &property,
625 reinterpret_cast<AudioObjectPropertyListenerProc>(
626 &osx_source::default_listener),
627 reinterpret_cast<void*>(this));
628 check_error(err, "Adding Default Input Audio Listener failed");
629 }
630
631 #else
632
633 // 10.5 and older
634
635 err = AudioHardwareAddPropertyListener(
636 kAudioHardwarePropertyDevices,
637 reinterpret_cast<AudioHardwarePropertyListenerProc>(
638 &osx_source::hardware_listener),
639 reinterpret_cast<void*>(this));
640 check_error(err, "Adding Audio Hardware Listener failed");
641
642 if (d_using_default_device) {
643
644 err = AudioHardwareAddPropertyListener(
645 kAudioHardwarePropertyDefaultInputDevice,
646 reinterpret_cast<AudioHardwarePropertyListenerProc>(
647 &osx_source::default_listener),
648 reinterpret_cast<void*>(this));
649 check_error(err, "Adding Default Input Audio Listener failed");
650 }
651
652 #endif
653
654 // initialize the AU for input, so that it is ready to be used
655
656 err = AudioUnitInitialize(d_input_au);
657 check_error_and_throw(err, "AudioUnitInitialize", "audio_osx_source::check_channels");
658
659 #if _OSX_AU_DEBUG_
660 std::cerr << std::endl
661 << "audio_osx_source Parameters:" << std::endl
662 << " Device Sample Rate is " << d_device_sample_rate << std::endl
663 << " Client Sample Rate is "
664 << (d_pass_through ? d_output_sample_rate : d_device_sample_rate)
665 << std::endl
666 << " User Sample Rate is " << d_output_sample_rate << std::endl
667 << " Do Passthrough is " << (d_pass_through ? "true" : "false")
668 << std::endl
669 << " Max Sample Count is " << d_buffer_sample_count << std::endl
670 << " # Device Channels is " << d_n_dev_channels << std::endl
671 << " Device Buffer Size in Frames = " << d_device_buffer_size_frames
672 << std::endl
673 << " Lead Size in Frames = " << d_lead_size_frames << std::endl
674 << " Trail Size in Frames = " << d_trail_size_frames << std::endl
675 << " Input Buffer Size in Frames = " << d_input_buffer_size_frames
676 << std::endl
677 << " Output Buffer Size in Frames = " << d_output_buffer_size_frames
678 << std::endl
679 << std::endl;
680 #endif
681 }
682
alloc_audio_buffer_list(AudioBufferList ** t_abl,UInt32 n_channels,UInt32 input_buffer_size_bytes)683 void osx_source::alloc_audio_buffer_list(AudioBufferList** t_abl,
684 UInt32 n_channels,
685 UInt32 input_buffer_size_bytes)
686 {
687 free_audio_buffer_list(t_abl);
688 UInt32 prop_size =
689 (offsetof(AudioBufferList, mBuffers[0]) + (sizeof(AudioBuffer) * n_channels));
690 *t_abl = (AudioBufferList*)calloc(1, prop_size);
691 (*t_abl)->mNumberBuffers = n_channels;
692
693 int counter = n_channels;
694
695 #if _OSX_AU_DEBUG_
696 std::cerr << "alloc_audio_buffer_list: (#chan, #bytes) == (" << n_channels << ", "
697 << input_buffer_size_bytes << ")" << std::endl;
698 #endif
699
700 while (--counter >= 0) {
701 AudioBuffer* t_ab = &((*t_abl)->mBuffers[counter]);
702 t_ab->mNumberChannels = 1;
703 t_ab->mDataByteSize = input_buffer_size_bytes;
704 t_ab->mData = calloc(1, input_buffer_size_bytes);
705 }
706 }
707
free_audio_buffer_list(AudioBufferList ** t_abl)708 void osx_source::free_audio_buffer_list(AudioBufferList** t_abl)
709 {
710 // free pre-allocated audio buffer, if it exists
711 if (*t_abl) {
712 int counter = (*t_abl)->mNumberBuffers;
713 while (--counter >= 0) {
714 AudioBuffer* t_ab = &((*t_abl)->mBuffers[counter]);
715 free(t_ab->mData);
716 t_ab->mData = 0;
717 }
718 free(*t_abl);
719 (*t_abl) = 0;
720 }
721 }
722
is_running()723 bool osx_source::is_running()
724 {
725 UInt32 au_running = 0;
726 if (d_input_au) {
727
728 UInt32 prop_size = (UInt32)sizeof(au_running);
729 OSStatus err = AudioUnitGetProperty(d_input_au,
730 kAudioOutputUnitProperty_IsRunning,
731 kAudioUnitScope_Global,
732 0,
733 &au_running,
734 &prop_size);
735 check_error_and_throw(
736 err, "AudioUnitGetProperty IsRunning", "audio_osx_source::is_running");
737 }
738
739 return (au_running != 0);
740 }
741
start()742 bool osx_source::start()
743 {
744 #if _OSX_AU_DEBUG_
745 std::cerr << ((void*)(pthread_self())) << " : audio_osx_source::start: Starting."
746 << std::endl;
747 #endif
748
749 if ((!is_running()) && d_input_au) {
750
751 #if _OSX_AU_DEBUG_
752 std::cerr << ((void*)(pthread_self()))
753 << " : audio_osx_source::start: Starting Audio Unit." << std::endl;
754 #endif
755
756 // reset buffers before starting
757
758 for (UInt32 nn = 0; nn < d_buffers.size(); ++nn) {
759 d_buffers[nn]->reset();
760 }
761
762 // start the audio unit
763
764 OSStatus err = AudioOutputUnitStart(d_input_au);
765 check_error_and_throw(err, "AudioOutputUnitStart", "audio_osx_source::start");
766
767 // clear reset (will sometimes be necessary, and it has to
768 // happen after AudioOutputUnitStart)
769
770 d_do_reset = false;
771 }
772
773 #if _OSX_AU_DEBUG_
774 std::cerr << ((void*)(pthread_self())) << " : audio_osx_source::start: Returning."
775 << std::endl;
776 #endif
777
778 return (true);
779 }
780
stop()781 bool osx_source::stop()
782 {
783 #if _OSX_AU_DEBUG_
784 std::cerr << ((void*)(pthread_self())) << " : audio_osx_source::stop: Starting."
785 << std::endl;
786 #endif
787 if (is_running()) {
788
789 #if _OSX_AU_DEBUG_
790 std::cerr << ((void*)(pthread_self()))
791 << " : audio_osx_source::stop: stopping audio unit." << std::endl;
792 #endif
793
794 // stop the audio unit
795
796 OSStatus err = AudioOutputUnitStop(d_input_au);
797 check_error_and_throw(err, "AudioOutputUnitStart", "audio_osx_source::stop");
798
799 // abort all buffers
800
801 for (UInt32 nn = 0; nn < d_n_user_channels; ++nn) {
802 d_buffers[nn]->abort();
803 }
804 }
805
806 #if _OSX_AU_DEBUG_
807 std::cerr << ((void*)(pthread_self())) << " : audio_osx_source::stop: Returning."
808 << std::endl;
809 #endif
810
811 return (true);
812 }
813
teardown()814 void osx_source::teardown()
815 {
816 #if _OSX_AU_DEBUG_
817 std::cerr << ((void*)(pthread_self())) << " : audio_osx_source::teardown: Starting."
818 << std::endl;
819 #endif
820
821 OSStatus err = noErr;
822
823 // stop the AudioUnit
824
825 stop();
826
827 // remove the listeners
828
829 #ifndef GR_USE_OLD_AUDIO_UNIT
830
831 // 10.4 and newer
832 {
833 AudioObjectPropertyAddress property = { kAudioHardwarePropertyDevices,
834 kAudioObjectPropertyScopeGlobal,
835 kAudioObjectPropertyElementMaster };
836
837 err = AudioObjectRemovePropertyListener(
838 kAudioObjectSystemObject,
839 &property,
840 reinterpret_cast<AudioObjectPropertyListenerProc>(
841 &osx_source::hardware_listener),
842 reinterpret_cast<void*>(this));
843 #if _OSX_AU_DEBUG_
844 check_error(err,
845 "teardown: AudioObjectRemovePropertyListener "
846 "hardware failed");
847 #endif
848 }
849
850 if (d_using_default_device) {
851
852 AudioObjectPropertyAddress property = { kAudioHardwarePropertyDefaultInputDevice,
853 kAudioObjectPropertyScopeGlobal,
854 kAudioObjectPropertyElementMaster };
855
856 err = AudioObjectRemovePropertyListener(
857 kAudioObjectSystemObject,
858 &property,
859 reinterpret_cast<AudioObjectPropertyListenerProc>(
860 &osx_source::default_listener),
861 reinterpret_cast<void*>(this));
862 #if _OSX_AU_DEBUG_
863 check_error(err, "AudioObjectRemovePropertyListener default");
864 #endif
865
866 d_using_default_device = false;
867 }
868 #else
869
870 // 10.5 and older
871
872 err = AudioHardwareRemovePropertyListener(
873 kAudioHardwarePropertyDevices,
874 reinterpret_cast<AudioHardwarePropertyListenerProc>(
875 &osx_source::hardware_listener));
876 #if _OSX_AU_DEBUG_
877 check_error(err, "AudioObjectRemovePropertyListener hardware");
878 #endif
879
880 if (d_using_default_device) {
881 err = AudioHardwareRemovePropertyListener(
882 kAudioHardwarePropertyDefaultInputDevice,
883 reinterpret_cast<AudioHardwarePropertyListenerProc>(
884 &osx_source::default_listener));
885 #if _OSX_AU_DEBUG_
886 check_error(err, "AudioObjectRemovePropertyListener default");
887 #endif
888 d_using_default_device = false;
889 }
890
891 #endif // GR_USE_OLD_AUDIO_UNIT
892
893 // free pre-allocated audio buffers
894 free_audio_buffer_list(&d_input_buffer);
895
896 if (!d_pass_through) {
897 err = AudioConverterDispose(d_audio_converter);
898 #if _OSX_AU_DEBUG_
899 check_error(err, "~audio_osx_source: AudioConverterDispose");
900 #endif
901 free_audio_buffer_list(&d_output_buffer);
902 }
903
904 // remove the audio unit
905 err = AudioUnitUninitialize(d_input_au);
906 #if _OSX_AU_DEBUG_
907 check_error(err, "~audio_osx_source: AudioUnitUninitialize");
908 #endif
909
910 #ifndef GR_USE_OLD_AUDIO_UNIT
911 err = AudioComponentInstanceDispose(d_input_au);
912 #if _OSX_AU_DEBUG_
913 check_error(err, "~audio_osx_source: AudioComponentInstanceDispose");
914 #endif
915 #else
916 err = CloseComponent(d_input_au);
917 #if _OSX_AU_DEBUG_
918 check_error(err, "~audio_osx_source: CloseComponent");
919 #endif
920 #endif
921
922 // empty and delete the queues
923
924 for (UInt32 nn = 0; nn < d_buffers.size(); ++nn) {
925 delete d_buffers[nn];
926 d_buffers[nn] = 0;
927 }
928 d_buffers.resize(0);
929
930 // clear important variables; not # user channels
931
932 d_queue_sample_count = 0;
933 d_device_sample_rate = 0;
934 d_n_dev_channels = 0;
935 d_input_ad_id = 0;
936 d_input_au = 0;
937 d_input_buffer = d_output_buffer = 0;
938 d_audio_converter = 0;
939 d_using_default_device = false;
940
941 #if _OSX_AU_DEBUG_
942 std::cerr << ((void*)(pthread_self())) << " : audio_osx_source::teardown: Returning."
943 << std::endl;
944 #endif
945 }
946
check_topology(int ninputs,int noutputs)947 bool osx_source::check_topology(int ninputs, int noutputs)
948 {
949 // check # inputs to make sure it's valid
950 if (ninputs != 0) {
951
952 GR_LOG_FATAL(d_logger,
953 boost::format("check_topology(): number of input "
954 "streams provided (%d) should be 0.") %
955 ninputs);
956 throw std::runtime_error("audio_osx_source::check_topology");
957 }
958
959 // check # outputs to make sure it's valid
960 if ((noutputs < 1) | (noutputs > (int)d_n_dev_channels)) {
961
962 GR_LOG_FATAL(d_logger,
963 boost::format("check_topology(): number of output "
964 "streams provided (%d) should be in [1,%d] "
965 "for the selected input audio device.") %
966 noutputs % d_n_dev_channels);
967 throw std::runtime_error("audio_osx_source::check_topology");
968 }
969
970 // save the actual number of output (user) channels
971
972 d_n_user_channels = noutputs;
973
974 #if _OSX_AU_DEBUG_
975 std::cerr << "chk_topo: Actual # user output channels = " << noutputs << std::endl;
976 #endif
977
978 return (true);
979 }
980
work(int noutput_items,gr_vector_const_void_star & input_items,gr_vector_void_star & output_items)981 int osx_source::work(int noutput_items,
982 gr_vector_const_void_star& input_items,
983 gr_vector_void_star& output_items)
984 {
985 #if _OSX_AU_DEBUG_RENDER_
986 std::cerr << ((void*)(pthread_self())) << " : audio_osx_source::work: Starting."
987 << std::endl;
988 #endif
989 if (d_do_reset) {
990 if (d_hardware_changed) {
991
992 // see if the current AudioDeviceID is still available
993
994 std::vector<AudioDeviceID> all_ad_ids;
995 osx::find_audio_devices(d_desired_name, true, &all_ad_ids, NULL);
996 bool found = false;
997 for (UInt32 nn = 0; (nn < all_ad_ids.size()) && (!found); ++nn) {
998 found = (all_ad_ids[nn] == d_input_ad_id);
999 }
1000 if (!found) {
1001
1002 GR_LOG_FATAL(d_logger,
1003 boost::format("The selected input audio device ('%s') "
1004 "is no longer available.\n") %
1005 d_selected_name);
1006 return (gr::block::WORK_DONE);
1007 }
1008
1009 d_do_reset = d_hardware_changed = false;
1010
1011 } else {
1012
1013 #if _OSX_AU_DEBUG_RENDER_
1014 std::cerr << "audio_osx_source::work: doing reset." << std::endl;
1015 #endif
1016
1017 GR_LOG_WARN(d_logger,
1018 boost::format("\n\nThe default input audio device has "
1019 "changed; resetting audio.\nThere may "
1020 "be a sound glitch while resetting.\n"));
1021
1022 // for any changes, just tear down the current
1023 // configuration, then set it up again using the user's
1024 // parameters to try to make selections.
1025
1026 teardown();
1027
1028 gr::thread::scoped_lock l(d_internal);
1029
1030 #if _OSX_AU_DEBUG_RENDER_
1031 std::cerr << "audio_osx_source::work: mutex locked." << std::endl;
1032 #endif
1033
1034 setup();
1035 start();
1036
1037 #if _OSX_AU_DEBUG_RENDER_
1038 std::cerr << "audio_osx_source::work: returning after reset." << std::endl;
1039 #endif
1040 return (0);
1041 }
1042 }
1043
1044 gr::thread::scoped_lock l(d_internal);
1045
1046 #if _OSX_AU_DEBUG_RENDER_
1047 std::cerr << "audio_osx_source::work: mutex locked." << std::endl;
1048 #endif
1049
1050 #if _OSX_AU_DEBUG_RENDER_
1051 std::cerr << "work1: SC = " << d_queue_sample_count << ", #OI = " << noutput_items
1052 << ", #Chan = " << output_items.size() << std::endl;
1053 #endif
1054
1055 // set the actual # of output items to the 'desired' amount then
1056 // verify that data is available; if not enough data is
1057 // available, either wait until it is (is "ok_to_block" is
1058 // true), return (0) is no data is available and "ok_to_block"
1059 // is false, or process the actual amount of available data.
1060
1061 UInt32 actual_noutput_items = noutput_items;
1062
1063 if (d_queue_sample_count < actual_noutput_items) {
1064 if (d_queue_sample_count == 0) {
1065 // no data; ok_to_block decides what to do
1066 if (d_ok_to_block == true) {
1067 // block until there is data to return, or on reset
1068 while (d_queue_sample_count == 0) {
1069 // release control so-as to allow data to be retrieved;
1070 // block until there is data to return
1071 #if _OSX_AU_DEBUG_RENDER_
1072 std::cerr << "audio_osx_source::work: waiting." << std::endl;
1073 #endif
1074 d_waiting_for_data = true;
1075 d_cond_data.wait(l);
1076 d_waiting_for_data = false;
1077 #if _OSX_AU_DEBUG_RENDER_
1078 std::cerr << "audio_osx_source::work: done waiting." << std::endl;
1079 #endif
1080 // the condition's 'notify' was called; acquire control to
1081 // keep thread safe
1082
1083 // if doing a reset, just return here; reset will pick
1084 // up the next time this method is called.
1085 if (d_do_reset) {
1086 #if _OSX_AU_DEBUG_RENDER_
1087 std::cerr << "audio_osx_source::work: "
1088 "returning for reset."
1089 << std::endl;
1090 #endif
1091 return (0);
1092 }
1093 }
1094 } else {
1095 // no data & not blocking; return nothing
1096 #if _OSX_AU_DEBUG_RENDER_
1097 std::cerr << "audio_osx_source::work: no data "
1098 "& not blocking; returning 0."
1099 << std::endl;
1100 #endif
1101 return (0);
1102 }
1103 }
1104
1105 // use the actual amount of available data
1106 actual_noutput_items = d_queue_sample_count;
1107 }
1108
1109 #if _OSX_AU_DEBUG_RENDER_
1110 std::cerr << "audio_osx_source::work: copying " << actual_noutput_items
1111 << " items per channel" << std::endl;
1112 #endif
1113
1114 // number of channels
1115 int l_counter = (int)output_items.size();
1116
1117 // copy the items from the circular buffer(s) to 'work's output
1118 // buffers; verify that the number copied out is as expected.
1119
1120 while (--l_counter >= 0) {
1121
1122 size_t t_n_output_items = actual_noutput_items;
1123 d_buffers[l_counter]->dequeue((float*)output_items[l_counter], &t_n_output_items);
1124
1125 if (t_n_output_items != actual_noutput_items) {
1126
1127 GR_LOG_FATAL(d_logger,
1128 boost::format("work(): ERROR: number of available "
1129 "items changing unexpectedly; expecting %d"
1130 ", got %d.") %
1131 actual_noutput_items % t_n_output_items);
1132 throw std::runtime_error("audio_osx_source::work()");
1133 }
1134 }
1135
1136 // subtract the actual number of items removed from the buffer(s)
1137 // from the local accounting of the number of available samples
1138
1139 d_queue_sample_count -= actual_noutput_items;
1140
1141 #if _OSX_AU_DEBUG_RENDER_
1142 std::cerr << "work2: SC = " << d_queue_sample_count
1143 << ", act#OI = " << actual_noutput_items << std::endl
1144 << "Returning." << std::endl;
1145 #endif
1146 #if _OSX_AU_DEBUG_RENDER_
1147 std::cerr << "audio_osx_source::work: returning." << std::endl;
1148 #endif
1149
1150 return (actual_noutput_items);
1151 }
1152
converter_callback(AudioConverterRef in_audio_converter,UInt32 * io_number_data_packets,AudioBufferList * io_data,AudioStreamPacketDescription ** out_aspd,void * in_user_data)1153 OSStatus osx_source::converter_callback(AudioConverterRef in_audio_converter,
1154 UInt32* io_number_data_packets,
1155 AudioBufferList* io_data,
1156 AudioStreamPacketDescription** out_aspd,
1157 void* in_user_data)
1158 {
1159 // This callback is for us to provide the buffers to CoreAudio
1160 // for conversion. We need to set the buffers in the provided
1161 // buffer list (io_data) to the buffers we know about and use to
1162 // do data input (d_input_buffers).
1163
1164 osx_source* This = static_cast<osx_source*>(in_user_data);
1165 AudioBufferList* l_input_abl = This->d_input_buffer;
1166 UInt32 total_input_buffer_size_bytes = ((*io_number_data_packets) * sizeof(float));
1167 int counter = This->d_n_dev_channels;
1168 io_data->mNumberBuffers = This->d_n_dev_channels;
1169 This->d_n_actual_input_frames = (*io_number_data_packets);
1170
1171 #if _OSX_AU_DEBUG_RENDER_
1172 std::cerr << "cc1: io#DP = " << (*io_number_data_packets)
1173 << ", TIBSB = " << total_input_buffer_size_bytes << ", #C = " << counter
1174 << std::endl;
1175 #endif
1176
1177 while (--counter >= 0) {
1178 AudioBuffer* t_ab = &(io_data->mBuffers[counter]);
1179 t_ab->mNumberChannels = 1;
1180 t_ab->mData = l_input_abl->mBuffers[counter].mData;
1181 t_ab->mDataByteSize = total_input_buffer_size_bytes;
1182 }
1183
1184 #if _OSX_AU_DEBUG_RENDER_
1185 std::cerr << "cc2: Returning." << std::endl;
1186 #endif
1187
1188 return (noErr);
1189 }
1190
au_input_callback(void * in_ref_con,AudioUnitRenderActionFlags * io_action_flags,const AudioTimeStamp * in_time_stamp,UInt32 in_bus_number,UInt32 in_number_frames,AudioBufferList * io_data)1191 OSStatus osx_source::au_input_callback(void* in_ref_con,
1192 AudioUnitRenderActionFlags* io_action_flags,
1193 const AudioTimeStamp* in_time_stamp,
1194 UInt32 in_bus_number,
1195 UInt32 in_number_frames,
1196 AudioBufferList* io_data)
1197 {
1198 #if _OSX_AU_DEBUG_RENDER_
1199 std::cerr << ((void*)(pthread_self()))
1200 << " : audio_osx_source::au_input_callback: Starting." << std::endl;
1201 #endif
1202
1203 osx_source* This = reinterpret_cast<osx_source*>(in_ref_con);
1204 gr::thread::scoped_lock l(This->d_internal);
1205 gr::logger_ptr d_logger = This->d_logger;
1206
1207 #if _OSX_AU_DEBUG_RENDER_
1208 std::cerr << "audio_osx_source::au_input_callback: mutex locked." << std::endl;
1209 #endif
1210
1211 OSStatus err = noErr;
1212
1213 #if _OSX_AU_DEBUG_RENDER_
1214 std::cerr << "cb0: in#Fr = " << in_number_frames << ", inBus# = " << in_bus_number
1215 << ", idD = " << ((void*)io_data)
1216 << ", d_ib = " << ((void*)(This->d_input_buffer))
1217 << ", d_ib#c = " << This->d_input_buffer->mNumberBuffers
1218 << ", SC = " << This->d_queue_sample_count << std::endl;
1219 #endif
1220
1221 if (This->d_do_reset) {
1222
1223 // clear audio data; do not render since it will generate an error
1224
1225 AudioBufferList* t_abl = This->d_input_buffer;
1226 for (UInt32 nn = 0; nn < t_abl->mNumberBuffers; ++nn) {
1227 AudioBuffer* t_ab = &(t_abl->mBuffers[nn]);
1228 memset(t_ab->mData,
1229 0,
1230 (size_t)((t_ab->mDataByteSize) * (t_ab->mNumberChannels)));
1231 }
1232 } else {
1233
1234 // Get the new audio data from the input device
1235
1236 err = AudioUnitRender(This->d_input_au,
1237 io_action_flags,
1238 in_time_stamp,
1239 1, // inBusNumber,
1240 in_number_frames,
1241 This->d_input_buffer);
1242 check_error_and_throw(
1243 err, "AudioUnitRender", "audio_osx_source::au_input_callback");
1244 }
1245
1246 UInt32 available_input_frames = This->d_n_available_input_frames = in_number_frames;
1247
1248 // get the number of actual output frames,
1249 // either via converting the buffer or not
1250
1251 UInt32 actual_output_frames = available_input_frames;
1252
1253 if (!This->d_pass_through) {
1254 UInt32 available_input_bytes = available_input_frames * sizeof(float);
1255 UInt32 available_output_bytes = available_input_bytes;
1256 UInt32 prop_size = sizeof(available_output_bytes);
1257 err = AudioConverterGetProperty(This->d_audio_converter,
1258 kAudioConverterPropertyCalculateOutputBufferSize,
1259 &prop_size,
1260 &available_output_bytes);
1261 check_error_and_throw(
1262 err, "Get Output Buffer Size failed", "audio_osx_source::au_input_callback");
1263
1264 UInt32 available_output_frames = available_output_bytes / sizeof(float);
1265
1266 #if 0
1267 // when decimating too much, the output sounds warbly due to
1268 // fluctuating # of output frames
1269 // This should not be a surprise, but there's probably some
1270 // clever programming that could lessed the effect ...
1271 // like finding the "ideal" # of output frames, and keeping
1272 // that number constant no matter the # of input frames
1273
1274 UInt32 l_input_bytes = available_output_bytes;
1275 prop_size = sizeof(available_output_bytes);
1276 err = AudioConverterGetProperty
1277 (This->d_audio_converter,
1278 kAudioConverterPropertyCalculateInputBufferSize,
1279 &prop_size, &l_input_bytes);
1280 check_error_and_throw
1281 (err, "Get Input Buffer Size failed",
1282 "audio_osx_source::au_input_callback");
1283
1284 if(l_input_bytes < available_input_bytes) {
1285 // OK to zero pad the input a little
1286 ++available_output_frames;
1287 available_output_bytes = available_output_frames * sizeof(float);
1288 }
1289
1290 #endif
1291
1292 #if _OSX_AU_DEBUG_RENDER_
1293 std::cerr << "cb1: avail: #IF = " << available_input_frames
1294 << ", #OF = " << available_output_frames << std::endl;
1295 #endif
1296 actual_output_frames = available_output_frames;
1297
1298 // convert the data to the correct rate; on input,
1299 // actual_output_frames is the number of available output frames
1300
1301 err = AudioConverterFillComplexBuffer(
1302 This->d_audio_converter,
1303 reinterpret_cast<AudioConverterComplexInputDataProc>(
1304 &(This->converter_callback)),
1305 in_ref_con,
1306 &actual_output_frames,
1307 This->d_output_buffer,
1308 NULL);
1309 check_error_and_throw(err,
1310 "AudioConverterFillComplexBuffer failed",
1311 "audio_osx_source::au_input_callback");
1312
1313 // on output, actual_output_frames is the actual number of
1314 // output frames
1315
1316 #if _OSX_AU_DEBUG_RENDER_
1317 std::cerr << "cb2: actual: #IF = " << This->d_n_actual_input_frames
1318 << ", #OF = " << actual_output_frames << std::endl;
1319 if (This->d_n_actual_input_frames != available_input_frames)
1320 std::cerr << "cb2.1: avail#IF = " << available_input_frames
1321 << ", actual#IF = " << This->d_n_actual_input_frames << std::endl;
1322 #endif
1323 }
1324
1325 // add the output frames to the buffers' queue, checking for overflow
1326
1327 int counter = This->d_n_user_channels;
1328 int res = 0;
1329
1330 while (--counter >= 0) {
1331 float* in_buffer = (float*)This->d_output_buffer->mBuffers[counter].mData;
1332
1333 #if _OSX_AU_DEBUG_RENDER_
1334 std::cerr << "cb3: enqueuing audio data." << std::endl;
1335 #endif
1336
1337 int l_res = This->d_buffers[counter]->enqueue(in_buffer, actual_output_frames);
1338 if (l_res == -1)
1339 res = -1;
1340 }
1341
1342 if (res == -1) {
1343 // data coming in too fast
1344 // drop oldest buffer
1345 fputs("aO", stderr);
1346 fflush(stderr);
1347 // set the local number of samples available to the max
1348 This->d_queue_sample_count = This->d_buffers[0]->buffer_length_items();
1349 } else {
1350 // keep up the local sample count
1351 This->d_queue_sample_count += actual_output_frames;
1352 }
1353
1354 #if _OSX_AU_DEBUG_RENDER_
1355 std::cerr << "cb4: #OI = " << actual_output_frames
1356 << ", #Cnt = " << This->d_queue_sample_count
1357 << ", mSC = " << This->d_buffer_sample_count << std::endl;
1358 #endif
1359
1360 // signal that data is available, if appropriate
1361
1362 if (This->d_waiting_for_data) {
1363 This->d_cond_data.notify_one();
1364 }
1365
1366 #if _OSX_AU_DEBUG_RENDER_
1367 std::cerr << "cb5: returning." << std::endl;
1368 #endif
1369
1370 return (err);
1371 }
1372
1373 #ifndef GR_USE_OLD_AUDIO_UNIT
1374
hardware_listener(AudioObjectID in_object_id,UInt32 in_num_addresses,const AudioObjectPropertyAddress in_addresses[],void * in_client_data)1375 OSStatus osx_source::hardware_listener(AudioObjectID in_object_id,
1376 UInt32 in_num_addresses,
1377 const AudioObjectPropertyAddress in_addresses[],
1378 void* in_client_data)
1379
1380 #else
1381
1382 OSStatus osx_source::hardware_listener(AudioHardwarePropertyID in_property_id,
1383 void* in_client_data)
1384
1385 #endif
1386 {
1387 osx_source* This = reinterpret_cast<osx_source*>(in_client_data);
1388 This->reset(true);
1389 return (noErr);
1390 }
1391
1392 #ifndef GR_USE_OLD_AUDIO_UNIT
1393
default_listener(AudioObjectID in_object_id,UInt32 in_num_addresses,const AudioObjectPropertyAddress in_addresses[],void * in_client_data)1394 OSStatus osx_source::default_listener(AudioObjectID in_object_id,
1395 UInt32 in_num_addresses,
1396 const AudioObjectPropertyAddress in_addresses[],
1397 void* in_client_data)
1398
1399 #else
1400
1401 OSStatus osx_source::default_listener(AudioHardwarePropertyID in_property_id,
1402 void* in_client_data)
1403
1404 #endif
1405 {
1406 osx_source* This = reinterpret_cast<osx_source*>(in_client_data);
1407 This->reset(false);
1408 return (noErr);
1409 }
1410
1411 } /* namespace audio */
1412 } /* namespace gr */
1413