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