1 /*
2 Copyright (C) 2008 Remon Sijrier
3 Copyright (C) Grame, 2003.
4 Copyright (C) Johnny Petrantoni, 2003.
5 
6 This file is part of Traverso
7 
8 Traverso is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
12 
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 GNU General Public License for more details.
17 
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA.
21 
22  Grame Research Laboratory, 9, rue du Garet 69001 Lyon - France
23  grame@rd.grame.fr
24 
25  Johnny Petrantoni, johnny@lato-b.com - Italy, Rome.
26 
27  Jan 30, 2004: Johnny Petrantoni: first code of the coreaudio driver, based on portaudio driver by Stephane Letz.
28  Feb 02, 2004: Johnny Petrantoni: fixed null cycle, removed double copy of buffers in AudioRender, the driver works fine (tested with Built-in Audio and Hammerfall RME), but no cpu load is displayed.
29  Feb 03, 2004: Johnny Petrantoni: some little fix.
30  Feb 03, 2004: Stephane Letz: some fix in AudioRender.cpp code.
31  Feb 03, 2004: Johnny Petrantoni: removed the default device stuff (useless, in jackosx, because JackPilot manages this behavior), the device must be specified. and all parameter must be correct.
32  Feb 04, 2004: Johnny Petrantoni: now the driver supports interfaces with multiple interleaved streams (such as the MOTU 828).
33  Nov 05, 2004: S.Letz: correct management of -I option for use with JackPilot.
34  Nov 15, 2004: S.Letz: Set a default value for deviceID.
35  Nov 30, 2004: S.Letz: In coreaudio_driver_write : clear to avoid playing dirty buffers when the client does not produce output anymore.
36  Dec 05, 2004: S.Letz: XRun detection
37  Dec 09, 2004: S.Letz: Dynamic buffer size change
38  Dec 23, 2004: S.Letz: Correct bug in dynamic buffer size change : update period_usecs
39  Jan 20, 2005: S.Letz: Almost complete rewrite using AUHAL.
40  May 20, 2005: S.Letz: Add "systemic" latencies management.
41  Jun 06, 2005: S.Letz: Remove the "-I" parameter, change the semantic of "-n" parameter : -n (driver name) now correctly uses the PropertyDeviceUID
42 					   (persistent accross reboot...) as the identifier for the used coreaudio driver.
43  Jun 14, 2005: S.Letz: Since the "-I" parameter is not used anymore, rename the "systemic" latencies management parametes "-I" and "-O" like for the ALSA driver.
44  Aug 16, 2005: S.Letz: Remove get_device_id_from_num, use get_default_device instead. If the -n option is not used or the device name cannot
45 					   be found, the default device is used. Note: the default device can be used only if both default input and default output are the same.
46  Dec 19, 2005: S.Letz: Add -d option (display_device_names).
47  Apri 7, 2006: S.Letz: Synchronization with the jackdmp coreaudio driver version: improve half-duplex management.
48  May 17, 2006: S.Letz: Minor fix in driver_initialize.
49  May 18, 2006: S.Letz: Document sample rate default value.
50  May 31, 2006: S.Letz: Apply Rui patch for more consistent driver parameter naming.
51  Dec 04, 2007: S.Letz: Fix a bug in sample rate management (occuring in particular with "aggregate" devices).
52  Dec 05, 2007: S.Letz: Correct sample_rate management in Open. Better handling in sample_rate change listener.
53  Nov 11, 2008: Remon Sijrier: Ported to C++ for Traverso
54 
55 */
56 
57 /* CoreAudio driver based on jack-audio-connection-kit-0.xxx.x coreaudio_driver.c */
58 
59 
60 #include "CoreAudioDriver.h"
61 #include "AudioChannel.h"
62 #include "AudioDevice.h"
63 
64 #include <Utils.h>
65 
66 #include <stdio.h>
67 #include <string.h>
68 
69 #include "Debugger.h"
70 
71 //#define PRINTDEBUG 1
72 
73 
CoreAudioDriver(AudioDevice * dev,int rate,nframes_t bufferSize)74 CoreAudioDriver::CoreAudioDriver(AudioDevice * dev, int rate, nframes_t bufferSize)
75 	: Driver(dev, rate, bufferSize)
76 {
77 	PENTERCONS;
78 }
79 
~CoreAudioDriver()80 CoreAudioDriver::~ CoreAudioDriver()
81 {
82 	PENTERDES;
83 }
84 
85 
86 
JCALog(char * fmt,...)87 void JCALog(char *fmt, ...)
88 {
89 #ifdef PRINTDEBUG
90     va_list ap;
91     va_start(ap, fmt);
92     fprintf(stderr, "JCA: ");
93     vfprintf(stderr, fmt, ap);
94     va_end(ap);
95 #endif
96 }
97 
printError(OSStatus err)98 void printError(OSStatus err)
99 {
100 #ifdef DEBUG
101     switch (err) {
102         case kAudioHardwareNoError:
103             JCALog("error code : kAudioHardwareNoError\n");
104             break;
105         case kAudioHardwareNotRunningError:
106             JCALog("error code : kAudioHardwareNotRunningError\n");
107             break;
108         case kAudioHardwareUnspecifiedError:
109             JCALog("error code : kAudioHardwareUnspecifiedError\n");
110             break;
111         case kAudioHardwareUnknownPropertyError:
112             JCALog("error code : kAudioHardwareUnknownPropertyError\n");
113             break;
114         case kAudioHardwareBadPropertySizeError:
115             JCALog("error code : kAudioHardwareBadPropertySizeError\n");
116             break;
117         case kAudioHardwareIllegalOperationError:
118             JCALog("error code : kAudioHardwareIllegalOperationError\n");
119             break;
120         case kAudioHardwareBadDeviceError:
121             JCALog("error code : kAudioHardwareBadDeviceError\n");
122             break;
123         case kAudioHardwareBadStreamError:
124             JCALog("error code : kAudioHardwareBadStreamError\n");
125             break;
126         case kAudioDeviceUnsupportedFormatError:
127             JCALog("error code : kAudioDeviceUnsupportedFormatError\n");
128             break;
129         case kAudioDevicePermissionsError:
130             JCALog("error code : kAudioDevicePermissionsError\n");
131             break;
132         default:
133             JCALog("error code : unknown %ld\n", err);
134             break;
135     }
136 #endif
137 }
138 
get_device_name_from_id(AudioDeviceID id,char name[256])139 OSStatus get_device_name_from_id(AudioDeviceID id, char name[256])
140 {
141 	UInt32 size = sizeof(char) * 256;
142 	OSStatus res = AudioDeviceGetProperty(id, 0, false,
143 						kAudioDevicePropertyDeviceName,
144 						&size,
145 						&name[0]);
146 	return res;
147 }
148 
get_device_id_from_uid(char * UID,AudioDeviceID * id)149 OSStatus get_device_id_from_uid(char* UID, AudioDeviceID* id)
150 {
151 	UInt32 size = sizeof(AudioValueTranslation);
152 	CFStringRef inIUD = CFStringCreateWithCString(NULL, UID, CFStringGetSystemEncoding());
153 	AudioValueTranslation value = { &inIUD, sizeof(CFStringRef), id, sizeof(AudioDeviceID) };
154 	if (inIUD == NULL) {
155 		return kAudioHardwareUnspecifiedError;
156 	} else {
157 		OSStatus res = AudioHardwareGetProperty(kAudioHardwarePropertyDeviceForUID, &size, &value);
158 		CFRelease(inIUD);
159 		JCALog("get_device_id_from_uid %s %ld \n", UID, *id);
160 		return (*id == kAudioDeviceUnknown) ? kAudioHardwareBadDeviceError : res;
161 	}
162 }
163 
get_default_device(AudioDeviceID * id)164 OSStatus get_default_device(AudioDeviceID * id)
165 {
166 	OSStatus res;
167 	UInt32 theSize = sizeof(UInt32);
168 	AudioDeviceID inDefault;
169 	AudioDeviceID outDefault;
170 
171 	if ((res = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice,
172 					&theSize, &inDefault)) != noErr)
173 		return res;
174 
175 	if ((res = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice,
176 					&theSize, &outDefault)) != noErr)
177 		return res;
178 
179 	JCALog("get_default_device: input %ld output %ld\n", inDefault, outDefault);
180 
181 	// Get the device only if default input and ouput are the same
182 	if (inDefault == outDefault) {
183 		*id = inDefault;
184 		return noErr;
185 	} else {
186 		PERROR("CoreAudioDriver:: Default input and output devices are not the same !!");
187 		return kAudioHardwareBadDeviceError;
188 	}
189 }
190 
get_default_input_device(AudioDeviceID * id)191 OSStatus get_default_input_device(AudioDeviceID* id)
192 {
193 	OSStatus res;
194 	UInt32 theSize = sizeof(UInt32);
195 	AudioDeviceID inDefault;
196 
197 	if ((res = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice,
198 						&theSize, &inDefault)) != noErr)
199 		return res;
200 
201 	JCALog("get_default_input_device: input = %ld \n", inDefault);
202 	*id = inDefault;
203 	return noErr;
204 }
205 
get_default_output_device(AudioDeviceID * id)206 OSStatus get_default_output_device(AudioDeviceID* id)
207 {
208 	OSStatus res;
209 	UInt32 theSize = sizeof(UInt32);
210 	AudioDeviceID outDefault;
211 
212 	if ((res = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice,
213 						&theSize, &outDefault)) != noErr)
214 		return res;
215 
216 	JCALog("get_default_output_device: output = %ld\n", outDefault);
217 	*id = outDefault;
218 	return noErr;
219 }
220 
get_total_channels(AudioDeviceID device,int * channelCount,bool isInput)221 OSStatus get_total_channels(AudioDeviceID device, int* channelCount, bool isInput)
222 {
223 	OSStatus			err = noErr;
224 	UInt32				outSize;
225 	Boolean				outWritable;
226 	AudioBufferList*	bufferList = 0;
227 	AudioStreamID*		streamList = 0;
228 	int					i, numStream;
229 
230 	err = AudioDeviceGetPropertyInfo(device, 0, isInput, kAudioDevicePropertyStreams, &outSize, &outWritable);
231 	if (err == noErr) {
232 		streamList = (AudioStreamID*)malloc(outSize);
233 		numStream = outSize/sizeof(AudioStreamID);
234 		JCALog("get_total_channels device stream number = %ld numStream = %ld\n", device, numStream);
235 		err = AudioDeviceGetProperty(device, 0, isInput, kAudioDevicePropertyStreams, &outSize, streamList);
236 		if (err == noErr) {
237 			AudioStreamBasicDescription streamDesc;
238 			outSize = sizeof(AudioStreamBasicDescription);
239 			for (i = 0; i < numStream; i++) {
240 				err = AudioStreamGetProperty(streamList[i], 0, kAudioDevicePropertyStreamFormat, &outSize, &streamDesc);
241 				JCALog("get_total_channels streamDesc mFormatFlags = %ld mChannelsPerFrame = %ld\n", streamDesc.mFormatFlags, streamDesc.mChannelsPerFrame);
242 			}
243 		}
244 	}
245 
246 	*channelCount = 0;
247 	err = AudioDeviceGetPropertyInfo(device, 0, isInput, kAudioDevicePropertyStreamConfiguration, &outSize, &outWritable);
248 	if (err == noErr) {
249 		bufferList = (AudioBufferList*)malloc(outSize);
250 		err = AudioDeviceGetProperty(device, 0, isInput, kAudioDevicePropertyStreamConfiguration, &outSize, bufferList);
251 		if (err == noErr) {
252 		for (i = 0; i < bufferList->mNumberBuffers; i++)
253 			*channelCount += bufferList->mBuffers[i].mNumberChannels;
254 		}
255 	}
256 
257 	if (streamList)
258 		free(streamList);
259 	if (bufferList)
260 		free(bufferList);
261 
262 	return err;
263 }
264 
display_device_names()265 OSStatus display_device_names()
266 {
267 	UInt32 size;
268 	Boolean isWritable;
269 	int i, deviceNum;
270 	OSStatus err;
271 	CFStringRef UIname;
272 
273 	err = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDevices, &size, &isWritable);
274 	if (err != noErr)
275 			return err;
276 
277 	deviceNum = size/sizeof(AudioDeviceID);
278 	AudioDeviceID devices[deviceNum];
279 
280 	err = AudioHardwareGetProperty(kAudioHardwarePropertyDevices, &size, devices);
281 	if (err != noErr)
282 			return err;
283 
284 	for (i = 0; i < deviceNum; i++) {
285         char device_name[256];
286 		char internal_name[256];
287 
288 		size = sizeof(CFStringRef);
289 		UIname = NULL;
290 		err = AudioDeviceGetProperty(devices[i], 0, false, kAudioDevicePropertyDeviceUID, &size, &UIname);
291 		if (err == noErr) {
292 			CFStringGetCString(UIname, internal_name, 256, CFStringGetSystemEncoding());
293 		} else {
294 			goto error;
295 		}
296 
297 		size = 256;
298 		err = AudioDeviceGetProperty(devices[i], 0, false, kAudioDevicePropertyDeviceName, &size, device_name);
299 		if (err != noErr)
300 			return err;
301 		printf("ICI\n");
302 		printf("Device name = \'%s\', internal_name = \'%s\' (to be used as -d parameter)\n", device_name, internal_name);
303 	}
304 
305 	return noErr;
306 
307 error:
308 	if (UIname != NULL)
309 		CFRelease(UIname);
310 	return err;
311 }
312 
render(AudioUnitRenderActionFlags * ioActionFlags,const AudioTimeStamp * inTimeStamp,UInt32 inBusNumber,UInt32 inNumberFrames,AudioBufferList * ioData)313 OSStatus CoreAudioDriver::render(AudioUnitRenderActionFlags 	*ioActionFlags,
314 		const AudioTimeStamp 		*inTimeStamp,
315 		UInt32 				inBusNumber,
316 		UInt32 				inNumberFrames,
317 		AudioBufferList 		*ioData)
318 {
319 	int res, i;
320 
321 	AudioUnitRender(au_hal, ioActionFlags, inTimeStamp, 1, inNumberFrames, input_list);
322 
323 	if (xrun_detected > 0) { /* XRun was detected */
324 		trav_time_t current_time = get_microseconds ();
325 		device->delay(current_time - (last_wait_ust + period_usecs));
326 		last_wait_ust = current_time;
327 		xrun_detected = 0;
328 		return 0;
329 	} else {
330 		last_wait_ust = get_microseconds();
331 		device->transport_cycle_start(get_microseconds());
332 		res = device->run_cycle(inNumberFrames, 0);
333 	}
334 
335 	if (null_cycle_occured) {
336 		null_cycle_occured = 0;
337 		for (i = 0; i < playback_nchannels; i++) {
338 			memset((float*)ioData->mBuffers[i].mData, 0, sizeof(float) * inNumberFrames);
339 		}
340 	} else {
341 		// TODO find out if ioData->mBuffers[i] correspond with the playbackChannels indices
342 		audio_sample_t* buf;
343 		for (int i=0; i<playbackChannels.size(); ++i) {
344 			AudioChannel* channel = playbackChannels.at(i);
345 			if (!channel->has_data()) {
346 				continue;
347 			}
348 			buf = channel->get_data();
349 
350 			memcpy((float*)ioData->mBuffers[i].mData, buf, sizeof(float) * inNumberFrames);
351 
352 			// Not sure if this is needed? I think so though
353 			channel->silence_buffer(inNumberFrames);
354 		}
355 	}
356 
357 	return res;
358 }
359 
render_input(AudioUnitRenderActionFlags * ioActionFlags,const AudioTimeStamp * inTimeStamp,UInt32 inBusNumber,UInt32 inNumberFrames,AudioBufferList * ioData)360 OSStatus CoreAudioDriver::render_input(  AudioUnitRenderActionFlags 	*ioActionFlags,
361 			const AudioTimeStamp 		*inTimeStamp,
362 			UInt32 				inBusNumber,
363 			UInt32 				inNumberFrames,
364 			AudioBufferList 		*ioData)
365 {
366 	AudioUnitRender(au_hal, ioActionFlags, inTimeStamp, 1, inNumberFrames, input_list);
367 	if (xrun_detected > 0) { /* XRun was detected */
368 		trav_time_t current_time = get_microseconds();
369 		device->delay(current_time - (last_wait_ust + period_usecs));
370 		last_wait_ust = current_time;
371 		xrun_detected = 0;
372 		return 0;
373     } else {
374 		last_wait_ust = get_microseconds();
375 		device->transport_cycle_start(get_microseconds());
376 		return device->run_cycle(inNumberFrames, 0);
377 	}
378 }
379 
380 
sr_notification(AudioDeviceID inDevice,UInt32 inChannel,Boolean isInput,AudioDevicePropertyID inPropertyID)381 OSStatus CoreAudioDriver::sr_notification(AudioDeviceID inDevice,
382         UInt32 inChannel,
383         Boolean	isInput,
384         AudioDevicePropertyID inPropertyID)
385 {
386 
387 	switch (inPropertyID) {
388 
389 		case kAudioDevicePropertyNominalSampleRate: {
390 			JCALog("JackCoreAudioDriver::SRNotificationCallback kAudioDevicePropertyNominalSampleRate \n");
391 			state = 1;
392 			break;
393 		}
394 	}
395 
396 	return noErr;
397 }
398 
notification(AudioDeviceID inDevice,UInt32 inChannel,Boolean isInput,AudioDevicePropertyID inPropertyID)399 OSStatus CoreAudioDriver::notification(AudioDeviceID inDevice,
400 	UInt32 inChannel,
401 	Boolean	isInput,
402 	AudioDevicePropertyID inPropertyID)
403 {
404 	switch (inPropertyID) {
405 
406 		case kAudioDeviceProcessorOverload:
407 			xrun_detected = 1;
408 			break;
409 
410 		case kAudioDevicePropertyNominalSampleRate: {
411 			UInt32 outSize =  sizeof(Float64);
412 			Float64 sampleRate;
413 			AudioStreamBasicDescription srcFormat, dstFormat;
414 
415 			// FIXME kAudioDeviceSectionGlobal not declared  compile error ?
416 			OSStatus err;
417 /*			OSStatus err = AudioDeviceGetProperty(device_id, 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyNominalSampleRate, &outSize, &sampleRate);
418 			if (err != noErr) {
419 				PERROR("Cannot get current sample rate");
420 				return kAudioHardwareUnsupportedOperationError;
421 			}*/
422 			JCALog("JackCoreAudioDriver::NotificationCallback kAudioDevicePropertyNominalSampleRate %ld\n", (long)sampleRate);
423 			outSize = sizeof(AudioStreamBasicDescription);
424 
425 			// Update SR for input
426 			err = AudioUnitGetProperty(au_hal, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &srcFormat, &outSize);
427 			if (err != noErr) {
428 				PERROR("Error calling AudioUnitSetProperty - kAudioUnitProperty_StreamFormat kAudioUnitScope_Input");
429 			}
430 			srcFormat.mSampleRate = sampleRate;
431 			err = AudioUnitSetProperty(au_hal, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &srcFormat, outSize);
432 			if (err != noErr) {
433 				PERROR("Error calling AudioUnitSetProperty - kAudioUnitProperty_StreamFormat kAudioUnitScope_Input");
434 			}
435 
436 			// Update SR for output
437 			err = AudioUnitGetProperty(au_hal, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 1, &dstFormat, &outSize);
438 			if (err != noErr) {
439 				PERROR("Error calling AudioUnitSetProperty - kAudioUnitProperty_StreamFormat kAudioUnitScope_Output");
440 			}
441 			dstFormat.mSampleRate = sampleRate;
442 			err = AudioUnitSetProperty(au_hal, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 1, &dstFormat, outSize);
443 			if (err != noErr) {
444 				PERROR("Error calling AudioUnitSetProperty - kAudioUnitProperty_StreamFormat kAudioUnitScope_Output");
445 			}
446 			break;
447 		}
448 	}
449 	return noErr;
450 }
451 
452 
453 
attach()454 int CoreAudioDriver::attach()
455 {
456 	int port_flags;
457 	channel_t chn;
458 	AudioChannel* chan;
459 	char buf[32];
460 	char channel_name[64];
461 	OSStatus err;
462 	UInt32 size;
463 	UInt32 value1,value2;
464 	Boolean isWritable;
465 
466 	device->set_buffer_size (frames_per_cycle);
467 	device->set_sample_rate (frame_rate);
468 
469 	port_flags = PortIsOutput|PortIsPhysical|PortIsTerminal;
470 
471 	for (chn = 0; chn < capture_nchannels; chn++) {
472 		err = AudioDeviceGetPropertyInfo(device_id, chn + 1, true, kAudioDevicePropertyChannelName, &size, &isWritable);
473 		if (err == noErr && size > 0)  {
474 			err = AudioDeviceGetProperty(device_id, chn + 1, true, kAudioDevicePropertyChannelName, &size, channel_name);
475 			if (err != noErr)
476 				JCALog("AudioDeviceGetProperty kAudioDevicePropertyChannelName error \n");
477 			snprintf(buf, sizeof(buf) - 1, "%s:out_%s%lu", capture_driver_name, channel_name, chn + 1);
478 		} else {
479 			snprintf(buf, sizeof(buf) - 1, "%s:out%lu", capture_driver_name, chn + 1);
480 		}
481 
482 		chan = device->register_capture_channel(buf, "32 bit float audio", port_flags, frames_per_cycle, chn);
483 		chan->set_latency( frames_per_cycle + capture_frame_latency );
484 		captureChannels.append(chan);
485 
486 		size = sizeof(UInt32);
487 		value1 = value2 = 0;
488 		err = AudioDeviceGetProperty(device_id, 0, true, kAudioDevicePropertyLatency, &size, &value1);
489 		if (err != noErr)
490 			JCALog("AudioDeviceGetProperty kAudioDevicePropertyLatency error \n");
491 		err = AudioDeviceGetProperty(device_id, 0, true, kAudioDevicePropertySafetyOffset, &size, &value2);
492 		if (err != noErr)
493 			JCALog("AudioDeviceGetProperty kAudioDevicePropertySafetyOffset error \n");
494 
495 	}
496 
497 	port_flags = PortIsInput|PortIsPhysical|PortIsTerminal;
498 
499 	for (chn = 0; chn < playback_nchannels; chn++) {
500 		err = AudioDeviceGetPropertyInfo(device_id, chn + 1, false, kAudioDevicePropertyChannelName, &size, &isWritable);
501 		if (err == noErr && size > 0)  {
502 			err = AudioDeviceGetProperty(device_id, chn + 1, false, kAudioDevicePropertyChannelName, &size, channel_name);
503 			if (err != noErr)
504 				JCALog("AudioDeviceGetProperty kAudioDevicePropertyChannelName error \n");
505 			snprintf(buf, sizeof(buf) - 1, "%s:in_%s%lu", playback_driver_name, channel_name, chn + 1);
506 		} else {
507 			snprintf(buf, sizeof(buf) - 1, "%s:in%lu", playback_driver_name, chn + 1);
508 		}
509 
510 		chan = device->register_playback_channel(buf, "32 bit float audio", port_flags, frames_per_cycle, chn);
511 		chan->set_latency( frames_per_cycle + capture_frame_latency );
512 		playbackChannels.append(chan);
513 
514 		size = sizeof(UInt32);
515 		value1 = value2 = 0;
516 		err = AudioDeviceGetProperty(device_id, 0, false, kAudioDevicePropertyLatency, &size, &value1);
517 		if (err != noErr)
518 			JCALog("AudioDeviceGetProperty kAudioDevicePropertyLatency error \n");
519 		err = AudioDeviceGetProperty(device_id, 0, false, kAudioDevicePropertySafetyOffset, &size, &value2);
520 		if (err != noErr)
521 			JCALog("AudioDeviceGetProperty kAudioDevicePropertySafetyOffset error \n");
522 	}
523 
524 
525 	// Input buffers do no change : prepare them only once
526 	for (chn = 0; chn < capture_nchannels; chn++) {
527 		input_list->mBuffers[chn].mData = (audio_sample_t*)(captureChannels.at(chn)->get_buffer(frames_per_cycle));
528 	}
529 
530 	return 1;
531 }
532 
533 
setup(bool capture,bool playback,const QString & cardDevice)534 int CoreAudioDriver::setup(bool capture, bool playback, const QString & cardDevice)
535 {
536 	return -1;
537 }
538 
539 
540 
_render(void * inRefCon,AudioUnitRenderActionFlags * ioActionFlags,const AudioTimeStamp * inTimeStamp,UInt32 inBusNumber,UInt32 inNumberFrames,AudioBufferList * ioData)541 static OSStatus _render(void * inRefCon, AudioUnitRenderActionFlags * ioActionFlags, const AudioTimeStamp * inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList * ioData)
542 {
543 	CoreAudioDriver* driver = (CoreAudioDriver*)inRefCon;
544 	return driver->render(ioActionFlags, inTimeStamp, inBusNumber, inNumberFrames, ioData);
545 }
546 
_render_input(void * inRefCon,AudioUnitRenderActionFlags * ioActionFlags,const AudioTimeStamp * inTimeStamp,UInt32 inBusNumber,UInt32 inNumberFrames,AudioBufferList * ioData)547 static OSStatus _render_input(void * inRefCon, AudioUnitRenderActionFlags * ioActionFlags, const AudioTimeStamp * inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList * ioData)
548 {
549 	CoreAudioDriver* driver = (CoreAudioDriver*)inRefCon;
550 	return driver->render_input(ioActionFlags, inTimeStamp, inBusNumber, inNumberFrames, ioData);
551 }
552 
_sr_notification(AudioDeviceID inDevice,UInt32 inChannel,Boolean isInput,AudioDevicePropertyID inPropertyID,void * inClientData)553 static OSStatus _sr_notification(AudioDeviceID inDevice, UInt32 inChannel, Boolean isInput, AudioDevicePropertyID inPropertyID, void * inClientData)
554 {
555 	CoreAudioDriver* driver = (CoreAudioDriver*)inClientData;
556 	return driver->sr_notification(inDevice, inChannel, isInput, inPropertyID);
557 }
558 
_notification(AudioDeviceID inDevice,UInt32 inChannel,Boolean isInput,AudioDevicePropertyID inPropertyID,void * inClientData)559 static OSStatus _notification(AudioDeviceID inDevice, UInt32 inChannel, Boolean isInput, AudioDevicePropertyID inPropertyID, void * inClientData)
560 {
561 	CoreAudioDriver* driver = (CoreAudioDriver*)inClientData;
562 	return driver->notification(inDevice, inChannel, isInput, inPropertyID);
563 }
564 
565