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 "IOAudioEngine.h"
25#include "IOAudioEngineUserClient.h"
26#include "IOAudioDevice.h"
27#include "IOAudioStream.h"
28#include "IOAudioTypes.h"
29#include "IOAudioDefines.h"
30#include "IOAudioControl.h"
31#include "AudioTracepoints.h"
32
33#include <IOKit/IOLib.h>
34#include <IOKit/IOWorkLoop.h>
35#include <IOKit/IOCommandGate.h>
36
37#include <libkern/c++/OSArray.h>
38#include <libkern/c++/OSNumber.h>
39#include <libkern/c++/OSOrderedSet.h>
40
41#include <kern/clock.h>
42
43#define WATCHDOG_THREAD_LATENCY_PADDING_NS	(125000)	// 125us
44#define DEFAULT_MIX_CLIP_OVERHEAD			10			// <rdar://12188841>
45
46// <rdar://8518215>
47enum
48{
49	kCommandGateStatus_Normal				= 0,
50	kCommandGateStatus_RemovalPending,
51	kCommandGateStatus_Invalid
52};
53
54#define super IOService
55
56OSDefineMetaClassAndAbstractStructors(IOAudioEngine, IOService)
57
58OSMetaClassDefineReservedUsed(IOAudioEngine, 0);
59OSMetaClassDefineReservedUsed(IOAudioEngine, 1);
60OSMetaClassDefineReservedUsed(IOAudioEngine, 2);
61OSMetaClassDefineReservedUsed(IOAudioEngine, 3);
62OSMetaClassDefineReservedUsed(IOAudioEngine, 4);
63OSMetaClassDefineReservedUsed(IOAudioEngine, 5);
64OSMetaClassDefineReservedUsed(IOAudioEngine, 6);
65OSMetaClassDefineReservedUsed(IOAudioEngine, 7);
66OSMetaClassDefineReservedUsed(IOAudioEngine, 8);
67OSMetaClassDefineReservedUsed(IOAudioEngine, 9);
68OSMetaClassDefineReservedUsed(IOAudioEngine, 10);
69OSMetaClassDefineReservedUsed(IOAudioEngine, 11);
70OSMetaClassDefineReservedUsed(IOAudioEngine, 12);
71OSMetaClassDefineReservedUsed(IOAudioEngine, 13);
72OSMetaClassDefineReservedUsed(IOAudioEngine, 14);
73
74OSMetaClassDefineReservedUnused(IOAudioEngine, 15);
75OSMetaClassDefineReservedUnused(IOAudioEngine, 16);
76OSMetaClassDefineReservedUnused(IOAudioEngine, 17);
77OSMetaClassDefineReservedUnused(IOAudioEngine, 18);
78OSMetaClassDefineReservedUnused(IOAudioEngine, 19);
79OSMetaClassDefineReservedUnused(IOAudioEngine, 20);
80OSMetaClassDefineReservedUnused(IOAudioEngine, 21);
81OSMetaClassDefineReservedUnused(IOAudioEngine, 22);
82OSMetaClassDefineReservedUnused(IOAudioEngine, 23);
83OSMetaClassDefineReservedUnused(IOAudioEngine, 24);
84OSMetaClassDefineReservedUnused(IOAudioEngine, 25);
85OSMetaClassDefineReservedUnused(IOAudioEngine, 26);
86OSMetaClassDefineReservedUnused(IOAudioEngine, 27);
87OSMetaClassDefineReservedUnused(IOAudioEngine, 28);
88OSMetaClassDefineReservedUnused(IOAudioEngine, 29);
89OSMetaClassDefineReservedUnused(IOAudioEngine, 30);
90OSMetaClassDefineReservedUnused(IOAudioEngine, 31);
91OSMetaClassDefineReservedUnused(IOAudioEngine, 32);
92OSMetaClassDefineReservedUnused(IOAudioEngine, 33);
93OSMetaClassDefineReservedUnused(IOAudioEngine, 34);
94OSMetaClassDefineReservedUnused(IOAudioEngine, 35);
95OSMetaClassDefineReservedUnused(IOAudioEngine, 36);
96OSMetaClassDefineReservedUnused(IOAudioEngine, 37);
97OSMetaClassDefineReservedUnused(IOAudioEngine, 38);
98OSMetaClassDefineReservedUnused(IOAudioEngine, 39);
99OSMetaClassDefineReservedUnused(IOAudioEngine, 40);
100OSMetaClassDefineReservedUnused(IOAudioEngine, 41);
101OSMetaClassDefineReservedUnused(IOAudioEngine, 42);
102OSMetaClassDefineReservedUnused(IOAudioEngine, 43);
103OSMetaClassDefineReservedUnused(IOAudioEngine, 44);
104OSMetaClassDefineReservedUnused(IOAudioEngine, 45);
105OSMetaClassDefineReservedUnused(IOAudioEngine, 46);
106OSMetaClassDefineReservedUnused(IOAudioEngine, 47);
107
108// OSMetaClassDefineReservedUsed(IOAudioEngine, 13);
109IOReturn IOAudioEngine::setAttributeForConnection( SInt32 connectIndex, UInt32 attribute, uintptr_t value )
110{
111	return kIOReturnUnsupported;
112}
113
114// OSMetaClassDefineReservedUsed(IOAudioEngine, 14);
115IOReturn IOAudioEngine::getAttributeForConnection( SInt32 connectIndex, UInt32 attribute, uintptr_t * value )
116{
117	return kIOReturnUnsupported;
118}
119
120// New Code:
121// OSMetaClassDefineReservedUsed(IOAudioEngine, 12);
122IOReturn IOAudioEngine::createUserClient(task_t task, void *securityID, UInt32 type, IOAudioEngineUserClient **newUserClient, OSDictionary *properties)
123{
124    IOReturn result = kIOReturnSuccess;
125    IOAudioEngineUserClient *userClient;
126
127    userClient = IOAudioEngineUserClient::withAudioEngine(this, task, securityID, type, properties);
128
129    if (userClient) {
130        *newUserClient = userClient;
131    } else {
132        result = kIOReturnNoMemory;
133    }
134
135    return result;
136}
137
138// OSMetaClassDefineReservedUsed(IOAudioEngine, 11);
139void IOAudioEngine::setInputSampleOffset(UInt32 numSamples) {
140    audioDebugIOLog(3, "+ IOAudioEngine[%p]::setInputSampleOffset(0x%lx)\n", this, (long unsigned int)numSamples);
141	assert(reserved);
142	reserved->inputSampleOffset = numSamples;
143    setProperty(kIOAudioEngineInputSampleOffsetKey, numSamples, sizeof(UInt32)*8);
144    audioDebugIOLog(3, "- IOAudioEngine[%p]::setInputSampleOffset(0x%lx)\n", this, (long unsigned int)numSamples);
145}
146
147// OSMetaClassDefineReservedUsed(IOAudioEngine, 10);
148void IOAudioEngine::setOutputSampleOffset(UInt32 numSamples) {
149    audioDebugIOLog(3, "+ IOAudioEngine[%p]::setOutputSampleOffset(0x%lx)\n", this, (long unsigned int)numSamples);
150	setSampleOffset(numSamples);
151    audioDebugIOLog(3, "- IOAudioEngine[%p]::setOutputSampleOffset(0x%lx)\n", this, (long unsigned int)numSamples);
152}
153
154// OSMetaClassDefineReservedUsed(IOAudioEngine, 9);
155IOReturn IOAudioEngine::convertInputSamplesVBR(const void *sampleBuf, void *destBuf, UInt32 firstSampleFrame, UInt32 &numSampleFrames, const IOAudioStreamFormat *streamFormat, IOAudioStream *audioStream)
156{
157	IOReturn result;
158
159    result = convertInputSamples(sampleBuf, destBuf, firstSampleFrame, numSampleFrames, streamFormat, audioStream);
160
161	return result;
162}
163
164// OSMetaClassDefineReservedUsed(IOAudioEngine, 8);
165void IOAudioEngine::setClockDomain(UInt32 inClockDomain) {
166
167	UInt32		clockDomain;
168
169	if (kIOAudioNewClockDomain == inClockDomain) {
170#if __LP64__
171		clockDomain = (UInt32) ((UInt64)this >> 2) ; // grab a couple of bits from the high address to help randomness
172#else
173		clockDomain = (UInt32) this ;
174#endif
175
176	} else {
177		clockDomain = inClockDomain;
178	}
179
180	setProperty(kIOAudioEngineClockDomainKey, clockDomain, sizeof(UInt32)*8);
181}
182
183// OSMetaClassDefineReservedUsed(IOAudioEngine, 7);
184void IOAudioEngine::setClockIsStable(bool clockIsStable) {
185	setProperty(kIOAudioEngineClockIsStableKey, clockIsStable);
186}
187
188// OSMetaClassDefineReservedUsed(IOAudioEngine, 6);
189IOAudioStream * IOAudioEngine::getStreamForID(UInt32 streamID) {
190	IOAudioStream *			stream = NULL;
191
192	assert(reserved);
193	if (reserved->streams) {
194		stream = OSDynamicCast (IOAudioStream, reserved->streams->getObject(streamID));
195	}
196
197	return stream;
198}
199
200// OSMetaClassDefineReservedUsed(IOAudioEngine, 5);
201UInt32 IOAudioEngine::getNextStreamID(IOAudioStream * newStream) {
202	bool			inserted;
203
204	assert(reserved);
205	if (!reserved->streams) {
206		reserved->streams = OSArray::withCapacity(1);
207	}
208
209	inserted = reserved->streams->setObject(newStream);
210
211	return reserved->streams->getCount() - 1;
212}
213
214// OSMetaClassDefineReservedUsed(IOAudioEngine, 4);
215void IOAudioEngine::lockStreamForIO(IOAudioStream *stream) {
216	stream->lockStreamForIO();
217}
218
219// OSMetaClassDefineReservedUsed(IOAudioEngine, 3);
220void IOAudioEngine::unlockStreamForIO(IOAudioStream *stream) {
221	stream->unlockStreamForIO();
222}
223
224// OSMetaClassDefineReservedUsed(IOAudioEngine, 2);
225IOReturn IOAudioEngine::performFormatChange(IOAudioStream *audioStream, const IOAudioStreamFormat *newFormat, const IOAudioStreamFormatExtension *formatExtension, const IOAudioSampleRate *newSampleRate)
226{
227    audioDebugIOLog(3, "+-IOAudioEngine[%p]::performFormatChange(%p, %p, %p, %p)\n", this, audioStream, newFormat, formatExtension, newSampleRate);
228
229    return kIOReturnUnsupported;
230}
231
232// OSMetaClassDefineReservedUsed(IOAudioEngine, 1);
233IOBufferMemoryDescriptor *IOAudioEngine::getStatusDescriptor()
234{
235    audioDebugIOLog(3, "+-IOAudioEngine[%p]::getStatusDescriptor()\n", this);
236	assert(reserved);
237
238	return reserved->statusDescriptor;
239}
240
241IOReturn IOAudioEngine::getNearestStartTime(IOAudioStream *audioStream, IOAudioTimeStamp *ioTimeStamp, bool isInput)
242{
243	return kIOReturnSuccess;
244}
245
246IOBufferMemoryDescriptor * IOAudioEngine::getBytesInInputBufferArrayDescriptor()
247{
248	assert(reserved);
249
250	return reserved->bytesInInputBufferArrayDescriptor;
251}
252
253IOBufferMemoryDescriptor * IOAudioEngine::getBytesInOutputBufferArrayDescriptor()
254{
255	assert(reserved);
256
257	return reserved->bytesInOutputBufferArrayDescriptor;
258}
259
260IOReturn IOAudioEngine::eraseOutputSamples(const void *mixBuf, void *sampleBuf, UInt32 firstSampleFrame, UInt32 numSampleFrames, const IOAudioStreamFormat *streamFormat, IOAudioStream *audioStream)
261{
262	if (mixBuf) {
263		int csize = streamFormat->fNumChannels * kIOAudioEngineDefaultMixBufferSampleSize;
264		bzero((UInt8*)mixBuf + firstSampleFrame * csize, numSampleFrames * csize);
265	}
266	if (sampleBuf) {
267		int csize = streamFormat->fNumChannels * streamFormat->fBitWidth / 8;
268		bzero((UInt8*)sampleBuf + (firstSampleFrame * csize), numSampleFrames * csize);
269	}
270	return kIOReturnSuccess;
271}
272
273void IOAudioEngine::setMixClipOverhead(UInt32 newMixClipOverhead)
274{
275	if (newMixClipOverhead > 1 && newMixClipOverhead < 99) {
276		reserved->mixClipOverhead = newMixClipOverhead;
277	}
278}
279
280// Original code from here forward:
281SInt32 compareAudioStreams(IOAudioStream *stream1, IOAudioStream *stream2, void *ref)
282{
283    UInt32 startingChannelID1, startingChannelID2;
284
285    startingChannelID1 = stream1->getStartingChannelID();
286    startingChannelID2 = stream2->getStartingChannelID();
287
288    return (startingChannelID1 > startingChannelID2) ? -1 : ((startingChannelID2 > startingChannelID1) ? 1 : 0);	// <rdar://9629411>
289}
290
291const OSSymbol *IOAudioEngine::gSampleRateWholeNumberKey = NULL;
292const OSSymbol *IOAudioEngine::gSampleRateFractionKey = NULL;
293
294void IOAudioEngine::initKeys()
295{
296    if (!gSampleRateWholeNumberKey) {
297        gSampleRateWholeNumberKey = OSSymbol::withCString(kIOAudioSampleRateWholeNumberKey);
298        gSampleRateFractionKey = OSSymbol::withCString(kIOAudioSampleRateFractionKey);
299    }
300}
301
302OSDictionary *IOAudioEngine::createDictionaryFromSampleRate(const IOAudioSampleRate *sampleRate, OSDictionary *rateDict)
303{
304    OSDictionary *newDict = NULL;
305
306    if (sampleRate) {
307        if (rateDict) {
308            newDict = rateDict;
309        } else {
310            newDict = OSDictionary::withCapacity(2);
311        }
312
313        if (newDict) {
314            OSNumber *num;
315
316            if (!gSampleRateWholeNumberKey) {
317                initKeys();
318            }
319
320            num = OSNumber::withNumber(sampleRate->whole, sizeof(UInt32)*8);
321            newDict->setObject(gSampleRateWholeNumberKey, num);
322            num->release();
323
324            num = OSNumber::withNumber(sampleRate->fraction, sizeof(UInt32)*8);
325            newDict->setObject(gSampleRateFractionKey, num);
326            num->release();
327        }
328    }
329
330    return newDict;
331}
332
333IOAudioSampleRate *IOAudioEngine::createSampleRateFromDictionary(const OSDictionary *rateDict, IOAudioSampleRate *sampleRate)
334{
335    IOAudioSampleRate *rate = NULL;
336    static IOAudioSampleRate staticSampleRate;
337
338    if (rateDict) {
339        if (sampleRate) {
340            rate = sampleRate;
341        } else {
342            rate = &staticSampleRate;
343        }
344
345        if (rate) {
346            OSNumber *num;
347
348            if (!gSampleRateWholeNumberKey) {
349                initKeys();
350            }
351
352            bzero(rate, sizeof(IOAudioSampleRate));
353
354            num = OSDynamicCast(OSNumber, rateDict->getObject(gSampleRateWholeNumberKey));
355            if (num) {
356                rate->whole = num->unsigned32BitValue();
357            }
358
359            num = OSDynamicCast(OSNumber, rateDict->getObject(gSampleRateFractionKey));
360            if (num) {
361                rate->fraction = num->unsigned32BitValue();
362            }
363        }
364    }
365
366    return rate;
367}
368
369//	<rdar://8121989>	Restructured for single point of entry and single point of exit so that
370//	the indentifier post processing tool can properly insert scope when post processing a log file
371//	obtained via fwkpfv.
372
373bool IOAudioEngine::init(OSDictionary *properties)
374{
375	bool			result = false;
376
377    audioDebugIOLog(3, "+ IOAudioEngine[%p]::init(%p)\n", this, properties);
378
379	OSDictionary * pDict = NULL;
380
381	if ( properties ) // properties is normally NULL
382	{
383		pDict = (OSDictionary*)properties->copyCollection();
384
385		audioDebugIOLog(3, "  Make copy of properties(%p) != pDict(%p)\n", properties, pDict);
386	}
387	else
388	{
389		audioDebugIOLog(3, "  properties(%p) == NULL\n", properties);
390	}
391
392	if ( super::init ( pDict ) )
393	{
394		duringStartup = true;
395
396		sampleRate.whole = 0;
397		sampleRate.fraction = 0;
398
399		numErasesPerBuffer = IOAUDIOENGINE_DEFAULT_NUM_ERASES_PER_BUFFER;
400		isRegistered = false;
401
402		numActiveUserClients = 0;
403
404		reserved = (ExpansionData *)IOMalloc (sizeof(struct ExpansionData));
405		if ( reserved )
406		{
407			reserved->pauseCount = 0;
408			reserved->bytesInInputBufferArrayDescriptor = NULL;
409			reserved->bytesInOutputBufferArrayDescriptor = NULL;
410			reserved->mixClipOverhead = DEFAULT_MIX_CLIP_OVERHEAD;		// <rdar://12188841>
411			reserved->streams = NULL;
412			reserved->commandGateStatus = kCommandGateStatus_Normal;	// <rdar://8518215>
413			reserved->commandGateUsage = 0;								// <rdar://8518215>
414
415			reserved->statusDescriptor = IOBufferMemoryDescriptor::withOptions(kIODirectionOutIn | kIOMemoryKernelUserShared, round_page_32(sizeof(IOAudioEngineStatus)), page_size);
416
417			if ( reserved->statusDescriptor)
418			{
419				status = (IOAudioEngineStatus *)reserved->statusDescriptor->getBytesNoCopy();
420
421				if ( status)
422				{
423					outputStreams = OSOrderedSet::withCapacity(1, (OSOrderedSet::OSOrderFunction)compareAudioStreams);
424					if ( outputStreams )
425					{
426						inputStreams = OSOrderedSet::withCapacity(1, (OSOrderedSet::OSOrderFunction)compareAudioStreams);
427						if ( inputStreams )
428						{
429							setClockDomain ();
430
431							maxNumOutputChannels = 0;
432							maxNumInputChannels = 0;
433
434							setSampleOffset (0);
435
436							userClients = OSSet::withCapacity (1);
437							if ( userClients )
438							{
439								bzero(status, round_page_32(sizeof(IOAudioEngineStatus)));
440								status->fVersion = kIOAudioEngineCurrentStatusStructVersion;
441
442								setState(kIOAudioEngineStopped);
443
444#if __i386__ || __x86_64__
445								setProperty(kIOAudioEngineFlavorKey, (UInt32)kIOAudioStreamByteOrderLittleEndian, sizeof(UInt32)*8);
446#elif __ppc__
447								setProperty(kIOAudioEngineFlavorKey, (unsigned long long)kIOAudioStreamByteOrderBigEndian, sizeof(UInt32)*8);
448#endif
449								result = true;
450							}
451						}
452					}
453				}
454			}
455		}
456	}
457
458    audioDebugIOLog(3, "- IOAudioEngine[%p]::init(%p)\n", this, properties);
459    return result;
460}
461
462// <rdar://12188841>
463void IOAudioEngine::free()
464{
465    audioDebugIOLog(3, "+ IOAudioEngine[%p]::free()\n", this);
466
467	if (reserved) {
468		if (reserved->statusDescriptor) {
469			reserved->statusDescriptor->release();
470			reserved->statusDescriptor = NULL;
471			status = NULL;
472		}
473
474		if (reserved->bytesInInputBufferArrayDescriptor) {
475			reserved->bytesInInputBufferArrayDescriptor->release();
476			reserved->bytesInInputBufferArrayDescriptor = NULL;
477		}
478
479		if (reserved->bytesInOutputBufferArrayDescriptor) {
480			reserved->bytesInOutputBufferArrayDescriptor->release();
481			reserved->bytesInOutputBufferArrayDescriptor = NULL;
482		}
483
484		if (reserved->streams) {
485			reserved->streams->release();
486			reserved->streams = NULL;
487		}
488
489		IOFree (reserved, sizeof(struct ExpansionData));
490	}
491
492    if (outputStreams) {
493        outputStreams->release();
494        outputStreams = NULL;
495    }
496
497    if (inputStreams) {
498        inputStreams->release();
499        inputStreams = NULL;
500    }
501
502    if (userClients) {
503        userClients->release();
504        userClients = NULL;
505    }
506
507    if (defaultAudioControls) {
508        removeAllDefaultAudioControls();
509        defaultAudioControls->release();
510        defaultAudioControls = NULL;
511    }
512
513    if (commandGate) {
514        if (workLoop) {
515            workLoop->removeEventSource(commandGate);
516        }
517
518        commandGate->release();
519        commandGate = NULL;
520    }
521
522    if (workLoop) {
523        workLoop->release();
524        workLoop = NULL;
525    }
526
527    super::free();
528
529    audioDebugIOLog(3, "- IOAudioEngine[%p]::free()\n", this);
530	return;
531}
532
533bool IOAudioEngine::initHardware(IOService *provider)
534{
535    audioDebugIOLog(3, "+-IOAudioEngine[%p]::initHardware(%p)\n", this, provider);
536
537    return true;
538}
539
540//	<rdar://8121989>	Restructured for single point of entry and single point of exit so that
541//	the indentifier post processing tool can properly insert scope when post processing a log file
542//	obtained via fwkpfv.
543
544bool IOAudioEngine::start(IOService *provider)
545{
546	bool			result = false;
547
548    audioDebugIOLog(3, "+ IOAudioEngine[%p]::start(%p)\n", this, provider);
549
550    result = start(provider, OSDynamicCast(IOAudioDevice, provider));
551
552    audioDebugIOLog(3, "- IOAudioEngine[%p]::start(%p) returns %d\n", this, provider, result);
553	return result;
554}
555
556//	<rdar://8121989>	Restructured for single point of entry and single point of exit so that
557//	the indentifier post processing tool can properly insert scope when post processing a log file
558//	obtained via fwkpfv.
559
560bool IOAudioEngine::start(IOService *provider, IOAudioDevice *device)
561{
562    bool result = false;
563
564    audioDebugIOLog(3, "+ IOAudioEngine[%p]::start(%p, %p)\n", this, provider, device);
565    AudioTrace_Start(kAudioTIOAudioEngine, kTPIOAudioEngineStart, (uintptr_t)this, (uintptr_t)provider, (uintptr_t)device, 0);
566
567	if ( super::start ( provider ) )
568	{
569		if ( 0 != device )
570		{
571			setAudioDevice ( device );
572
573			workLoop = audioDevice->getWorkLoop ();
574			if ( workLoop )
575			{
576				workLoop->retain();
577
578				commandGate = IOCommandGate::commandGate ( this );
579				if ( commandGate )
580				{
581					workLoop->addEventSource ( commandGate );
582
583					// for 2761764 & 3111501
584					setWorkLoopOnAllAudioControls ( workLoop );
585
586					result = initHardware ( provider );
587
588					duringStartup = false;
589				}
590			}
591		}
592	}
593
594    audioDebugIOLog(3, "- IOAudioEngine[%p]::start(%p, %p)\n", this, provider, device);
595    AudioTrace_End(kAudioTIOAudioEngine, kTPIOAudioEngineStart, (uintptr_t)this, (uintptr_t)provider, (uintptr_t)device, result);
596    return result;
597}
598
599void IOAudioEngine::stop(IOService *provider)
600{
601    audioDebugIOLog(3, "+ IOAudioEngine[%p]::stop(%p)\n", this, provider);
602
603    if (commandGate)
604	{
605        commandGate->runAction ( detachUserClientsAction );
606    }
607
608    audioDebugIOLog(3, "  about to stopAudioEngine ()\n" );
609    stopAudioEngine ();
610    audioDebugIOLog(3, "  about to detachAudioStreams ()\n" );
611
612	removeTimer();													//	<rdar://14198236>
613    detachAudioStreams ();
614    audioDebugIOLog(3, "  about to removeAllDefaultAudioControls ()\n" );
615    removeAllDefaultAudioControls ();
616    audioDebugIOLog(3, "  completed removeAllDefaultAudioControls ()\n" );
617
618	// <rdar://7233118>, <rdar://7029696> Remove the event source here as performing heavy workloop operation in free() could lead
619	// to deadlock since the context which free() is called is not known. stop() is called on the workloop, so it is safe to remove
620	// the event source here.
621	if (reserved->commandGateUsage == 0) {							// <rdar://8518215>
622		reserved->commandGateStatus = kCommandGateStatus_Invalid;	// <rdar://8518215>
623
624		if (commandGate)
625		{
626			if (workLoop)
627			{
628				workLoop->removeEventSource ( commandGate );
629				audioDebugIOLog(3, "  completed removeEventSource ( ... )\n" );
630			}
631
632			commandGate->release();
633			commandGate = NULL;
634			audioDebugIOLog(3, "  completed release ()\n" );
635		}
636	}
637	else {	// <rdar://8518215>
638		reserved->commandGateStatus = kCommandGateStatus_RemovalPending;
639	}
640
641    audioDebugIOLog(3, "  about to super::stop ( ... )\n" );
642    super::stop ( provider );
643    audioDebugIOLog(3, "- IOAudioEngine[%p]::stop(%p)\n", this, provider);
644}
645
646IOWorkLoop *IOAudioEngine::getWorkLoop() const
647{
648	audioDebugIOLog(7, "+-IOAudioEngine[%p]::getWorkLoop()\n", this);
649
650    return workLoop;
651}
652
653IOCommandGate *IOAudioEngine::getCommandGate() const
654{
655    audioDebugIOLog(7, "+-IOAudioEngine[%p]::getCommandGate()\n", this);
656
657    return commandGate;
658}
659
660void IOAudioEngine::registerService(IOOptionBits options)
661{
662    audioDebugIOLog(3, "+ IOAudioEngine[%p]::registerService(0x%lx)\n", this, (long unsigned int)options);
663
664    if (!isRegistered) {
665        OSCollectionIterator *iterator;
666        IOAudioStream *stream;
667
668        updateChannelNumbers();
669
670        super::registerService(options);
671
672        if (outputStreams && (outputStreams->getCount() > 0)) {
673            iterator = OSCollectionIterator::withCollection(outputStreams);
674            if (iterator) {
675                while ( (stream = OSDynamicCast(IOAudioStream, iterator->getNextObject())) ) {
676                    stream->registerService();
677                }
678                iterator->release();
679            }
680        }
681
682        if (inputStreams && (inputStreams->getCount() > 0)) {
683            iterator = OSCollectionIterator::withCollection(inputStreams);
684            if (iterator) {
685                while ( (stream = OSDynamicCast(IOAudioStream, iterator->getNextObject())) ) {
686                    stream->registerService();
687                }
688                iterator->release();
689            }
690        }
691
692        isRegistered = true;
693    }
694
695    audioDebugIOLog(3, "- IOAudioEngine[%p]::registerService(0x%lx)\n", this, (long unsigned int)options);
696	return;
697}
698
699OSString *IOAudioEngine::getGlobalUniqueID()
700{
701    const OSMetaClass * const myMetaClass = getMetaClass();
702    const char *className = NULL;
703    const char *location = NULL;
704    char *uniqueIDStr;
705    OSString *localID = NULL;
706    OSString *uniqueID = NULL;
707    UInt32 uniqueIDSize;
708
709    if (myMetaClass) {
710        className = myMetaClass->getClassName();
711    }
712
713    location = getLocation();
714
715    localID = getLocalUniqueID();
716
717    uniqueIDSize = 3;
718
719    if (className) {
720        uniqueIDSize += strlen(className);
721    }
722
723    if (location) {
724        uniqueIDSize += strlen(location);
725    }
726
727    if (localID) {
728        uniqueIDSize += localID->getLength();
729    }
730
731    uniqueIDStr = (char *)IOMallocAligned(uniqueIDSize, sizeof (char));
732
733    if (uniqueIDStr) {
734		bzero(uniqueIDStr, uniqueIDSize);
735
736        if (className) {
737            snprintf(uniqueIDStr, uniqueIDSize, "%s:", className);
738        }
739
740        if (location) {
741            strncat(uniqueIDStr, location, uniqueIDSize);
742            strncat(uniqueIDStr, ":", uniqueIDSize);
743        }
744
745        if (localID) {
746            strncat(uniqueIDStr, localID->getCStringNoCopy(), uniqueIDSize);
747            localID->release();
748        }
749
750        uniqueID = OSString::withCString(uniqueIDStr);
751
752        IOFreeAligned(uniqueIDStr, uniqueIDSize);
753    }
754
755    return uniqueID;
756}
757
758OSString *IOAudioEngine::getLocalUniqueID()
759{
760    OSString *localUniqueID;
761	int strSize = (sizeof(UInt32)*2)+1;
762    char localUniqueIDStr[strSize];
763
764    snprintf(localUniqueIDStr, strSize, "%lx", (long unsigned int)index);
765
766    localUniqueID = OSString::withCString(localUniqueIDStr);
767
768    return localUniqueID;
769}
770
771void IOAudioEngine::setIndex(UInt32 newIndex)
772{
773    OSString *uniqueID;
774
775    index = newIndex;
776
777    uniqueID = getGlobalUniqueID();
778    if (uniqueID) {
779        setProperty(kIOAudioEngineGlobalUniqueIDKey, uniqueID);
780        uniqueID->release();
781    }
782}
783
784void IOAudioEngine::setAudioDevice(IOAudioDevice *device)
785{
786    audioDevice = device;
787}
788
789void IOAudioEngine::setDescription(const char *description)
790{
791    if (description) {
792        setProperty(kIOAudioEngineDescriptionKey, description);
793    }
794}
795
796void IOAudioEngine::resetStatusBuffer()
797{
798    audioDebugIOLog(3, "+ IOAudioEngine[%p]::resetStatusBuffer()\n", this);
799
800    assert(status);
801
802    status->fCurrentLoopCount = 0;
803
804#if __LP64__
805	status->fLastLoopTime = 0;
806#else
807	status->fLastLoopTime.hi = 0;
808	status->fLastLoopTime.lo = 0;
809#endif
810
811    status->fEraseHeadSampleFrame = 0;
812
813    stopEngineAtPosition(NULL);
814
815    audioDebugIOLog(3, "- IOAudioEngine[%p]::resetStatusBuffer()\n", this);
816    return;
817}
818
819void IOAudioEngine::clearAllSampleBuffers()
820{
821    OSCollectionIterator *iterator;
822    IOAudioStream *stream;
823
824    if (outputStreams && (outputStreams->getCount() > 0)) {
825        iterator = OSCollectionIterator::withCollection(outputStreams);
826        if (iterator) {
827            while ( (stream = OSDynamicCast(IOAudioStream, iterator->getNextObject())) ) {
828                stream->clearSampleBuffer();
829            }
830            iterator->release();
831        }
832    }
833
834    if (inputStreams && (inputStreams->getCount() > 0)) {
835        iterator = OSCollectionIterator::withCollection(inputStreams);
836        if (iterator) {
837            while ( (stream = OSDynamicCast(IOAudioStream, iterator->getNextObject())) ) {
838                stream->clearSampleBuffer();
839            }
840            iterator->release();
841        }
842    }
843}
844
845IOReturn IOAudioEngine::createUserClient(task_t task, void *securityID, UInt32 type, IOAudioEngineUserClient **newUserClient)
846{
847    IOReturn result = kIOReturnSuccess;
848    IOAudioEngineUserClient *userClient;
849
850    userClient = IOAudioEngineUserClient::withAudioEngine(this, task, securityID, type);
851
852    if (userClient) {
853        *newUserClient = userClient;
854    } else {
855        result = kIOReturnNoMemory;
856    }
857
858    return result;
859}
860
861IOReturn IOAudioEngine::newUserClient(task_t task, void *securityID, UInt32 type, IOUserClient **handler)
862{
863#if __i386__ || __x86_64__
864    return kIOReturnUnsupported;
865#else
866    IOReturn				result = kIOReturnSuccess;
867    IOAudioEngineUserClient	*client;
868
869    audioDebugIOLog(3, "+ IOAudioEngine[%p]::newUserClient(0x%x, %p, 0x%lx, %p)\n", this, (unsigned int)task, securityID, type, handler);
870
871    if (!isInactive()) {
872        result = createUserClient(task, securityID, type, &client);
873
874        if ((result == kIOReturnSuccess) && (client != NULL)) {
875            if (!client->attach(this)) {
876                client->release();
877                result = kIOReturnError;
878            } else if (!client->start(this)) {
879                client->detach(this);
880                client->release();
881                result = kIOReturnError;
882            } else {
883                assert(workLoop);	// <rdar://7324947>
884
885                result = workLoop->runAction(_addUserClientAction, this, client);	// <rdar://7324947>, <rdar://7529580>
886
887                if (result == kIOReturnSuccess) {
888                    *handler = client;
889                }
890			}
891        } else {
892            result = kIOReturnNoMemory;
893        }
894    } else {
895        result = kIOReturnNoDevice;
896    }
897
898	audioDebugIOLog(3, "- IOAudioEngine[%p]::newUserClient(0x%x, %p, 0x%lx, %p)\n", this, (unsigned int)task, securityID, type, handler);
899   return result;
900#endif
901}
902
903IOReturn IOAudioEngine::newUserClient(task_t task, void *securityID, UInt32 type, OSDictionary *properties, IOUserClient **handler)
904{
905    IOReturn				result = kIOReturnSuccess;
906    IOAudioEngineUserClient	*client;
907
908	if (kIOReturnSuccess == newUserClient(task, securityID, type, handler)) {
909		return kIOReturnSuccess;
910	}
911
912    audioDebugIOLog(3, "+ IOAudioEngine[%p]::newUserClient(0x%p, %p, 0x%lx, %p, %p)\n", this, task, securityID, (long unsigned int)type, properties, handler);
913
914    if (!isInactive()) {
915        result = createUserClient(task, securityID, type, &client, properties);
916
917        if ((result == kIOReturnSuccess) && (client != NULL)) {
918            if (!client->attach(this)) {
919                client->release();
920                result = kIOReturnError;
921            } else if (!client->start(this)) {
922                client->detach(this);
923                client->release();
924                result = kIOReturnError;
925            } else {
926                assert(workLoop);	// <rdar://7324947>
927
928                result = workLoop->runAction(_addUserClientAction, this, client);	// <rdar://7324947>, <rdar://7529580>
929
930                if (result == kIOReturnSuccess) {
931                    *handler = client;
932                }
933			}
934        } else {
935            result = kIOReturnNoMemory;
936        }
937    } else {
938        result = kIOReturnNoDevice;
939    }
940
941    audioDebugIOLog(3, "- IOAudioEngine[%p]::newUserClient(0x%p, %p, 0x%lx, %p, %p)\n", this, task, securityID, (long unsigned int)type, properties, handler);
942    return result;
943}
944
945void IOAudioEngine::clientClosed(IOAudioEngineUserClient *client)
946{
947    audioDebugIOLog(3, "+ IOAudioEngine[%p]::clientClosed(%p)\n", this, client);
948
949    if (client) {
950        assert(workLoop);												// <rdar://7529580>
951
952        workLoop->runAction(_removeUserClientAction, this, client);		//	<rdar://7529580>
953    }
954    audioDebugIOLog(3, "- IOAudioEngine[%p]::clientClosed(%p)\n", this, client);
955}
956
957// <rdar://7529580>
958IOReturn IOAudioEngine::_addUserClientAction(OSObject *target, void *arg0, void *arg1, void *arg2, void *arg3)
959{
960    IOReturn result = kIOReturnBadArgument;
961
962    if (target) {
963        IOAudioEngine *audioEngine = OSDynamicCast(IOAudioEngine, target);
964        if (audioEngine) {
965            IOCommandGate *cg;
966
967            cg = audioEngine->getCommandGate();
968
969            if (cg) {
970				setCommandGateUsage(audioEngine, true);		// <rdar://8518215>
971                result = cg->runAction(addUserClientAction, arg0, arg1, arg2, arg3);
972				setCommandGateUsage(audioEngine, false);	// <rdar://8518215>
973            } else {
974                result = kIOReturnError;
975            }
976        }
977    }
978
979    return result;
980}
981
982IOReturn IOAudioEngine::addUserClientAction(OSObject *owner, void *arg1, void *arg2, void *arg3, void *arg4)
983{
984    IOReturn result = kIOReturnBadArgument;
985
986    audioDebugIOLog(3, "+ IOAudioEngine::addUserClientAction(%p, %p)\n", owner, arg1);
987
988    if (owner) {
989        IOAudioEngine *audioEngine = OSDynamicCast(IOAudioEngine, owner);
990        if (audioEngine) {
991            result = audioEngine->addUserClient((IOAudioEngineUserClient *)arg1);
992        }
993    }
994
995    audioDebugIOLog(3, "- IOAudioEngine::addUserClientAction(%p, %p) returns 0x%lX\n", owner, arg1, (long unsigned int)result );
996    return result;
997}
998
999// <rdar://7529580>
1000IOReturn IOAudioEngine::_removeUserClientAction(OSObject *target, void *arg0, void *arg1, void *arg2, void *arg3)
1001{
1002    IOReturn result = kIOReturnBadArgument;
1003
1004    if (target) {
1005        IOAudioEngine *audioEngine = OSDynamicCast(IOAudioEngine, target);
1006        if (audioEngine) {
1007            IOCommandGate *cg;
1008
1009            cg = audioEngine->getCommandGate();
1010
1011            if (cg) {
1012				setCommandGateUsage(audioEngine, true);		// <rdar://8518215>
1013                result = cg->runAction(removeUserClientAction, arg0, arg1, arg2, arg3);
1014				setCommandGateUsage(audioEngine, false);	// <rdar://8518215>
1015            } else {
1016                result = kIOReturnError;
1017            }
1018        }
1019    }
1020
1021    return result;
1022}
1023
1024IOReturn IOAudioEngine::removeUserClientAction(OSObject *owner, void *arg1, void *arg2, void *arg3, void *arg4)
1025{
1026    IOReturn result = kIOReturnBadArgument;
1027
1028    audioDebugIOLog(3, "+ IOAudioEngine::removeUserClientAction(%p, %p)\n", owner, arg1);
1029
1030    if (owner) {
1031        IOAudioEngine *audioEngine = OSDynamicCast(IOAudioEngine, owner);
1032        if (audioEngine) {
1033            result = audioEngine->removeUserClient((IOAudioEngineUserClient *)arg1);
1034        }
1035    }
1036
1037    audioDebugIOLog(3, "- IOAudioEngine::removeUserClientAction(%p, %p) returns 0x%lX\n", owner, arg1, (long unsigned int)result );
1038    return result;
1039}
1040
1041IOReturn IOAudioEngine::detachUserClientsAction(OSObject *owner, void *arg1, void *arg2, void *arg3, void *arg4)
1042{
1043    IOReturn result = kIOReturnBadArgument;
1044
1045    audioDebugIOLog(3, "+ IOAudioEngine::detachUserClientsAction(%p, %p, %p, %p, %p)\n", owner, arg1, arg2, arg3, arg4);
1046
1047    if (owner) {
1048        IOAudioEngine *audioEngine = OSDynamicCast(IOAudioEngine, owner);
1049        if (audioEngine) {
1050            result = audioEngine->detachUserClients();
1051        }
1052    }
1053
1054    audioDebugIOLog(3, "- IOAudioEngine::detachUserClientsAction(%p, %p, %p, %p, %p) returns 0x%lX\n", owner, arg1, arg2, arg3, arg4, (long unsigned int)result );
1055    return result;
1056}
1057
1058IOReturn IOAudioEngine::addUserClient(IOAudioEngineUserClient *newUserClient)
1059{
1060    IOReturn result = kIOReturnSuccess;
1061
1062    audioDebugIOLog(3, "+ IOAudioEngine[%p]::addUserClient(%p)\n", this, newUserClient);
1063
1064    assert(userClients);
1065
1066    userClients->setObject(newUserClient);
1067
1068    audioDebugIOLog(3, "- IOAudioEngine[%p]::addUserClient(%p) returns 0x%lX\n", this, newUserClient, (long unsigned int)result );
1069    return result;
1070}
1071
1072IOReturn IOAudioEngine::removeUserClient(IOAudioEngineUserClient *userClient)
1073{
1074    IOReturn result = kIOReturnSuccess;
1075
1076    audioDebugIOLog(3, "+ IOAudioEngine[%p]::removeUserClient(%p)\n", this, userClient);
1077
1078    assert(userClients);
1079
1080    userClient->retain();
1081
1082    userClients->removeObject(userClient);
1083
1084    if (userClient->isOnline()) {
1085        decrementActiveUserClients();
1086    }
1087
1088    if (!isInactive()) {
1089        userClient->terminate();
1090    }
1091
1092    userClient->release();
1093
1094    audioDebugIOLog(3, "- IOAudioEngine[%p]::removeUserClient(%p) returns 0x%lX\n", this, userClient, (long unsigned int)result );
1095    return result;
1096}
1097
1098IOReturn IOAudioEngine::detachUserClients()
1099{
1100    IOReturn result = kIOReturnSuccess;
1101
1102    audioDebugIOLog(3, "+ IOAudioEngine[%p]::detachUserClients\n", this);
1103
1104    assert(userClients);
1105
1106    if (!isInactive()) {	// Iterate through and terminate each user client
1107		audioDebugIOLog ( 3, "  !isInactive ()\n" );
1108        OSIterator *iterator;
1109
1110        iterator = OSCollectionIterator::withCollection(userClients);
1111
1112        if (iterator) {
1113            IOAudioEngineUserClient *userClient;
1114
1115            while ( (userClient = (IOAudioEngineUserClient *)iterator->getNextObject()) )
1116			{
1117				audioDebugIOLog ( 3, "  will invoke userClient->terminate ()\n" );
1118                userClient->terminate();
1119				audioDebugIOLog ( 3, "  completed userClient->terminate ()\n" );
1120            }
1121			audioDebugIOLog ( 3, "  will invoke iterator->release ()\n" );
1122            iterator->release();
1123			audioDebugIOLog ( 3, "  completed iterator->release ()\n" );
1124        }
1125    }
1126
1127	audioDebugIOLog ( 3, "  will invoke userClients->flushCollection ()\n" );
1128    userClients->flushCollection();
1129	audioDebugIOLog ( 3, "  completed userClients->flushCollection ()\n" );
1130
1131    if (getState() == kIOAudioEngineRunning) {
1132        IOAudioEnginePosition stopPosition;
1133
1134        assert(status);
1135
1136        stopPosition.fSampleFrame = getCurrentSampleFrame();
1137        stopPosition.fLoopCount = status->fCurrentLoopCount + 1;
1138
1139		audioDebugIOLog ( 3, "  will invoke stopEngineAtPosition ()\n" );
1140        stopEngineAtPosition(&stopPosition);
1141		audioDebugIOLog ( 3, "  completed stopEngineAtPosition ()\n" );
1142    }
1143
1144    audioDebugIOLog(3, "- IOAudioEngine[%p]::detachUserClients returns 0x%lX\n", this, (long unsigned int)result );
1145    return result;
1146}
1147
1148IOReturn IOAudioEngine::startClient(IOAudioEngineUserClient *userClient)
1149{
1150    IOReturn result = kIOReturnBadArgument;
1151
1152    audioDebugIOLog(3, "+ IOAudioEngine[%p]::startClient(%p)\n", this, userClient);
1153
1154	while ( audioDevice->getPowerState() == kIOAudioDeviceSleep )
1155	{
1156		retain();
1157
1158		//  <rdar://10885615> Make sure the command gate remains valid while it is being used.
1159		if (commandGate) {
1160			IOReturn err;
1161			setCommandGateUsage(this, true);	//	<rdar://8518215,10885615>
1162			err = commandGate->commandSleep( &audioDevice->currentPowerState );
1163			setCommandGateUsage(this, false);	//	<rdar://8518215,10885615>
1164
1165			//  <rdar://9487554,10885615> On interruption or time out return the appropriate error. This
1166			//  is to prevent it being stuck in the while loop waiting for the power state
1167			//  change.
1168			if ( THREAD_INTERRUPTED == err )
1169			{
1170				release();
1171				return kIOReturnAborted;
1172			}
1173			else if ( THREAD_TIMED_OUT == err )
1174			{
1175				release();
1176				return kIOReturnTimeout;
1177			}
1178			else if ( THREAD_RESTART == err )
1179			{
1180				release();
1181				return kIOReturnNotPermitted;
1182			}
1183		}
1184
1185        //  <rdar://11200354> If ::stop() is called while it is in command sleep, then the command gate
1186        //  will no longer be valid afterwards.
1187        if (isInactive() || (NULL == commandGate))
1188        {
1189            release();
1190            return kIOReturnNoDevice;
1191        }
1192
1193		release();
1194	}
1195
1196    if (userClient) {
1197        result = incrementActiveUserClients();
1198    }
1199
1200    audioDebugIOLog(3, "- IOAudioEngine[%p]::startClient(%p) returns 0x%lX\n", this, userClient, (long unsigned int)result );
1201    return result;
1202}
1203
1204IOReturn IOAudioEngine::stopClient(IOAudioEngineUserClient *userClient)
1205{
1206    IOReturn result = kIOReturnSuccess;
1207
1208    audioDebugIOLog(3, "+ IOAudioEngine[%p]::stopClient(%p)\n", this, userClient);
1209
1210    if (userClient) {
1211        if (userClient->isOnline()) {
1212            result = decrementActiveUserClients();
1213        }
1214    } else {
1215        result = kIOReturnBadArgument;
1216    }
1217
1218    audioDebugIOLog(3, "- IOAudioEngine[%p]::stopClient(%p) returns 0x%lX\n", this, userClient, (long unsigned int)result );
1219    return result;
1220}
1221
1222IOReturn IOAudioEngine::incrementActiveUserClients()
1223{
1224    IOReturn result = kIOReturnSuccess;
1225
1226    audioDebugIOLog(3, "+ IOAudioEngine[%p]::incrementActiveUserClients() - %ld\n", this, (long int)numActiveUserClients);
1227
1228    numActiveUserClients++;
1229
1230    setProperty(kIOAudioEngineNumActiveUserClientsKey, numActiveUserClients, sizeof(UInt32)*8);
1231
1232    if (numActiveUserClients == 1) {
1233        result = startAudioEngine();
1234    }
1235
1236	if (result != kIOReturnSuccess) {
1237		decrementActiveUserClients();
1238	}
1239
1240    audioDebugIOLog(3, "- IOAudioEngine[%p]::incrementActiveUserClients() - %ld returns %lX\n", this, (long int)numActiveUserClients, (long unsigned int)result );
1241    return result;
1242}
1243
1244IOReturn IOAudioEngine::decrementActiveUserClients()
1245{
1246    IOReturn result = kIOReturnSuccess;
1247
1248    audioDebugIOLog(3, "+ IOAudioEngine[%p]::decrementActiveUserClients() - %ld\n", this, (long int)numActiveUserClients);
1249
1250    numActiveUserClients--;
1251
1252    setProperty(kIOAudioEngineNumActiveUserClientsKey, numActiveUserClients, sizeof(UInt32)*8);
1253
1254    if ((numActiveUserClients == 0) && (getState() == kIOAudioEngineRunning)) {
1255        IOAudioEnginePosition stopPosition;
1256
1257        assert(status);
1258
1259        stopPosition.fSampleFrame = getCurrentSampleFrame();
1260        stopPosition.fLoopCount = status->fCurrentLoopCount + 1;
1261
1262        stopEngineAtPosition(&stopPosition);
1263    }
1264
1265    audioDebugIOLog(3, "- IOAudioEngine[%p]::decrementActiveUserClients() - %ld returns 0x%lX\n", this, (long int)numActiveUserClients, (long unsigned int)result );
1266    return result;
1267}
1268
1269//	<rdar://8121989>	Restructured for single point of entry and single point of exit so that
1270//	the indentifier post processing tool can properly insert scope when post processing a log file
1271//	obtained via fwkpfv.
1272
1273IOReturn IOAudioEngine::addAudioStream(IOAudioStream *stream)
1274{
1275    IOReturn result = kIOReturnBadArgument;
1276
1277    audioDebugIOLog(3, "+ IOAudioEngine[%p]::addAudioStream(%p)\n", this, stream);
1278
1279    if (stream) {
1280
1281        if (!stream->attach(this))
1282		{
1283            result = kIOReturnError;
1284        }
1285		else
1286		{
1287			if (!stream->start(this))
1288			{
1289				stream->detach(this);
1290				result = kIOReturnError;
1291			}
1292			else
1293			{
1294				switch ( stream->getDirection () )
1295				{
1296					case kIOAudioStreamDirectionOutput:
1297						assert(outputStreams);
1298
1299						outputStreams->setObject(stream);
1300
1301						maxNumOutputChannels += stream->getMaxNumChannels();
1302
1303						if (outputStreams->getCount() == 1) {
1304							setRunEraseHead(true);
1305						}
1306
1307						if (reserved->bytesInOutputBufferArrayDescriptor) {
1308							reserved->bytesInOutputBufferArrayDescriptor->release();
1309						}
1310						reserved->bytesInOutputBufferArrayDescriptor = IOBufferMemoryDescriptor::withOptions(kIODirectionOutIn | kIOMemoryKernelUserShared, round_page(outputStreams->getCount() * sizeof(UInt32)), page_size);
1311						break;
1312					case kIOAudioStreamDirectionInput:
1313						assert(inputStreams);
1314
1315						inputStreams->setObject(stream);
1316
1317						maxNumInputChannels += stream->getMaxNumChannels();
1318
1319						if (reserved->bytesInInputBufferArrayDescriptor) {
1320							reserved->bytesInInputBufferArrayDescriptor->release();
1321						}
1322						reserved->bytesInInputBufferArrayDescriptor = IOBufferMemoryDescriptor::withOptions(kIODirectionOutIn | kIOMemoryKernelUserShared, round_page(inputStreams->getCount() * sizeof(UInt32)), page_size);
1323						break;
1324				}
1325
1326				if (isRegistered) {
1327					stream->registerService();
1328				}
1329
1330				result = kIOReturnSuccess;
1331			}
1332		}
1333    }
1334
1335    audioDebugIOLog(3, "- IOAudioEngine[%p]::addAudioStream(%p) returns 0x%lX\n", this, stream, (long unsigned int)result );
1336    return result;
1337}
1338
1339void IOAudioEngine::detachAudioStreams()
1340{
1341    OSCollectionIterator *iterator;
1342    IOAudioStream *stream;
1343
1344    audioDebugIOLog(3, "+ IOAudioEngine[%p]::detachAudioStreams()\n", this);
1345
1346    if (outputStreams && (outputStreams->getCount() > 0)) {
1347        iterator = OSCollectionIterator::withCollection(outputStreams);
1348        if (iterator) {
1349            while ( (stream = OSDynamicCast(IOAudioStream, iterator->getNextObject())) ) {
1350                if (!isInactive()) {
1351					stream->detach(this);			//	<rdar://14773236>
1352                    stream->terminate();
1353                }
1354            }
1355            iterator->release();
1356        }
1357        outputStreams->flushCollection();
1358		if (reserved->bytesInOutputBufferArrayDescriptor) {
1359			reserved->bytesInOutputBufferArrayDescriptor->release();
1360			reserved->bytesInOutputBufferArrayDescriptor = NULL;
1361		}
1362    }
1363
1364    if (inputStreams && (inputStreams->getCount() > 0)) {
1365        iterator = OSCollectionIterator::withCollection(inputStreams);
1366        if (iterator) {
1367            while ( (stream = OSDynamicCast(IOAudioStream, iterator->getNextObject())) ) {
1368                if (!isInactive()) {
1369					stream->detach(this);				//	<rdar://14773236>
1370                    stream->terminate();
1371                }
1372            }
1373            iterator->release();
1374        }
1375        inputStreams->flushCollection();
1376		if (reserved->bytesInInputBufferArrayDescriptor) {
1377			reserved->bytesInInputBufferArrayDescriptor->release();
1378			reserved->bytesInInputBufferArrayDescriptor = NULL;
1379		}
1380    }
1381
1382	if (reserved->streams) {
1383		reserved->streams->flushCollection();
1384	}
1385
1386    audioDebugIOLog(3, "- IOAudioEngine[%p]::detachAudioStreams()\n", this);
1387	return;
1388}
1389
1390void IOAudioEngine::lockAllStreams()
1391{
1392    OSCollectionIterator *streamIterator;
1393
1394    if (outputStreams) {
1395        streamIterator = OSCollectionIterator::withCollection(outputStreams);
1396        if (streamIterator) {
1397            IOAudioStream *stream;
1398
1399            while ( (stream = (IOAudioStream *)streamIterator->getNextObject()) ) {
1400                stream->lockStreamForIO();
1401            }
1402            streamIterator->release();
1403        }
1404    }
1405
1406    if (inputStreams) {
1407        streamIterator = OSCollectionIterator::withCollection(inputStreams);
1408        if (streamIterator) {
1409            IOAudioStream *stream;
1410
1411            while ( (stream = (IOAudioStream *)streamIterator->getNextObject()) ) {
1412                stream->lockStreamForIO();
1413            }
1414            streamIterator->release();
1415        }
1416    }
1417}
1418
1419void IOAudioEngine::unlockAllStreams()
1420{
1421    OSCollectionIterator *streamIterator;
1422
1423    if (outputStreams) {
1424        streamIterator = OSCollectionIterator::withCollection(outputStreams);
1425        if (streamIterator) {
1426            IOAudioStream *stream;
1427
1428            while ( (stream = (IOAudioStream *)streamIterator->getNextObject()) ) {
1429                stream->unlockStreamForIO();
1430            }
1431            streamIterator->release();
1432        }
1433    }
1434
1435    if (inputStreams) {
1436        streamIterator = OSCollectionIterator::withCollection(inputStreams);
1437        if (streamIterator) {
1438            IOAudioStream *stream;
1439
1440            while ( (stream = (IOAudioStream *)streamIterator->getNextObject()) ) {
1441                stream->unlockStreamForIO();
1442            }
1443            streamIterator->release();
1444        }
1445    }
1446}
1447
1448IOAudioStream *IOAudioEngine::getAudioStream(IOAudioStreamDirection direction, UInt32 channelID)
1449{
1450    IOAudioStream *audioStream = NULL;
1451    OSCollection *streamCollection = NULL;
1452
1453    if (direction == kIOAudioStreamDirectionOutput) {
1454        streamCollection = outputStreams;
1455    } else {	// input
1456        streamCollection = inputStreams;
1457    }
1458
1459    if (streamCollection) {
1460        OSCollectionIterator *streamIterator;
1461
1462        streamIterator = OSCollectionIterator::withCollection(streamCollection);
1463        if (streamIterator) {
1464            IOAudioStream *stream;
1465
1466            while ( (stream = (IOAudioStream *)streamIterator->getNextObject()) ) {
1467                if ((channelID >= stream->startingChannelID) && (channelID < (stream->startingChannelID + stream->maxNumChannels))) {
1468                    audioStream = stream;
1469                    break;
1470                }
1471            }
1472            streamIterator->release();
1473        }
1474    }
1475
1476    return audioStream;
1477}
1478
1479void IOAudioEngine::updateChannelNumbers()
1480{
1481    OSCollectionIterator *iterator;
1482    SInt32 *outputChannelNumbers = NULL, *inputChannelNumbers = NULL;
1483    UInt32 currentChannelID;
1484    SInt32 currentChannelNumber;
1485
1486
1487	audioDebugIOLog ( 3, "+ IOAudioEngine[%p]::updateChannelNumbers ()\n", this );
1488
1489	// BEGIN <rdar://6997438> maxNumOutputChannels may not represent the true number of output channels at this point
1490	//					because the the number of formats in the stream may have changed. We recalculate the correct value here.
1491
1492	maxNumOutputChannels = 0;
1493	maxNumInputChannels = 0;
1494    assert(outputStreams);
1495    assert(inputStreams);
1496
1497    if (outputStreams->getCount() > 0) {
1498        iterator = OSCollectionIterator::withCollection(outputStreams);
1499        if (iterator) {
1500            IOAudioStream *audioStream;
1501
1502            while ( (audioStream = (IOAudioStream *)iterator->getNextObject()) ) {
1503				maxNumOutputChannels += audioStream->getMaxNumChannels();
1504			}
1505			iterator->release();
1506		}
1507	}
1508
1509	if (inputStreams->getCount() > 0) {
1510        iterator = OSCollectionIterator::withCollection(inputStreams);
1511        if (iterator) {
1512            IOAudioStream *audioStream;
1513
1514            while ( (audioStream = (IOAudioStream *)iterator->getNextObject()) ) {
1515				maxNumInputChannels += audioStream->getMaxNumChannels();
1516			}
1517			iterator->release();
1518		}
1519	}
1520	// END <rdar://6997438>
1521
1522	audioDebugIOLog(3, "  o=%ld i=%ld\n", (long int)maxNumOutputChannels, (long int)maxNumInputChannels);
1523
1524    if (maxNumOutputChannels > 0) {
1525        outputChannelNumbers = (SInt32 *)IOMallocAligned(maxNumOutputChannels * sizeof(SInt32), sizeof (SInt32));
1526    }
1527
1528    if (maxNumInputChannels > 0) {
1529        inputChannelNumbers = (SInt32 *)IOMallocAligned(maxNumInputChannels * sizeof(SInt32), sizeof (SInt32));
1530    }
1531
1532    currentChannelID = 1;
1533    currentChannelNumber = 1;
1534
1535    if (outputStreams->getCount() > 0) {
1536        iterator = OSCollectionIterator::withCollection(outputStreams);
1537        if (iterator) {
1538            IOAudioStream *audioStream;
1539
1540            while ( (audioStream = (IOAudioStream *)iterator->getNextObject()) ) {
1541                const IOAudioStreamFormat *format;
1542
1543                format = audioStream->getFormat();
1544                if (format) {
1545                    UInt32 numChannels, maxNumChannels;
1546                    UInt32 i;
1547
1548                    numChannels = format->fNumChannels;
1549                    maxNumChannels = audioStream->getMaxNumChannels();
1550
1551//                    assert(currentChannelID + maxNumChannels <= maxNumOutputChannels);		// double check that this calc is right.  MPC
1552
1553                    if (audioStream->getStreamAvailable()) {
1554                        audioStream->setStartingChannelNumber(currentChannelNumber);
1555                    } else {
1556                        numChannels = 0;
1557                        audioStream->setStartingChannelNumber(0);
1558                    }
1559
1560                    for (i = 0; i < numChannels; i++) {
1561                        outputChannelNumbers[currentChannelID + i - 1] = currentChannelNumber + i;
1562                    }
1563
1564                    for (i = numChannels; i < maxNumChannels; i++) {
1565                        outputChannelNumbers[currentChannelID + i - 1] = kIOAudioControlChannelNumberInactive;
1566                    }
1567
1568                    currentChannelID += maxNumChannels;
1569                    currentChannelNumber += numChannels;
1570                }
1571            }
1572
1573            iterator->release();
1574        }
1575    }
1576
1577    currentChannelID = 1;
1578    currentChannelNumber = 1;
1579
1580    if (inputStreams->getCount() > 0) {
1581        iterator = OSCollectionIterator::withCollection(inputStreams);
1582        if (iterator) {
1583            IOAudioStream *audioStream;
1584
1585            while ( (audioStream = (IOAudioStream *)iterator->getNextObject()) ) {
1586                const IOAudioStreamFormat *format;
1587
1588                format = audioStream->getFormat();
1589                if (format) {
1590                    UInt32 numChannels, maxNumChannels;
1591                    UInt32 i;
1592
1593                    numChannels = format->fNumChannels;
1594                    maxNumChannels = audioStream->getMaxNumChannels();
1595
1596//                    assert(currentChannelID + maxNumChannels <= maxNumInputChannels);		// double check that this calc is right.  MPC
1597
1598                    if (audioStream->getStreamAvailable()) {
1599                        audioStream->setStartingChannelNumber(currentChannelNumber);
1600                    } else {
1601                        numChannels = 0;
1602                        audioStream->setStartingChannelNumber(0);
1603                    }
1604
1605                    for (i = 0; i < numChannels; i++) {
1606                        inputChannelNumbers[currentChannelID + i - 1] = currentChannelNumber + i;
1607                    }
1608
1609                    for (i = numChannels; i < maxNumChannels; i++) {
1610                        inputChannelNumbers[currentChannelID + i - 1] = kIOAudioControlChannelNumberInactive;
1611                    }
1612
1613                    currentChannelID += maxNumChannels;
1614                    currentChannelNumber += numChannels;
1615                }
1616            }
1617
1618            iterator->release();
1619        }
1620    }
1621
1622    if (defaultAudioControls) {
1623        iterator = OSCollectionIterator::withCollection(defaultAudioControls);
1624        if (iterator) {
1625            IOAudioControl *control;
1626            while ( (control = (IOAudioControl *)iterator->getNextObject()) ) {
1627                UInt32 channelID;
1628
1629                channelID = control->getChannelID();
1630
1631                if (channelID != 0) {
1632                    switch (control->getUsage()) {
1633                        case kIOAudioControlUsageOutput:
1634								if (outputChannelNumbers && (channelID <= maxNumOutputChannels)) {
1635									control->setChannelNumber(outputChannelNumbers[channelID - 1]);
1636								} else {
1637									control->setChannelNumber(kIOAudioControlChannelNumberInactive);
1638							}
1639                            break;
1640                        case kIOAudioControlUsageInput:
1641							if (inputChannelNumbers && (channelID <= maxNumInputChannels)) {
1642								control->setChannelNumber(inputChannelNumbers[channelID - 1]);
1643							} else {
1644								control->setChannelNumber(kIOAudioControlChannelNumberInactive);
1645							}
1646                            break;
1647                        case kIOAudioControlUsagePassThru:
1648                            if (inputChannelNumbers) {
1649                                if (channelID <= maxNumInputChannels) {
1650                                    control->setChannelNumber(inputChannelNumbers[channelID - 1]);
1651                                } else {
1652                                    control->setChannelNumber(kIOAudioControlChannelNumberInactive);
1653                                }
1654                            } else if (outputChannelNumbers) {
1655                                if (channelID <= maxNumOutputChannels) {
1656                                    control->setChannelNumber(outputChannelNumbers[channelID - 1]);
1657                                } else {
1658                                    control->setChannelNumber(kIOAudioControlChannelNumberInactive);
1659                                }
1660                            } else {
1661                                control->setChannelNumber(kIOAudioControlChannelNumberInactive);
1662                            }
1663                            break;
1664                        default:
1665                            break;
1666                    }
1667                } else {
1668                    control->setChannelNumber(0);
1669                }
1670            }
1671            iterator->release();
1672        }
1673    }
1674
1675    if (outputChannelNumbers && (maxNumOutputChannels > 0)) {
1676        IOFreeAligned(outputChannelNumbers, maxNumOutputChannels * sizeof(SInt32));
1677    }
1678
1679    if (inputChannelNumbers && (maxNumInputChannels > 0)) {
1680        IOFreeAligned(inputChannelNumbers, maxNumInputChannels * sizeof(SInt32));
1681    }
1682
1683	audioDebugIOLog ( 3, "- IOAudioEngine[%p]::updateChannelNumbers ()\n", this );
1684	return;
1685}
1686
1687IOReturn IOAudioEngine::startAudioEngine()
1688{
1689    IOReturn result = kIOReturnSuccess;
1690
1691    audioDebugIOLog(3, "+ IOAudioEngine[%p]::startAudioEngine(state = %d)\n", this, getState());
1692
1693    switch(getState()) {
1694        case kIOAudioEnginePaused:
1695            result = resumeAudioEngine();
1696            break;
1697        case kIOAudioEngineStopped:
1698            audioDevice->audioEngineStarting();
1699        case kIOAudioEngineResumed:
1700            resetStatusBuffer();
1701
1702			reserved->pauseCount = 0;
1703            result = performAudioEngineStart();
1704            if (result == kIOReturnSuccess) {
1705                setState(kIOAudioEngineRunning);
1706                sendNotification(kIOAudioEngineStartedNotification);
1707            } else if (getState() == kIOAudioEngineStopped) {
1708                audioDevice->audioEngineStopped();
1709            }
1710            break;
1711        default:
1712            break;
1713    }
1714
1715    audioDebugIOLog(3, "- IOAudioEngine[%p]::startAudioEngine() returns 0x%lX\n", this, (long unsigned int)result );
1716    return result;
1717}
1718
1719IOReturn IOAudioEngine::stopAudioEngine()
1720{
1721    IOReturn result = kIOReturnSuccess;
1722
1723    audioDebugIOLog(3, "+ IOAudioEngine[%p]::stopAudioEngine()\n", this);
1724
1725    switch (getState()) {
1726        case kIOAudioEngineRunning:
1727            result = performAudioEngineStop();
1728        case kIOAudioEngineResumed:
1729            if (result == kIOReturnSuccess) {
1730                setState(kIOAudioEngineStopped);
1731                sendNotification(kIOAudioEngineStoppedNotification);
1732
1733                assert(audioDevice);
1734                audioDevice->audioEngineStopped();
1735            }
1736            break;
1737        default:
1738            break;
1739    }
1740
1741    audioDebugIOLog(3, "- IOAudioEngine[%p]::stopAudioEngine() returns 0x%lX\n", this, (long unsigned int)result );
1742    return result;
1743}
1744
1745IOReturn IOAudioEngine::pauseAudioEngine()
1746{
1747    IOReturn result = kIOReturnSuccess;
1748
1749    audioDebugIOLog(3, "+ IOAudioEngine[%p]::pauseAudioEngine()\n", this);
1750
1751	reserved->pauseCount++;
1752    switch(getState()) {
1753        case kIOAudioEngineRunning:
1754        case kIOAudioEngineResumed:
1755            // We should probably have the streams locked around performAudioEngineStop()
1756            // but we can't ensure that it won't make a call out that would attempt to take
1757            // one of the clientBufferLocks on an IOAudioEngineUserClient
1758            // If it did, that would create the potential for a deadlock
1759            result = performAudioEngineStop();
1760            if (result == kIOReturnSuccess) {
1761                lockAllStreams();
1762                setState(kIOAudioEnginePaused);
1763                unlockAllStreams();
1764				sendNotification(kIOAudioEnginePausedNotification);
1765
1766                clearAllSampleBuffers();
1767            }
1768            break;
1769        default:
1770            break;
1771    }
1772
1773    audioDebugIOLog(3, "- IOAudioEngine[%p]::pauseAudioEngine() returns 0x%lX\n", this, (long unsigned int)result );
1774    return result;
1775}
1776
1777IOReturn IOAudioEngine::resumeAudioEngine()
1778{
1779    IOReturn result = kIOReturnSuccess;
1780
1781    audioDebugIOLog(3, "+ IOAudioEngine[%p]::resumeAudioEngine()\n", this);
1782
1783	if (0 != reserved->pauseCount) {
1784		if (0 == --reserved->pauseCount) {
1785			if (getState() == kIOAudioEnginePaused) {
1786				setState(kIOAudioEngineResumed);
1787				sendNotification(kIOAudioEngineResumedNotification);
1788
1789				// <rdar://15485249>
1790				if (commandGate) {
1791					audioDebugIOLog(3, "send commandWakeup on resume for [%p]\n", this);
1792
1793					setCommandGateUsage(this, true);
1794					commandGate->commandWakeup(&state);
1795					setCommandGateUsage(this, false);
1796
1797					// <rdar://15917322,16383922> don't rely on audioEngineStopPosition if there are no clients and we've just resumed.
1798					if ((numActiveUserClients == 0) && !IOAUDIOENGINEPOSITION_IS_ZERO(&audioEngineStopPosition) && ( kIOAudioDeviceSleep != audioDevice->getPowerState() )) {
1799						stopAudioEngine();
1800					}
1801				}
1802			}
1803		}
1804	}
1805	else {
1806		audioDebugIOLog(1, "  attempting to resume while not paused\n" );
1807	}
1808
1809    audioDebugIOLog(3, "- IOAudioEngine[%p]::resumeAudioEngine() returns 0x%lX\n", this, (long unsigned int)result  );
1810    return result;
1811}
1812
1813IOReturn IOAudioEngine::performAudioEngineStart()
1814{
1815    return kIOReturnSuccess;
1816}
1817
1818IOReturn IOAudioEngine::performAudioEngineStop()
1819{
1820    return kIOReturnSuccess;
1821}
1822
1823const IOAudioEngineStatus *IOAudioEngine::getStatus()
1824{
1825    audioDebugIOLog(3, "+-IOAudioEngine[%p]::getStatus()\n", this);
1826
1827    return status;
1828}
1829
1830void IOAudioEngine::setNumSampleFramesPerBuffer(UInt32 numSampleFrames)
1831{
1832    audioDebugIOLog(3, "+ IOAudioEngine[%p]::setNumSampleFramesPerBuffer(0x%lx)\n", this, (long unsigned int)numSampleFrames);
1833
1834    if (getState() == kIOAudioEngineRunning) {
1835        IOLog("IOAudioEngine[%p]::setNumSampleFramesPerBuffer(0x%ld) - Error: can't change num sample frames while engine is running.\n", this, (long int) numSampleFrames);
1836    } else {
1837        numSampleFramesPerBuffer = numSampleFrames;
1838        setProperty(kIOAudioEngineNumSampleFramesPerBufferKey, numSampleFramesPerBuffer, sizeof(UInt32)*8);
1839
1840        // Notify all output streams
1841        if (outputStreams) {
1842            OSCollectionIterator *streamIterator;
1843
1844            streamIterator = OSCollectionIterator::withCollection(outputStreams);
1845            if (streamIterator) {
1846                IOAudioStream *audioStream;
1847
1848                while ( (audioStream = (IOAudioStream *)streamIterator->getNextObject()) ) {
1849                    audioStream->numSampleFramesPerBufferChanged();
1850                }
1851                streamIterator->release();
1852            }
1853        }
1854    }
1855    audioDebugIOLog(3, "- IOAudioEngine[%p]::setNumSampleFramesPerBuffer(0x%lx)\n", this, (long unsigned int)numSampleFrames);
1856	return;
1857}
1858
1859UInt32 IOAudioEngine::getNumSampleFramesPerBuffer()
1860{
1861    audioDebugIOLog(7, "+-IOAudioEngine[%p]::getNumSampleFramesPerBuffer() returns %ld\n", this, (long int)numSampleFramesPerBuffer );
1862
1863    return numSampleFramesPerBuffer;
1864}
1865
1866IOAudioEngineState IOAudioEngine::getState()
1867{
1868    return state;
1869}
1870
1871IOAudioEngineState IOAudioEngine::setState(IOAudioEngineState newState)
1872{
1873    IOAudioEngineState oldState;
1874
1875    audioDebugIOLog(3, "+-IOAudioEngine[%p]::setState(0x%x. oldState=%#x)\n", this, newState, state);
1876
1877    oldState = state;
1878    state = newState;
1879
1880    switch (state) {
1881        case kIOAudioEngineRunning:
1882            if (oldState != kIOAudioEngineRunning) {
1883                addTimer();
1884            }
1885            break;
1886        case kIOAudioEngineStopped:
1887            if (oldState == kIOAudioEngineRunning) {
1888                removeTimer();
1889                performErase();
1890            }
1891			// <rdar://15485249,17416423>
1892			if (oldState == kIOAudioEnginePaused) {
1893				if (commandGate) {
1894					audioDebugIOLog(3, "send commandWakeup on stop for [%p]\n", this);
1895
1896					setCommandGateUsage(this, true);
1897					commandGate->commandWakeup(&state);
1898					setCommandGateUsage(this, false);
1899				}
1900			}
1901            break;
1902        default:
1903            break;
1904    }
1905
1906    setProperty(kIOAudioEngineStateKey, newState, sizeof(UInt32)*8);
1907
1908    return oldState;
1909}
1910
1911const IOAudioSampleRate *IOAudioEngine::getSampleRate()
1912{
1913    return &sampleRate;
1914}
1915
1916void IOAudioEngine::setSampleRate(const IOAudioSampleRate *newSampleRate)
1917{
1918    OSDictionary *sampleRateDict;
1919
1920    audioDebugIOLog(3, "+-IOAudioEngine[%p]::setSampleRate(%p)\n", this, newSampleRate);
1921
1922    sampleRate = *newSampleRate;
1923
1924    sampleRateDict = createDictionaryFromSampleRate(&sampleRate);
1925    if (sampleRateDict) {
1926        setProperty(kIOAudioSampleRateKey, sampleRateDict);
1927        sampleRateDict->release();
1928    }
1929}
1930
1931IOReturn IOAudioEngine::hardwareSampleRateChanged(const IOAudioSampleRate *newSampleRate)
1932{
1933    if ((newSampleRate->whole != sampleRate.whole) || (newSampleRate->fraction != sampleRate.fraction)) {
1934        bool engineWasRunning;
1935
1936        engineWasRunning = (state == kIOAudioEngineRunning);
1937
1938        if (engineWasRunning) {
1939            pauseAudioEngine();
1940        }
1941
1942        setSampleRate(newSampleRate);
1943        if (!configurationChangeInProgress) {
1944            sendNotification(kIOAudioEngineChangeNotification);
1945        }
1946
1947        if (engineWasRunning) {
1948            resumeAudioEngine();
1949        }
1950    }
1951
1952    return kIOReturnSuccess;
1953}
1954
1955void IOAudioEngine::setSampleLatency(UInt32 numSamples)
1956{
1957    audioDebugIOLog(3, "+ IOAudioEngine[%p]::setSampleLatency(0x%lx)\n", this, (long unsigned int)numSamples);
1958    setOutputSampleLatency(numSamples);
1959    setInputSampleLatency(numSamples);
1960    audioDebugIOLog(3, "- IOAudioEngine[%p]::setSampleLatency(0x%lx)\n", this, (long unsigned int)numSamples);
1961	return;
1962}
1963
1964void IOAudioEngine::setOutputSampleLatency(UInt32 numSamples)
1965{
1966    audioDebugIOLog(3, "+ IOAudioEngine[%p]::setOutputSampleLatency(0x%lx)\n", this, (long unsigned int)numSamples);
1967    setProperty(kIOAudioEngineOutputSampleLatencyKey, numSamples, sizeof(UInt32)*8);
1968    audioDebugIOLog(3, "- IOAudioEngine[%p]::setOutputSampleLatency(0x%lx)\n", this, (long unsigned int)numSamples);
1969	return;
1970}
1971
1972void IOAudioEngine::setInputSampleLatency(UInt32 numSamples)
1973{
1974    audioDebugIOLog(3, "+ IOAudioEngine[%p]::setInputSampleLatency(0x%lx)\n", this, (long unsigned int)numSamples);
1975    setProperty(kIOAudioEngineInputSampleLatencyKey, numSamples, sizeof(UInt32)*8);
1976    audioDebugIOLog(3, "- IOAudioEngine[%p]::setInputSampleLatency(0x%lx)\n", this, (long unsigned int)numSamples);
1977	return;
1978}
1979
1980void IOAudioEngine::setSampleOffset(UInt32 numSamples)
1981{
1982    audioDebugIOLog(3, "+ IOAudioEngine[%p]::setSampleOffset(0x%lx)\n", this, (long unsigned int)numSamples);
1983    sampleOffset = numSamples;
1984    setProperty(kIOAudioEngineSampleOffsetKey, numSamples, sizeof(UInt32)*8);
1985    audioDebugIOLog(3, "- IOAudioEngine[%p]::setSampleOffset(0x%lx)\n", this, (long unsigned int)numSamples);
1986	return;
1987}
1988
1989void IOAudioEngine::setRunEraseHead(bool erase)
1990{
1991    audioDebugIOLog(3, "+-IOAudioEngine[%p]::setRunEraseHead(%d)\n", this, erase);
1992    runEraseHead = erase;
1993}
1994
1995bool IOAudioEngine::getRunEraseHead()
1996{
1997    audioDebugIOLog(7, "+-IOAudioEngine[%p]::getRunEraseHead()\n", this);
1998
1999    return runEraseHead;
2000}
2001
2002AbsoluteTime IOAudioEngine::getTimerInterval()
2003{
2004    AbsoluteTime interval;
2005    const IOAudioSampleRate *currentRate;
2006
2007    audioDebugIOLog(3, "+ IOAudioEngine[%p]::getTimerInterval()\n", this);
2008
2009    assert(status);
2010
2011    currentRate = getSampleRate();
2012
2013    if ((getNumSampleFramesPerBuffer() == 0) || (currentRate && (currentRate->whole == 0))) {
2014        nanoseconds_to_absolutetime(NSEC_PER_SEC, &interval);
2015    } else if ((numErasesPerBuffer == 0) || (!getRunEraseHead())) {	// Run once per ring buffer
2016        nanoseconds_to_absolutetime(((UInt64)NSEC_PER_SEC * (UInt64)getNumSampleFramesPerBuffer() / (UInt64)currentRate->whole), &interval);
2017    } else {
2018        OSCollectionIterator *outputIterator;
2019        IOAudioStream *outputStream;
2020		UInt32 bufferSize;
2021		UInt32 newNumErasesPerBuffer;
2022
2023		outputIterator = OSCollectionIterator::withCollection(outputStreams);
2024
2025		if (outputIterator)
2026		{
2027			while ( (outputStream = (IOAudioStream *)outputIterator->getNextObject()) ) {
2028				bufferSize = outputStream->getSampleBufferSize();
2029				if ((bufferSize / numErasesPerBuffer) > 65536) {
2030					newNumErasesPerBuffer = bufferSize / 65536;
2031					if (newNumErasesPerBuffer > numErasesPerBuffer) {
2032						numErasesPerBuffer = newNumErasesPerBuffer;
2033					}
2034				}
2035			}
2036			outputIterator->release();
2037		}
2038		nanoseconds_to_absolutetime(((UInt64)NSEC_PER_SEC * (UInt64)getNumSampleFramesPerBuffer() / (UInt64)currentRate->whole / (UInt64)numErasesPerBuffer), &interval);
2039    }
2040    audioDebugIOLog(3, "- IOAudioEngine[%p]::getTimerInterval()\n", this);
2041    return interval;
2042}
2043
2044void IOAudioEngine::timerCallback(OSObject *target, IOAudioDevice *device)
2045{
2046    IOAudioEngine *audioEngine;
2047
2048    audioDebugIOLog(7, "+ IOAudioEngine::timerCallback(%p, %p)\n", target, device);
2049
2050    audioEngine = OSDynamicCast(IOAudioEngine, target);
2051    if (audioEngine) {
2052        audioEngine->timerFired();
2053    }
2054    audioDebugIOLog(7, "- IOAudioEngine::timerCallback(%p, %p)\n", target, device);
2055	return;
2056}
2057
2058void IOAudioEngine::timerFired()
2059{
2060    audioDebugIOLog(7, "+ IOAudioEngine[%p]::timerFired()\n", this);
2061
2062    performErase();
2063    performFlush();
2064
2065    audioDebugIOLog(7, "- IOAudioEngine[%p]::timerFired()\n", this);
2066	return;
2067}
2068
2069// <rdar://12188841>
2070void IOAudioEngine::performErase()
2071{
2072    audioDebugIOLog(7, "+ IOAudioEngine[%p]::performErase()\n", this);
2073
2074    assert(status);
2075
2076    if (getRunEraseHead() && getState() == kIOAudioEngineRunning) {
2077		UInt32 streamIndex;
2078        IOAudioStream *outputStream;
2079		UInt32 currentSampleFrame, eraseHeadSampleFrame;
2080
2081		assert(outputStreams);
2082
2083		currentSampleFrame = getCurrentSampleFrame();
2084		eraseHeadSampleFrame = status->fEraseHeadSampleFrame;
2085
2086		//	<rdar://12188841> Modified code to remove OSCollectionIterator allocation on every call
2087		outputStreams->retain();
2088		for ( streamIndex = 0; streamIndex < outputStreams->getCount(); streamIndex++) {
2089			char *sampleBuf, *mixBuf;
2090			UInt32 sampleBufferFrameSize, mixBufferFrameSize;
2091
2092			outputStream = (IOAudioStream *)outputStreams->getObject(streamIndex);
2093			if ( outputStream ) {
2094				outputStream->lockStreamForIO();
2095
2096				sampleBuf = (char *)outputStream->getSampleBuffer();
2097				mixBuf = (char *)outputStream->getMixBuffer();
2098
2099				sampleBufferFrameSize = outputStream->format.fNumChannels * outputStream->format.fBitWidth / 8;
2100				mixBufferFrameSize = outputStream->format.fNumChannels * kIOAudioEngineDefaultMixBufferSampleSize;
2101
2102				if (currentSampleFrame < eraseHeadSampleFrame) {
2103					// <rdar://problem/10040608> Add additional checks to ensure buffer is still of the appropriate length
2104					if (	(outputStream->getSampleBufferSize() == 0) ||                      									  	//  <rdar://10905878> Don't use more stringent test if a driver is incorrectly reporting buffer size
2105							((currentSampleFrame * sampleBufferFrameSize <= outputStream->getSampleBufferSize() ) &&
2106							((currentSampleFrame * mixBufferFrameSize <= outputStream->getMixBufferSize() ) || !mixBuf ) &&			//	<rdar://10866244> Don't check mix buffer if it's not in use (eg. !fIsMixable)
2107							(numSampleFramesPerBuffer * sampleBufferFrameSize <= outputStream->getSampleBufferSize() ) &&
2108							((numSampleFramesPerBuffer * mixBufferFrameSize <= outputStream->getMixBufferSize() ) || !mixBuf ) &&	//	<rdar://10866244> Don't check mix buffer if it's not in use (eg. !fIsMixable)
2109							(numSampleFramesPerBuffer > eraseHeadSampleFrame)) ) {
2110						audioDebugIOLog(7, "IOAudioEngine[%p]::performErase() - erasing from frame: 0x%lx to 0x%lx\n", this, (long unsigned int)eraseHeadSampleFrame, (long unsigned int)numSampleFramesPerBuffer);
2111						audioDebugIOLog(7, "IOAudioEngine[%p]::performErase() - erasing from frame: 0x%x to 0x%lx\n", this, 0, (long unsigned int)currentSampleFrame);
2112						eraseOutputSamples(mixBuf, sampleBuf, 0, currentSampleFrame, &outputStream->format, outputStream);
2113						eraseOutputSamples(mixBuf, sampleBuf, eraseHeadSampleFrame, numSampleFramesPerBuffer - eraseHeadSampleFrame, &outputStream->format, outputStream);
2114					}
2115				} else {
2116					// <rdar://problem/10040608> Add additional checks to ensure buffer is still of the appropriate length
2117					if (	(outputStream->getSampleBufferSize() == 0) ||                       									//  <rdar://10905878> Don't use more stringent test if a driver is incorrectly reporting buffer size
2118							( (currentSampleFrame * sampleBufferFrameSize <= outputStream->getSampleBufferSize() ) &&
2119							( (currentSampleFrame * mixBufferFrameSize <= outputStream->getMixBufferSize() ) || !mixBuf ) ) ) {		//	<rdar://10866244> Don't check mix buffer if it's not in use (eg. !fIsMixable)
2120						audioDebugIOLog(7, "IOAudioEngine[%p]::performErase() - erasing from frame: 0x%lx to 0x%lx\n", this, (long unsigned int)eraseHeadSampleFrame, (long unsigned int)currentSampleFrame);
2121						eraseOutputSamples(mixBuf, sampleBuf, eraseHeadSampleFrame, currentSampleFrame - eraseHeadSampleFrame, &outputStream->format, outputStream);
2122					}
2123				}
2124
2125				outputStream->unlockStreamForIO();
2126			}
2127		}
2128		outputStreams->release();
2129
2130		status->fEraseHeadSampleFrame = currentSampleFrame;
2131    }
2132
2133    audioDebugIOLog(7, "- IOAudioEngine[%p]::performErase()\n", this);
2134	return;
2135}
2136
2137void IOAudioEngine::stopEngineAtPosition(IOAudioEnginePosition *endingPosition)
2138{
2139    audioDebugIOLog(3, "+ IOAudioEngine[%p]::stopEngineAtPosition(%lx,%lx)\n", this, endingPosition ? (long unsigned int)endingPosition->fLoopCount : 0, endingPosition ? (long unsigned int)endingPosition->fSampleFrame : 0);
2140
2141    if (endingPosition) {
2142        audioEngineStopPosition = *endingPosition;
2143    } else {
2144        audioEngineStopPosition.fLoopCount = 0;
2145        audioEngineStopPosition.fSampleFrame = 0;
2146    }
2147
2148    audioDebugIOLog(3, "- IOAudioEngine[%p]::stopEngineAtPosition(%lx,%lx)\n", this, endingPosition ? (long unsigned int)endingPosition->fLoopCount : 0, endingPosition ? (long unsigned int)endingPosition->fSampleFrame : 0);
2149	return;
2150}
2151
2152void IOAudioEngine::performFlush()
2153{
2154    audioDebugIOLog(6, "+ IOAudioEngine[%p]::performFlush()\n", this);
2155
2156    if ((numActiveUserClients == 0) && (getState() == kIOAudioEngineRunning)) {
2157        IOAudioEnginePosition currentPosition;
2158
2159        assert(status);
2160
2161        currentPosition.fLoopCount = status->fCurrentLoopCount;
2162        currentPosition.fSampleFrame = getCurrentSampleFrame();
2163
2164        if (CMP_IOAUDIOENGINEPOSITION(&currentPosition, &audioEngineStopPosition) > 0) {
2165            stopAudioEngine();
2166        }
2167    }
2168
2169    audioDebugIOLog(6, "- IOAudioEngine[%p]::performFlush()\n", this);
2170	return;
2171}
2172
2173//	<rdar://8121989>	Restructured for single point of entry and single point of exit so that
2174//	the indentifier post processing tool can properly insert scope when post processing a log file
2175//	obtained via fwkpfv.
2176
2177void IOAudioEngine::addTimer()
2178{
2179    audioDebugIOLog(3, "+ IOAudioEngine[%p]::addTimer()\n", this);
2180
2181    if ( audioDevice )
2182	{
2183		audioDevice->addTimerEvent(this, &IOAudioEngine::timerCallback, getTimerInterval());
2184    }
2185
2186    audioDebugIOLog(3, "- IOAudioEngine[%p]::addTimer()\n", this);
2187	return;
2188}
2189
2190//	<rdar://8121989>	Restructured for single point of entry and single point of exit so that
2191//	the indentifier post processing tool can properly insert scope when post processing a log file
2192//	obtained via fwkpfv.
2193
2194void IOAudioEngine::removeTimer()
2195{
2196    audioDebugIOLog(3, "+ IOAudioEngine[%p]::removeTimer()\n", this);
2197
2198    if ( audioDevice )
2199	{
2200		audioDevice->removeTimerEvent(this);
2201    }
2202
2203    audioDebugIOLog(3, "- IOAudioEngine[%p]::removeTimer()\n", this);
2204	return;
2205}
2206
2207IOReturn IOAudioEngine::clipOutputSamples(const void *mixBuf, void *sampleBuf, UInt32 firstSampleFrame, UInt32 numSampleFrames, const IOAudioStreamFormat *streamFormat, IOAudioStream *audioStream)
2208{
2209    audioDebugIOLog(6, "+-IOAudioEngine[%p]::clipOutputSamples(%p, %p, 0x%lx, 0x%lx, %p, %p)\n", this, mixBuf, sampleBuf, (long unsigned int)firstSampleFrame, (long unsigned int)numSampleFrames, streamFormat, audioStream);
2210
2211    return kIOReturnUnsupported;
2212}
2213
2214void IOAudioEngine::resetClipPosition(IOAudioStream *audioStream, UInt32 clipSampleFrame)
2215{
2216    audioDebugIOLog(6, "+-IOAudioEngine[%p]::resetClipPosition(%p, 0x%lx)\n", this, audioStream, (long unsigned int)clipSampleFrame);
2217
2218    return;
2219}
2220
2221
2222IOReturn IOAudioEngine::convertInputSamples(const void *sampleBuf, void *destBuf, UInt32 firstSampleFrame, UInt32 numSampleFrames, const IOAudioStreamFormat *streamFormat, IOAudioStream *audioStream)
2223{
2224    audioDebugIOLog(6, "+-IOAudioEngine[%p]::convertInputSamples(%p, %p, 0x%lx, 0x%lx, %p, %p)\n", this, sampleBuf, destBuf, (long unsigned int)firstSampleFrame, (long unsigned int)numSampleFrames, streamFormat, audioStream);
2225
2226    return kIOReturnUnsupported;
2227}
2228
2229void IOAudioEngine::takeTimeStamp(bool incrementLoopCount, AbsoluteTime *timestamp)
2230{
2231    AbsoluteTime uptime, *ts;
2232
2233    if (timestamp) {
2234        ts = timestamp;
2235    } else {
2236        clock_get_uptime(&uptime);
2237        ts = &uptime;
2238    }
2239
2240    assert(status);
2241
2242#if __LP64__
2243    status->fLastLoopTime = *ts;
2244#else
2245    status->fLastLoopTime.hi = ts->hi;
2246    status->fLastLoopTime.lo = ts->lo;
2247#endif
2248
2249    if (incrementLoopCount) {
2250        ++status->fCurrentLoopCount;
2251    }
2252}
2253
2254IOReturn IOAudioEngine::getLoopCountAndTimeStamp(UInt32 *loopCount, AbsoluteTime *timestamp)
2255{
2256    IOReturn result = kIOReturnBadArgument;
2257    UInt32 nextLoopCount;
2258    AbsoluteTime nextTimestamp;
2259
2260    if (loopCount && timestamp) {
2261        assert(status);
2262
2263#if __LP64__
2264		*timestamp = status->fLastLoopTime;
2265#else
2266        timestamp->hi = status->fLastLoopTime.hi;
2267		timestamp->lo = status->fLastLoopTime.lo;
2268#endif
2269        *loopCount = status->fCurrentLoopCount;
2270
2271#if __LP64__
2272        nextTimestamp = status->fLastLoopTime;
2273#else
2274        nextTimestamp.hi = status->fLastLoopTime.hi;
2275        nextTimestamp.lo = status->fLastLoopTime.lo;
2276#endif
2277        nextLoopCount = status->fCurrentLoopCount;
2278
2279        while ((*loopCount != nextLoopCount) || (CMP_ABSOLUTETIME(timestamp, &nextTimestamp) != 0)) {
2280            *timestamp = nextTimestamp;
2281            *loopCount = nextLoopCount;
2282
2283#if __LP64__
2284            nextTimestamp = status->fLastLoopTime;
2285
2286#else
2287            nextTimestamp.hi = status->fLastLoopTime.hi;
2288            nextTimestamp.lo = status->fLastLoopTime.lo;
2289#endif
2290            nextLoopCount = status->fCurrentLoopCount;
2291        }
2292
2293        result = kIOReturnSuccess;
2294    }
2295
2296    return result;
2297}
2298
2299IOReturn IOAudioEngine::calculateSampleTimeout(AbsoluteTime *sampleInterval, UInt32 numSampleFrames, IOAudioEnginePosition *startingPosition, AbsoluteTime *wakeupTime)
2300{
2301    IOReturn result = kIOReturnBadArgument;
2302
2303    if (sampleInterval && (numSampleFrames != 0) && startingPosition) {
2304        IOAudioEnginePosition wakeupPosition;
2305        UInt32 wakeupOffset;
2306        AbsoluteTime lastLoopTime;
2307        UInt32 currentLoopCount;
2308        AbsoluteTime wakeupInterval;
2309        AbsoluteTime currentTime;									// <rdar://10145205>
2310        UInt64 wakeupIntervalScalar;
2311        UInt32 samplesFromLoopStart;
2312        AbsoluteTime wakeupThreadLatencyPaddingInterval;
2313
2314        // Total wakeup interval now calculated at 90% minus 125us
2315
2316        wakeupOffset = (numSampleFrames / reserved->mixClipOverhead) + sampleOffset;
2317
2318        if (wakeupOffset <= startingPosition->fSampleFrame) {
2319            wakeupPosition = *startingPosition;
2320            wakeupPosition.fSampleFrame -= wakeupOffset;
2321        } else {
2322            wakeupPosition.fLoopCount = startingPosition->fLoopCount - 1;
2323            wakeupPosition.fSampleFrame = numSampleFramesPerBuffer - (wakeupOffset - startingPosition->fSampleFrame);
2324        }
2325
2326        getLoopCountAndTimeStamp(&currentLoopCount, &lastLoopTime);
2327
2328        samplesFromLoopStart = ((wakeupPosition.fLoopCount - currentLoopCount) * numSampleFramesPerBuffer) + wakeupPosition.fSampleFrame;
2329
2330        wakeupIntervalScalar = AbsoluteTime_to_scalar(sampleInterval);
2331        wakeupIntervalScalar *= samplesFromLoopStart;
2332
2333        //wakeupInterval = scalar_to_AbsoluteTime(&wakeupIntervalScalar);
2334        wakeupInterval = *(AbsoluteTime *)(&wakeupIntervalScalar);
2335
2336        nanoseconds_to_absolutetime(WATCHDOG_THREAD_LATENCY_PADDING_NS, &wakeupThreadLatencyPaddingInterval);
2337
2338        SUB_ABSOLUTETIME(&wakeupInterval, &wakeupThreadLatencyPaddingInterval);
2339
2340        *wakeupTime = lastLoopTime;
2341        ADD_ABSOLUTETIME(wakeupTime, &wakeupInterval);
2342
2343		// <rdar://10145205> Sanity check the calculated time
2344		clock_get_uptime(&currentTime);
2345
2346		if ( CMP_ABSOLUTETIME(wakeupTime, &currentTime) > 0 ) {
2347	        result = kIOReturnSuccess;
2348		}
2349		else {
2350			result = kIOReturnIsoTooOld;
2351		}
2352    }
2353
2354    return result;
2355}
2356
2357IOReturn IOAudioEngine::performFormatChange(IOAudioStream *audioStream, const IOAudioStreamFormat *newFormat, const IOAudioSampleRate *newSampleRate)
2358{
2359    audioDebugIOLog(3, "+-IOAudioEngine[%p]::performFormatChange(%p, %p, %p)\n", this, audioStream, newFormat, newSampleRate);
2360
2361    return kIOReturnSuccess;
2362}
2363
2364void IOAudioEngine::sendFormatChangeNotification(IOAudioStream *audioStream)
2365{
2366    audioDebugIOLog(3, "+ IOAudioEngine[%p]::sendFormatChangeNotification(%p)\n", this, audioStream);
2367
2368    if (!configurationChangeInProgress) {
2369        OSCollectionIterator *userClientIterator;
2370        IOAudioEngineUserClient *userClient;
2371
2372        assert(userClients);
2373
2374        userClientIterator = OSCollectionIterator::withCollection(userClients);
2375        if (userClientIterator) {
2376            while ( (userClient = OSDynamicCast(IOAudioEngineUserClient, userClientIterator->getNextObject())) ) {
2377                userClient->sendFormatChangeNotification(audioStream);
2378            }
2379
2380            userClientIterator->release();
2381        }
2382    }
2383
2384    audioDebugIOLog(3, "- IOAudioEngine[%p]::sendFormatChangeNotification(%p)\n", this, audioStream);
2385	return;
2386}
2387
2388void IOAudioEngine::sendNotification(UInt32 notificationType)
2389{
2390    OSCollectionIterator *userClientIterator;
2391    IOAudioEngineUserClient *userClient;
2392
2393    assert(userClients);
2394
2395    userClientIterator = OSCollectionIterator::withCollection(userClients);
2396    if (userClientIterator) {
2397        while ( (userClient = OSDynamicCast(IOAudioEngineUserClient, userClientIterator->getNextObject())) ) {
2398            userClient->sendNotification(notificationType);
2399        }
2400
2401        userClientIterator->release();
2402    }
2403}
2404
2405void IOAudioEngine::beginConfigurationChange()
2406{
2407    audioDebugIOLog(3, "+-IOAudioEngine[%p]::beginConfigurationChange()\n", this);
2408
2409    configurationChangeInProgress = true;
2410}
2411
2412void IOAudioEngine::completeConfigurationChange()
2413{
2414    audioDebugIOLog(3, "+ IOAudioEngine[%p]::completeConfigurationChange()\n", this);
2415
2416    if (configurationChangeInProgress) {
2417        configurationChangeInProgress = false;
2418        sendNotification(kIOAudioEngineChangeNotification);
2419
2420		// If any controls have notifications queued up, now's the time to send them.
2421		if (defaultAudioControls) {
2422			if (!isInactive()) {
2423				OSCollectionIterator *controlIterator;
2424
2425				controlIterator = OSCollectionIterator::withCollection(defaultAudioControls);
2426
2427				if (controlIterator) {
2428					IOAudioControl *control;
2429
2430					while ( (control = (IOAudioControl *)controlIterator->getNextObject()) ) {
2431						control->sendQueuedNotifications();
2432					}
2433
2434					controlIterator->release();
2435				}
2436			}
2437		}
2438    }
2439
2440    audioDebugIOLog(3, "- IOAudioEngine[%p]::completeConfigurationChange()\n", this);
2441	return;
2442}
2443
2444void IOAudioEngine::cancelConfigurationChange()
2445{
2446    audioDebugIOLog(3, "+-IOAudioEngine[%p]::cancelConfigurationChange()\n", this);
2447
2448    configurationChangeInProgress = false;
2449}
2450
2451IOReturn IOAudioEngine::addDefaultAudioControl(IOAudioControl *defaultAudioControl)
2452{
2453    IOReturn result = kIOReturnBadArgument;
2454
2455    if (defaultAudioControl) {
2456		if (workLoop) {
2457			defaultAudioControl->setWorkLoop(workLoop);
2458		}
2459        if (defaultAudioControl->attachAndStart(this)) {
2460            if (!defaultAudioControls) {
2461                defaultAudioControls = OSSet::withObjects((const OSObject **)&defaultAudioControl, 1, 1);
2462            } else {
2463                defaultAudioControls->setObject(defaultAudioControl);
2464            }
2465
2466            if (isRegistered) {
2467                updateChannelNumbers();
2468            }
2469
2470            result = kIOReturnSuccess;
2471        } else {
2472            result = kIOReturnError;
2473        }
2474    }
2475
2476    return result;
2477}
2478
2479IOReturn IOAudioEngine::removeDefaultAudioControl(IOAudioControl *defaultAudioControl)
2480{
2481    IOReturn result = kIOReturnNotFound;
2482
2483    if (defaultAudioControl) {
2484        if ((state != kIOAudioEngineRunning) && (state != kIOAudioEngineResumed)) {
2485            if (defaultAudioControls && defaultAudioControls->containsObject(defaultAudioControl)) {
2486                defaultAudioControl->retain();
2487
2488                defaultAudioControls->removeObject(defaultAudioControl);
2489
2490                defaultAudioControl->detach(this); // <rdar://14347861>
2491
2492                if (defaultAudioControl->getProvider() == this) {
2493                    defaultAudioControl->terminate();
2494                }
2495
2496                defaultAudioControl->release();
2497
2498                if (!configurationChangeInProgress) {
2499                    sendNotification(kIOAudioEngineChangeNotification);
2500                }
2501
2502                result = kIOReturnSuccess;
2503            }
2504        } else {
2505            result = kIOReturnNotPermitted;
2506        }
2507    } else {
2508        result = kIOReturnBadArgument;
2509    }
2510
2511    return result;
2512}
2513
2514void IOAudioEngine::removeAllDefaultAudioControls()
2515{
2516    audioDebugIOLog(3, "+ IOAudioEngine[%p]::removeAllDefaultAudioControls()\n", this);
2517
2518    if (defaultAudioControls) {
2519        if (!isInactive()) {
2520            OSCollectionIterator *controlIterator;
2521
2522            controlIterator = OSCollectionIterator::withCollection(defaultAudioControls);
2523
2524            if (controlIterator) {
2525                IOAudioControl *control;
2526
2527                while ( (control = (IOAudioControl *)controlIterator->getNextObject()) ) {
2528                    control->detach(this); // <rdar://14347861>
2529
2530                    if (control->getProvider() == this) {
2531                        control->terminate();
2532                    }
2533                }
2534
2535                controlIterator->release();
2536            }
2537        }
2538
2539        defaultAudioControls->flushCollection();
2540    }
2541
2542    audioDebugIOLog(3, "- IOAudioEngine[%p]::removeAllDefaultAudioControls()\n", this);
2543	return;
2544}
2545
2546void IOAudioEngine::setWorkLoopOnAllAudioControls(IOWorkLoop *wl)
2547{
2548    if (defaultAudioControls) {
2549        if (!isInactive()) {
2550            OSCollectionIterator *controlIterator;
2551
2552            controlIterator = OSCollectionIterator::withCollection(defaultAudioControls);
2553
2554            if (controlIterator) {
2555                IOAudioControl *control;
2556				while ( (control = (IOAudioControl *)controlIterator->getNextObject()) ) {
2557					if (control->getProvider() == this) {
2558						control->setWorkLoop(wl);
2559					}
2560				}
2561                controlIterator->release();
2562            }
2563        }
2564    }
2565}
2566
2567// <rdar://8518215>
2568void IOAudioEngine::setCommandGateUsage(IOAudioEngine *engine, bool increment)
2569{
2570	if (engine->reserved) {
2571		if (increment) {
2572			switch (engine->reserved->commandGateStatus)
2573			{
2574				case kCommandGateStatus_Normal:
2575				case kCommandGateStatus_RemovalPending:
2576					engine->reserved->commandGateUsage++;
2577					break;
2578				case kCommandGateStatus_Invalid:
2579					// Should never be here. If so, something went bad...
2580					break;
2581			}
2582		}
2583		else {
2584			switch (engine->reserved->commandGateStatus)
2585			{
2586				case kCommandGateStatus_Normal:
2587					if (engine->reserved->commandGateUsage > 0) {
2588						engine->reserved->commandGateUsage--;
2589					}
2590					break;
2591				case kCommandGateStatus_RemovalPending:
2592					if (engine->reserved->commandGateUsage > 0) {
2593						engine->reserved->commandGateUsage--;
2594
2595						if (engine->reserved->commandGateUsage == 0) {
2596							engine->reserved->commandGateStatus = kCommandGateStatus_Invalid;
2597
2598							if (engine->commandGate) {
2599								if (engine->workLoop) {
2600									engine->workLoop->removeEventSource(engine->commandGate);
2601								}
2602
2603								engine->commandGate->release();
2604								engine->commandGate = NULL;
2605							}
2606						}
2607					}
2608					break;
2609				case kCommandGateStatus_Invalid:
2610					// Should never be here. If so, something went bad...
2611					break;
2612			}
2613		}
2614	}
2615}
2616
2617// <rdar://15485249>
2618IOReturn IOAudioEngine::waitForEngineResume ( void )
2619{
2620	IOReturn err, result = kIOReturnError;
2621
2622	if (commandGate) {
2623		retain();
2624
2625		audioDebugIOLog(3, "Waiting on engine[%p] resume...\n", this);
2626		setCommandGateUsage(this, true);
2627		err = commandGate->commandSleep( &state );
2628		setCommandGateUsage(this, false);
2629
2630		audioDebugIOLog(3, "...wait completed for engine[%p] with err=%#x\n", this, err);
2631
2632		if ( THREAD_INTERRUPTED == err ) {
2633			result = kIOReturnAborted;
2634		}
2635		else if ( THREAD_TIMED_OUT == err ) {
2636			result = kIOReturnTimeout;
2637		}
2638		else if ( THREAD_RESTART == err ) {
2639			result = kIOReturnNotPermitted;
2640		}
2641		else if ( THREAD_AWAKENED == err )	{
2642			result = kIOReturnSuccess;
2643		}
2644
2645		release();
2646	}
2647
2648	return result;
2649}
2650
2651