1/*
2 * Copyright (c) 1998-2014 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License").  You may not use this file except in compliance with the
9 * License.  Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
11 *
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22
23#include "IOAudioDebug.h"
24#include "IOAudioEngineUserClient.h"
25#include "IOAudioEngine.h"
26#include "IOAudioTypes.h"
27#include "IOAudioStream.h"
28#include "IOAudioDebug.h"
29#include "IOAudioDefines.h"
30
31#include <IOKit/IOLib.h>
32#include <IOKit/IOMemoryDescriptor.h>
33#include <IOKit/IOWorkLoop.h>
34#include <IOKit/IOCommandGate.h>
35#include <IOKit/IOKitKeys.h>
36
37// <rdar://8518215>
38enum
39{
40	kCommandGateStatus_Normal				= 0,
41	kCommandGateStatus_RemovalPending,
42	kCommandGateStatus_Invalid
43};
44
45// <rdar://15277619>
46enum
47{
48    kLoopCountMaximumDifference             = 5
49};
50
51#define super OSObject
52
53class IOAudioClientBufferSet : public OSObject
54{
55    OSDeclareDefaultStructors(IOAudioClientBufferSet);
56
57public:
58    UInt32							bufferSetID;
59    IOAudioEngineUserClient	*		userClient;
60    IOAudioClientBuffer64	*		outputBufferList;
61    IOAudioClientBuffer64	*		inputBufferList;
62    IOAudioEnginePosition			nextOutputPosition;
63    AbsoluteTime					outputTimeout;
64    AbsoluteTime					sampleInterval;
65    IOAudioClientBufferSet *		mNextBufferSet;
66    thread_call_t					watchdogThreadCall;
67    UInt32							generationCount;
68    bool							timerPending;
69
70    bool init(UInt32 setID, IOAudioEngineUserClient *client);
71    void free();
72
73#ifdef DEBUG
74    void retain() const;
75    void release() const;
76#endif
77
78    void resetNextOutputPosition();
79
80    void allocateWatchdogTimer();
81    void freeWatchdogTimer();
82
83    void setWatchdogTimeout(AbsoluteTime *timeout);
84    void cancelWatchdogTimer();
85
86    static void watchdogTimerFired(IOAudioClientBufferSet *clientBufferSet, UInt32 generationCount);
87};
88
89OSDefineMetaClassAndStructors(IOAudioClientBufferSet, OSObject)
90
91//	<rdar://8121989>	Restructured for single point of entry and single point of exit so that
92//	the indentifier post processing tool can properly insert scope when post processing a log file
93//	obtained via fwkpfv.
94
95bool IOAudioClientBufferSet::init(UInt32 setID, IOAudioEngineUserClient *client)
96{
97	bool			result = false;
98
99    audioDebugIOLog(3, "+ IOAudioClientBufferSet[%p]::init(%lx, %p)\n", this, (long unsigned int)setID, client);
100
101	if ( super::init () )
102	{
103		if ( 0 != client )
104		{
105			bufferSetID = setID;
106			client->retain();
107			userClient = client;
108
109			outputBufferList = NULL;
110			inputBufferList = NULL;
111			mNextBufferSet = NULL;
112			watchdogThreadCall = NULL;
113			generationCount = 0;
114			timerPending = false;
115
116			resetNextOutputPosition();
117			result = true;
118		}
119	}
120
121    audioDebugIOLog(3, "- IOAudioClientBufferSet[%p]::init(%lx, %p) returns %d\n", this, (long unsigned int)setID, client, result );
122    return result;
123}
124
125void IOAudioClientBufferSet::free()
126{
127    audioDebugIOLog(3, "+ IOAudioClientBufferSet[%p]::free()\n", this);
128
129    if (watchdogThreadCall) {
130        freeWatchdogTimer();
131    }
132
133    if (userClient != NULL) {
134        userClient->release();
135        userClient = NULL;
136    }
137
138    super::free();
139
140    audioDebugIOLog(3, "- IOAudioClientBufferSet[%p]::free()\n", this);
141	return;
142}
143
144#ifdef DEBUG
145void IOAudioClientBufferSet::retain() const
146{
147   super::retain();
148}
149
150void IOAudioClientBufferSet::release() const
151{
152    super::release();
153}
154#endif
155
156void IOAudioClientBufferSet::resetNextOutputPosition()
157{
158    nextOutputPosition.fLoopCount = 0;
159    nextOutputPosition.fSampleFrame = 0;
160}
161
162void IOAudioClientBufferSet::allocateWatchdogTimer()
163{
164    audioDebugIOLog(3, "+ IOAudioClientBufferSet[%p]::allocateWatchdogTimer()\n", this);
165
166    if (watchdogThreadCall == NULL) {
167        watchdogThreadCall = thread_call_allocate((thread_call_func_t)IOAudioClientBufferSet::watchdogTimerFired, (thread_call_param_t)this);
168    }
169
170    audioDebugIOLog(3, "- IOAudioClientBufferSet[%p]::allocateWatchdogTimer()\n", this);
171	return;
172}
173
174void IOAudioClientBufferSet::freeWatchdogTimer()
175{
176    audioDebugIOLog(3, "+ IOAudioClientBufferSet[%p]::freeWatchdogTimer()\n", this);
177
178    if (watchdogThreadCall != NULL) {
179        cancelWatchdogTimer();
180        thread_call_free(watchdogThreadCall);
181        watchdogThreadCall = NULL;
182    }
183
184    audioDebugIOLog(3, "- IOAudioClientBufferSet[%p]::freeWatchdogTimer()\n", this);
185	return;
186}
187
188void IOAudioClientBufferSet::setWatchdogTimeout(AbsoluteTime *timeout)
189{
190	bool				result;
191
192    if (watchdogThreadCall == NULL) {
193        // allocate it here
194        IOLog("IOAudioClientBufferSet[%p]::setWatchdogTimeout() - no thread call.\n", this);
195    }
196
197    assert(watchdogThreadCall);
198
199    outputTimeout = *timeout;
200
201    generationCount++;
202
203	userClient->lockBuffers();
204
205	retain();
206
207    timerPending = true;
208
209    result = thread_call_enter1_delayed(watchdogThreadCall, (thread_call_param_t)(uintptr_t)generationCount, outputTimeout);
210	if (result) {
211		release();		// canceled the previous call
212	}
213
214	userClient->unlockBuffers();
215}
216
217void IOAudioClientBufferSet::cancelWatchdogTimer()
218{
219    audioDebugIOLog(3, "+ IOAudioClientBufferSet[%p]::cancelWatchdogTimer()\n", this);
220
221	if (NULL != userClient) {
222		userClient->retain();
223		userClient->lockBuffers();
224		if (timerPending) {
225			timerPending = false;
226			if (thread_call_cancel(watchdogThreadCall))
227				release();
228		}
229		userClient->unlockBuffers();
230		userClient->release();
231	}
232
233    audioDebugIOLog(3, "- IOAudioClientBufferSet[%p]::cancelWatchdogTimer()\n", this);
234	return;
235}
236
237void IOAudioClientBufferSet::watchdogTimerFired(IOAudioClientBufferSet *clientBufferSet, UInt32 generationCount)
238{
239    IOAudioEngineUserClient *userClient;
240
241	assert(clientBufferSet);
242    assert(clientBufferSet->userClient);
243
244	if (clientBufferSet) {
245#ifdef DEBUG
246		AbsoluteTime now;
247		clock_get_uptime(&now);
248
249#ifdef __LP64__
250		audioDebugIOLog(3, "+ IOAudioClientBufferSet[%p]::watchdogTimerFired(%ld):(%llu)(%llu)(%lx,%lx)\n",
251							clientBufferSet,
252							(long int)generationCount,
253							now,
254							clientBufferSet->outputTimeout,
255							(long unsigned int)clientBufferSet->nextOutputPosition.fLoopCount,
256							(long unsigned int)clientBufferSet->nextOutputPosition.fSampleFrame);
257#else	/* __LP64__ */
258		audioDebugIOLog(3, "+ IOAudioClientBufferSet[%p]::watchdogTimerFired(%ld):(%lx,%lx)(%lx,%lx)(%lx,%lx)\n",
259							clientBufferSet,
260							(long int)generationCount,
261							now.hi,
262							now.lo,
263							clientBufferSet->outputTimeout.hi,
264							clientBufferSet->outputTimeout.lo,
265							clientBufferSet->nextOutputPosition.fLoopCount,
266							clientBufferSet->nextOutputPosition.fSampleFrame);
267#endif	/* __LP64__ */
268
269#endif /* DEBUG */
270
271		userClient = clientBufferSet->userClient;
272		if (userClient) {
273			userClient->retain();
274			userClient->lockBuffers();
275
276			if(clientBufferSet->timerPending != false) {
277				userClient->performWatchdogOutput(clientBufferSet, generationCount);
278			}
279
280			clientBufferSet->release();
281
282			userClient->unlockBuffers();
283			userClient->release();
284		}
285
286		// clientBufferSet->release code was down here...
287
288#ifdef DEBUG
289#ifdef __LP64__
290		audioDebugIOLog(3, "- IOAudioClientBufferSet[%p]::watchdogTimerFired(%ld):(%llu)(%llu)(%lx,%lx)\n",
291							clientBufferSet,
292							(long int)generationCount,
293							now,
294							clientBufferSet->outputTimeout,
295							(long unsigned int)clientBufferSet->nextOutputPosition.fLoopCount,
296							(long unsigned int)clientBufferSet->nextOutputPosition.fSampleFrame);
297#else	/* __LP64__ */
298		audioDebugIOLog(3, "- IOAudioClientBufferSet[%p]::watchdogTimerFired(%ld):(%lx,%lx)(%lx,%lx)(%lx,%lx)\n",
299							clientBufferSet,
300							(long int)generationCount,
301							now.hi,
302							now.lo,
303							clientBufferSet->outputTimeout.hi,
304							clientBufferSet->outputTimeout.lo,
305							clientBufferSet->nextOutputPosition.fLoopCount,
306							clientBufferSet->nextOutputPosition.fSampleFrame);
307#endif	/* __LP64__ */
308#endif /* DEBUG */
309	} else {
310		IOLog ("IOAudioClientBufferSet::watchdogTimerFired assert (clientBufferSet == NULL) failed\n");
311	}
312	return;
313}
314
315#undef super
316#define super IOUserClient
317
318OSDefineMetaClassAndStructors(IOAudioEngineUserClient, IOUserClient)
319
320OSMetaClassDefineReservedUsed(IOAudioEngineUserClient, 0);
321OSMetaClassDefineReservedUsed(IOAudioEngineUserClient, 1);
322OSMetaClassDefineReservedUsed(IOAudioEngineUserClient, 2);
323OSMetaClassDefineReservedUsed(IOAudioEngineUserClient, 3);
324OSMetaClassDefineReservedUsed(IOAudioEngineUserClient, 4);
325OSMetaClassDefineReservedUsed(IOAudioEngineUserClient, 5);
326OSMetaClassDefineReservedUsed(IOAudioEngineUserClient, 6);
327OSMetaClassDefineReservedUsed(IOAudioEngineUserClient, 7);
328OSMetaClassDefineReservedUsed(IOAudioEngineUserClient, 8);
329OSMetaClassDefineReservedUsed(IOAudioEngineUserClient, 9);
330OSMetaClassDefineReservedUsed(IOAudioEngineUserClient, 10);
331OSMetaClassDefineReservedUsed(IOAudioEngineUserClient, 11);
332
333
334OSMetaClassDefineReservedUnused(IOAudioEngineUserClient, 12);
335OSMetaClassDefineReservedUnused(IOAudioEngineUserClient, 13);
336OSMetaClassDefineReservedUnused(IOAudioEngineUserClient, 14);
337OSMetaClassDefineReservedUnused(IOAudioEngineUserClient, 15);
338OSMetaClassDefineReservedUnused(IOAudioEngineUserClient, 16);
339OSMetaClassDefineReservedUnused(IOAudioEngineUserClient, 17);
340OSMetaClassDefineReservedUnused(IOAudioEngineUserClient, 18);
341OSMetaClassDefineReservedUnused(IOAudioEngineUserClient, 19);
342OSMetaClassDefineReservedUnused(IOAudioEngineUserClient, 20);
343OSMetaClassDefineReservedUnused(IOAudioEngineUserClient, 21);
344OSMetaClassDefineReservedUnused(IOAudioEngineUserClient, 22);
345OSMetaClassDefineReservedUnused(IOAudioEngineUserClient, 23);
346OSMetaClassDefineReservedUnused(IOAudioEngineUserClient, 24);
347OSMetaClassDefineReservedUnused(IOAudioEngineUserClient, 25);
348OSMetaClassDefineReservedUnused(IOAudioEngineUserClient, 26);
349OSMetaClassDefineReservedUnused(IOAudioEngineUserClient, 27);
350OSMetaClassDefineReservedUnused(IOAudioEngineUserClient, 28);
351OSMetaClassDefineReservedUnused(IOAudioEngineUserClient, 29);
352OSMetaClassDefineReservedUnused(IOAudioEngineUserClient, 30);
353OSMetaClassDefineReservedUnused(IOAudioEngineUserClient, 31);
354
355// New code added here
356
357// OSMetaClassDefineReservedUsed(IOAudioEngineUserClient, 5);
358//	<rdar://8121989>	Restructured for single point of entry and single point of exit so that
359//	the indentifier post processing tool can properly insert scope when post processing a log file
360//	obtained via fwkpfv.
361
362bool IOAudioEngineUserClient::initWithAudioEngine(IOAudioEngine *engine, task_t task, void *securityToken, UInt32 type, OSDictionary* properties)
363{
364	bool			result = false;
365
366    audioDebugIOLog(3, "+ IOAudioEngineUserClient[%p]::initWithAudioEngine(%p, 0x%lx, %p, 0x%lx, %p)\n", this, engine, (long unsigned int)task, securityToken, (long unsigned int)type, properties);
367
368	// Declare Rosetta compatibility
369	if ( properties )
370	{
371		properties->setObject ( kIOUserClientCrossEndianCompatibleKey, kOSBooleanTrue );
372	}
373
374	if ( initWithTask ( task, securityToken, type, properties ) )
375	{
376		if ( engine && task )
377		{
378			clientTask = task;
379			audioEngine = engine;
380
381			setOnline(false);
382
383			clientBufferSetList = NULL;
384
385			clientBufferLock = IORecursiveLockAlloc();
386			if ( clientBufferLock )
387			{
388				workLoop = audioEngine->getWorkLoop();
389				if ( workLoop )
390				{
391					workLoop->retain();
392
393					commandGate = IOCommandGate::commandGate(this);
394					if ( commandGate )
395					{
396						reserved = (ExpansionData *)IOMalloc (sizeof(struct ExpansionData));
397						if ( reserved )
398						{
399							reserved->extendedInfo = NULL;
400							reserved->classicMode = 0;
401							reserved->commandGateStatus = kCommandGateStatus_Normal;	// <rdar://8518215>
402							reserved->commandGateUsage = 0;								// <rdar://8518215>
403
404							workLoop->addEventSource(commandGate);
405
406							reserved->methods[kIOAudioEngineCallRegisterClientBuffer].object = this;
407							reserved->methods[kIOAudioEngineCallRegisterClientBuffer].func = (IOMethod) &IOAudioEngineUserClient::registerBuffer64;
408							reserved->methods[kIOAudioEngineCallRegisterClientBuffer].count0 = 4;
409							reserved->methods[kIOAudioEngineCallRegisterClientBuffer].count1 = 0;
410							reserved->methods[kIOAudioEngineCallRegisterClientBuffer].flags = kIOUCScalarIScalarO;
411
412							reserved->methods[kIOAudioEngineCallUnregisterClientBuffer].object = this;
413							reserved->methods[kIOAudioEngineCallUnregisterClientBuffer].func = (IOMethod) &IOAudioEngineUserClient::unregisterBuffer64;
414							reserved->methods[kIOAudioEngineCallUnregisterClientBuffer].count0 = 2;
415							reserved->methods[kIOAudioEngineCallUnregisterClientBuffer].count1 = 0;
416							reserved->methods[kIOAudioEngineCallUnregisterClientBuffer].flags = kIOUCScalarIScalarO;
417
418							reserved->methods[kIOAudioEngineCallGetConnectionID].object = this;
419							reserved->methods[kIOAudioEngineCallGetConnectionID].func = (IOMethod) &IOAudioEngineUserClient::getConnectionID;
420							reserved->methods[kIOAudioEngineCallGetConnectionID].count0 = 0;
421							reserved->methods[kIOAudioEngineCallGetConnectionID].count1 = 1;
422							reserved->methods[kIOAudioEngineCallGetConnectionID].flags = kIOUCScalarIScalarO;
423
424							reserved->methods[kIOAudioEngineCallStart].object = this;
425							reserved->methods[kIOAudioEngineCallStart].func = (IOMethod) &IOAudioEngineUserClient::clientStart;
426							reserved->methods[kIOAudioEngineCallStart].count0 = 0;
427							reserved->methods[kIOAudioEngineCallStart].count1 = 0;
428							reserved->methods[kIOAudioEngineCallStart].flags = kIOUCScalarIScalarO;
429
430							reserved->methods[kIOAudioEngineCallStop].object = this;
431							reserved->methods[kIOAudioEngineCallStop].func = (IOMethod) &IOAudioEngineUserClient::clientStop;
432							reserved->methods[kIOAudioEngineCallStop].count0 = 0;
433							reserved->methods[kIOAudioEngineCallStop].count1 = 0;
434							reserved->methods[kIOAudioEngineCallStop].flags = kIOUCScalarIScalarO;
435
436							reserved->methods[kIOAudioEngineCallGetNearestStartTime].object = this;
437							reserved->methods[kIOAudioEngineCallGetNearestStartTime].func = (IOMethod) &IOAudioEngineUserClient::getNearestStartTime;
438							reserved->methods[kIOAudioEngineCallGetNearestStartTime].count0 = 3;
439							reserved->methods[kIOAudioEngineCallGetNearestStartTime].count1 = 0;
440							reserved->methods[kIOAudioEngineCallGetNearestStartTime].flags = kIOUCScalarIScalarO;
441
442							trap.object = this;
443							trap.func = (IOTrap) &IOAudioEngineUserClient::performClientIO;
444							result = true;
445						}
446					}
447				}
448			}
449		}
450	}
451
452    audioDebugIOLog(3, "- IOAudioEngineUserClient[%p]::initWithAudioEngine(%p, 0x%lx, %p, 0x%lx, %p) returns %d\n", this, engine, (long unsigned int)task, securityToken, (long unsigned int)type, properties, result);
453    return result;
454}
455
456// Used so that a pointer to a kernel IOAudioStream isn't passed out of the kernel ( 32 bit version )
457//	<rdar://8121989>	Restructured for single point of entry and single point of exit so that
458//	the indentifier post processing tool can properly insert scope when post processing a log file
459//	obtained via fwkpfv.
460
461IOReturn IOAudioEngineUserClient::safeRegisterClientBuffer(UInt32 audioStreamIndex, void * sourceBuffer, UInt32 bufSizeInBytes, UInt32 bufferSetID) {
462
463	audioDebugIOLog(3, "IOAudioEngineUserClient::safeRegisterClientBuffer deprecated for 32 bit %p \n", sourceBuffer);
464	IOAudioStream *					audioStream;
465	IOReturn						result = kIOReturnBadArgument;
466
467	audioDebugIOLog(3, "+ IOAudioEngineUserClient::safeRegisterClientBuffer32 %p \n", sourceBuffer);
468
469	audioStream = audioEngine->getStreamForID(audioStreamIndex);
470	if (!audioStream)
471	{
472		audioDebugIOLog(3, "no stream associated with audioStreamIndex 0x%lx \n", (long unsigned int)audioStreamIndex);
473	}
474	else
475	{
476		result = registerClientBuffer(audioStream, sourceBuffer, bufSizeInBytes, bufferSetID);
477	}
478
479	audioDebugIOLog(3, "- IOAudioEngineUserClient::safeRegisterClientBuffer32 %p returns 0x%lX\n", sourceBuffer, (long unsigned int)result );
480	return result;
481
482}
483
484// Used so that a pointer to a kernel IOAudioStream isn't passed out of the kernel ( 64 bit version ) <rdar://problems/5321701>
485// New method added for 64 bit support <rdar://problems/5321701>
486IOReturn IOAudioEngineUserClient::safeRegisterClientBuffer64(UInt32 audioStreamIndex, mach_vm_address_t * sourceBuffer, UInt32 bufSizeInBytes, UInt32 bufferSetID)
487{
488	IOReturn				retVal = kIOReturnBadArgument;
489	IOAudioStream *			audioStream;
490	audioDebugIOLog(3, "+ IOAudioEngineUserClient::safeRegisterClientBuffer64 %p \n", sourceBuffer);
491
492	audioStream = audioEngine->getStreamForID(audioStreamIndex);
493	if (!audioStream) {
494		audioDebugIOLog(3, "  no stream associated with audioStreamIndex 0x%lx \n", (long unsigned int)audioStreamIndex);
495	}
496	else
497	{
498		retVal = registerClientBuffer64(audioStream, * sourceBuffer, bufSizeInBytes, bufferSetID);
499	}
500	audioDebugIOLog(3, "- IOAudioEngineUserClient::safeRegisterClientBuffer64  returns 0x%lX\n", (long unsigned int)retVal  );
501	return retVal;
502}
503// Used to pass extra information about how many samples are actually in a buffer and other things related to interesting non-mixable audio formats.
504IOReturn IOAudioEngineUserClient::registerClientParameterBuffer (void  * paramBuffer, UInt32 bufferSetID)
505{
506	IOReturn						result = kIOReturnSuccess;
507	IOAudioClientBufferSet			*bufferSet = NULL;
508	IOAudioClientBufferExtendedInfo64 *extendedInfo;
509
510	audioDebugIOLog(3, "+ IOAudioEngineUserClient::registerClientParameterBuffer() - result = 0x%x\n", result);
511
512    if (!isInactive()) {
513        if (!paramBuffer || ((IOAudioStreamDataDescriptor *)paramBuffer)->fVersion > kStreamDataDescriptorCurrentVersion) {
514            return kIOReturnBadArgument;
515        }
516
517        lockBuffers();		// added here because it was turned off in findBufferSet // MPC
518
519		// this buffer set can't have already been registered with extended info
520        extendedInfo = findExtendedInfo64 (bufferSetID);
521		if (extendedInfo)
522		{
523			unlockBuffers();
524            return kIOReturnBadArgument;
525		}
526
527		// make sure that this buffer set has already been registered for output
528        bufferSet = findBufferSet(bufferSetID);
529
530		unlockBuffers();
531
532        if (bufferSet) {
533			IOAudioClientBufferExtendedInfo64 *info;
534
535			extendedInfo = (IOAudioClientBufferExtendedInfo64*)IOMalloc (sizeof (IOAudioClientBufferExtendedInfo64));
536			if (!extendedInfo) {
537				return kIOReturnError;
538			}
539
540			// Can only be for output buffers, so always kIODirectionIn
541			extendedInfo->mAudioClientBufferExtended32.paramBufferDescriptor = IOMemoryDescriptor::withAddressRange(* (mach_vm_address_t*)paramBuffer, (((IOAudioStreamDataDescriptor *)paramBuffer)->fNumberOfStreams * 4) + 8, kIODirectionIn, clientTask);
542			if (!extendedInfo->mAudioClientBufferExtended32.paramBufferDescriptor)
543			{
544				result = kIOReturnInternalError;
545				goto Exit;
546			}
547
548			if ((result = extendedInfo->mAudioClientBufferExtended32.paramBufferDescriptor->prepare()) != kIOReturnSuccess)
549			{
550				goto Exit;
551			}
552
553			extendedInfo->mAudioClientBufferExtended32.paramBufferMap = extendedInfo->mAudioClientBufferExtended32.paramBufferDescriptor->map();
554
555			if (extendedInfo->mAudioClientBufferExtended32.paramBufferMap == NULL)
556			{
557				IOLog("IOAudioEngineUserClient<0x%p>::registerClientParameterBuffer() - error mapping memory.\n", this);
558				result = kIOReturnVMError;
559				goto Exit;
560			}
561
562			extendedInfo->mAudioClientBufferExtended32.paramBuffer = (void *)extendedInfo->mAudioClientBufferExtended32.paramBufferMap->getVirtualAddress();
563			if (extendedInfo->mAudioClientBufferExtended32.paramBuffer == NULL)
564			{
565				result = kIOReturnVMError;
566				goto Exit;
567			}
568
569			extendedInfo->mUnmappedParamBuffer64 = * (mach_vm_address_t*)paramBuffer;
570			extendedInfo->mNextExtended64 = NULL;
571
572			if (reserved->extendedInfo)
573			{
574				// Get to the end of the linked list of extended info and add this new entry there
575				info = reserved->extendedInfo;
576				if (info)
577				{
578					while (info->mNextExtended64)
579					{
580						info = info->mNextExtended64;
581					}
582
583					info->mNextExtended64 = extendedInfo;
584				}
585			}
586			else
587			{
588				// The list is empty, so this the start of the list
589				reserved->extendedInfo = extendedInfo;
590			}
591		}
592     }
593	 else
594	 {
595        result = kIOReturnNoDevice;
596    }
597
598Exit:
599	audioDebugIOLog(3, "- IOAudioEngineUserClient::registerClientParameterBuffer() - result = 0x%lX\n", (long unsigned int)result);
600	return result;
601}
602
603IOAudioClientBufferExtendedInfo *IOAudioEngineUserClient::findExtendedInfo(UInt32 bufferSetID)
604{
605	IOAudioClientBufferExtendedInfo64 *extendedInfo; // <rdar://problems/5321701>
606
607IOAudioClientBufferExtendedInfo * retVal = NULL;
608    extendedInfo = reserved->extendedInfo;
609    while (extendedInfo && (extendedInfo->mAudioClientBufferExtended32.bufferSetID != bufferSetID))
610	{
611        extendedInfo = extendedInfo->mNextExtended64;
612    }
613    if ( extendedInfo)
614	{
615    	retVal = &(extendedInfo->mAudioClientBufferExtended32);
616	}
617	return retVal;
618}
619
620// New method added for 64 bit support <rdar://problems/5321701>
621IOAudioClientBufferExtendedInfo64 *IOAudioEngineUserClient::findExtendedInfo64(UInt32 bufferSetID)
622{
623    IOAudioClientBufferExtendedInfo64 *extendedInfo; // <rdar://problems/5321701>
624
625    extendedInfo = reserved->extendedInfo;
626    while (extendedInfo && (extendedInfo->mAudioClientBufferExtended32.bufferSetID != bufferSetID)) {
627        extendedInfo = extendedInfo->mNextExtended64;
628    }
629
630    return extendedInfo;
631}
632IOReturn IOAudioEngineUserClient::getNearestStartTime(IOAudioStream *audioStream, IOAudioTimeStamp *ioTimeStamp, UInt32 isInput)
633{
634	IOReturn ret = kIOReturnError;
635
636	// <rdar://7363756>, <rdar://7529580>
637	if ( workLoop )
638	{
639		ret = workLoop->runAction(_getNearestStartTimeAction, this, (void *)audioStream, (void *)ioTimeStamp, (void *)(uintptr_t)isInput);	// <rdar://7529580>
640	}
641
642	return ret;
643}
644
645// <rdar://7529580>
646IOReturn IOAudioEngineUserClient::_getNearestStartTimeAction(OSObject *target, void *arg0, void *arg1, void *arg2, void *arg3)
647{
648    IOReturn result = kIOReturnBadArgument;
649
650    if (target) {
651        IOAudioEngineUserClient *userClient = OSDynamicCast(IOAudioEngineUserClient, target);
652        if (userClient) {
653			if (userClient->commandGate) {
654				setCommandGateUsage(userClient, true);	// <rdar://8518215>
655                result = userClient->commandGate->runAction(getNearestStartTimeAction, arg0, arg1, arg2, arg3);
656				setCommandGateUsage(userClient, false);	// <rdar://8518215>
657            } else {
658                result = kIOReturnError;
659            }
660        }
661    }
662
663    return result;
664}
665
666IOReturn IOAudioEngineUserClient::getNearestStartTimeAction(OSObject *owner, void *arg1, void *arg2, void *arg3, void *arg4)
667{
668    IOReturn result = kIOReturnBadArgument;
669
670    if (owner) {
671        IOAudioEngineUserClient *userClient = OSDynamicCast(IOAudioEngineUserClient, owner);
672
673        if (userClient) {
674
675#if __LP64__
676			UInt32 tempBoolArgument = (UInt64)arg4;
677#else
678			UInt32 tempBoolArgument = (UInt32)arg4;
679#endif
680
681            result = userClient->getClientNearestStartTime((IOAudioStream *)arg1, (IOAudioTimeStamp *)arg2, tempBoolArgument);
682        }
683    }
684
685    return result;
686}
687
688IOReturn IOAudioEngineUserClient::getClientNearestStartTime(IOAudioStream *audioStream, IOAudioTimeStamp *ioTimeStamp, UInt32 isInput)
689{
690    IOReturn result = kIOReturnSuccess;
691
692    if (audioEngine && !isInactive()) {
693		result = audioEngine->getNearestStartTime(audioStream, ioTimeStamp, isInput);
694	}
695
696	return result;
697}
698
699IOAudioEngineUserClient *IOAudioEngineUserClient::withAudioEngine(IOAudioEngine *engine, task_t clientTask, void *securityToken, UInt32 type, OSDictionary *properties)
700{
701    IOAudioEngineUserClient *client;
702
703    audioDebugIOLog(3, "+ IOAudioEngineUserClient::withAudioEngine(%p, 0x%lx, %p, 0x%lx, %p)\n", engine, (long unsigned int)clientTask, securityToken, (long unsigned int)type, properties);
704
705    client = new IOAudioEngineUserClient;
706
707    if (client) {
708        if (!client->initWithAudioEngine(engine, clientTask, securityToken, type, properties)) {
709            client->release();
710            client = NULL;
711        }
712    }
713
714    audioDebugIOLog(3, "- IOAudioEngineUserClient::withAudioEngine(%p, 0x%lx, %p, 0x%lx, %p) returns %p\n", engine, (long unsigned int)clientTask, securityToken, (long unsigned int)type, properties, client );
715    return client;
716}
717
718// Original code
719IOAudioEngineUserClient *IOAudioEngineUserClient::withAudioEngine(IOAudioEngine *engine, task_t clientTask, void *securityToken, UInt32 type)
720{
721	IOAudioEngineUserClient *client;
722
723	audioDebugIOLog(3, "+ IOAudioEngineUserClient::withAudioEngine(%p, 0x%lx, %p, 0x%lx)\n", engine, (long unsigned int)clientTask, securityToken, (long unsigned int)type);
724
725	client = new IOAudioEngineUserClient;
726
727	if (client) {
728		if (!client->initWithAudioEngine(engine, clientTask, securityToken, type)) {
729			client->release();
730			client = NULL;
731		}
732	}
733
734	audioDebugIOLog(3, "- IOAudioEngineUserClient::withAudioEngine(%p, 0x%lx, %p, 0x%lx) returns %p\n", engine, (long unsigned int)clientTask, securityToken, (long unsigned int)type, client);
735	return client;
736}
737
738//	<rdar://8121989>	Restructured for single point of entry and single point of exit so that
739//	the indentifier post processing tool can properly insert scope when post processing a log file
740//	obtained via fwkpfv.
741
742bool IOAudioEngineUserClient::initWithAudioEngine(IOAudioEngine *engine, task_t task, void *securityToken, UInt32 type)
743{
744	bool			result = false;
745
746    audioDebugIOLog(3, "+ IOAudioEngineUserClient[%p]::initWithAudioEngine(%p, 0x%lx, %p, 0x%lx)\n", this, engine, (long unsigned int)task, securityToken, (long unsigned int)type);
747
748	if ( initWithTask( task, securityToken, type ) )
749	{
750		if ( engine && task )
751		{
752			clientTask = task;
753			audioEngine = engine;
754
755			setOnline(false);
756
757			clientBufferSetList = NULL;
758
759			clientBufferLock = IORecursiveLockAlloc();
760			if ( clientBufferLock )
761			{
762				workLoop = audioEngine->getWorkLoop();
763				if ( workLoop )
764				{
765					workLoop->retain();
766
767					commandGate = IOCommandGate::commandGate(this);
768					if ( commandGate )
769					{
770						reserved = (ExpansionData *)IOMalloc (sizeof(struct ExpansionData));
771						if ( reserved )
772						{
773							reserved->extendedInfo = NULL;
774							reserved->classicMode = 0;
775							reserved->commandGateStatus = kCommandGateStatus_Normal;	// <rdar://8518215>
776							reserved->commandGateUsage = 0;								// <rdar://8518215>
777
778							workLoop->addEventSource(commandGate);
779
780							reserved->methods[kIOAudioEngineCallRegisterClientBuffer].object = this;
781							reserved->methods[kIOAudioEngineCallRegisterClientBuffer].func = (IOMethod) &IOAudioEngineUserClient::registerBuffer64;
782							reserved->methods[kIOAudioEngineCallRegisterClientBuffer].count0 = 4;
783							reserved->methods[kIOAudioEngineCallRegisterClientBuffer].count1 = 0;
784							reserved->methods[kIOAudioEngineCallRegisterClientBuffer].flags = kIOUCScalarIScalarO;
785
786							reserved->methods[kIOAudioEngineCallUnregisterClientBuffer].object = this;
787							reserved->methods[kIOAudioEngineCallUnregisterClientBuffer].func = (IOMethod) &IOAudioEngineUserClient::unregisterBuffer64;
788							reserved->methods[kIOAudioEngineCallUnregisterClientBuffer].count0 = 2;
789							reserved->methods[kIOAudioEngineCallUnregisterClientBuffer].count1 = 0;
790							reserved->methods[kIOAudioEngineCallUnregisterClientBuffer].flags = kIOUCScalarIScalarO;
791
792							reserved->methods[kIOAudioEngineCallGetConnectionID].object = this;
793							reserved->methods[kIOAudioEngineCallGetConnectionID].func = (IOMethod) &IOAudioEngineUserClient::getConnectionID;
794							reserved->methods[kIOAudioEngineCallGetConnectionID].count0 = 0;
795							reserved->methods[kIOAudioEngineCallGetConnectionID].count1 = 1;
796							reserved->methods[kIOAudioEngineCallGetConnectionID].flags = kIOUCScalarIScalarO;
797
798							reserved->methods[kIOAudioEngineCallStart].object = this;
799							reserved->methods[kIOAudioEngineCallStart].func = (IOMethod) &IOAudioEngineUserClient::clientStart;
800							reserved->methods[kIOAudioEngineCallStart].count0 = 0;
801							reserved->methods[kIOAudioEngineCallStart].count1 = 0;
802							reserved->methods[kIOAudioEngineCallStart].flags = kIOUCScalarIScalarO;
803
804							reserved->methods[kIOAudioEngineCallStop].object = this;
805							reserved->methods[kIOAudioEngineCallStop].func = (IOMethod) &IOAudioEngineUserClient::clientStop;
806							reserved->methods[kIOAudioEngineCallStop].count0 = 0;
807							reserved->methods[kIOAudioEngineCallStop].count1 = 0;
808							reserved->methods[kIOAudioEngineCallStop].flags = kIOUCScalarIScalarO;
809
810							reserved->methods[kIOAudioEngineCallGetNearestStartTime].object = this;
811							reserved->methods[kIOAudioEngineCallGetNearestStartTime].func = (IOMethod) &IOAudioEngineUserClient::getNearestStartTime;
812							reserved->methods[kIOAudioEngineCallGetNearestStartTime].count0 = 3;
813							reserved->methods[kIOAudioEngineCallGetNearestStartTime].count1 = 0;
814							reserved->methods[kIOAudioEngineCallGetNearestStartTime].flags = kIOUCScalarIScalarO;
815
816							trap.object = this;
817							trap.func = (IOTrap) &IOAudioEngineUserClient::performClientIO;
818							result = true;
819						}
820					}
821				}
822			}
823		}
824	}
825
826    audioDebugIOLog(3, "- IOAudioEngineUserClient[%p]::initWithAudioEngine(%p, 0x%lx, %p, 0x%lx) returns %d\n", this, engine, (long unsigned int)task, securityToken, (long unsigned int)type, result );
827    return result;
828}
829
830void IOAudioEngineUserClient::free()
831{
832	IOAudioClientBufferExtendedInfo64 *			cur;
833	IOAudioClientBufferExtendedInfo64 *			prev;
834
835    audioDebugIOLog(3, "+ IOAudioEngineUserClient[%p]::free()\n", this);
836
837    freeClientBufferSetList();			// Moved above clientBufferLock code below
838
839    if (clientBufferLock) {
840        IORecursiveLockFree(clientBufferLock);
841        clientBufferLock = NULL;
842    }
843
844    if (notificationMessage) {
845        IOFreeAligned(notificationMessage, sizeof(IOAudioNotificationMessage));
846        notificationMessage = NULL;
847    }
848
849    if (commandGate) {
850        if (workLoop) {
851            workLoop->removeEventSource(commandGate);
852        }
853
854        commandGate->release();
855        commandGate = NULL;
856    }
857
858    if (workLoop) {
859        workLoop->release();
860        workLoop = NULL;
861    }
862
863	if (reserved) {
864		if (NULL != reserved->extendedInfo) {
865			cur = reserved->extendedInfo;
866			while (cur) {
867				prev = cur;
868				if (NULL != prev) {
869					IOFree (prev, sizeof (IOAudioClientBufferExtendedInfo64));
870				}
871				cur = cur->mNextExtended64;
872			}
873		}
874		IOFree (reserved, sizeof(struct ExpansionData));
875	}
876
877    super::free();
878
879    audioDebugIOLog(3, "- IOAudioEngineUserClient[%p]::free()\n", this);
880	return;
881}
882
883void IOAudioEngineUserClient::freeClientBufferSetList()
884{
885	// <rdar://9180891> Lock the buffers to synchronize access to the client buffer list.
886	// This is to prevent race condition between freeClientBufferList, unregisterClientBuffer64
887	// & stopClient when calling IOAudioStream::removeClient().
888	lockBuffers();
889
890    while (clientBufferSetList) {
891        IOAudioClientBufferSet *nextSet;
892
893		// Move call up here to fix 3472373
894        clientBufferSetList->cancelWatchdogTimer();
895
896        while (clientBufferSetList->outputBufferList) {
897            IOAudioClientBuffer64 *nextBuffer = clientBufferSetList->outputBufferList->mNextBuffer64;
898
899            freeClientBuffer(clientBufferSetList->outputBufferList);
900
901            clientBufferSetList->outputBufferList = nextBuffer;
902        }
903
904        while (clientBufferSetList->inputBufferList) {
905            IOAudioClientBuffer64 *next = clientBufferSetList->inputBufferList->mNextBuffer64;
906
907            freeClientBuffer(clientBufferSetList->inputBufferList);
908
909            clientBufferSetList->inputBufferList = next;
910        }
911
912        nextSet = clientBufferSetList->mNextBufferSet;
913
914        clientBufferSetList->release();
915
916        clientBufferSetList = nextSet;
917    }
918
919	unlockBuffers();	// <rdar://9180891>
920}
921
922void IOAudioEngineUserClient::freeClientBuffer(IOAudioClientBuffer64 *clientBuffer)
923{
924    if (clientBuffer) {
925        if (clientBuffer->mAudioClientBuffer32.audioStream) {
926            clientBuffer->mAudioClientBuffer32.audioStream->removeClient(&(clientBuffer->mAudioClientBuffer32) );
927            clientBuffer->mAudioClientBuffer32.audioStream->release();
928			clientBuffer->mAudioClientBuffer32.audioStream = NULL;
929        }
930
931        if (clientBuffer->mAudioClientBuffer32.sourceBufferDescriptor != NULL) {
932            clientBuffer->mAudioClientBuffer32.sourceBufferDescriptor->complete();
933            clientBuffer->mAudioClientBuffer32.sourceBufferDescriptor->release();
934			clientBuffer->mAudioClientBuffer32.sourceBufferDescriptor = NULL;
935        }
936
937        if (clientBuffer->mAudioClientBuffer32.sourceBufferMap != NULL) {
938            clientBuffer->mAudioClientBuffer32.sourceBufferMap->release();
939			clientBuffer->mAudioClientBuffer32.sourceBufferMap = NULL;
940        }
941
942        IOFreeAligned(clientBuffer, sizeof(IOAudioClientBuffer64));
943		clientBuffer = NULL;
944    }
945}
946
947void IOAudioEngineUserClient::stop(IOService *provider)
948{
949    audioDebugIOLog(3, "+ IOAudioEngineUserClient[%p]::stop(%p)\n", this, provider);
950
951
952	// <rdar://7363756>
953	if ( commandGate )
954	{
955		commandGate->runAction(stopClientAction);
956	}
957
958    // We should be both inactive and offline at this point,
959    // so it is safe to free the client buffer set list without holding the lock
960
961    freeClientBufferSetList();
962
963	// <rdar://7233118>, <rdar://7029696> Remove the event source here as performing heavy workloop operation in free() could lead
964	// to deadlock since the context which free() is called is not known. stop() is called on the workloop, so it is safe to remove
965	// the event source here.
966	if (reserved->commandGateUsage == 0) {							// <rdar://8518215>
967		reserved->commandGateStatus = kCommandGateStatus_Invalid;	// <rdar://8518215>
968
969		if (commandGate) {
970			if (workLoop) {
971				workLoop->removeEventSource(commandGate);
972			}
973
974			commandGate->release();
975			commandGate = NULL;
976		}
977	}
978	else {	// <rdar://8518215>
979		reserved->commandGateStatus = kCommandGateStatus_RemovalPending;
980	}
981
982    super::stop(provider);
983
984    audioDebugIOLog(3, "- IOAudioEngineUserClient[%p]::stop(%p)\n", this, provider);
985	return;
986}
987
988IOReturn IOAudioEngineUserClient::clientClose()
989{
990    IOReturn result = kIOReturnSuccess;
991
992    audioDebugIOLog(3, "+ IOAudioEngineUserClient[%p]::clientClose()\n", this);
993
994	// <rdar://7363756>
995    if (audioEngine && workLoop && !isInactive()) {					// <rdar://7529580>
996        result = workLoop->runAction(_closeClientAction, this);		// <rdar://7529580>
997    }
998
999    audioDebugIOLog(3, "- IOAudioEngineUserClient[%p]::clientClose() returns 0x%lX\n", this, (long unsigned int)result );
1000    return result;
1001}
1002
1003//	<rdar://8121989>	Restructured for single point of entry and single point of exit so that
1004//	the indentifier post processing tool can properly insert scope when post processing a log file
1005//	obtained via fwkpfv.
1006
1007IOReturn IOAudioEngineUserClient::clientDied()
1008{
1009	IOReturn			result;
1010
1011    audioDebugIOLog(3, "+ IOAudioEngineUserClient[%p]::clientDied()\n", this);
1012
1013    result = clientClose();
1014
1015    audioDebugIOLog(3, "- IOAudioEngineUserClient[%p]::clientDied() returns 0x%lX\n", this, (long unsigned int)result);
1016	return result;
1017}
1018
1019// <rdar://7529580>
1020IOReturn IOAudioEngineUserClient::_closeClientAction(OSObject *target, void *arg0, void *arg1, void *arg2, void *arg3)
1021{
1022    IOReturn result = kIOReturnBadArgument;
1023
1024    if (target) {
1025        IOAudioEngineUserClient *userClient = OSDynamicCast(IOAudioEngineUserClient, target);
1026        if (userClient) {
1027			if (userClient->commandGate) {
1028				setCommandGateUsage(userClient, true);	// <rdar://8518215>
1029                result = userClient->commandGate->runAction(closeClientAction, arg0, arg1, arg2, arg3);
1030				setCommandGateUsage(userClient, false);	// <rdar://8518215>
1031            } else {
1032                result = kIOReturnError;
1033            }
1034        }
1035    }
1036
1037    return result;
1038}
1039
1040IOReturn IOAudioEngineUserClient::closeClientAction(OSObject *owner, void *arg1, void *arg2, void *arg3, void *arg4)
1041{
1042    IOReturn result = kIOReturnBadArgument;
1043
1044    if (owner) {
1045        IOAudioEngineUserClient *userClient = OSDynamicCast(IOAudioEngineUserClient, owner);
1046        if (userClient) {
1047            result = userClient->closeClient();
1048        }
1049    }
1050
1051    return result;
1052}
1053
1054IOReturn IOAudioEngineUserClient::closeClient()
1055{
1056    audioDebugIOLog(3, "+ IOAudioEngineUserClient[%p]::closeClient()\n", this);
1057
1058    if (audioEngine && !isInactive()) {
1059        if (isOnline()) {
1060            stopClient();
1061        }
1062        audioEngine->clientClosed(this);
1063        audioEngine = NULL;
1064    }
1065
1066    audioDebugIOLog(3, "- IOAudioEngineUserClient[%p]::closeClient() returns 0x%lX\n", this, (long unsigned int)kIOReturnSuccess );
1067    return kIOReturnSuccess;
1068}
1069
1070void IOAudioEngineUserClient::setOnline(bool newOnline)
1071{
1072    audioDebugIOLog(3, "+ IOAudioEngineUserClient[%p]::setOnline(%d)\n", this, newOnline);
1073
1074    if (online != newOnline) {
1075        online = newOnline;
1076        setProperty(kIOAudioEngineUserClientActiveKey, (unsigned long long)(online ? 1 : 0), sizeof(unsigned long long)*8);
1077    }
1078
1079    audioDebugIOLog(3, "- IOAudioEngineUserClient[%p]::setOnline(%d)\n", this, newOnline);
1080	return;
1081}
1082
1083bool IOAudioEngineUserClient::isOnline()
1084{
1085    return online;
1086}
1087
1088void IOAudioEngineUserClient::lockBuffers()
1089{
1090    assert(clientBufferLock);
1091
1092    IORecursiveLockLock(clientBufferLock);
1093}
1094
1095void IOAudioEngineUserClient::unlockBuffers()
1096{
1097    assert(clientBufferLock);
1098
1099    IORecursiveLockUnlock(clientBufferLock);
1100}
1101
1102IOReturn IOAudioEngineUserClient::clientMemoryForType(UInt32 type, UInt32 *flags, IOMemoryDescriptor **memory)
1103{
1104    IOReturn						result = kIOReturnSuccess;
1105	IOBufferMemoryDescriptor		*theMemoryDescriptor = NULL;
1106
1107    audioDebugIOLog(3, "+ IOAudioEngineUserClient[%p]::clientMemoryForType(0x%lx, 0x%lx, %p)\n", this, (long unsigned int)type, (long unsigned int)*flags, memory);
1108
1109	assert(audioEngine);
1110
1111    switch(type) {
1112        case kIOAudioStatusBuffer:
1113			theMemoryDescriptor = audioEngine->getStatusDescriptor();
1114            break;
1115		case kIOAudioBytesInInputBuffer:
1116			theMemoryDescriptor = audioEngine->getBytesInInputBufferArrayDescriptor();
1117			break;
1118		case kIOAudioBytesInOutputBuffer:
1119			theMemoryDescriptor = audioEngine->getBytesInOutputBufferArrayDescriptor();
1120			break;
1121        default:
1122            result = kIOReturnUnsupported;
1123            break;
1124    }
1125
1126	if (!result && theMemoryDescriptor) {
1127		theMemoryDescriptor->retain();		// Don't release it, it will be released by mach-port automatically
1128		*memory = theMemoryDescriptor;
1129		*flags = kIOMapReadOnly;
1130	} else {
1131		result = kIOReturnError;
1132	}
1133
1134    audioDebugIOLog(3, "- IOAudioEngineUserClient[%p]::clientMemoryForType(0x%lx, 0x%lx, %p) returns 0x%lX\n", this, (long unsigned int)type, (long unsigned int)*flags, memory, (long unsigned int)result );
1135    return result;
1136}
1137
1138IOExternalMethod *IOAudioEngineUserClient::getExternalMethodForIndex(UInt32 index)
1139{
1140    IOExternalMethod *method = 0;
1141
1142    if (index < kIOAudioEngineNumCalls) {
1143        method = &reserved->methods[index];
1144    }
1145
1146    return method;
1147}
1148
1149IOExternalTrap *IOAudioEngineUserClient::getExternalTrapForIndex( UInt32 index )
1150{
1151	IOExternalTrap *result = NULL;
1152
1153    if (index == kIOAudioEngineTrapPerformClientIO) {
1154		result = &trap;
1155	} else if (index == (0x1000 | kIOAudioEngineTrapPerformClientIO)) {
1156		reserved->classicMode = 1;
1157		result = &trap;
1158    }
1159
1160    return result;
1161}
1162
1163IOReturn IOAudioEngineUserClient::registerNotificationPort(mach_port_t port, UInt32 type, UInt32 refCon)
1164{
1165    IOReturn result = kIOReturnSuccess;
1166
1167    audioDebugIOLog(3, "+ IOAudioEngineUserClient[%p]::registerNotificationPort(0x%lx, 0x%lx, 0x%lx)\n", this, (long unsigned int)port, (long unsigned int)type, (long unsigned int)refCon);
1168
1169    switch (type) {
1170        case kIOAudioEngineAllNotifications:
1171			// <rdar://7363756>, <rdar://7529580>
1172			if ( workLoop )
1173			{
1174				result = workLoop->runAction(_registerNotificationAction, this, (void *)port, (void *)(uintptr_t)refCon);	// <rdar://7529580>
1175			}
1176			else
1177			{
1178				result = kIOReturnError;
1179			}
1180
1181            break;
1182        default:
1183            IOLog("IOAudioEngineUserClient[%p]::registerNotificationPort() - ERROR: invalid notification type specified - no notifications will be sent.\n", this);
1184            result = kIOReturnBadArgument;
1185            break;
1186    }
1187    // Create a single message, but keep a dict or something of all of the IOAudioStreams registered for
1188    // refCon is IOAudioStream *
1189
1190    audioDebugIOLog(3, "- IOAudioEngineUserClient[%p]::registerNotificationPort(0x%lx, 0x%lx, 0x%lx) returns 0x%lX\n", this, (long unsigned int)port, (long unsigned int)type, (long unsigned int)refCon, (long unsigned int)result );
1191    return result;
1192}
1193
1194// <rdar://7529580>
1195IOReturn IOAudioEngineUserClient::_registerNotificationAction(OSObject *target, void *arg0, void *arg1, void *arg2, void *arg3)
1196{
1197    IOReturn result = kIOReturnBadArgument;
1198
1199    if (target) {
1200        IOAudioEngineUserClient *userClient = OSDynamicCast(IOAudioEngineUserClient, target);
1201        if (userClient) {
1202            if (userClient->commandGate) {
1203				setCommandGateUsage(userClient, true);	// <rdar://8518215>
1204                result = userClient->commandGate->runAction(registerNotificationAction, arg0, arg1, arg2, arg3);
1205				setCommandGateUsage(userClient, false);	// <rdar://8518215>
1206            } else {
1207                result = kIOReturnError;
1208            }
1209        }
1210    }
1211
1212    return result;
1213}
1214
1215IOReturn IOAudioEngineUserClient::registerNotificationAction(OSObject *owner, void *arg1, void *arg2, void *arg3, void *arg4)
1216{
1217    IOReturn result = kIOReturnBadArgument;
1218
1219    audioDebugIOLog(3, "+ IOAudioEngineUserClient::registerNotificationAction(%p, %p)\n", owner, arg1);
1220
1221    if (owner) {
1222        IOAudioEngineUserClient *userClient = OSDynamicCast(IOAudioEngineUserClient, owner);
1223
1224        if (userClient) {
1225#if __LP64__
1226			UInt64	refCon = (UInt64) arg2;
1227#else
1228			UInt32	refCon = (UInt32) arg2;
1229#endif
1230
1231            result = userClient->registerNotification((mach_port_t)arg1, refCon);
1232        }
1233    }
1234
1235    audioDebugIOLog(3, "- IOAudioEngineUserClient::registerNotificationAction(%p, %p) returns 0x%lX\n", owner, arg1, (long unsigned int)result );
1236    return result;
1237}
1238
1239IOReturn IOAudioEngineUserClient::registerNotification(mach_port_t port, UInt32 refCon)
1240{
1241    IOReturn result = kIOReturnSuccess;
1242
1243    audioDebugIOLog(3, "+ IOAudioEngineUserClient[%p]::registerFormatNotification(0x%lx, 0x%lx)\n", this, (long unsigned int)port, (long unsigned int)refCon);
1244
1245    if (!isInactive()) {
1246        if (port == MACH_PORT_NULL) {	// We need to remove this notification
1247            if (notificationMessage != NULL) {
1248                notificationMessage->messageHeader.msgh_remote_port = MACH_PORT_NULL;
1249            }
1250        } else {
1251            if (notificationMessage == NULL) {
1252                notificationMessage = (IOAudioNotificationMessage *)IOMallocAligned(sizeof(IOAudioNotificationMessage), sizeof (IOAudioNotificationMessage *));
1253
1254                if (notificationMessage) {
1255                    notificationMessage->messageHeader.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0);
1256                    notificationMessage->messageHeader.msgh_size = sizeof(IOAudioNotificationMessage);
1257                    notificationMessage->messageHeader.msgh_local_port = MACH_PORT_NULL;
1258                    notificationMessage->messageHeader.msgh_reserved = 0;
1259                    notificationMessage->messageHeader.msgh_id = 0;
1260                    notificationMessage->messageHeader.msgh_remote_port = port;
1261                    notificationMessage->ref = refCon;
1262                } else {
1263                    result = kIOReturnNoMemory;
1264                }
1265            } else {
1266            	notificationMessage->messageHeader.msgh_remote_port = port;
1267                notificationMessage->ref = refCon;
1268            }
1269        }
1270    } else {
1271        result = kIOReturnNoDevice;
1272    }
1273
1274    audioDebugIOLog(3, "- IOAudioEngineUserClient[%p]::registerFormatNotification(0x%lx, 0x%lx) returns 0x%lX\n", this, (long unsigned int)port, (long unsigned int)refCon, (long unsigned int)result );
1275    return result;
1276}
1277
1278
1279IOReturn IOAudioEngineUserClient::externalMethod ( uint32_t selector, IOExternalMethodArguments * arguments,
1280	IOExternalMethodDispatch * dispatch, OSObject * target, void * reference)
1281{
1282	IOReturn result = kIOReturnBadArgument;
1283	audioDebugIOLog(3, "+ IOAudioEngineUserClient::externalMethod, selector=0x%x,   arg0 0x%llX, arg1 0x%llx, arg2 0x%llx arg3 0x%llx \n",
1284					selector, arguments->scalarInput[0], arguments->scalarInput[1], arguments->scalarInput[2], arguments->scalarInput[3]);
1285    audioDebugIOLog(3, "  scalarInputCount=0x%x  structureInputSize 0x%x, scalarOutputCount 0x%x, structureOutputSize 0x%x \n",
1286					arguments->scalarInputCount, arguments->structureInputSize, arguments->scalarOutputCount, arguments->structureOutputSize );
1287
1288	// Dispatch the method call
1289	switch (selector)
1290	{
1291	case kIOAudioEngineCallRegisterClientBuffer:
1292		if (arguments != 0)
1293		{
1294			if ( arguments->scalarInputCount >= 4 )		//	<rdar://9204853>
1295			{
1296			result = registerBuffer64((IOAudioStream *)arguments->scalarInput[0], (mach_vm_address_t)arguments->scalarInput[1], (UInt32)arguments->scalarInput[2], (UInt32)arguments->scalarInput[3] );
1297		}
1298			else
1299			{
1300				audioDebugIOLog(3, "  kIOAudioEngineCallRegisterClientBuffer: invalid input argument count %d. Need at least 4.\n", arguments->scalarInputCount);
1301			}
1302		}
1303		break;
1304	case kIOAudioEngineCallUnregisterClientBuffer:
1305		if (arguments != 0)
1306		{
1307			if ( arguments->scalarInputCount >= 2 )		//	<rdar://9204853>
1308			{
1309			result = unregisterBuffer64((mach_vm_address_t)arguments->scalarInput[0], (UInt32)arguments->scalarInput[1] );
1310		}
1311			else
1312			{
1313				audioDebugIOLog(3, "  kIOAudioEngineCallUnregisterClientBuffer: invalid input argument count %d. Need at least 2.\n", arguments->scalarInputCount);
1314			}
1315		}
1316		break;	default:
1317		result = super::externalMethod(selector, arguments, dispatch, target, reference );
1318		break;
1319	}
1320	audioDebugIOLog(3, "- IOAudioEngineUserClient::externalMethod returns 0x%lX\n", (long unsigned int)result );
1321	return result;
1322}
1323
1324// 32 bit version <rdar://problems/5321701>
1325IOReturn IOAudioEngineUserClient::registerBuffer(IOAudioStream *audioStream, void * sourceBuffer, UInt32 bufSizeInBytes, UInt32 bufferSetID)
1326{
1327    audioDebugIOLog(3, "+-IOAudioEngineUserClient::registerBuffer Deprecated 0x%llx %p 0x%lx 0x%lx\n", (unsigned long long )audioStream, sourceBuffer, (long unsigned int)bufSizeInBytes, (long unsigned int)bufferSetID);
1328
1329    return kIOReturnUnsupported;
1330}
1331
1332// 64 bit version <rdar://problems/5321701>
1333IOReturn IOAudioEngineUserClient::registerBuffer64(IOAudioStream *audioStream, mach_vm_address_t sourceBuffer, UInt32 bufSizeInBytes, UInt32 bufferSetID)
1334{
1335	IOReturn ret = kIOReturnError;
1336
1337	audioDebugIOLog(3, "+ IOAudioEngineUserClient::registerBuffer64 0x%llx 0x%llx 0x%lx 0x%lx\n", (unsigned long long )audioStream, sourceBuffer, (long unsigned int)bufSizeInBytes, (long unsigned int)bufferSetID);
1338
1339	// <rdar://7363756>, <rdar://7529580>
1340	if ( workLoop )
1341	{
1342		ret = workLoop->runAction(_registerBufferAction, this, audioStream, &sourceBuffer, (void *)(uintptr_t)bufSizeInBytes, (void *)(uintptr_t)bufferSetID);	// <rdar://7529580>
1343	}
1344
1345	audioDebugIOLog(3, "- IOAudioEngineUserClient::registerBuffer64 0x%llx 0x%llx 0x%lx 0x%lx returns 0x%lX\n", (unsigned long long )audioStream, sourceBuffer, (long unsigned int)bufSizeInBytes, (long unsigned int)bufferSetID, (long unsigned int)ret );
1346	return ret;
1347}
1348
1349// 32 bit version <rdar://problems/5321701>
1350IOReturn IOAudioEngineUserClient::unregisterBuffer( void * sourceBuffer, UInt32 bufferSetID)
1351{
1352 	audioDebugIOLog(3, "+-IOAudioEngineUserClient::unregisterBuffer 32 bit version NOT SUPPORTED \n" );
1353    return kIOReturnUnsupported;
1354}
1355
1356// 64 bit version <rdar://problems/5321701>
1357IOReturn IOAudioEngineUserClient::unregisterBuffer64( mach_vm_address_t  sourceBuffer, UInt32 bufferSetID)
1358{
1359	IOReturn ret = kIOReturnError;
1360
1361	// <rdar://7363756>, <rdar://7529580>
1362	if ( workLoop )
1363	{
1364		ret = workLoop->runAction(_unregisterBufferAction, this, ( void * ) &sourceBuffer, (void *)(uintptr_t)bufferSetID);	// <rdar://7529580>
1365	}
1366
1367	return ret;
1368}
1369
1370// <rdar://7529580>
1371IOReturn IOAudioEngineUserClient::_registerBufferAction(OSObject *target, void *arg0, void *arg1, void *arg2, void *arg3)
1372{
1373    IOReturn result = kIOReturnBadArgument;
1374
1375    if (target) {
1376        IOAudioEngineUserClient *userClient = OSDynamicCast(IOAudioEngineUserClient, target);
1377        if (userClient) {
1378            if (userClient->commandGate) {
1379				setCommandGateUsage(userClient, true);	// <rdar://8518215>
1380                result = userClient->commandGate->runAction(registerBufferAction, arg0, arg1, arg2, arg3);
1381				setCommandGateUsage(userClient, false);	// <rdar://8518215>
1382            } else {
1383                result = kIOReturnError;
1384            }
1385        }
1386    }
1387
1388    return result;
1389}
1390
1391IOReturn IOAudioEngineUserClient::registerBufferAction(OSObject *owner, void *arg1, void *arg2, void *arg3, void *arg4)
1392{
1393    IOReturn result = kIOReturnBadArgument;
1394
1395	audioDebugIOLog(3, "+ IOAudioEngineUserClient::registerBufferAction %p \n", arg1 );
1396
1397    if (owner) {
1398        IOAudioEngineUserClient *userClient = OSDynamicCast(IOAudioEngineUserClient, owner);
1399
1400        if (userClient) {
1401#if __LP64__
1402			UInt32 bufSizeInBytes	= (UInt32)((UInt64)arg3 & 0x00000000FFFFFFFFLLU);
1403			UInt32 bufferSetID		= (UInt32)((UInt64)arg4 & 0x00000000FFFFFFFFLLU);
1404			UInt32 audioStreamIndex	= (UInt32)((UInt64)arg1 & 0x00000000FFFFFFFFLLU);
1405#else
1406			UInt32 bufSizeInBytes	= (UInt32) arg3;
1407			UInt32 bufferSetID		= (UInt32) arg4;
1408			UInt32 audioStreamIndex = (UInt32) arg1;
1409#endif
1410
1411			result = userClient->safeRegisterClientBuffer64( audioStreamIndex, ( mach_vm_address_t * ) arg2, bufSizeInBytes, bufferSetID);
1412        }
1413    }
1414
1415	audioDebugIOLog(3, "- IOAudioEngineUserClient::registerBufferAction %p returns 0x%lX\n", arg1, (long unsigned int)result );
1416    return result;
1417}
1418
1419// <rdar://7529580>
1420IOReturn IOAudioEngineUserClient::_unregisterBufferAction(OSObject *target, void *arg0, void *arg1, void *arg2, void *arg3)
1421{
1422    IOReturn result = kIOReturnBadArgument;
1423
1424    if (target) {
1425        IOAudioEngineUserClient *userClient = OSDynamicCast(IOAudioEngineUserClient, target);
1426        if (userClient) {
1427            if (userClient->commandGate) {
1428				setCommandGateUsage(userClient, true);	// <rdar://8518215>
1429                result = userClient->commandGate->runAction(unregisterBufferAction, arg0, arg1, arg2, arg3);
1430				setCommandGateUsage(userClient, false);	// <rdar://8518215>
1431            } else {
1432                result = kIOReturnError;
1433            }
1434        }
1435    }
1436
1437    return result;
1438}
1439
1440IOReturn IOAudioEngineUserClient::unregisterBufferAction(OSObject *owner, void *arg1, void *arg2, void *arg3, void *arg4)
1441{
1442    IOReturn result = kIOReturnBadArgument;
1443
1444    if (owner) {
1445        IOAudioEngineUserClient *userClient = OSDynamicCast(IOAudioEngineUserClient, owner);
1446
1447        if (userClient) {
1448#if __LP64__
1449			UInt32 bufferSetID =  (UInt32)((UInt64)arg2 & 0x00000000FFFFFFFFLLU);
1450#else
1451			UInt32 bufferSetID =  (UInt32) arg2;
1452#endif
1453            result = userClient->unregisterClientBuffer64( ( mach_vm_address_t * )arg1, bufferSetID);
1454        }
1455    }
1456
1457    return result;
1458}
1459// 32 bit version <rdar://problems/5321701>
1460IOReturn IOAudioEngineUserClient::registerClientBuffer(IOAudioStream *audioStream, void * sourceBuffer, UInt32 bufSizeInBytes, UInt32 bufferSetID)
1461{
1462	audioDebugIOLog(3, "+-IOAudioEngineUserClient[%p]::registerClientBuffer  32 bit version Deprecated (%p[%ld], %p, 0x%lx, 0x%lx)\n", this, audioStream, (long int)audioStream->getStartingChannelID(), sourceBuffer, (long unsigned int)bufSizeInBytes, (long unsigned int)bufferSetID);
1463	return kIOReturnUnsupported;
1464}
1465// 64 bit version <rdar://problems/5321701>
1466IOReturn IOAudioEngineUserClient::registerClientBuffer64(IOAudioStream *audioStream, mach_vm_address_t  sourceBuffer, UInt32 bufSizeInBytes, UInt32 bufferSetID)
1467{
1468    IOReturn result = kIOReturnSuccess;
1469    IOAudioClientBuffer64 *clientBuffer;
1470    IODirection bufferDirection;
1471    const IOAudioStreamFormat *streamFormat;
1472
1473    audioDebugIOLog(3, "+ IOAudioEngineUserClient[%p]::registerClientBuffer64  (%p[%ld], 0x%llx, 0x%lx, 0x%lx)\n", this, audioStream, (long int)audioStream->getStartingChannelID(), sourceBuffer, (long unsigned int)bufSizeInBytes, (long unsigned int)bufferSetID);
1474    if (!isInactive())
1475	{
1476        IOAudioClientBufferSet *clientBufferSet;
1477        IOAudioClientBuffer64 **clientBufferList;
1478
1479        if (!sourceBuffer || !audioStream || (bufSizeInBytes == 0) )
1480		{
1481			audioDebugIOLog(3, "  bad argument\n");
1482           return kIOReturnBadArgument;
1483        }
1484
1485		streamFormat = audioStream->getFormat();
1486        if (!streamFormat)
1487		{
1488			audioDebugIOLog(3, "  no format\n");
1489            return kIOReturnError;
1490        }
1491
1492        // Return an error if this is an unmixable stream and it already has a client
1493        if (!streamFormat->fIsMixable && (audioStream->getNumClients() != 0))
1494		{
1495			audioDebugIOLog(3, "  mix problem or client exists\n");
1496            return kIOReturnExclusiveAccess;
1497        }
1498
1499		// <rdar://10282154> Check if the source buffer is already registered in the
1500		// buffer set. If it is already registered, unregister the existing source
1501		// buffer from the buffer set.
1502		lockBuffers();
1503
1504        clientBufferSet = findBufferSet(bufferSetID);
1505		if (clientBufferSet) {
1506			if (audioStream->getDirection() == kIOAudioStreamDirectionOutput) {
1507				clientBufferList = &clientBufferSet->outputBufferList;
1508			} else {
1509				clientBufferList = &clientBufferSet->inputBufferList;
1510			}
1511
1512			assert(clientBufferList);
1513
1514			if (*clientBufferList != NULL) {
1515				IOAudioClientBuffer64 *clientBufPtr = *clientBufferList;
1516				while (clientBufPtr != NULL) {
1517					if (clientBufPtr->mUnmappedSourceBuffer64 == sourceBuffer) {
1518						audioDebugIOLog(3, "  source buffer (0x%llx) already registered in buffer set 0x%lx. Unregister existing source buffer...\n", sourceBuffer, (long unsigned int)bufferSetID);
1519						unregisterClientBuffer64(&sourceBuffer, bufferSetID);
1520						break;
1521					}
1522					clientBufPtr = clientBufPtr->mNextBuffer64;
1523				}
1524			}
1525		}
1526
1527		unlockBuffers();
1528
1529        // allocate IOAudioClientBuffer to hold buffer descriptor, etc...
1530        clientBuffer = (IOAudioClientBuffer64 *)IOMallocAligned(sizeof(IOAudioClientBuffer64), sizeof (IOAudioClientBuffer64 *));
1531        if (!clientBuffer)
1532		{
1533			audioDebugIOLog(3, "  no clientbuffer\n");
1534	        result = kIOReturnNoMemory;
1535            goto Exit;
1536        }
1537
1538		// make sure everthing is set to NULL [2851917]
1539		bzero(clientBuffer,sizeof(IOAudioClientBuffer64));
1540
1541        clientBuffer->mAudioClientBuffer32.userClient = this;
1542
1543        bufferDirection = audioStream->getDirection() == kIOAudioStreamDirectionOutput ? kIODirectionIn : kIODirectionOut;
1544
1545        audioStream->retain();
1546        clientBuffer->mAudioClientBuffer32.audioStream = audioStream;
1547
1548         clientBuffer->mAudioClientBuffer32.sourceBufferDescriptor = IOMemoryDescriptor::withAddressRange((mach_vm_address_t)sourceBuffer, (mach_vm_size_t)bufSizeInBytes, kIODirectionNone, clientTask);
1549        if (!clientBuffer->mAudioClientBuffer32.sourceBufferDescriptor)
1550		{
1551			audioDebugIOLog(3, "  no sourcebufferdescriptor\n");
1552			result = kIOReturnInternalError;
1553            goto Exit;
1554        }
1555
1556        if ( kIOReturnSuccess != (result = clientBuffer->mAudioClientBuffer32.sourceBufferDescriptor->prepare( kIODirectionOutIn ) ) )
1557		{
1558				audioDebugIOLog(3, "  prepare error \n");
1559				goto Exit;
1560	      }
1561
1562        clientBuffer->mAudioClientBuffer32.sourceBufferMap = clientBuffer->mAudioClientBuffer32.sourceBufferDescriptor->map();
1563
1564
1565        if (clientBuffer->mAudioClientBuffer32.sourceBufferMap == NULL)
1566		{
1567            IOLog("IOAudioEngineUserClient<0x%p>::registerClientBuffer64() - error mapping memory.\n", this);
1568            result = kIOReturnVMError;
1569            goto Exit;
1570        }
1571
1572        clientBuffer->mAudioClientBuffer32.sourceBuffer = (void *)clientBuffer->mAudioClientBuffer32.sourceBufferMap->getVirtualAddress();
1573        if (clientBuffer->mAudioClientBuffer32.sourceBuffer == NULL)
1574		{
1575            result = kIOReturnVMError;
1576            goto Exit;
1577        }
1578		// offset past per buffer info
1579        audioDebugIOLog(3, "  clientBuffer->mAudioClientBuffer32.sourceBuffer before offset: %p, offset size: %ld\n", clientBuffer->mAudioClientBuffer32.sourceBuffer, offsetof(IOAudioBufferDataDescriptor, fData));
1580		clientBuffer->mAudioClientBuffer32.bufferDataDescriptor = (IOAudioBufferDataDescriptor *)(clientBuffer->mAudioClientBuffer32.sourceBuffer);
1581		clientBuffer->mAudioClientBuffer32.sourceBuffer = (UInt8 *)(clientBuffer->mAudioClientBuffer32.sourceBuffer) + offsetof(IOAudioBufferDataDescriptor, fData);
1582        audioDebugIOLog(3, "  clientBuffer->mAudioClientBuffer32.sourceBuffer after offset: %p\n", clientBuffer->mAudioClientBuffer32.sourceBuffer);
1583
1584		numSampleFrames = bufSizeInBytes;
1585		if (streamFormat->fIsMixable) {
1586			// If it's mixable the data is floats, so that's the size of each sample
1587			clientBuffer->mAudioClientBuffer32.numSampleFrames = ( bufSizeInBytes - offsetof(IOAudioBufferDataDescriptor, fData) ) / (kIOAudioEngineDefaultMixBufferSampleSize * streamFormat->fNumChannels);
1588		} else {
1589			// If it's not mixable then the size is whatever the bitwidth is
1590			clientBuffer->mAudioClientBuffer32.numSampleFrames = ( bufSizeInBytes - offsetof(IOAudioBufferDataDescriptor, fData) ) / ((streamFormat->fBitWidth / 8) * streamFormat->fNumChannels);
1591		}
1592        clientBuffer->mAudioClientBuffer32.numChannels = streamFormat->fNumChannels;
1593        clientBuffer->mUnmappedSourceBuffer64 = sourceBuffer;
1594		clientBuffer->mAudioClientBuffer32.unmappedSourceBuffer = (void *)sourceBuffer;
1595		clientBuffer->mNextBuffer64 = NULL;
1596        clientBuffer->mAudioClientBuffer32.mNextBuffer32 = NULL;
1597        clientBuffer->mAudioClientBuffer32.nextClip = NULL;
1598        clientBuffer->mAudioClientBuffer32.previousClip = NULL;
1599        clientBuffer->mAudioClientBuffer32.nextClient = NULL;
1600
1601        lockBuffers();
1602
1603        clientBufferSet = findBufferSet(bufferSetID);
1604        if (clientBufferSet == NULL) {
1605			audioDebugIOLog(3, "  creating new IOAudioClientBufferSet \n" );
1606			clientBufferSet = new IOAudioClientBufferSet;
1607
1608            if (clientBufferSet == NULL) {
1609                result = kIOReturnNoMemory;
1610                unlockBuffers();
1611                goto Exit;
1612            }
1613
1614            if (!clientBufferSet->init(bufferSetID, this)) {
1615                result = kIOReturnError;
1616                unlockBuffers();
1617                goto Exit;
1618            }
1619
1620            clientBufferSet->mNextBufferSet = clientBufferSetList;
1621
1622            clientBufferSetList = clientBufferSet;
1623        }
1624
1625        if (audioStream->getDirection() == kIOAudioStreamDirectionOutput) {
1626			audioDebugIOLog(3, "  output \n" );
1627            clientBufferList = &clientBufferSet->outputBufferList;
1628            if (clientBufferSet->watchdogThreadCall == NULL) {
1629                clientBufferSet->allocateWatchdogTimer();
1630                if (clientBufferSet->watchdogThreadCall == NULL) {
1631                    result = kIOReturnNoMemory;
1632                    unlockBuffers();
1633                    goto Exit;
1634                }
1635            }
1636        } else {
1637 			audioDebugIOLog(3, "  input \n" );
1638            clientBufferList = &clientBufferSet->inputBufferList;
1639        }
1640
1641        assert(clientBufferList);
1642
1643        if (*clientBufferList == NULL) {
1644            *clientBufferList = clientBuffer;
1645        } else {
1646            IOAudioClientBuffer64 *clientBufPtr = *clientBufferList;
1647            while (clientBufPtr->mNextBuffer64 != NULL) {
1648                clientBufPtr = clientBufPtr->mNextBuffer64;
1649            }
1650			audioDebugIOLog(3, "  assigning  clientBufPtr->mAudioClientBuffer32.mNextBuffer32 %p \n", &clientBuffer->mAudioClientBuffer32 );
1651            clientBufPtr->mNextBuffer64 = clientBuffer;
1652			clientBufPtr->mAudioClientBuffer32.mNextBuffer32 = &clientBuffer->mAudioClientBuffer32;
1653        }
1654
1655        //  <rdar://11731381>   Add the client while holding the buffers lock to avoid race conditions.
1656        if (isOnline()) {
1657			audioDebugIOLog(3, "  isOnline adding client \n" );
1658
1659            result = audioStream->addClient( &clientBuffer->mAudioClientBuffer32 );
1660
1661            // Clean up the client buffer list in the event of failure.
1662            if (kIOReturnSuccess != result) {
1663                if (*clientBufferList == clientBuffer) {
1664                    *clientBufferList = NULL;
1665                } else {
1666                    IOAudioClientBuffer64 *clientBufPtr = *clientBufferList;
1667                    while ((NULL != clientBufPtr) && (clientBufPtr->mNextBuffer64 != clientBuffer)) {
1668                        clientBufPtr = clientBufPtr->mNextBuffer64;
1669                    }
1670                    clientBufPtr->mNextBuffer64 = NULL;
1671                    clientBufPtr->mAudioClientBuffer32.mNextBuffer32 = NULL;
1672                }
1673            }
1674        }
1675		else {
1676			audioDebugIOLog(3, "  !isOnline \n" );
1677		}
1678
1679        unlockBuffers();
1680
1681    Exit:
1682
1683        if (result != kIOReturnSuccess) {
1684 			audioDebugIOLog(3, "  result (0x%x) != kIOReturnSuccess \n", result );
1685           if (clientBuffer != NULL) {
1686                if (clientBuffer->mAudioClientBuffer32.sourceBufferDescriptor != NULL) {
1687                    clientBuffer->mAudioClientBuffer32.sourceBufferDescriptor->release();
1688					clientBuffer->mAudioClientBuffer32.sourceBufferDescriptor = NULL;
1689                }
1690                if (clientBuffer->mAudioClientBuffer32.sourceBufferMap != NULL) {
1691                    clientBuffer->mAudioClientBuffer32.sourceBufferMap->release();
1692					clientBuffer->mAudioClientBuffer32.sourceBufferMap = NULL;
1693                }
1694                if (clientBuffer->mAudioClientBuffer32.audioStream) {
1695                    clientBuffer->mAudioClientBuffer32.audioStream->release();
1696					clientBuffer->mAudioClientBuffer32.audioStream = NULL;
1697                }
1698                IOFreeAligned(clientBuffer, sizeof(IOAudioClientBuffer64));
1699				clientBuffer = NULL;
1700            }
1701        }
1702
1703    } else {
1704		audioDebugIOLog(3, "  !isActive - no Device \n" );
1705        result = kIOReturnNoDevice;
1706    }
1707	audioDebugIOLog(3, "- IOAudioEngineUserClient::registerClientBuffer64() result 0x%lX\n", (long unsigned int)result);
1708
1709    return result;
1710}
1711// 32 bit version <rdar://problems/5321701>
1712IOReturn IOAudioEngineUserClient::unregisterClientBuffer( void * sourceBuffer, UInt32 bufferSetID)
1713{
1714	IOReturn result = kIOReturnUnsupported;
1715	audioDebugIOLog(3, "+-IOAudioEngineUserClient[%p]::unregisterClientBuffer NOT SUPPORTED for 32 bit buffer( %p, 0x%lx)\n", this, sourceBuffer, (long unsigned int)bufferSetID);
1716	return result;
1717}
1718// 64 bit version <rdar://problems/5321701>
1719IOReturn IOAudioEngineUserClient::unregisterClientBuffer64( mach_vm_address_t * sourceBuffer, UInt32 bufferSetID)
1720{
1721    IOReturn result = kIOReturnBadArgument;
1722
1723    audioDebugIOLog(3, "+ IOAudioEngineUserClient[%p]::unregisterClientBuffer64(0x%p, 0x%lx)\n", this, sourceBuffer, (long unsigned int)bufferSetID);
1724
1725    if (sourceBuffer) {
1726        IOAudioClientBufferSet *bufferSet;
1727
1728        lockBuffers();
1729
1730        bufferSet = findBufferSet(bufferSetID);
1731
1732        if (bufferSet) {
1733            IOAudioClientBuffer64 *clientBuf = NULL, *previousBuf = NULL;
1734            IOAudioClientBuffer64 **clientBufferList = NULL;
1735
1736            if (bufferSet->outputBufferList)
1737			{
1738                clientBufferList = &bufferSet->outputBufferList;
1739				audioDebugIOLog(3, "  searching for sourceBuffer 0x%llx \n", *sourceBuffer);
1740                clientBuf = bufferSet->outputBufferList;
1741                previousBuf = NULL;
1742
1743                while (clientBuf && (clientBuf->mUnmappedSourceBuffer64 != *sourceBuffer))
1744				{
1745					audioDebugIOLog(3, "  checking against 0x%llx \n", clientBuf->mUnmappedSourceBuffer64);
1746                   previousBuf = clientBuf;
1747                    clientBuf = clientBuf->mNextBuffer64;
1748                }
1749            }
1750			else
1751			{
1752				audioDebugIOLog(3, "  clientBuf for output not found \n");
1753			}
1754
1755            // If we didn't find the buffer in the output list, check the input list
1756            if (!clientBuf && bufferSet->inputBufferList) {
1757				audioDebugIOLog(3, "  checking input \n");
1758				clientBufferList = &bufferSet->inputBufferList;
1759                clientBuf = bufferSet->inputBufferList;
1760                previousBuf = NULL;
1761                while (clientBuf && (clientBuf->mUnmappedSourceBuffer64 != *sourceBuffer)) {
1762                    previousBuf = clientBuf;
1763                    clientBuf = clientBuf->mNextBuffer64;
1764                }
1765            }
1766
1767            if (clientBuf) {
1768
1769                assert(clientBuf->mUnmappedSourceBuffer64 == *sourceBuffer);
1770
1771                if (previousBuf) {
1772                    previousBuf->mNextBuffer64 = clientBuf->mNextBuffer64;
1773                } else {
1774                    assert(clientBufferList);
1775                    *clientBufferList = clientBuf->mNextBuffer64;
1776                }
1777
1778                if (bufferSet->outputBufferList == NULL) {
1779                    if (bufferSet->inputBufferList == NULL) {
1780                        removeBufferSet(bufferSet);
1781                    } else if (bufferSet->watchdogThreadCall != NULL) {
1782                        bufferSet->freeWatchdogTimer();
1783                    }
1784                }
1785
1786                freeClientBuffer(clientBuf);		// Moved below above if statement
1787
1788                result = kIOReturnSuccess;
1789            } else
1790			{
1791				audioDebugIOLog(3, "  no clientbuffer found \n" );
1792				result = kIOReturnNotFound;
1793            }
1794        } else
1795		{
1796			audioDebugIOLog(3, "  no bufferSet found for id 0x%lx \n", (long unsigned int)bufferSetID);
1797            result = kIOReturnNotFound;
1798        }
1799
1800        unlockBuffers();
1801    }
1802    else
1803	{
1804	    audioDebugIOLog(3, "  no sourcebuffer \n" );
1805	}
1806	audioDebugIOLog(3, "- IOAudioEngineUserClient::unregisterClientBuffer64 no sourcebuffer returns 0x%lX\n", (long unsigned int)result );
1807	return result;
1808}
1809
1810IOAudioClientBufferSet *IOAudioEngineUserClient::findBufferSet(UInt32 bufferSetID)
1811{
1812    IOAudioClientBufferSet *bufferSet = NULL;
1813
1814	audioDebugIOLog(7, "+ IOAudioEngineUserClient::findBufferSet ( bufferSetID %ld )\n", (long int)bufferSetID );		// <rdar://9725460>
1815
1816	if (0 == clientBufferSetList)
1817	{
1818 		audioDebugIOLog(3, "  null clientBufferSetList\n");
1819	}
1820    bufferSet = clientBufferSetList;
1821    while (bufferSet && (bufferSet->bufferSetID != bufferSetID)) {
1822        bufferSet = bufferSet->mNextBufferSet;
1823    }
1824    if ( !bufferSet || ( bufferSet->bufferSetID != bufferSetID ) )
1825	{
1826		audioDebugIOLog(3, "  did not find clientBufferSetList for ID 0x%lx \n", (long unsigned int)bufferSetID);
1827	}
1828	audioDebugIOLog(7, "- IOAudioEngineUserClient::findBufferSet ( bufferSetID %ld ) returns %p\n", (long int)bufferSetID, bufferSet );		// <rdar://9725460>
1829    return bufferSet;
1830}
1831
1832void IOAudioEngineUserClient::removeBufferSet(IOAudioClientBufferSet *bufferSet)
1833{
1834    IOAudioClientBufferSet *prevSet, *nextSet;
1835
1836    audioDebugIOLog(3, "+ IOAudioEngineUserClient[%p]::removeBufferSet(%p)\n", this, bufferSet);
1837
1838    lockBuffers();
1839
1840    nextSet = clientBufferSetList;
1841    prevSet = NULL;
1842    while (nextSet && (nextSet != bufferSet)) {
1843        prevSet = nextSet;
1844        nextSet = nextSet->mNextBufferSet;
1845    }
1846
1847    if (nextSet) {
1848        assert(nextSet == bufferSet);
1849
1850        nextSet->cancelWatchdogTimer();
1851
1852        if (prevSet) {
1853            prevSet->mNextBufferSet = nextSet->mNextBufferSet;
1854        } else {
1855            clientBufferSetList = nextSet->mNextBufferSet;
1856        }
1857
1858        nextSet->release();
1859    }
1860
1861    unlockBuffers();
1862
1863    audioDebugIOLog(3, "- IOAudioEngineUserClient[%p]::removeBufferSet(%p)\n", this, bufferSet);
1864	return;
1865}
1866
1867IOReturn IOAudioEngineUserClient::performClientIO(UInt32 firstSampleFrame, UInt32 loopCount, bool inputIO, UInt32 bufferSetID, UInt32 sampleIntervalHi, UInt32 sampleIntervalLo)
1868{
1869    IOReturn result = kIOReturnSuccess;
1870
1871    audioDebugIOLog(7, "+ IOAudioEngineUserClient[%p]::performClientIO(0x%lx, 0x%lx, %d, 0x%lx, 0x%lx, 0x%lx )\n",
1872						this,
1873						(long unsigned int)firstSampleFrame,
1874						(long unsigned int)loopCount, inputIO,
1875						(long unsigned int)bufferSetID,
1876						(long unsigned int)sampleIntervalHi,
1877						(long unsigned int)sampleIntervalLo );
1878    assert(audioEngine);
1879
1880    if (!isInactive())
1881	{
1882        lockBuffers();
1883
1884        if (isOnline() && (audioEngine->getState() == kIOAudioEngineRunning) && audioEngine->status && ( audioEngine->status->fCurrentLoopCount || audioEngine->status->fLastLoopTime )  )			//	<rdar://12879939>	Wait for first takeTimeStamp call before allowing audio
1885		{
1886            if (firstSampleFrame < audioEngine->numSampleFramesPerBuffer)
1887			{
1888                IOAudioClientBufferSet *bufferSet;
1889
1890                bufferSet = findBufferSet(bufferSetID);
1891                if (bufferSet)
1892				{
1893
1894                    if (inputIO)
1895					{
1896                        result = performClientInput(firstSampleFrame, bufferSet);
1897                    } else
1898					{
1899                        result = performClientOutput(firstSampleFrame, loopCount, bufferSet, sampleIntervalHi, sampleIntervalLo);
1900                    }
1901                }
1902				else
1903				{
1904					audioDebugIOLog(3, "  no bufferset\n");
1905 				}
1906            }
1907			else
1908			{
1909				audioDebugIOLog(3, " firstSampleFrame ( 0x%lx) is out of range - 0x%lx frames per buffer.\n",  (long unsigned int)firstSampleFrame,  (long unsigned int)audioEngine->numSampleFramesPerBuffer);
1910                result = kIOReturnBadArgument;
1911            }
1912        }
1913		else
1914		{
1915			audioDebugIOLog(3, "IOAudioEngineUserClient[%p] - AUDIO OFFLINE. online=%d. state=%d. loopCount=%d, lastLoopTime=%d\n", this, isOnline(), audioEngine->getState(), audioEngine->status->fCurrentLoopCount, (unsigned int)audioEngine->status->fLastLoopTime);
1916 	        result = kIOReturnOffline;
1917        }
1918
1919        unlockBuffers();
1920    } else
1921	{
1922        result = kIOReturnNoDevice;
1923    }
1924
1925	audioDebugIOLog(7, "- IOAudioEngineUserClient::performClientIO result = 0x%lX\n", (long unsigned int)result);		// <rdar://9725460>
1926    return result;
1927}
1928
1929// model a SwapFloat32 after CF
1930inline uint32_t CFSwapInt32(uint32_t arg) {
1931#if defined(__i386__) && defined(__GNUC__)
1932    __asm__("bswap %0" : "+r" (arg));
1933    return arg;
1934#elif defined(__x86_64__) && defined(__GNUC__)		// <rdar://6612182>
1935    __asm__("bswap %0" : "+r" (arg));
1936    return arg;
1937#elif defined(__ppc__) && defined(__GNUC__)
1938    uint32_t result;
1939    __asm__("lwbrx %0,0,%1" : "=r" (result) : "r" (&arg), "m" (arg));
1940    return result;
1941#else
1942    uint32_t result;
1943    result = ((arg & 0xFF) << 24) | ((arg & 0xFF00) << 8) | ((arg >> 8) & 0xFF00) | ((arg >> 24) & 0xFF);
1944    return result;
1945#endif
1946}
1947
1948
1949void FlipFloats(void *p, long fcnt)
1950{
1951	UInt32 *ip = (UInt32 *)p;
1952
1953	while (fcnt--) {
1954		*ip = CFSwapInt32(*ip);
1955		ip++;
1956	}
1957}
1958
1959static inline IOAudioBufferDataDescriptor * FlipBufferDataDescriptor(IOAudioBufferDataDescriptor *in, IOAudioBufferDataDescriptor *tmp, UInt32 doFlip)
1960{
1961	if (in && doFlip) {
1962		tmp->fActualDataByteSize = CFSwapInt32(in->fActualDataByteSize);
1963		tmp->fActualNumSampleFrames = CFSwapInt32(in->fActualNumSampleFrames);
1964		tmp->fTotalDataByteSize = CFSwapInt32(in->fTotalDataByteSize);
1965		tmp->fNominalDataByteSize = CFSwapInt32(in->fNominalDataByteSize);
1966		return tmp;
1967	}
1968	return in;
1969}
1970
1971IOReturn IOAudioEngineUserClient::performClientOutput(UInt32 firstSampleFrame, UInt32 loopCount, IOAudioClientBufferSet *bufferSet, UInt32 sampleIntervalHi, UInt32 sampleIntervalLo)
1972{
1973    IOReturn tmpResult, result = kIOReturnSuccess;
1974
1975	// <rdar://9725460>
1976	audioDebugIOLog ( 4, "+ IOAudioEngineUserClient[%p]::performClientOutput ( firstSampleFrame %ld, loopCount %ld,  bufferSet %p, sampleIntervalHi %ld, sampleIntervalLo %ld )\n",
1977					this,
1978					(long int)firstSampleFrame,
1979					(long int)loopCount,
1980					bufferSet,
1981					(long int)sampleIntervalHi,
1982					(long int)sampleIntervalLo );
1983
1984	assert(audioEngine != NULL);
1985
1986    // <rdar://10145205,15277619> Sanity check the loop count
1987	if ( ( loopCount >= audioEngine->status->fCurrentLoopCount ) &&
1988         ( loopCount <= audioEngine->status->fCurrentLoopCount + kLoopCountMaximumDifference ) )
1989    {
1990#if __LP64__
1991		UInt64 tempHI = sampleIntervalHi;
1992		bufferSet->sampleInterval = tempHI << 32 | sampleIntervalLo;
1993#else
1994		bufferSet->sampleInterval.hi = sampleIntervalHi;
1995		bufferSet->sampleInterval.lo = sampleIntervalLo;
1996#endif
1997
1998        if (bufferSet->outputBufferList != NULL) {
1999            IOAudioEnginePosition			outputEndingPosition;
2000            IOAudioClientBuffer64			*clientBuf;
2001            UInt32							sampleFrames, numSampleFramesPerBuffer;
2002            UInt32							clientIndex;
2003
2004            clientIndex = 0;
2005
2006            clientBuf = bufferSet->outputBufferList;
2007
2008            IOAudioBufferDataDescriptor localBufferDataDescriptor;
2009            IOAudioBufferDataDescriptor * localBufferDataDescriptorPtr = FlipBufferDataDescriptor ( clientBuf->mAudioClientBuffer32.bufferDataDescriptor, &localBufferDataDescriptor, reserved->classicMode );
2010
2011            if (NULL != localBufferDataDescriptorPtr) {
2012                audioDebugIOLog(6, "  performClientOutput -------------%ld-----------------\n", (long int)clientIndex);
2013                audioDebugIOLog ( 6, "  actual frames = %ld, actual bytes = %ld, nominal bytes = %ld, total bytes = %ld\n",
2014                                    (long int)localBufferDataDescriptorPtr->fActualNumSampleFrames,
2015                                    (long int)localBufferDataDescriptorPtr->fActualDataByteSize,
2016                                    (long int)localBufferDataDescriptorPtr->fNominalDataByteSize,
2017                                    (long int)localBufferDataDescriptorPtr->fTotalDataByteSize );
2018                sampleFrames = localBufferDataDescriptorPtr->fActualNumSampleFrames;
2019            } else {
2020                audioDebugIOLog(6, "  no buffer descriptor found, using bufferSet->outputBufferList->numSampleFrames\n");
2021                sampleFrames = bufferSet->outputBufferList->mAudioClientBuffer32.numSampleFrames;
2022            }
2023
2024            numSampleFramesPerBuffer = audioEngine->getNumSampleFramesPerBuffer();
2025
2026            outputEndingPosition.fLoopCount = loopCount;
2027            outputEndingPosition.fSampleFrame = firstSampleFrame + sampleFrames;
2028
2029            if (outputEndingPosition.fSampleFrame >= numSampleFramesPerBuffer) {
2030                outputEndingPosition.fSampleFrame -= numSampleFramesPerBuffer;
2031                outputEndingPosition.fLoopCount++;
2032            }
2033
2034            // We only want to do output if we haven't already gone past the new samples
2035            // If the samples are late, the watchdog will already have skipped them
2036            if (CMP_IOAUDIOENGINEPOSITION(&outputEndingPosition, &bufferSet->nextOutputPosition) >= 0)  {
2037                AbsoluteTime outputTimeout;
2038
2039                audioDebugIOLog(6, "  CMP_IOAUDIOENGINEPOSITION >= 0 \n");
2040                clientBuf = bufferSet->outputBufferList;
2041
2042                while (clientBuf) {
2043                    IOAudioStream *					audioStream;
2044                    UInt32							maxNumSampleFrames;
2045
2046                    audioStream = clientBuf->mAudioClientBuffer32.audioStream;
2047
2048                    assert(audioStream);
2049                    assert(audioStream->getDirection() == kIOAudioStreamDirectionOutput);
2050                    assert(clientBuf->mAudioClientBuffer32.sourceBuffer != NULL);
2051
2052                    audioStream->lockStreamForIO();
2053
2054                    maxNumSampleFrames = clientBuf->mAudioClientBuffer32.numSampleFrames;
2055                    // <rdar://6865619>, <rdar://6917678> Validate the parameters passed in IOAudioBufferDataDescriptor vs the maximum buffer size.
2056                    if ( sampleFrames > maxNumSampleFrames ) {
2057                        audioDebugIOLog ( 1, "  **** VBR OUTPUT ERROR! - actual sample frames (%ld) is larger than max sample frames (%ld)\n", (long int)sampleFrames, (long int)maxNumSampleFrames);
2058                        audioStream->unlockStreamForIO();
2059                        result = kIOReturnBadArgument;
2060                        goto Exit;
2061                    }
2062                    // get the per buffer info
2063                    if (NULL != localBufferDataDescriptorPtr) {
2064                        audioDebugIOLog ( 6, "  clientBuffer = %p: actual frames = %lu, actual bytes = %lu, nominal bytes = %lu, total bytes = %lu, source buffer size = %lu\n",
2065                                                clientBuf,
2066                                                (long unsigned int)localBufferDataDescriptorPtr->fActualNumSampleFrames,
2067                                                (long unsigned int)localBufferDataDescriptorPtr->fActualDataByteSize,
2068                                                (long unsigned int)localBufferDataDescriptorPtr->fNominalDataByteSize,
2069                                                (long unsigned int)localBufferDataDescriptorPtr->fTotalDataByteSize,
2070                                                (long unsigned int)clientBuf->mAudioClientBuffer32.sourceBufferDescriptor->getLength () - offsetof ( IOAudioBufferDataDescriptor, fData ) );
2071
2072                        clientBuf->mAudioClientBuffer32.numSampleFrames = sampleFrames;
2073
2074                        if ((localBufferDataDescriptorPtr->fActualDataByteSize > (clientBuf->mAudioClientBuffer32.sourceBufferDescriptor->getLength () - offsetof(IOAudioBufferDataDescriptor, fData))) ||
2075                            (localBufferDataDescriptorPtr->fActualDataByteSize > localBufferDataDescriptorPtr->fTotalDataByteSize) ||
2076                            (localBufferDataDescriptorPtr->fNominalDataByteSize > localBufferDataDescriptorPtr->fTotalDataByteSize)) {
2077                            audioDebugIOLog ( 1, "  **** VBR OUTPUT ERROR! clientBuffer = %p: actual frames = %ld, actual bytes = %ld, nominal bytes = %ld, total bytes = %ld, source buffer size = %ld\n",
2078                                                clientBuf,
2079                                                (long unsigned int)localBufferDataDescriptorPtr->fActualNumSampleFrames,
2080                                                (long unsigned int)localBufferDataDescriptorPtr->fActualDataByteSize,
2081                                                (long unsigned int)localBufferDataDescriptorPtr->fNominalDataByteSize,
2082                                                (long unsigned int)localBufferDataDescriptorPtr->fTotalDataByteSize,
2083                                                (long unsigned int)clientBuf->mAudioClientBuffer32.sourceBufferDescriptor->getLength () - offsetof(IOAudioBufferDataDescriptor, fData ) );
2084                            audioStream->unlockStreamForIO();
2085                            result = kIOReturnBadArgument;
2086                            goto Exit;
2087                        }
2088#ifdef DEBUG
2089                        if (clientBuf->mAudioClientBuffer32.numSampleFrames != localBufferDataDescriptorPtr->fActualDataByteSize / (audioStream->format.fNumChannels * sizeof(float))) {
2090                            audioDebugIOLog ( 6, "  DEBUGGING - calculated sample frames (%ld) does not match actual sample frames (%ld)\n",
2091                                                (long unsigned int)localBufferDataDescriptorPtr->fActualDataByteSize / (audioStream->format.fNumChannels * sizeof(float)),
2092                                                (long unsigned int)clientBuf->mAudioClientBuffer32.numSampleFrames);
2093                        }
2094#endif
2095                    }
2096
2097 #if __i386__ || __x86_64__	// <rdar://6612182>
2098                    if (reserved->classicMode && clientBuf->mAudioClientBuffer32.sourceBuffer != NULL) {
2099                        const IOAudioStreamFormat *fmt = audioStream->getFormat();
2100                        if (fmt->fIsMixable && fmt->fSampleFormat == kIOAudioStreamSampleFormatLinearPCM) {
2101                            FlipFloats(clientBuf->mAudioClientBuffer32.sourceBuffer, clientBuf->mAudioClientBuffer32.numSampleFrames * clientBuf->mAudioClientBuffer32.numChannels);
2102                        }
2103                    }
2104#endif
2105
2106                    tmpResult = audioStream->processOutputSamples( &( clientBuf->mAudioClientBuffer32 ), firstSampleFrame, loopCount, true);
2107
2108                    clientBuf->mAudioClientBuffer32.numSampleFrames = maxNumSampleFrames;
2109
2110                    audioStream->unlockStreamForIO();
2111
2112                    if (tmpResult != kIOReturnSuccess) {
2113                        audioDebugIOLog ( 3, "  processOutputSamples failed - result 0x%x\n", tmpResult );
2114                        result = tmpResult;
2115                    }
2116
2117                    clientBuf = clientBuf->mNextBuffer64;
2118
2119                    if (clientBuf) {		// need to update localBufferDataDescriptor for the current client buffer
2120                        localBufferDataDescriptorPtr = FlipBufferDataDescriptor ( clientBuf->mAudioClientBuffer32.bufferDataDescriptor, &localBufferDataDescriptor, reserved->classicMode );
2121
2122                        if (NULL != localBufferDataDescriptorPtr) {
2123                            sampleFrames = localBufferDataDescriptorPtr->fActualNumSampleFrames;
2124                        } else {
2125                            sampleFrames = clientBuf->mAudioClientBuffer32.numSampleFrames;
2126                        }
2127                    }
2128
2129                    clientIndex++;
2130                }
2131
2132                bufferSet->nextOutputPosition = outputEndingPosition;
2133
2134                tmpResult = audioEngine->calculateSampleTimeout(&bufferSet->sampleInterval, sampleFrames, &bufferSet->nextOutputPosition, &outputTimeout);
2135
2136				if (tmpResult == kIOReturnSuccess) {
2137					assert(bufferSet->watchdogThreadCall != NULL);			// We better have a thread call if we are doing output
2138
2139					bufferSet->setWatchdogTimeout(&outputTimeout);
2140				} else {
2141					audioDebugIOLog ( 3, "  calculateSampleTimeout failed - result 0x%x\n", tmpResult );
2142					result = tmpResult;
2143				}
2144            } else {
2145                audioDebugIOLog(3, "  performClientOutput(%lx,%lx) - missed samples (%lx,%lx)\n",
2146                                (long unsigned int)loopCount,
2147                                (long unsigned int)firstSampleFrame,
2148                                (long unsigned int)bufferSet->nextOutputPosition.fLoopCount,
2149                                (long unsigned int)bufferSet->nextOutputPosition.fSampleFrame);
2150                result = kIOReturnIsoTooOld;
2151            }
2152        }
2153    } else {
2154		audioDebugIOLog(3, "  performClientOutput(%lx,%lx) - missed samples (%lx,%lx). fCurrentLoopCount=%lx\n",
2155						(long unsigned int)loopCount,
2156						(long unsigned int)firstSampleFrame,
2157						(long unsigned int)bufferSet->nextOutputPosition.fLoopCount,
2158						(long unsigned int)bufferSet->nextOutputPosition.fSampleFrame,
2159						(long unsigned int)audioEngine->status->fCurrentLoopCount);
2160		result = kIOReturnIsoTooOld;
2161	}
2162
2163Exit:
2164	// <rdar://9725460>
2165	audioDebugIOLog ( 4, "- IOAudioEngineUserClient[%p]::performClientOutput ( firstSampleFrame %ld, loopCount %ld,  bufferSet %p, sampleIntervalHi %ld, sampleIntervalLo %ld ) returns 0x%lX\n",
2166					this,
2167					(long int)firstSampleFrame,
2168					(long int)loopCount,
2169					bufferSet,
2170					(long int)sampleIntervalHi,
2171					(long int)sampleIntervalLo,
2172					(long unsigned int)result );
2173    return result;
2174}
2175
2176IOReturn IOAudioEngineUserClient::performClientInput(UInt32 firstSampleFrame, IOAudioClientBufferSet *bufferSet)
2177{
2178    IOReturn						result = kIOReturnSuccess;
2179    IOAudioClientBuffer64			*clientBuf;
2180	UInt32							sampleFrames = 0;
2181
2182	audioDebugIOLog ( 4, "+  IOAudioEngineUserClient[%p]::performClientInput ( firstSampleFrame %ld,  bufferSet %p)\n", this, (long int)firstSampleFrame, bufferSet );			// <rdar://problem/9725460>
2183
2184    clientBuf = bufferSet->inputBufferList;
2185
2186	IOAudioBufferDataDescriptor localBufferDataDescriptor;
2187	IOAudioBufferDataDescriptor * localBufferDataDescriptorPtr = 0;
2188
2189	if (NULL != clientBuf) {
2190		localBufferDataDescriptorPtr = FlipBufferDataDescriptor ( clientBuf->mAudioClientBuffer32.bufferDataDescriptor, &localBufferDataDescriptor, reserved->classicMode );
2191		if (NULL != localBufferDataDescriptorPtr) {
2192			audioDebugIOLog(6, "  performClientInput ------------------------------\n");
2193			audioDebugIOLog ( 6, "  found buffer descriptor, using actual frames = %ld\n",
2194								(long int)localBufferDataDescriptorPtr->fActualNumSampleFrames);
2195			sampleFrames = localBufferDataDescriptorPtr->fActualNumSampleFrames;
2196		} else {
2197			audioDebugIOLog(6, "  no buffer descriptor found, using bufferSet->inputBufferList->numSampleFrames\n");
2198			sampleFrames = bufferSet->inputBufferList->mAudioClientBuffer32.numSampleFrames;
2199		}
2200	}
2201
2202    while (clientBuf) {
2203        IOAudioStream *					audioStream;
2204		UInt32							maxNumSampleFrames;
2205		UInt32							numSampleFramesRead;
2206        IOReturn						tmpResult;
2207
2208        audioStream = clientBuf->mAudioClientBuffer32.audioStream;
2209
2210        assert(audioStream);
2211        assert(audioStream->getDirection() == kIOAudioStreamDirectionInput);
2212        assert(clientBuf->mAudioClientBuffer32.sourceBuffer != NULL);
2213
2214        audioStream->lockStreamForIO();
2215
2216		maxNumSampleFrames = clientBuf->mAudioClientBuffer32.numSampleFrames;
2217		// <rdar://6865619>, <rdar://6917678> Validate the parameters passed in IOAudioBufferDataDescriptor vs the maximum buffer size.
2218		if ( sampleFrames > maxNumSampleFrames )
2219		{
2220			audioDebugIOLog ( 6, "  **** VBR INPUT ERROR! - actual sample frames (%ld) is larger than max sample frames (%ld)\n", (long int)sampleFrames, (long int)maxNumSampleFrames);
2221			audioStream->unlockStreamForIO();
2222			result = kIOReturnBadArgument;
2223			goto Exit;
2224		}
2225
2226		if (NULL != localBufferDataDescriptorPtr) {
2227
2228			clientBuf->mAudioClientBuffer32.numSampleFrames = sampleFrames;
2229
2230			audioDebugIOLog ( 6, "  clientBuffer = %p:  actual frames = %lu, actual bytes = %lu, nominal bytes = %lu, total bytes = %lu, source buffer size = %lu\n",
2231									clientBuf,
2232									(long unsigned int)clientBuf->mAudioClientBuffer32.numSampleFrames,
2233									(long unsigned int)localBufferDataDescriptorPtr->fActualDataByteSize,
2234									(long unsigned int)localBufferDataDescriptorPtr->fNominalDataByteSize,
2235									(long unsigned int)localBufferDataDescriptorPtr->fTotalDataByteSize,
2236									(long unsigned int)clientBuf->mAudioClientBuffer32.sourceBufferDescriptor->getLength () - offsetof ( IOAudioBufferDataDescriptor, fData ) );
2237
2238	#ifdef DEBUG
2239			if (clientBuf->mAudioClientBuffer32.numSampleFrames != localBufferDataDescriptorPtr->fActualDataByteSize / (audioStream->format.fNumChannels * sizeof(float))) {
2240				audioDebugIOLog ( 6, "  DEBUGGING - calculated sample frames (%ld) does not match actual sample frames (%ld)\n",
2241									localBufferDataDescriptorPtr->fActualDataByteSize / (audioStream->format.fNumChannels * sizeof(float)),
2242									(long int)clientBuf->mAudioClientBuffer32.numSampleFrames);
2243			}
2244	#endif
2245			if ((localBufferDataDescriptorPtr->fActualDataByteSize > (clientBuf->mAudioClientBuffer32.sourceBufferDescriptor->getLength () - offsetof(IOAudioBufferDataDescriptor, fData))) ||
2246				(localBufferDataDescriptorPtr->fActualDataByteSize > localBufferDataDescriptorPtr->fTotalDataByteSize)) {
2247				audioDebugIOLog (1, "  *** VBR INPUT ERROR! clientBuffer = %p: actual frames = %ld, actual bytes = %ld, nominal bytes = %ld, total bytes = %ld, source buffer size = %ld\n",
2248									clientBuf,
2249									(long unsigned int)clientBuf->mAudioClientBuffer32.numSampleFrames,
2250									(long unsigned int)localBufferDataDescriptorPtr->fActualDataByteSize,
2251									(long unsigned int)localBufferDataDescriptorPtr->fNominalDataByteSize,
2252									(long unsigned int)localBufferDataDescriptorPtr->fTotalDataByteSize,
2253									(long unsigned int)clientBuf->mAudioClientBuffer32.sourceBufferDescriptor->getLength () - offsetof ( IOAudioBufferDataDescriptor, fData ) );
2254				audioStream->unlockStreamForIO();
2255				result = kIOReturnBadArgument;
2256				goto Exit;
2257			}
2258		}
2259
2260		// set the default number of frames read.  This allows drivers to override readInputSamples and still work in the VBR world
2261		audioStream->setDefaultNumSampleFramesRead(sampleFrames);
2262
2263        tmpResult = audioStream->readInputSamples( &( clientBuf->mAudioClientBuffer32 ), firstSampleFrame);
2264
2265#if __i386__ || __x86_64__	// <rdar://6612182>
2266		if (reserved->classicMode && clientBuf->mAudioClientBuffer32.sourceBuffer != NULL) {
2267			const IOAudioStreamFormat *fmt = audioStream->getFormat();
2268			if (fmt->fIsMixable && fmt->fSampleFormat == kIOAudioStreamSampleFormatLinearPCM)
2269			{
2270				FlipFloats(clientBuf->mAudioClientBuffer32.sourceBuffer, clientBuf->mAudioClientBuffer32.numSampleFrames * clientBuf->mAudioClientBuffer32.numChannels);
2271			}
2272		}
2273#endif
2274
2275		// get how many samples the driver actually read & update the rest of the structures
2276		numSampleFramesRead = audioStream->getNumSampleFramesRead();
2277		localBufferDataDescriptorPtr->fActualDataByteSize = numSampleFramesRead * audioStream->format.fNumChannels * sizeof(float);
2278		localBufferDataDescriptorPtr->fActualNumSampleFrames = numSampleFramesRead;
2279		FlipBufferDataDescriptor(localBufferDataDescriptorPtr, clientBuf->mAudioClientBuffer32.bufferDataDescriptor, reserved->classicMode); // save changes back to clientBuf
2280
2281		audioDebugIOLog ( 5, "  numSampleFramesRead = %ld, fActualNumSampleFrames = %ld, fActualDataByteSize = %ld\n",
2282							(long int)numSampleFramesRead,
2283							(long int)localBufferDataDescriptorPtr->fActualNumSampleFrames,
2284							(long int)localBufferDataDescriptorPtr->fActualDataByteSize );
2285
2286		clientBuf->mAudioClientBuffer32.numSampleFrames = maxNumSampleFrames;
2287
2288        audioStream->unlockStreamForIO();
2289
2290        if (tmpResult != kIOReturnSuccess) {
2291			audioDebugIOLog ( 3, "  readInputSamples failed - result 0x%x\n", tmpResult );
2292            result = tmpResult;
2293        }
2294
2295		audioDebugIOLog ( 7, "  next clientBuf \n" );
2296		clientBuf = clientBuf->mNextBuffer64;
2297
2298		if (clientBuf) {  // need to update localBufferDataDescriptor for the current client buffer
2299			localBufferDataDescriptorPtr = FlipBufferDataDescriptor ( clientBuf->mAudioClientBuffer32.bufferDataDescriptor, &localBufferDataDescriptor, reserved->classicMode );
2300
2301			if (NULL != localBufferDataDescriptorPtr) {
2302				sampleFrames = localBufferDataDescriptorPtr->fActualNumSampleFrames;
2303			} else {
2304				sampleFrames = clientBuf->mAudioClientBuffer32.numSampleFrames;
2305			}
2306		}
2307    }
2308
2309Exit:
2310	audioDebugIOLog ( 4, "-  IOAudioEngineUserClient[%p]::performClientInput ( firstSampleFrame %ld,  bufferSet %p) returns 0x%lX\n", this, (long int)firstSampleFrame, bufferSet, (long unsigned int)result );
2311    return result;
2312}
2313
2314void IOAudioEngineUserClient::performWatchdogOutput(IOAudioClientBufferSet *clientBufferSet, UInt32 generationCount)
2315{
2316	IOReturn tmpResult;
2317
2318	audioDebugIOLog(3, "+ IOAudioEngineUserClient[%p]::performWatchdogOutput(%p, %ld) - (%lx,%lx)\n",
2319						this, clientBufferSet,
2320						(long int)generationCount,
2321						(long unsigned int)clientBufferSet->nextOutputPosition.fLoopCount,
2322						(long unsigned int)clientBufferSet->nextOutputPosition.fSampleFrame);
2323
2324    lockBuffers();
2325
2326    if (!isInactive() && isOnline()) {
2327        if (clientBufferSet->timerPending) {
2328            // If the generation count of the clientBufferSet is different than the
2329            // generation count passed in, then a new client IO was received just before
2330            // the timer fired, and we don't need to do the fake IO
2331            // We just leave the timerPending field set
2332            if (clientBufferSet->generationCount == generationCount) {
2333                IOAudioClientBuffer64 *clientBuffer;
2334				IOAudioBufferDataDescriptor localBufferDataDescriptor;			// <rdar://8500809>
2335				IOAudioBufferDataDescriptor * localBufferDataDescriptorPtr;		// <rdar://8500809>
2336				UInt32 sampleFrames, numSampleFramesPerBuffer;				// <rdar://8500809>
2337
2338                clientBuffer = clientBufferSet->outputBufferList;
2339
2340                while (clientBuffer) {
2341                    IOAudioStream *	audioStream;
2342					UInt32			maxNumSampleFrames;			// <rdar://8500809>
2343
2344                    audioStream = clientBuffer->mAudioClientBuffer32.audioStream;
2345
2346                    assert(audioStream);
2347                    assert(audioStream->getDirection() == kIOAudioStreamDirectionOutput);
2348
2349					// <rdar://8500809>	Similar to performClientOutput, look at the buffer data descriptor to find the number of
2350					// sample frames to process.
2351					localBufferDataDescriptorPtr = FlipBufferDataDescriptor ( clientBuffer->mAudioClientBuffer32.bufferDataDescriptor, &localBufferDataDescriptor, reserved->classicMode );
2352
2353					if (NULL != localBufferDataDescriptorPtr) {
2354						audioDebugIOLog(6, "  performWatchdogOutput ------------------------------\n");
2355						audioDebugIOLog ( 6, "  actual frames = %ld, actual bytes = %ld, nominal bytes = %ld, total bytes = %ld\n",
2356										 (long int)localBufferDataDescriptorPtr->fActualNumSampleFrames,
2357										 (long int)localBufferDataDescriptorPtr->fActualDataByteSize,
2358										 (long int)localBufferDataDescriptorPtr->fNominalDataByteSize,
2359										 (long int)localBufferDataDescriptorPtr->fTotalDataByteSize );
2360						sampleFrames = localBufferDataDescriptorPtr->fNominalDataByteSize / ( clientBuffer->mAudioClientBuffer32.numChannels * sizeof(float) );
2361					} else {
2362						audioDebugIOLog(6, "  no buffer descriptor found, using bufferSet->outputBufferList->numSampleFrames\n");
2363						sampleFrames = clientBuffer->mAudioClientBuffer32.numSampleFrames;
2364					}
2365
2366                    audioStream->lockStreamForIO();
2367
2368					// <rdar://8500809> Make sure that the number of sample frames to process is less than the total number of sample frames
2369					// in the buffer.
2370					maxNumSampleFrames = clientBuffer->mAudioClientBuffer32.numSampleFrames;
2371
2372					if (sampleFrames <= maxNumSampleFrames) {	// <rdar://10320402>
2373						// Update the client buffer's numSampleFrames field if there is data descriptor.
2374						if (NULL != localBufferDataDescriptorPtr) {
2375							clientBuffer->mAudioClientBuffer32.numSampleFrames = sampleFrames;
2376						}
2377
2378						audioStream->processOutputSamples( &(clientBuffer->mAudioClientBuffer32), clientBufferSet->nextOutputPosition.fSampleFrame, clientBufferSet->nextOutputPosition.fLoopCount, false);
2379
2380						// Restore the client buffer's numSampleFrames field.
2381						clientBuffer->mAudioClientBuffer32.numSampleFrames = maxNumSampleFrames;
2382					}
2383
2384                    audioStream->unlockStreamForIO();
2385
2386                    clientBuffer = clientBuffer->mNextBuffer64;
2387                }
2388
2389                if (clientBufferSet->outputBufferList != NULL) {
2390                    AbsoluteTime outputTimeout;
2391
2392					// <rdar://8101171> Use the nominal number of sample frames in client buffer if it is available. Don't use
2393					// fActualNumSampleFrames as it will vary (due to cadence) in the case of device aggregation.
2394					localBufferDataDescriptorPtr = FlipBufferDataDescriptor ( clientBufferSet->outputBufferList->mAudioClientBuffer32.bufferDataDescriptor, &localBufferDataDescriptor, reserved->classicMode );	// <rdar://8500809>
2395
2396					if (NULL != localBufferDataDescriptorPtr) {
2397						audioDebugIOLog(6, "  performWatchdogOutput ------------------------------\n");
2398						audioDebugIOLog ( 6, "  actual frames = %ld, actual bytes = %ld, nominal bytes = %ld, total bytes = %ld\n",
2399										 (long int)localBufferDataDescriptorPtr->fActualNumSampleFrames,
2400										 (long int)localBufferDataDescriptorPtr->fActualDataByteSize,
2401										 (long int)localBufferDataDescriptorPtr->fNominalDataByteSize,
2402										 (long int)localBufferDataDescriptorPtr->fTotalDataByteSize );
2403						sampleFrames = localBufferDataDescriptorPtr->fNominalDataByteSize / ( clientBufferSet->outputBufferList->mAudioClientBuffer32.numChannels * sizeof(float) );
2404					} else {
2405						audioDebugIOLog(6, "  no buffer descriptor found, using bufferSet->outputBufferList->numSampleFrames\n");
2406						sampleFrames = clientBufferSet->outputBufferList->mAudioClientBuffer32.numSampleFrames;
2407					}
2408
2409                    numSampleFramesPerBuffer = audioEngine->getNumSampleFramesPerBuffer();
2410
2411					audioDebugIOLog(6, "numSampleFrames = %u, numSampleFramesPerBuffer = %u\n", (unsigned int)sampleFrames, (unsigned int)numSampleFramesPerBuffer);
2412
2413					clientBufferSet->nextOutputPosition.fSampleFrame += sampleFrames;
2414
2415                    if (clientBufferSet->nextOutputPosition.fSampleFrame >= numSampleFramesPerBuffer) {
2416                        clientBufferSet->nextOutputPosition.fSampleFrame -= numSampleFramesPerBuffer;
2417                        clientBufferSet->nextOutputPosition.fLoopCount++;
2418                    }
2419
2420                    // <rdar://10145205> Sanity check the calculated timeout value
2421					tmpResult = audioEngine->calculateSampleTimeout(&clientBufferSet->sampleInterval, sampleFrames, &clientBufferSet->nextOutputPosition, &outputTimeout);
2422                    if ( kIOReturnSuccess == tmpResult ) {
2423	                    clientBufferSet->setWatchdogTimeout(&outputTimeout);
2424					}
2425					else {
2426						audioDebugIOLog(3, "IOAudioEngineUserClient[%p]::performWatchdogOutput failed to calculateSampleTimeout (returned %#x)\n", this, tmpResult);
2427
2428						clientBufferSet->timerPending = false;
2429					}
2430                } else {
2431                    clientBufferSet->timerPending = false;
2432                }
2433            }
2434        }
2435    } else {
2436        clientBufferSet->timerPending = false;
2437    }
2438
2439    unlockBuffers();
2440
2441	audioDebugIOLog(3, "- IOAudioEngineUserClient[%p]::performWatchdogOutput(%p, %ld) - (%lx,%lx)\n",
2442						this, clientBufferSet,
2443						(long int)generationCount,
2444						(long unsigned int)clientBufferSet->nextOutputPosition.fLoopCount,
2445						(long unsigned int)clientBufferSet->nextOutputPosition.fSampleFrame);
2446	return;
2447}
2448
2449IOReturn IOAudioEngineUserClient::getConnectionID(UInt32 *connectionID)
2450{
2451    audioDebugIOLog(3, "+-IOAudioEngineUserClient[%p]::getConnectionID(%p)\n", this, connectionID);
2452
2453    *connectionID = (UInt32) (((UInt64)this >> 8) & 0x00000000FFFFFFFFLLU) ;
2454    return kIOReturnSuccess;
2455}
2456
2457IOReturn IOAudioEngineUserClient::clientStart()
2458{
2459	IOReturn ret = kIOReturnError;
2460
2461	// <rdar://7363756>, <rdar://7529580>
2462	if ( workLoop )
2463	{
2464		ret = workLoop->runAction(_startClientAction, this);	// <rdar://7529580>
2465	}
2466
2467	return ret;
2468}
2469
2470IOReturn IOAudioEngineUserClient::clientStop()
2471{
2472	IOReturn ret = kIOReturnError;
2473
2474	// <rdar://7363756>, <rdar://7529580>
2475	if ( workLoop )
2476	{
2477		ret = workLoop->runAction(_stopClientAction, this);		// <rdar://7529580>
2478	}
2479
2480	return ret;
2481}
2482
2483// <rdar://7529580>
2484IOReturn IOAudioEngineUserClient::_startClientAction(OSObject *target, void *arg0, void *arg1, void *arg2, void *arg3)
2485{
2486    IOReturn result = kIOReturnBadArgument;
2487
2488    if (target) {
2489        IOAudioEngineUserClient *userClient = OSDynamicCast(IOAudioEngineUserClient, target);
2490        if (userClient) {
2491            if (userClient->commandGate) {
2492				setCommandGateUsage(userClient, true);	// <rdar://8518215>
2493                result = userClient->commandGate->runAction(startClientAction, arg0, arg1, arg2, arg3);
2494				setCommandGateUsage(userClient, false);	// <rdar://8518215>
2495            } else {
2496                result = kIOReturnError;
2497            }
2498        }
2499    }
2500
2501    return result;
2502}
2503
2504IOReturn IOAudioEngineUserClient::startClientAction(OSObject *owner, void *arg1, void *arg2, void *arg3, void *arg4)
2505{
2506    IOReturn result = kIOReturnBadArgument;
2507
2508    if (owner) {
2509        IOAudioEngineUserClient *userClient = OSDynamicCast(IOAudioEngineUserClient, owner);
2510        if (userClient) {
2511            result = userClient->startClient();
2512        }
2513    }
2514
2515    return result;
2516}
2517
2518// <rdar://7529580>
2519IOReturn IOAudioEngineUserClient::_stopClientAction(OSObject *target, void *arg0, void *arg1, void *arg2, void *arg3)
2520{
2521    IOReturn result = kIOReturnBadArgument;
2522
2523    if (target) {
2524        IOAudioEngineUserClient *userClient = OSDynamicCast(IOAudioEngineUserClient, target);
2525        if (userClient) {
2526            if (userClient->commandGate) {
2527				setCommandGateUsage(userClient, true);	// <rdar://8518215>
2528                result = userClient->commandGate->runAction(stopClientAction, arg0, arg1, arg2, arg3);
2529				setCommandGateUsage(userClient, false);	// <rdar://8518215>
2530            } else {
2531                result = kIOReturnError;
2532            }
2533        }
2534    }
2535
2536    return result;
2537}
2538
2539IOReturn IOAudioEngineUserClient::stopClientAction(OSObject *owner, void *arg1, void *arg2, void *arg3, void *arg4)
2540{
2541    IOReturn result = kIOReturnBadArgument;
2542
2543    if (owner) {
2544        IOAudioEngineUserClient *userClient = OSDynamicCast(IOAudioEngineUserClient, owner);
2545        if (userClient) {
2546            result = userClient->stopClient();
2547        }
2548    }
2549
2550    return result;
2551}
2552
2553IOReturn IOAudioEngineUserClient::startClient()
2554{
2555    IOReturn	result = kIOReturnNoDevice;
2556    bool		engineStillPaused = false;
2557
2558    audioDebugIOLog(3, "+ IOAudioEngineUserClient[%p]::startClient() - %ld\n", this, (long int)( audioEngine ? audioEngine->numActiveUserClients : 0 ) );
2559
2560	retain();
2561
2562    if (audioEngine && !isInactive()) {
2563		audioDebugIOLog(3, "  audioEngine && !isInactive(). State = %d \n", audioEngine->getState());
2564
2565		// <rdar://15485249> Pause here until the engine is no longer paused
2566		if (audioEngine->getState() == kIOAudioEnginePaused) {
2567			audioDebugIOLog(3, "Will need to wait for engine to resume\n");
2568			result = audioEngine->waitForEngineResume ();
2569
2570			if ( result != kIOReturnSuccess ) {
2571				engineStillPaused = true;
2572			}
2573		}
2574
2575		// We only need to start things up if we're not already online
2576		if (!engineStillPaused && !isInactive()) {
2577			audioDebugIOLog(3, "  audioEngine->getState() != kIOAudioEnginePaused \n");
2578
2579			if (!isOnline()) {
2580				setOnline(true);
2581				audioDebugIOLog(3, "  !isOnline() setting online \n");
2582				result = audioEngine->startClient(this);
2583
2584				if (result == kIOReturnSuccess) {
2585					audioDebugIOLog(3, "  engine started \n");
2586				   IOAudioClientBufferSet *bufferSet;
2587
2588					lockBuffers();
2589
2590					// add buffers to streams
2591					bufferSet = clientBufferSetList;
2592					while (bufferSet) {
2593						IOAudioClientBuffer64 *clientBuffer;
2594						audioDebugIOLog(3, "  bufferSet %p \n", bufferSet);
2595
2596						clientBuffer = bufferSet->outputBufferList;
2597						while (clientBuffer) {
2598							if (clientBuffer->mAudioClientBuffer32.audioStream) {
2599								audioDebugIOLog(3, "  output clientBuffer %p \n", clientBuffer);
2600							   	result = clientBuffer->mAudioClientBuffer32.audioStream->addClient( &clientBuffer->mAudioClientBuffer32 );
2601								if (result != kIOReturnSuccess) {
2602									audioEngine->stopClient(this);				//	<rdar://13412666> stopClient on failure
2603									break;
2604								}
2605							}
2606							clientBuffer = clientBuffer->mNextBuffer64;
2607						}
2608
2609						if (result == kIOReturnSuccess) {
2610							clientBuffer = bufferSet->inputBufferList;
2611							while (clientBuffer) {
2612								audioDebugIOLog(3, "  input clientBuffer %p \n", clientBuffer);
2613								if (clientBuffer->mAudioClientBuffer32.audioStream) {
2614									result = clientBuffer->mAudioClientBuffer32.audioStream->addClient( &( clientBuffer->mAudioClientBuffer32 ) );
2615									if (result != kIOReturnSuccess) {
2616										audioEngine->stopClient(this);				//	<rdar://13412666> stopClient on failure
2617										break;
2618									}
2619								}
2620								clientBuffer = clientBuffer->mNextBuffer64;
2621							}
2622						}
2623
2624						bufferSet->resetNextOutputPosition();
2625
2626						bufferSet = bufferSet->mNextBufferSet;
2627					}
2628
2629					unlockBuffers();
2630				}
2631				else
2632				{
2633					audioDebugIOLog(3, "  engine NOT started \n");
2634				}
2635			}
2636			else {
2637				result = kIOReturnSuccess;
2638			}
2639		}
2640
2641		if ( isInactive() )
2642		{
2643			audioDebugIOLog(3, "Device no longer exists\n");
2644			result = kIOReturnNoDevice;
2645		}
2646    }
2647
2648	if (kIOReturnSuccess != result) {
2649		audioDebugIOLog(3, "  error (0x%x) - setting offline \n", result );
2650		setOnline(false);
2651	}
2652
2653	release();
2654
2655    audioDebugIOLog(3, "- IOAudioEngineUserClient[%p]::startClient() - %ld returns 0x%lX\n", this, (long int)( audioEngine ? audioEngine->numActiveUserClients : 0 ), (long unsigned int)result );
2656	return result;
2657}
2658
2659IOReturn IOAudioEngineUserClient::stopClient()
2660{
2661    IOReturn result = kIOReturnSuccess;
2662
2663    audioDebugIOLog(3, "+ IOAudioEngineUserClient[%p]::stopClient() - %ld\n", this, (long int)( audioEngine ? audioEngine->numActiveUserClients : 0 ));
2664
2665    if (isOnline()) {
2666        IOAudioClientBufferSet *bufferSet;
2667
2668        lockBuffers();
2669
2670        bufferSet = clientBufferSetList;
2671        while (bufferSet) {
2672            IOAudioClientBuffer64 *clientBuffer;
2673
2674            bufferSet->cancelWatchdogTimer();
2675
2676            clientBuffer = bufferSet->outputBufferList;
2677            while (clientBuffer) {
2678                if (clientBuffer->mAudioClientBuffer32.audioStream) {
2679                    clientBuffer->mAudioClientBuffer32.audioStream->removeClient( &( clientBuffer->mAudioClientBuffer32 ) );
2680                }
2681                clientBuffer = clientBuffer->mNextBuffer64;
2682            }
2683
2684            clientBuffer = bufferSet->inputBufferList;
2685            while (clientBuffer) {
2686                if (clientBuffer->mAudioClientBuffer32.audioStream) {
2687                    clientBuffer->mAudioClientBuffer32.audioStream->removeClient( &(clientBuffer->mAudioClientBuffer32 ));
2688                }
2689                clientBuffer = clientBuffer->mNextBuffer64;
2690            }
2691
2692            bufferSet = bufferSet->mNextBufferSet;
2693        }
2694
2695        unlockBuffers();
2696
2697        if (audioEngine) {
2698            result = audioEngine->stopClient(this);
2699        }
2700
2701        setOnline(false);
2702    }
2703
2704    audioDebugIOLog(3, "- IOAudioEngineUserClient[%p]::stopClient() - %ld returns 0x%lX\n", this, (long int)( audioEngine ? audioEngine->numActiveUserClients : 0 ), (long unsigned int)result );
2705    return result;
2706}
2707
2708// Must be done on workLoop
2709void IOAudioEngineUserClient::sendFormatChangeNotification(IOAudioStream *audioStream)
2710{
2711    audioDebugIOLog(3, "+ IOAudioEngineUserClient[%p]::sendFormatChangeNotification(%p)\n", this, audioStream);
2712
2713	//  <rdar://problems/6674310&6687920>
2714    if ( ( !isInactive () ) && audioStream && notificationMessage && ( notificationMessage->messageHeader.msgh_remote_port != MACH_PORT_NULL ) ) {
2715        io_object_t clientStreamRef;
2716
2717        audioStream->retain();
2718        if (exportObjectToClient(clientTask, audioStream, &clientStreamRef) == kIOReturnSuccess) {
2719            kern_return_t kr;
2720
2721            notificationMessage->type = kIOAudioEngineStreamFormatChangeNotification;
2722            notificationMessage->sender = clientStreamRef;
2723
2724            kr = mach_msg_send_from_kernel(&notificationMessage->messageHeader, notificationMessage->messageHeader.msgh_size);
2725            if (kr != MACH_MSG_SUCCESS) {
2726                IOLog("IOAudioEngineUserClient::sendFormatChangeNotification() failed - msg_send returned: %d\n", kr);
2727                // Should also release the clientStreamRef here...
2728            }
2729        } else {
2730            IOLog("IOAudioEngineUserClient[%p]::sendFormatChangeNotification() - ERROR - unable to export stream object for notification - notification not sent\n", this);
2731        }
2732    } else {
2733		if (notificationMessage) {
2734			audioDebugIOLog(5, "IOAudioEngineUserClient[%p]::sendFormatChangeNotification() - ERROR - notification not sent - audioStream = %p - notificationMessage = %p - port = %p\n", this, audioStream, notificationMessage, notificationMessage->messageHeader.msgh_remote_port);
2735		} else {
2736			audioDebugIOLog(4, "IOAudioEngineUserClient[%p]::sendFormatChangeNotification() - ERROR - notification not sent - audioStream = %p - notificationMessage = %p\n", this, audioStream, notificationMessage);
2737		}
2738    }
2739
2740    audioDebugIOLog(3, "- IOAudioEngineUserClient[%p]::sendFormatChangeNotification(%p)\n", this, audioStream);
2741	return;
2742}
2743
2744IOReturn IOAudioEngineUserClient::sendNotification(UInt32 notificationType)
2745{
2746    IOReturn result = kIOReturnSuccess;
2747
2748    audioDebugIOLog(3, "+ IOAudioEngineUserClient[%p]::sendNotification(%ld)\n", this, (long int)notificationType);
2749
2750    if (notificationType == kIOAudioEnginePausedNotification) {
2751        stopClient();
2752    }
2753
2754    if (notificationMessage && (notificationMessage->messageHeader.msgh_remote_port != MACH_PORT_NULL)) {
2755        kern_return_t kr;
2756
2757        notificationMessage->type = notificationType;
2758        notificationMessage->sender = NULL;
2759
2760        kr = mach_msg_send_from_kernel(&notificationMessage->messageHeader, notificationMessage->messageHeader.msgh_size);
2761        if (kr != MACH_MSG_SUCCESS) {
2762            result = kIOReturnError;
2763        }
2764    }
2765
2766    audioDebugIOLog(3, "- IOAudioEngineUserClient[%p]::sendNotification(%ld) returns 0x%lX\n", this, (long int)notificationType, (long unsigned int)result );
2767    return result;
2768}
2769
2770// <rdar://8518215>
2771void IOAudioEngineUserClient::setCommandGateUsage(IOAudioEngineUserClient *userClient, bool increment)
2772{
2773	if (userClient->reserved) {
2774		if (increment) {
2775			switch (userClient->reserved->commandGateStatus)
2776			{
2777				case kCommandGateStatus_Normal:
2778				case kCommandGateStatus_RemovalPending:
2779					userClient->reserved->commandGateUsage++;
2780					break;
2781				case kCommandGateStatus_Invalid:
2782					// Should never be here. If so, something went bad...
2783					break;
2784			}
2785		}
2786		else {
2787			switch (userClient->reserved->commandGateStatus)
2788			{
2789				case kCommandGateStatus_Normal:
2790					if (userClient->reserved->commandGateUsage > 0) {
2791						userClient->reserved->commandGateUsage--;
2792					}
2793					break;
2794				case kCommandGateStatus_RemovalPending:
2795					if (userClient->reserved->commandGateUsage > 0) {
2796						userClient->reserved->commandGateUsage--;
2797
2798						if (userClient->reserved->commandGateUsage == 0) {
2799							userClient->reserved->commandGateStatus = kCommandGateStatus_Invalid;
2800
2801							if (userClient->commandGate) {
2802								if (userClient->workLoop) {
2803									userClient->workLoop->removeEventSource(userClient->commandGate);
2804								}
2805
2806								userClient->commandGate->release();
2807								userClient->commandGate = NULL;
2808							}
2809						}
2810					}
2811					break;
2812				case kCommandGateStatus_Invalid:
2813					// Should never be here. If so, something went bad...
2814					break;
2815			}
2816		}
2817	}
2818}
2819