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 "IOAudioStream.h"
25#include "IOAudioEngine.h"
26#include "IOAudioEngineUserClient.h"
27#include "IOAudioControl.h"
28#include "IOAudioTypes.h"
29#include "IOAudioDefines.h"
30
31#include <IOKit/IOLib.h>
32#include <IOKit/IOWorkLoop.h>
33#include <IOKit/IOCommandGate.h>
34
35#include <libkern/c++/OSSymbol.h>
36#include <libkern/c++/OSNumber.h>
37#include <libkern/c++/OSArray.h>
38#include <libkern/c++/OSDictionary.h>
39
40typedef struct IOAudioStreamFormatExtensionDesc {
41    UInt32								version;
42    UInt32								flags;
43	UInt32								framesPerPacket;
44	UInt32								bytesPerPacket;
45} IOAudioStreamFormatExtensionDesc;
46
47typedef struct IOAudioStreamFormatDesc {
48    IOAudioStreamFormat					format;
49    IOAudioSampleRate					minimumSampleRate;
50    IOAudioSampleRate					maximumSampleRate;
51    IOAudioStream::AudioIOFunction		*ioFunctionList;
52    UInt32								numIOFunctions;
53    IOAudioStreamFormatExtensionDesc	formatExtension;
54} IOAudioStreamFormatDesc;
55
56#define super IOService
57OSDefineMetaClassAndStructors(IOAudioStream, IOService)
58
59OSMetaClassDefineReservedUsed(IOAudioStream, 0);
60OSMetaClassDefineReservedUsed(IOAudioStream, 1);
61OSMetaClassDefineReservedUsed(IOAudioStream, 2);
62OSMetaClassDefineReservedUsed(IOAudioStream, 3);
63OSMetaClassDefineReservedUsed(IOAudioStream, 4);
64OSMetaClassDefineReservedUsed(IOAudioStream, 5);
65OSMetaClassDefineReservedUsed(IOAudioStream, 6);
66OSMetaClassDefineReservedUsed(IOAudioStream, 7);
67OSMetaClassDefineReservedUsed(IOAudioStream, 8);
68OSMetaClassDefineReservedUsed(IOAudioStream, 9);
69OSMetaClassDefineReservedUsed(IOAudioStream, 10);
70OSMetaClassDefineReservedUsed(IOAudioStream, 11);
71
72OSMetaClassDefineReservedUnused(IOAudioStream, 12);
73OSMetaClassDefineReservedUnused(IOAudioStream, 13);
74OSMetaClassDefineReservedUnused(IOAudioStream, 14);
75OSMetaClassDefineReservedUnused(IOAudioStream, 15);
76OSMetaClassDefineReservedUnused(IOAudioStream, 16);
77OSMetaClassDefineReservedUnused(IOAudioStream, 17);
78OSMetaClassDefineReservedUnused(IOAudioStream, 18);
79OSMetaClassDefineReservedUnused(IOAudioStream, 19);
80OSMetaClassDefineReservedUnused(IOAudioStream, 20);
81OSMetaClassDefineReservedUnused(IOAudioStream, 21);
82OSMetaClassDefineReservedUnused(IOAudioStream, 22);
83OSMetaClassDefineReservedUnused(IOAudioStream, 23);
84OSMetaClassDefineReservedUnused(IOAudioStream, 24);
85OSMetaClassDefineReservedUnused(IOAudioStream, 25);
86OSMetaClassDefineReservedUnused(IOAudioStream, 26);
87OSMetaClassDefineReservedUnused(IOAudioStream, 27);
88OSMetaClassDefineReservedUnused(IOAudioStream, 28);
89OSMetaClassDefineReservedUnused(IOAudioStream, 29);
90OSMetaClassDefineReservedUnused(IOAudioStream, 30);
91OSMetaClassDefineReservedUnused(IOAudioStream, 31);
92OSMetaClassDefineReservedUnused(IOAudioStream, 32);
93OSMetaClassDefineReservedUnused(IOAudioStream, 33);
94OSMetaClassDefineReservedUnused(IOAudioStream, 34);
95OSMetaClassDefineReservedUnused(IOAudioStream, 35);
96OSMetaClassDefineReservedUnused(IOAudioStream, 36);
97OSMetaClassDefineReservedUnused(IOAudioStream, 37);
98OSMetaClassDefineReservedUnused(IOAudioStream, 38);
99OSMetaClassDefineReservedUnused(IOAudioStream, 39);
100OSMetaClassDefineReservedUnused(IOAudioStream, 40);
101OSMetaClassDefineReservedUnused(IOAudioStream, 41);
102OSMetaClassDefineReservedUnused(IOAudioStream, 42);
103OSMetaClassDefineReservedUnused(IOAudioStream, 43);
104OSMetaClassDefineReservedUnused(IOAudioStream, 44);
105OSMetaClassDefineReservedUnused(IOAudioStream, 45);
106OSMetaClassDefineReservedUnused(IOAudioStream, 46);
107OSMetaClassDefineReservedUnused(IOAudioStream, 47);
108
109// New code added here:
110
111#define CMPSAMPLERATE(left, right) ((left.whole < right->whole) ? -1 : (left.whole == right->whole) ? (left.fraction < right->fraction) ? -1 : 0 : 1)
112
113// <rdar://problem/5994776> Amount of frames allowed to go over the pseudo mix buffer size. We use the source buffer as a mix buffer in encoded format mode.
114// But we can't clip an arbitrary amount of data. We need to limit it to what the size of the source buffer is. The problem seems to
115// be that the source buffer size is hidden by some VBR change. The true size of the source buffer is saved off an then readded after we can use it.
116// So through imperical testing it looks like the source buffer size is 4 times the IOBufferSize. We set it to 3 times to be safe.
117
118#define kMixBufferMaxSize ( 2043 ) //  Limit to 2 pages but there is 16 bytes taken out of the sample buffer for VBR stuff
119
120bool IOAudioStream::validateFormat(IOAudioStreamFormat *streamFormat, IOAudioStreamFormatExtension *formatExtension, IOAudioStreamFormatDesc *formatDesc, const IOAudioSampleRate *sampleRate)
121{
122    bool foundFormat = false;
123
124    audioDebugIOLog(3, "+ IOAudioStream[%p]::validateFormat(%p, %p, %p)\n", this, streamFormat, formatExtension, formatDesc);
125
126
127    if (streamFormat && availableFormats && (numAvailableFormats > 0) && sampleRate) {
128        UInt32 formatIndex;
129
130        for (formatIndex = 0; formatIndex < numAvailableFormats; formatIndex++) {
131			audioDebugIOLog(3, "  %ld: streamFormat->fNumChannels = %ld\n", (long int)availableFormats[formatIndex].format.fNumChannels, (long int)streamFormat->fNumChannels);
132			audioDebugIOLog(3, "  0x%lx: streamFormat->fSampleFormat = 0x%lx\n", (long unsigned int)availableFormats[formatIndex].format.fSampleFormat, (long unsigned int)streamFormat->fSampleFormat);
133			audioDebugIOLog(3, "  0x%lx: streamFormat->fNumericRepresentation = 0x%lx\n", (long unsigned int)availableFormats[formatIndex].format.fNumericRepresentation, (long unsigned int)streamFormat->fNumericRepresentation);
134			audioDebugIOLog(3, "  %d: streamFormat->fBitDepth = %d\n", availableFormats[formatIndex].format.fBitDepth, streamFormat->fBitDepth);
135			audioDebugIOLog(3, "  %d: streamFormat->fBitWidth = %d\n", availableFormats[formatIndex].format.fBitWidth, streamFormat->fBitWidth);
136			audioDebugIOLog(3, "  %d: streamFormat->fAlignment = %d\n", availableFormats[formatIndex].format.fAlignment, streamFormat->fAlignment);
137			audioDebugIOLog(3, "  %d: streamFormat->fByteOrder = %d\n", availableFormats[formatIndex].format.fByteOrder, streamFormat->fByteOrder);
138            if ((availableFormats[formatIndex].format.fNumChannels == streamFormat->fNumChannels)
139				&& (availableFormats[formatIndex].format.fSampleFormat == streamFormat->fSampleFormat)
140				&& (availableFormats[formatIndex].format.fNumericRepresentation == streamFormat->fNumericRepresentation)
141				&& (availableFormats[formatIndex].format.fBitDepth == streamFormat->fBitDepth)
142				&& (availableFormats[formatIndex].format.fBitWidth == streamFormat->fBitWidth)
143				&& (availableFormats[formatIndex].format.fAlignment == streamFormat->fAlignment)
144				&& (availableFormats[formatIndex].format.fByteOrder == streamFormat->fByteOrder)
145				&& (availableFormats[formatIndex].format.fIsMixable == streamFormat->fIsMixable)) {
146
147				bool passSRCheck = true;
148				if (0 != sampleRate->whole) {
149					if ((CMPSAMPLERATE (availableFormats[formatIndex].minimumSampleRate, sampleRate) > 0) || (CMPSAMPLERATE (availableFormats[formatIndex].maximumSampleRate, sampleRate) < 0)) {
150						passSRCheck = false;
151					}
152				}
153				if (passSRCheck) {
154					// <rdar://10957396> Only update the tag if required
155					if ( streamFormat->fDriverTag != availableFormats[formatIndex].format.fDriverTag ) {
156						streamFormat->fDriverTag = availableFormats[formatIndex].format.fDriverTag;
157					}
158
159	//				streamFormat->fIsMixable = availableFormats[formatIndex].format.fIsMixable;
160					if (formatDesc) {
161						memcpy(formatDesc, &availableFormats[formatIndex], sizeof(IOAudioStreamFormatDesc));
162					}
163					foundFormat = true;
164					break;
165				}
166            }
167        }
168    }
169
170    audioDebugIOLog(3, "- IOAudioStream[%p]::validateFormat(%p, %p, %p) returns %d\n", this, streamFormat, formatExtension, formatDesc, foundFormat );
171    return foundFormat;
172}
173
174const IOAudioStreamFormatExtension *IOAudioStream::getFormatExtension()
175{
176	assert(reserved);
177	return &reserved->streamFormatExtension;
178}
179
180IOReturn IOAudioStream::setFormat(const IOAudioStreamFormat *streamFormat, const IOAudioStreamFormatExtension *formatExtension, bool callDriver)
181{
182    IOReturn result = kIOReturnSuccess;
183    OSDictionary *formatDict = NULL;
184	IOAudioStreamFormatExtension validFormatExtension;
185
186    if (streamFormat) {
187		if (!formatExtension) {
188			IOAudioStreamFormatDesc formatDesc;
189			validateFormat((IOAudioStreamFormat *)streamFormat, NULL, &formatDesc);
190			memcpy (&validFormatExtension, &formatDesc.formatExtension, sizeof (validFormatExtension));
191		} else {
192			validFormatExtension = *formatExtension;
193		}
194        if ( (formatDict = createDictionaryFromFormat(streamFormat, &validFormatExtension)) ) {
195            result = setFormat(streamFormat, &validFormatExtension, formatDict, callDriver);
196            formatDict->release();
197        } else {
198            result = kIOReturnError;
199        }
200    } else {
201        result = kIOReturnBadArgument;
202    }
203
204    return result;
205}
206
207//	<rdar://8121989>	Restructured for single point of entry and single point of exit so that
208//	the indentifier post processing tool can properly insert scope when post processing a log file
209//	obtained via fwkpfv.
210
211IOReturn IOAudioStream::setFormat(const IOAudioStreamFormat *streamFormat, const IOAudioStreamFormatExtension *formatExtension, OSDictionary *formatDict, bool callDriver)
212{
213    IOReturn result = kIOReturnSuccess;
214    IOAudioStreamFormat validFormat;
215    IOAudioStreamFormatDesc formatDesc;
216	IOAudioStreamFormatExtension validFormatExtension;
217    const IOAudioSampleRate *requestedSampleRate = NULL;
218    OSDictionary *sampleRateDict;
219
220    audioDebugIOLog(3, "+ IOAudioStream[%p]::setFormat(%p, %p)\n", this, streamFormat, formatDict);
221
222    if (!streamFormat || !formatDict)
223	{
224        result = kIOReturnBadArgument;
225    }
226	else
227	{
228	#ifdef DEBUG
229		setProperty("IOAudioStreamPendingFormat", formatDict);
230	#endif
231
232		validFormat = *streamFormat;
233		if (NULL != formatExtension) {
234			validFormatExtension = *formatExtension;
235		} else {
236			validFormatExtension.fVersion = kFormatExtensionCurrentVersion;
237			validFormatExtension.fFlags = 0;
238			validFormatExtension.fFramesPerPacket = 1;
239			validFormatExtension.fBytesPerPacket = streamFormat->fNumChannels * (streamFormat->fBitWidth / 8);
240		}
241
242		sampleRateDict = OSDynamicCast(OSDictionary, formatDict->getObject(kIOAudioSampleRateKey));
243		if (sampleRateDict) {
244			requestedSampleRate = IOAudioEngine::createSampleRateFromDictionary(sampleRateDict);
245		} else {
246			requestedSampleRate = audioEngine->getSampleRate();
247		}
248
249		if (validateFormat(&validFormat, &validFormatExtension, &formatDesc, requestedSampleRate)) {
250	//        OSDictionary *sampleRateDict;
251			IOAudioSampleRate *newSampleRate = NULL;
252			OSSet *userClientsToLock;
253
254			sampleRateDict = OSDynamicCast(OSDictionary, formatDict->getObject(kIOAudioSampleRateKey));
255			if (sampleRateDict) {
256				const IOAudioSampleRate *currentSampleRate;
257
258				newSampleRate = IOAudioEngine::createSampleRateFromDictionary(sampleRateDict);
259				currentSampleRate = audioEngine->getSampleRate();
260				if (newSampleRate && (newSampleRate->whole == currentSampleRate->whole) && (newSampleRate->fraction == currentSampleRate->fraction)) {
261					newSampleRate = NULL;
262				}
263			}
264
265			// In order to avoid deadlocks, we need to ensure we hold all of the user client locks
266			// before making calls while holding our IO lock.  Everything works fine as long
267			// as the order of the locks is workLoop -> user client -> stream.
268			// Any other order is sure to cause trouble.
269
270			// Because we pause the engine while doing the format change, the user clients will be removed
271			// from our list before we complete.  Therefore, we must make a copy of the list to allow
272			// all of the clients to be unlocked when we are done.
273			userClientsToLock = OSSet::withCapacity(numClients);
274			if (userClientsToLock) {
275				OSCollectionIterator *clientIterator;
276				IOAudioClientBuffer *clientBuf;
277				IOAudioEngineUserClient *userClient;
278
279				lockStreamForIO();										// <rdar://13186726>
280
281				clientBuf = userClientList;
282				while (clientBuf) {
283					assert(clientBuf->userClient);
284
285					userClientsToLock->setObject(clientBuf->userClient);
286					clientBuf = clientBuf->nextClient;
287				}
288
289				unlockStreamForIO();									// <rdar://13186726>
290
291				clientIterator = OSCollectionIterator::withCollection(userClientsToLock);
292				if (!clientIterator) {
293					userClientsToLock->release();
294					result = kIOReturnNoMemory;
295					goto Done;
296				}
297
298				while ( (userClient = (IOAudioEngineUserClient *)clientIterator->getNextObject()) ) {
299					userClient->lockBuffers();
300				}
301
302				clientIterator->release();
303
304				lockStreamForIO();
305
306				audioEngine->pauseAudioEngine();
307
308				if (callDriver) {
309					result = audioEngine->performFormatChange(this, &validFormat, &validFormatExtension, newSampleRate);
310					if ( result == kIOReturnUnsupported )
311					{
312						result = audioEngine->performFormatChange(this, &validFormat, newSampleRate);
313					}
314				}
315
316				if (result == kIOReturnSuccess) {
317					OSDictionary *newFormatDict;
318
319					if (formatDesc.ioFunctionList && (formatDesc.numIOFunctions > 0)) {
320						setIOFunctionList(formatDesc.ioFunctionList, formatDesc.numIOFunctions);
321					}
322
323					newFormatDict = createDictionaryFromFormat(&validFormat, &validFormatExtension);
324					if (newFormatDict) {
325						UInt32 oldNumChannels;
326
327						if (mixBuffer != NULL) {
328							// If we have a mix buffer and the new format is not mixable, free the mix buffer
329							if (!validFormat.fIsMixable) {
330								setMixBuffer(NULL, 0);
331							} else if (streamAllocatedMixBuffer && (format.fNumChannels != validFormat.fNumChannels)) {	// We need to reallocate the mix buffer
332								UInt32 newMixBufSize;
333
334								assert(audioEngine);
335								newMixBufSize = validFormat.fNumChannels * kIOAudioEngineDefaultMixBufferSampleSize * audioEngine->numSampleFramesPerBuffer;
336
337								if (newMixBufSize > 0) {
338									void *newMixBuf = IOMallocAligned(newMixBufSize, 32);
339									if (newMixBuf) {
340										setMixBuffer(newMixBuf, newMixBufSize);
341										streamAllocatedMixBuffer = true;
342									}
343								}
344							}
345						}
346
347						oldNumChannels = format.fNumChannels;
348
349						format = validFormat;
350						setProperty(kIOAudioStreamFormatKey, newFormatDict);
351						newFormatDict->release();
352
353						if (format.fNumChannels != oldNumChannels) {
354							audioEngine->updateChannelNumbers();
355						}
356
357						if (newSampleRate) {
358							audioEngine->setSampleRate(newSampleRate);
359						}
360					} else {
361						result = kIOReturnError;
362					}
363				} else {
364					if ( kIOReturnNotReady != result ) {	//	<rdar://8094567>
365					IOLog("IOAudioStream<%p>::setFormat(0x%p, 0x%p) - audio engine unable to change format\n", this, streamFormat, formatDict);
366					}
367				}
368
369				if (result == kIOReturnSuccess) {
370					audioEngine->sendFormatChangeNotification(this);
371				}
372
373				audioEngine->resumeAudioEngine();
374
375				unlockStreamForIO();
376
377				// Unlock all of the user clients we originally locked
378				assert(userClientsToLock);
379				clientIterator = OSCollectionIterator::withCollection(userClientsToLock);
380				if (clientIterator) {
381					while ( (userClient = (IOAudioEngineUserClient *)clientIterator->getNextObject()) ) {
382						userClient->unlockBuffers();
383					}
384					clientIterator->release();
385				} else {
386					// Uh oh... we're in trouble now!
387					// We have to unlock the clients, but we can't get an iterator on the collection.
388					// All existing clients will now hang trying to play audio
389					result = kIOReturnNoMemory;
390				}
391
392				userClientsToLock->release();
393			} else {
394				result = kIOReturnNoMemory;
395			}
396		} else {
397			IOLog("IOAudioStream<0x%p>::setFormat(0x%p, 0x%p) - invalid format.\n", this, streamFormat, formatDict);
398			result = kIOReturnBadArgument;
399		}
400	}
401
402Done:
403
404    audioDebugIOLog(3, "IOAudioStream[%p]::setFormat(%p, %p) returns 0x%lx", this, streamFormat, formatDict, (long unsigned int)result);
405
406    return result;
407}
408
409void IOAudioStream::addAvailableFormat(const IOAudioStreamFormat *streamFormat, const IOAudioStreamFormatExtension *formatExtension, const IOAudioSampleRate *minRate, const IOAudioSampleRate *maxRate, const AudioIOFunction *ioFunctionList, UInt32 numFunctions)
410{
411    assert(availableFormatDictionaries);
412
413    if (streamFormat && minRate && maxRate) {
414        IOAudioStreamFormatDesc *newAvailableFormatList;
415		IOAudioStreamFormatExtension	localFormatExtension;
416
417        newAvailableFormatList = (IOAudioStreamFormatDesc *)IOMallocAligned((numAvailableFormats+1) * sizeof(IOAudioStreamFormatDesc), sizeof (IOAudioStreamFormatDesc *));
418        if (newAvailableFormatList) {
419            if (availableFormats && (numAvailableFormats > 0)) {
420                memcpy(newAvailableFormatList, availableFormats, numAvailableFormats * sizeof(IOAudioStreamFormatDesc));
421            }
422            newAvailableFormatList[numAvailableFormats].format = *streamFormat;
423            newAvailableFormatList[numAvailableFormats].minimumSampleRate = *minRate;
424            newAvailableFormatList[numAvailableFormats].maximumSampleRate = *maxRate;
425            if (formatExtension) {
426				localFormatExtension = *formatExtension;
427                newAvailableFormatList[numAvailableFormats].formatExtension.flags = formatExtension->fFlags;
428                newAvailableFormatList[numAvailableFormats].formatExtension.framesPerPacket = formatExtension->fFramesPerPacket;
429                newAvailableFormatList[numAvailableFormats].formatExtension.bytesPerPacket = formatExtension->fBytesPerPacket;
430            } else {
431                newAvailableFormatList[numAvailableFormats].formatExtension.flags = localFormatExtension.fFlags = 0;
432                newAvailableFormatList[numAvailableFormats].formatExtension.framesPerPacket = localFormatExtension.fFramesPerPacket = 1;
433                newAvailableFormatList[numAvailableFormats].formatExtension.bytesPerPacket = localFormatExtension.fBytesPerPacket = streamFormat->fNumChannels * (streamFormat->fBitWidth / 8);
434            }
435
436            if (ioFunctionList && (numFunctions > 0)) {
437                newAvailableFormatList[numAvailableFormats].ioFunctionList = (AudioIOFunction *)IOMallocAligned(numFunctions * sizeof(AudioIOFunction), sizeof (AudioIOFunction *));
438                newAvailableFormatList[numAvailableFormats].numIOFunctions = numFunctions;
439                memcpy(newAvailableFormatList[numAvailableFormats].ioFunctionList, ioFunctionList, numFunctions * sizeof(AudioIOFunction));
440            } else {
441                newAvailableFormatList[numAvailableFormats].ioFunctionList = NULL;
442                newAvailableFormatList[numAvailableFormats].numIOFunctions = 0;
443            }
444
445            IOFreeAligned(availableFormats, numAvailableFormats * sizeof(IOAudioStreamFormatDesc));
446            availableFormats = newAvailableFormatList;
447            numAvailableFormats++;
448        }
449
450        OSDictionary *formatDict = createDictionaryFromFormat(streamFormat, &localFormatExtension);
451        if (formatDict) {
452            OSDictionary *sampleRateDict;
453
454            sampleRateDict = IOAudioEngine::createDictionaryFromSampleRate(minRate);
455            if (sampleRateDict) {
456                formatDict->setObject(gMinimumSampleRateKey, sampleRateDict);
457                sampleRateDict->release();
458
459                sampleRateDict = IOAudioEngine::createDictionaryFromSampleRate(maxRate);
460                if (sampleRateDict) {
461					OSArray *newAvailableFormats;
462					OSArray *oldAvailableFormats;
463
464					oldAvailableFormats = availableFormatDictionaries;
465					newAvailableFormats = OSDynamicCast(OSArray, availableFormatDictionaries->copyCollection());  // copyCollection() does a deep copy
466
467					if (newAvailableFormats) {
468						formatDict->setObject(gMaximumSampleRateKey, sampleRateDict);
469						newAvailableFormats->setObject(formatDict);
470						availableFormatDictionaries = newAvailableFormats;
471						setProperty(kIOAudioStreamAvailableFormatsKey, availableFormatDictionaries);
472						oldAvailableFormats->release();
473						if (streamFormat->fNumChannels > maxNumChannels) {
474							maxNumChannels = streamFormat->fNumChannels;
475						}
476					}
477
478					sampleRateDict->release();
479                }
480            }
481            formatDict->release();
482        }
483    }
484}
485
486void IOAudioStream::addAvailableFormat(const IOAudioStreamFormat *streamFormat, const IOAudioStreamFormatExtension *formatExtension, const IOAudioSampleRate *minRate, const IOAudioSampleRate *maxRate, AudioIOFunction ioFunction)
487{
488    addAvailableFormat(streamFormat, formatExtension, minRate, maxRate, &ioFunction, 1);
489}
490
491bool IOAudioStream::validateFormat(IOAudioStreamFormat *streamFormat, IOAudioStreamFormatExtension *formatExtension, IOAudioStreamFormatDesc *formatDesc)
492{
493	return validateFormat(streamFormat, formatExtension, formatDesc, audioEngine->getSampleRate());
494}
495
496void IOAudioStream::setTerminalType(const UInt32 terminalType)
497{
498    if (terminalType) {
499        setProperty(kIOAudioStreamTerminalTypeKey, terminalType, 32);
500    }
501}
502
503IOReturn IOAudioStream::mixOutputSamples(const void *sourceBuf, void *mixBuf, UInt32 firstSampleFrame, UInt32 numSampleFrames, const IOAudioStreamFormat *streamFormat, IOAudioStream *audioStream)
504{
505	bcopy (sourceBuf, (float *)mixBuf + (firstSampleFrame * streamFormat->fNumChannels), numSampleFrames * sizeof (float) * streamFormat->fNumChannels);
506
507	return kIOReturnSuccess;
508}
509
510void IOAudioStream::setSampleLatency(UInt32 numSamples)
511{
512    audioDebugIOLog(3, "+-IOAudioStream[%p]::setSampleLatency(0x%lx)\n", this, (long unsigned int)numSamples);
513    setProperty(kIOAudioStreamSampleLatencyKey, numSamples, sizeof(UInt32)*8);
514}
515
516UInt32 IOAudioStream::getNumSampleFramesRead()
517{
518	assert(reserved);
519    audioDebugIOLog(4, "+-IOAudioStream[%p]::getNumSampleFramesRead() returns %ld\n", this, (long unsigned int)reserved->mSampleFramesReadByEngine);
520	return reserved->mSampleFramesReadByEngine;
521}
522
523void IOAudioStream::setDefaultNumSampleFramesRead(UInt32 inDefaultNumFramesRead)
524{
525	assert(reserved);
526    audioDebugIOLog(4, "+-IOAudioStream[%p]::setDefaultNumSampleFramesRead(%ld)\n", this, (long unsigned int)inDefaultNumFramesRead);
527	reserved->mSampleFramesReadByEngine = inDefaultNumFramesRead;
528}
529
530// Original code from here on:
531const OSSymbol *IOAudioStream::gDirectionKey = NULL;
532const OSSymbol *IOAudioStream::gNumChannelsKey = NULL;
533const OSSymbol *IOAudioStream::gSampleFormatKey = NULL;
534const OSSymbol *IOAudioStream::gNumericRepresentationKey = NULL;
535const OSSymbol *IOAudioStream::gBitDepthKey = NULL;
536const OSSymbol *IOAudioStream::gBitWidthKey = NULL;
537const OSSymbol *IOAudioStream::gAlignmentKey = NULL;
538const OSSymbol *IOAudioStream::gByteOrderKey = NULL;
539const OSSymbol *IOAudioStream::gIsMixableKey = NULL;
540const OSSymbol *IOAudioStream::gDriverTagKey = NULL;
541const OSSymbol *IOAudioStream::gMinimumSampleRateKey = NULL;
542const OSSymbol *IOAudioStream::gMaximumSampleRateKey = NULL;
543
544void IOAudioStream::initKeys()
545{
546    if (!gNumChannelsKey) {
547        gNumChannelsKey = OSSymbol::withCString(kIOAudioStreamNumChannelsKey);
548        gSampleFormatKey = OSSymbol::withCString(kIOAudioStreamSampleFormatKey);
549        gNumericRepresentationKey = OSSymbol::withCString(kIOAudioStreamNumericRepresentationKey);
550        gBitDepthKey = OSSymbol::withCString(kIOAudioStreamBitDepthKey);
551        gBitWidthKey = OSSymbol::withCString(kIOAudioStreamBitWidthKey);
552        gAlignmentKey = OSSymbol::withCString(kIOAudioStreamAlignmentKey);
553        gByteOrderKey = OSSymbol::withCString(kIOAudioStreamByteOrderKey);
554        gIsMixableKey = OSSymbol::withCString(kIOAudioStreamIsMixableKey);
555        gDriverTagKey = OSSymbol::withCString(kIOAudioStreamDriverTagKey);
556
557        gDirectionKey = OSSymbol::withCString(kIOAudioStreamDirectionKey);
558
559        gMinimumSampleRateKey = OSSymbol::withCString(kIOAudioStreamMinimumSampleRateKey);
560        gMaximumSampleRateKey = OSSymbol::withCString(kIOAudioStreamMaximumSampleRateKey);
561    }
562}
563
564OSDictionary *IOAudioStream::createDictionaryFromFormat(const IOAudioStreamFormat *streamFormat, const IOAudioStreamFormatExtension *formatExtension, OSDictionary *formatDict)
565{
566    OSDictionary *newDict = NULL;
567
568    if (streamFormat) {
569        if (formatDict) {
570            newDict = formatDict;
571        } else {
572            newDict = OSDictionary::withCapacity(7);
573        }
574
575        if (newDict) {
576            OSNumber *num;
577
578            if (!gNumChannelsKey) {
579                initKeys();
580            }
581
582            num = OSNumber::withNumber(streamFormat->fNumChannels, 32);
583            newDict->setObject(gNumChannelsKey, num);
584            num->release();
585
586            num = OSNumber::withNumber(streamFormat->fSampleFormat, 32);
587            newDict->setObject(gSampleFormatKey, num);
588            num->release();
589
590            num = OSNumber::withNumber(streamFormat->fNumericRepresentation, 32);
591            newDict->setObject(gNumericRepresentationKey, num);
592            num->release();
593
594            num = OSNumber::withNumber(streamFormat->fBitDepth, 8);
595            newDict->setObject(gBitDepthKey, num);
596            num->release();
597
598            num = OSNumber::withNumber(streamFormat->fBitWidth, 8);
599            newDict->setObject(gBitWidthKey, num);
600            num->release();
601
602            num = OSNumber::withNumber(streamFormat->fAlignment, 8);
603            newDict->setObject(gAlignmentKey, num);
604            num->release();
605
606            num = OSNumber::withNumber(streamFormat->fByteOrder, 8);
607            newDict->setObject(gByteOrderKey, num);
608            num->release();
609
610            num = OSNumber::withNumber(streamFormat->fIsMixable, 8);
611            newDict->setObject(gIsMixableKey, num);
612            num->release();
613
614            num = OSNumber::withNumber(streamFormat->fDriverTag, 32);
615            newDict->setObject(gDriverTagKey, num);
616            num->release();
617
618			if (formatExtension && formatExtension->fVersion >= kFormatExtensionCurrentVersion) {
619				num = OSNumber::withNumber(formatExtension->fFlags, 32);
620				newDict->setObject(kIOAudioStreamFormatFlagsKey, num);
621				num->release();
622
623				num = OSNumber::withNumber(formatExtension->fFramesPerPacket, 32);
624				newDict->setObject(kIOAudioStreamFramesPerPacketKey, num);
625				num->release();
626
627				num = OSNumber::withNumber(formatExtension->fBytesPerPacket, 32);
628				newDict->setObject(kIOAudioStreamBytesPerPacketKey, num);
629				num->release();
630			}
631        }
632    }
633
634
635    return newDict;
636}
637
638IOAudioStreamFormat *IOAudioStream::createFormatFromDictionary(const OSDictionary *formatDict, IOAudioStreamFormat *streamFormat, IOAudioStreamFormatExtension *formatExtension)
639{
640    IOAudioStreamFormat *format = NULL;
641    static IOAudioStreamFormat staticFormat;
642
643    if (formatDict) {
644        if (streamFormat) {
645            format = streamFormat;
646        } else {
647            format = &staticFormat;
648        }
649
650        if (format) {
651            OSNumber *num;
652
653            if (!gNumChannelsKey) {
654                initKeys();
655            }
656
657            bzero(format, sizeof(IOAudioStreamFormat));
658
659            num = OSDynamicCast(OSNumber, formatDict->getObject(gNumChannelsKey));
660            if (num) {
661                format->fNumChannels = num->unsigned32BitValue();
662            }
663
664            num = OSDynamicCast(OSNumber, formatDict->getObject(gSampleFormatKey));
665            if (num) {
666                format->fSampleFormat = num->unsigned32BitValue();
667            }
668
669            num = OSDynamicCast(OSNumber, formatDict->getObject(gNumericRepresentationKey));
670            if (num) {
671                format->fNumericRepresentation = num->unsigned32BitValue();
672            }
673
674            num = OSDynamicCast(OSNumber, formatDict->getObject(gBitDepthKey));
675            if (num) {
676                format->fBitDepth = num->unsigned8BitValue();
677            }
678
679            num = OSDynamicCast(OSNumber, formatDict->getObject(gBitWidthKey));
680            if (num) {
681                format->fBitWidth = num->unsigned8BitValue();
682            }
683
684            num = OSDynamicCast(OSNumber, formatDict->getObject(gAlignmentKey));
685            if (num) {
686                format->fAlignment = num->unsigned8BitValue();
687            }
688
689            num = OSDynamicCast(OSNumber, formatDict->getObject(gByteOrderKey));
690            if (num) {
691                format->fByteOrder = num->unsigned8BitValue();
692            }
693
694            num = OSDynamicCast(OSNumber, formatDict->getObject(gIsMixableKey));
695            if (num) {
696                format->fIsMixable = num->unsigned8BitValue();
697            }
698
699            num = OSDynamicCast(OSNumber, formatDict->getObject(gDriverTagKey));
700            if (num) {
701                format->fDriverTag = num->unsigned32BitValue();
702            }
703
704			if (formatExtension) {
705				formatExtension->fVersion = kFormatExtensionCurrentVersion;
706
707				num = OSDynamicCast(OSNumber, formatDict->getObject(kIOAudioStreamFormatFlagsKey));
708				if (num) {
709					formatExtension->fFlags = num->unsigned32BitValue();
710				}
711
712				num = OSDynamicCast(OSNumber, formatDict->getObject(kIOAudioStreamFramesPerPacketKey));
713				if (num) {
714					formatExtension->fFramesPerPacket = num->unsigned32BitValue();
715				}
716
717				num = OSDynamicCast(OSNumber, formatDict->getObject(kIOAudioStreamBytesPerPacketKey));
718				if (num) {
719					formatExtension->fBytesPerPacket = num->unsigned32BitValue();
720				}
721
722			}
723        }
724    }
725
726    return format;
727}
728
729
730bool IOAudioStream::initWithAudioEngine(IOAudioEngine *engine, IOAudioStreamDirection dir, UInt32 startChannelID, const char *streamDescription, OSDictionary *properties)
731{
732	UInt32				streamID;
733
734    if (!gNumChannelsKey) {
735        initKeys();
736    }
737
738    if (!engine) {
739        return false;
740    }
741
742    if (!super::init(properties)) {
743        return false;
744    }
745
746    audioEngine = engine;
747
748	reserved = (ExpansionData *)IOMalloc (sizeof(struct ExpansionData));
749	if (!reserved) {
750		return false;
751	}
752
753    workLoop = audioEngine->getWorkLoop();
754    if (!workLoop) {
755        return false;
756    }
757
758    workLoop->retain();
759
760    commandGate = IOCommandGate::commandGate(this);
761    if (!commandGate) {
762        return false;
763    }
764
765    streamIOLock = IORecursiveLockAlloc();
766    if (!streamIOLock) {
767        return false;
768    }
769
770    setDirection(dir);
771
772    startingChannelID = startChannelID;
773    setProperty(kIOAudioStreamStartingChannelIDKey, startingChannelID, sizeof(UInt32)*8);
774
775    maxNumChannels = 0;
776
777    if (streamDescription) {
778        setProperty(kIOAudioStreamDescriptionKey, streamDescription);
779    }
780
781    availableFormatDictionaries = OSArray::withCapacity(1);
782    if (!availableFormatDictionaries) {
783        return false;
784    }
785    setProperty(kIOAudioStreamAvailableFormatsKey, availableFormatDictionaries);
786
787	// This needs to change to passing up a token rather than the "this" pointer.
788	streamID = engine->getNextStreamID (this);
789    setProperty(kIOAudioStreamIDKey, streamID, sizeof(UInt32)*8);
790//    setProperty(kIOAudioStreamIDKey, (UInt32)this, sizeof(UInt32)*8);
791
792    streamAvailable = true;
793    setProperty(kIOAudioStreamAvailableKey, (UInt8)1, sizeof(UInt8)*8);
794
795    numClients = 0;
796    updateNumClients();
797
798    resetClipInfo();
799
800    clientBufferListStart = NULL;
801    clientBufferListEnd = NULL;
802
803    userClientList = NULL;
804
805    audioIOFunctions = NULL;
806    numIOFunctions = false;
807
808    streamAllocatedMixBuffer = false;
809
810    workLoop->addEventSource(commandGate);
811
812    return true;
813}
814
815void IOAudioStream::free()
816{
817    if (availableFormatDictionaries) {
818        availableFormatDictionaries->release();
819        availableFormatDictionaries = NULL;
820    }
821
822    if (mixBuffer && streamAllocatedMixBuffer) {
823        IOFreeAligned(mixBuffer, mixBufferSize);
824        mixBuffer = NULL;
825        mixBufferSize = 0;
826    }
827
828    if (defaultAudioControls) {
829        removeDefaultAudioControls();
830        defaultAudioControls->release();
831        defaultAudioControls = NULL;
832    }
833
834    if (commandGate) {
835        if (workLoop) {
836            workLoop->removeEventSource(commandGate);
837        }
838
839        commandGate->release();
840        commandGate = NULL;
841    }
842
843    if (workLoop) {
844        workLoop->release();
845        workLoop = NULL;
846    }
847
848    if (streamIOLock) {
849        IORecursiveLockFree(streamIOLock);
850        streamIOLock = NULL;
851    }
852
853    if (audioIOFunctions && (numIOFunctions > 0)) {
854        IOFreeAligned(audioIOFunctions, numIOFunctions * sizeof(AudioIOFunction));
855        audioIOFunctions = NULL;
856        numIOFunctions = 0;
857    }
858
859    if (availableFormats && (numAvailableFormats > 0)) {
860        UInt32 formatNum;
861
862        for (formatNum = 0; formatNum < numAvailableFormats; formatNum++) {
863            if (availableFormats[formatNum].ioFunctionList && (availableFormats[formatNum].numIOFunctions > 0)) {
864                IOFreeAligned(availableFormats[formatNum].ioFunctionList, availableFormats[formatNum].numIOFunctions * sizeof(AudioIOFunction));
865            }
866        }
867
868        IOFreeAligned(availableFormats, numAvailableFormats * sizeof(IOAudioStreamFormatDesc));
869        availableFormats = NULL;
870        numAvailableFormats = 0;
871    }
872
873	if (reserved) {
874		IOFree (reserved, sizeof(struct ExpansionData));
875	}
876
877    super::free();
878}
879
880void IOAudioStream::stop(IOService *provider)
881{
882    if (commandGate) {
883        if (workLoop) {
884            workLoop->removeEventSource(commandGate);
885        }
886
887        commandGate->release();
888        commandGate = NULL;
889    }
890
891    super::stop(provider);
892}
893
894IOWorkLoop *IOAudioStream::getWorkLoop() const
895{
896    return workLoop;
897}
898
899IOReturn IOAudioStream::setProperties(OSObject *properties)
900{
901    OSDictionary *props;
902    IOReturn result = kIOReturnSuccess;
903
904    audioDebugIOLog(3, "+ IOAudioStream[%p]::setProperties(%p)\n", this, properties);
905
906    if (properties && (props = OSDynamicCast(OSDictionary, properties))) {
907        OSCollectionIterator *iterator;
908        OSObject *iteratorKey;
909
910        iterator = OSCollectionIterator::withCollection(props);
911        if (iterator) {
912            while ( (iteratorKey = iterator->getNextObject()) ) {
913                OSSymbol *key;
914
915                key = OSDynamicCast(OSSymbol, iteratorKey);
916                if (key && key->isEqualTo(kIOAudioStreamFormatKey)) {
917                    OSDictionary *formatDict = OSDynamicCast(OSDictionary, props->getObject(key));
918                    if (formatDict) {
919                        assert(workLoop);													// <rdar://8568040,8691669>
920						result = workLoop->runAction(_setFormatAction, this, formatDict);	// <rdar://8568040,8691669>
921                    }
922                }
923            }
924            iterator->release();
925        } else {
926            result = kIOReturnError;
927        }
928    } else {
929        result = kIOReturnBadArgument;
930    }
931
932    audioDebugIOLog(3, "- IOAudioStream[%p]::setProperties(%p) returns 0x%lX\n", this, properties, (long unsigned int)result );
933    return result;
934}
935
936void IOAudioStream::setDirection(IOAudioStreamDirection dir)
937{
938    direction = dir;
939    setProperty(kIOAudioStreamDirectionKey, direction, 8);
940}
941
942IOAudioStreamDirection IOAudioStream::getDirection()
943{
944    return direction;
945}
946
947void IOAudioStream::setSampleBuffer(void *buffer, UInt32 size)
948{
949    lockStreamForIO();
950
951    sampleBuffer = buffer;
952
953    if (sampleBuffer) {
954        sampleBufferSize = size;
955        bzero(sampleBuffer, sampleBufferSize);
956    } else {
957        sampleBufferSize = 0;
958    }
959
960    unlockStreamForIO();
961}
962
963void *IOAudioStream::getSampleBuffer()
964{
965    return sampleBuffer;
966}
967
968UInt32 IOAudioStream::getSampleBufferSize()
969{
970    return sampleBufferSize;
971}
972
973void IOAudioStream::setMixBuffer(void *buffer, UInt32 size)
974{
975    lockStreamForIO();
976
977    if (mixBuffer && streamAllocatedMixBuffer) {
978        IOFreeAligned(mixBuffer, mixBufferSize);
979        mixBuffer = NULL;
980        mixBufferSize = 0;
981        streamAllocatedMixBuffer = false;
982    }
983
984    mixBuffer = buffer;
985
986    if (mixBuffer) {
987        mixBufferSize = size;
988        bzero(mixBuffer, mixBufferSize);
989    } else {
990        mixBufferSize = 0;
991    }
992
993    unlockStreamForIO();
994}
995
996void *IOAudioStream::getMixBuffer()
997{
998    return mixBuffer;
999}
1000
1001UInt32 IOAudioStream::getMixBufferSize()
1002{
1003    return mixBufferSize;
1004}
1005
1006void IOAudioStream::numSampleFramesPerBufferChanged()
1007{
1008    if (mixBuffer && streamAllocatedMixBuffer) {
1009        setMixBuffer(NULL, 0);
1010    }
1011}
1012
1013void IOAudioStream::clearSampleBuffer()
1014{
1015    if (sampleBuffer && (sampleBufferSize > 0)) {
1016        bzero(sampleBuffer, sampleBufferSize);
1017    }
1018
1019    if (mixBuffer && (mixBufferSize > 0)) {
1020        bzero(mixBuffer, mixBufferSize);
1021    }
1022}
1023
1024void IOAudioStream::setIOFunction(AudioIOFunction ioFunction)
1025{
1026    setIOFunctionList(&ioFunction, 1);
1027}
1028
1029void IOAudioStream::setIOFunctionList(const AudioIOFunction *ioFunctionList, UInt32 numFunctions)
1030{
1031    lockStreamForIO();
1032
1033    if (audioIOFunctions && (numIOFunctions > 0)) {
1034        IOFreeAligned(audioIOFunctions, numIOFunctions * sizeof(AudioIOFunction));
1035        audioIOFunctions = NULL;
1036        numIOFunctions = 0;
1037    }
1038
1039    if (ioFunctionList && (numFunctions != 0)) {
1040        audioIOFunctions = (AudioIOFunction *)IOMallocAligned(numFunctions * sizeof(AudioIOFunction), sizeof (AudioIOFunction *));
1041        if (audioIOFunctions) {
1042            memcpy(audioIOFunctions, ioFunctionList, numFunctions * sizeof(AudioIOFunction));
1043            numIOFunctions = numFunctions;
1044        }
1045    }
1046
1047    unlockStreamForIO();
1048}
1049
1050const IOAudioStreamFormat *IOAudioStream::getFormat()
1051{
1052    return &format;
1053}
1054
1055// <rdar://8568040,8691669>
1056IOReturn IOAudioStream::_setFormatAction(OSObject *target, void *arg0, void *arg1, void *arg2, void *arg3)
1057{
1058    IOReturn result = kIOReturnBadArgument;
1059
1060    if (target) {
1061        IOAudioStream *stream = OSDynamicCast(IOAudioStream, target);
1062        if (stream) {
1063            if (stream->commandGate) {
1064                result = stream->commandGate->runAction(setFormatAction, arg0, arg1, arg2, arg3);
1065            } else {
1066                result = kIOReturnError;
1067            }
1068        }
1069    }
1070
1071    return result;
1072}
1073
1074IOReturn IOAudioStream::setFormatAction(OSObject *owner, void *arg1, void *arg2, void *arg3, void *arg4)
1075{
1076    IOReturn result = kIOReturnBadArgument;
1077
1078    if (owner) {
1079        IOAudioStream *audioStream = OSDynamicCast(IOAudioStream, owner);
1080        if (audioStream) {
1081            result = audioStream->setFormat((OSDictionary *)arg1);
1082        }
1083    }
1084
1085    return result;
1086}
1087
1088IOReturn IOAudioStream::setFormat(const IOAudioStreamFormat *streamFormat, bool callDriver)
1089{
1090    return setFormat(streamFormat, (IOAudioStreamFormatExtension *)NULL, callDriver);
1091}
1092
1093IOReturn IOAudioStream::setFormat(OSDictionary *formatDict)
1094{
1095    IOReturn result = kIOReturnSuccess;
1096
1097    if (formatDict) {
1098        IOAudioStreamFormat streamFormat;
1099		IOAudioStreamFormatExtension formatExtension;
1100        if (createFormatFromDictionary(formatDict, &streamFormat, &formatExtension)) {
1101            result = setFormat(&streamFormat, &formatExtension, formatDict);
1102        } else {
1103            result = kIOReturnBadArgument;
1104        }
1105    } else {
1106        result = kIOReturnBadArgument;
1107    }
1108
1109    return result;
1110}
1111
1112IOReturn IOAudioStream::setFormat(const IOAudioStreamFormat *streamFormat, OSDictionary *formatDict, bool callDriver)
1113{
1114	return setFormat(streamFormat, NULL, formatDict, callDriver);
1115}
1116
1117IOReturn IOAudioStream::hardwareFormatChanged(const IOAudioStreamFormat *streamFormat)
1118{
1119	assert(reserved);
1120    return setFormat(streamFormat, &reserved->streamFormatExtension, false);
1121}
1122
1123void IOAudioStream::addAvailableFormat(const IOAudioStreamFormat *streamFormat, const IOAudioSampleRate *minRate, const IOAudioSampleRate *maxRate, AudioIOFunction ioFunction)
1124{
1125    addAvailableFormat(streamFormat, NULL, minRate, maxRate, &ioFunction, 1);
1126}
1127
1128void IOAudioStream::addAvailableFormat(const IOAudioStreamFormat *streamFormat, const IOAudioSampleRate *minRate, const IOAudioSampleRate *maxRate, const AudioIOFunction *ioFunctionList, UInt32 numFunctions)
1129{
1130    addAvailableFormat(streamFormat, NULL, minRate, maxRate, ioFunctionList, numFunctions);
1131}
1132
1133void IOAudioStream::clearAvailableFormats()
1134{
1135	OSArray*	oldAvailableFormats;
1136	OSArray*	clearedAvailableFormats;
1137
1138    assert(availableFormatDictionaries);
1139
1140	oldAvailableFormats = availableFormatDictionaries;
1141
1142    clearedAvailableFormats = OSArray::withCapacity(1);
1143    if (!clearedAvailableFormats) {
1144        return;
1145    }
1146	availableFormatDictionaries = clearedAvailableFormats;
1147    setProperty(kIOAudioStreamAvailableFormatsKey, availableFormatDictionaries);
1148
1149    oldAvailableFormats->release();
1150
1151	//	<rdar://9059646> Clean up the available formats array.
1152	if (availableFormats && (numAvailableFormats > 0)) {
1153		IOFreeAligned(availableFormats, numAvailableFormats * sizeof(IOAudioStreamFormatDesc));
1154	}
1155	availableFormats = NULL;
1156	numAvailableFormats = 0;
1157}
1158
1159bool IOAudioStream::validateFormat(IOAudioStreamFormat *streamFormat, IOAudioStreamFormatDesc *formatDesc)
1160{
1161	return validateFormat(streamFormat, NULL, formatDesc);
1162}
1163
1164UInt32 IOAudioStream::getStartingChannelID()
1165{
1166    return startingChannelID;
1167}
1168
1169UInt32 IOAudioStream::getMaxNumChannels()
1170{
1171    return maxNumChannels;
1172}
1173
1174void IOAudioStream::setStartingChannelNumber(UInt32 channelNumber)
1175{
1176    setProperty(kIOAudioStreamStartingChannelNumberKey, channelNumber, sizeof(UInt32)*8);
1177}
1178
1179void IOAudioStream::updateNumClients()
1180{
1181    setProperty(kIOAudioStreamNumClientsKey, numClients, sizeof(UInt32)*8);
1182}
1183
1184IOReturn IOAudioStream::addClient(IOAudioClientBuffer *clientBuffer)
1185{
1186    IOReturn result = kIOReturnBadArgument;
1187
1188    audioDebugIOLog(3, "+ IOAudioStream[%p]::addClient(%p)\n", this, clientBuffer);
1189
1190    if (clientBuffer) {
1191        assert(clientBuffer->audioStream == this);
1192
1193        lockStreamForIO();
1194
1195        // <rdar://11731381> Make sure this buffer is not in the list
1196		bool bufferInList = false;
1197        if ((clientBuffer->nextClip == NULL) && (clientBuffer->previousClip == NULL) && (clientBuffer != clientBufferListStart) && (clientBuffer->nextClient == NULL) && (clientBuffer != userClientList)) {
1198
1199			// <rdar://11731381> Make sure that the clientBuffer is not at the end of the list.
1200			IOAudioClientBuffer *tmpClientBuffer = userClientList;
1201			while (tmpClientBuffer && (tmpClientBuffer != clientBuffer)) {
1202				tmpClientBuffer = tmpClientBuffer->nextClient;
1203			}
1204			if (tmpClientBuffer) {
1205				audioDebugIOLog(3, "   clientBuffer %p is already in the list.\n", tmpClientBuffer);
1206				bufferInList = true;
1207			}
1208		}
1209		else {
1210			audioDebugIOLog(3, "   unexpected clientBuffer values (%p, %p, %p, %p, %p, %p)\n", clientBuffer->nextClip, clientBuffer->previousClip, clientBuffer, clientBufferListStart, clientBuffer->nextClient, userClientList );
1211			bufferInList = true;
1212		}
1213
1214		if (!bufferInList) {	// <rdar://11731381>
1215
1216            // It's OK to allow a new client if this is a mixable format
1217            // or if its not mixable but we don't have any clients
1218            // or if we are an input stream
1219            if (format.fIsMixable || (numClients == 0) || (getDirection() == kIOAudioStreamDirectionInput)) {
1220                numClients++;
1221                updateNumClients();
1222
1223                clientBuffer->nextClient = userClientList;
1224                userClientList = clientBuffer;
1225
1226                if (getDirection() == kIOAudioStreamDirectionOutput) {
1227
1228                    clientBuffer->mixedPosition.fLoopCount = 0;
1229                    clientBuffer->mixedPosition.fSampleFrame = 0;
1230
1231                    clientBuffer->previousClip = NULL;
1232                    clientBuffer->nextClip = NULL;
1233
1234                    if (!mixBuffer && format.fIsMixable && sampleBuffer && (sampleBufferSize > 0)) {
1235                        assert(audioEngine);
1236
1237                        UInt32 mixBufSize = format.fNumChannels * kIOAudioEngineDefaultMixBufferSampleSize * audioEngine->numSampleFramesPerBuffer;
1238
1239                        if (mixBufSize > 0) {
1240                            void *mixBuf = IOMallocAligned(mixBufSize, 32);
1241                            if (mixBuf) {
1242                                setMixBuffer(mixBuf, mixBufSize);
1243                                streamAllocatedMixBuffer = true;
1244                            }
1245                        }
1246                    }
1247                }
1248
1249                result = kIOReturnSuccess;
1250            } else {
1251				audioDebugIOLog(3, "   clientBuffer invalid (%d, %d, %d).\n", format.fIsMixable, numClients, getDirection());
1252                result = kIOReturnExclusiveAccess;
1253            }
1254        }
1255		else {
1256			// <rdar://13412666> Return success if the buffers are already registered
1257			result = kIOReturnSuccess;
1258		}
1259
1260        unlockStreamForIO();
1261    }
1262
1263    audioDebugIOLog(3, "- IOAudioStream[%p]::addClient(%p) returns 0x%lX\n", this, clientBuffer, (long unsigned int)result );
1264    return result;
1265}
1266
1267void IOAudioStream::removeClient(IOAudioClientBuffer *clientBuffer)
1268{
1269    audioDebugIOLog(3, "+ IOAudioStream[%p]::removeClient(%p)\n", this, clientBuffer);
1270
1271    if (clientBuffer) {
1272        IOAudioClientBuffer *tmpClientBuffer, *previousClientBuffer = NULL;
1273
1274        assert(clientBuffer->audioStream == this);
1275
1276        lockStreamForIO();
1277
1278        tmpClientBuffer = userClientList;
1279        while (tmpClientBuffer && (tmpClientBuffer != clientBuffer)) {
1280            previousClientBuffer = tmpClientBuffer;
1281            tmpClientBuffer = tmpClientBuffer->nextClient;
1282        }
1283
1284        if (tmpClientBuffer) {
1285            if (previousClientBuffer) {
1286                previousClientBuffer->nextClient = tmpClientBuffer->nextClient;
1287            } else {
1288                assert(tmpClientBuffer == userClientList);
1289                userClientList = tmpClientBuffer->nextClient;
1290            }
1291
1292            tmpClientBuffer->nextClient = NULL;
1293
1294            numClients--;
1295            updateNumClients();
1296        }
1297
1298        // Make sure the buffer is in the list
1299        if ((clientBuffer->nextClip != NULL) || (clientBuffer->previousClip != NULL) || (clientBuffer == clientBufferListStart)) {
1300            if (getDirection() == kIOAudioStreamDirectionOutput) {
1301                if (numClients == 0) {
1302                    resetClipInfo();
1303                }
1304
1305                if (clientBuffer->previousClip != NULL) {
1306                    clientBuffer->previousClip->nextClip = clientBuffer->nextClip;
1307                }
1308
1309                if (clientBuffer->nextClip != NULL) {
1310                    clientBuffer->nextClip->previousClip = clientBuffer->previousClip;
1311                }
1312
1313                if (clientBufferListEnd == clientBuffer) {
1314                    assert(clientBuffer->nextClip == NULL);
1315                    clientBufferListEnd = clientBuffer->previousClip;
1316                }
1317
1318                if (clientBufferListStart == clientBuffer) {
1319                    assert(clientBuffer->previousClip == NULL);
1320                    clientBufferListStart = clientBuffer->nextClip;
1321                    if (clientBufferListStart != NULL) {
1322                        clipIfNecessary();
1323                    }
1324                }
1325            }
1326        }
1327
1328		// clear these values for bug 2851917
1329		clientBuffer->previousClip = NULL;
1330		clientBuffer->nextClip = NULL;
1331		clientBuffer->nextClient = NULL;
1332		unlockStreamForIO();
1333    }
1334
1335    audioDebugIOLog(3, "- IOAudioStream[%p]::removeClient(%p)\n", this, clientBuffer);
1336	return;
1337}
1338
1339UInt32 IOAudioStream::getNumClients()
1340{
1341    return numClients;
1342}
1343
1344void dumpList(IOAudioClientBuffer *start)
1345{
1346    IOAudioClientBuffer *tmp;
1347
1348    tmp = start;
1349    while (tmp) {
1350        audioDebugIOLog(3, "  (%lx,%lx)\n", (long unsigned int)tmp->mixedPosition.fLoopCount, (long unsigned int)tmp->mixedPosition.fSampleFrame);
1351        tmp = tmp->nextClip;
1352    }
1353}
1354
1355void validateList(IOAudioClientBuffer *start)
1356{
1357    IOAudioClientBuffer *tmp;
1358
1359    tmp = start;
1360    while (tmp) {
1361        if (tmp->nextClip && (CMP_IOAUDIOENGINEPOSITION(&tmp->mixedPosition, &tmp->nextClip->mixedPosition) > 0)) {
1362            audioDebugIOLog(3, "+-IOAudioStream: ERROR - client buffer list not sorted!\n");
1363            dumpList(start);
1364            break;
1365        }
1366        tmp = tmp->nextClip;
1367    }
1368}
1369
1370IOReturn IOAudioStream::readInputSamples(IOAudioClientBuffer *clientBuffer, UInt32 firstSampleFrame)
1371{
1372    IOReturn result = kIOReturnError;
1373
1374    assert(audioEngine);
1375    assert(getDirection() == kIOAudioStreamDirectionInput);
1376    assert(reserved);
1377
1378    if (clientBuffer) {
1379        UInt32 numWrappedFrames = 0;
1380        UInt32 numReadFrames = 0;
1381        UInt32 numSampleFramesPerBuffer;
1382
1383        numSampleFramesPerBuffer = audioEngine->getNumSampleFramesPerBuffer();
1384
1385        if ((firstSampleFrame + clientBuffer->numSampleFrames) > numSampleFramesPerBuffer) {
1386            numWrappedFrames = clientBuffer->numSampleFrames - (numSampleFramesPerBuffer - firstSampleFrame);
1387        }
1388
1389        if (audioIOFunctions && (numIOFunctions != 0)) {
1390            UInt32 functionNum;
1391
1392            for (functionNum = 0; functionNum < numIOFunctions; functionNum++) {
1393                if (audioIOFunctions[functionNum]) {
1394                    result = audioIOFunctions[functionNum](sampleBuffer, clientBuffer->sourceBuffer, firstSampleFrame, clientBuffer->numSampleFrames - numWrappedFrames, &format, this);
1395                    if (result != kIOReturnSuccess) {
1396                        break;
1397                    }
1398                }
1399            }
1400
1401            if (numWrappedFrames > 0) {
1402                for (functionNum = 0; functionNum < numIOFunctions; functionNum++) {
1403                    if (audioIOFunctions[functionNum]) {
1404                        result = audioIOFunctions[functionNum](sampleBuffer, &((float *)clientBuffer->sourceBuffer)[(numSampleFramesPerBuffer - firstSampleFrame) * format.fNumChannels], 0, numWrappedFrames, &format, this);
1405                        if (result != kIOReturnSuccess) {
1406                            break;
1407                        }
1408                    }
1409                }
1410            }
1411        } else {
1412			numReadFrames = clientBuffer->numSampleFrames - numWrappedFrames;
1413            // numReadFrames passed by reference, value may or may not be modified by the engine.
1414            result = audioEngine->convertInputSamplesVBR(sampleBuffer, clientBuffer->sourceBuffer, firstSampleFrame, numReadFrames, &format, this);
1415			// override the default value set before this call with driver actual value
1416            reserved->mSampleFramesReadByEngine = numReadFrames;
1417
1418			if ((result == kIOReturnSuccess) && (numWrappedFrames > 0)) {
1419				numReadFrames = numWrappedFrames;
1420				if (format.fIsMixable) {	// <rdar://8572755>
1421					// Use float format to compute offset for destination buffer
1422                result = audioEngine->convertInputSamplesVBR(sampleBuffer, &((float *)clientBuffer->sourceBuffer)[(numSampleFramesPerBuffer - firstSampleFrame) * format.fNumChannels], 0, numReadFrames, &format, this);
1423				} else {
1424					// Use native format to compute offset for destination buffer
1425					result = audioEngine->convertInputSamplesVBR(sampleBuffer, ((UInt8 *)clientBuffer->sourceBuffer) + ((numSampleFramesPerBuffer - firstSampleFrame) * format.fNumChannels * (format.fBitWidth / 8)), 0, numReadFrames, &format, this);
1426				}
1427				reserved->mSampleFramesReadByEngine += numReadFrames;
1428            }
1429        }
1430    } else {
1431        result = kIOReturnBadArgument;
1432    }
1433
1434    return result;
1435}
1436
1437IOReturn IOAudioStream::processOutputSamples(IOAudioClientBuffer *clientBuffer, UInt32 firstSampleFrame, UInt32 loopCount, bool samplesAvailable)
1438{
1439    IOReturn result = kIOReturnSuccess;
1440
1441    //audioDebugIOLog(6, "IOAudioStream[%p]::processOutputSamples(%p, 0x%lx)\n", this, clientBuffer, firstSampleFrame);
1442    //audioDebugIOLog(6, "m(%lx,%lx,%lx)\n", loopCount, firstSampleFrame, clientBuffer->numSampleFrames);
1443
1444    assert(direction == kIOAudioStreamDirectionOutput);
1445    if (clientBuffer) {
1446        // We can go ahead if we have a mix buffer or if the format is not mixable
1447        if (mixBuffer || !format.fIsMixable) {
1448            UInt32 numSampleFramesPerBuffer = audioEngine->getNumSampleFramesPerBuffer();
1449            UInt32 nextSampleFrame = 0;
1450            UInt32 mixBufferWrapped = false;
1451            UInt32 numSamplesToMix = 0;
1452            IOAudioClientBuffer *tmpBuf = NULL;
1453
1454            assert(audioEngine);
1455
1456
1457
1458            // If we haven't mixed any samples for this client yet,
1459            // we have to figure out which loop those samples belong to
1460            if (IOAUDIOENGINEPOSITION_IS_ZERO(&clientBuffer->mixedPosition)) {
1461                clientBuffer->mixedPosition.fSampleFrame = firstSampleFrame;
1462                clientBuffer->mixedPosition.fLoopCount = loopCount;
1463            } else {
1464                // If firstSampleFrame is not the same as the previous mixed position sample frame,
1465                // then adjust it to the firstSampleFrame - looping if necessary
1466                if ((clientBuffer->mixedPosition.fSampleFrame != firstSampleFrame) || (clientBuffer->mixedPosition.fLoopCount != loopCount)) {
1467                    audioDebugIOLog(6, "IOAudioStream[%p]::processOutputSamples(%p) - Mix start position (%lx,%lx) is not previous mixed position (%lx,%lx)\n",
1468										this,
1469										clientBuffer,
1470										(long unsigned int)loopCount,
1471										(long unsigned int)firstSampleFrame,
1472										(long unsigned int)clientBuffer->mixedPosition.fLoopCount,
1473										(long unsigned int)clientBuffer->mixedPosition.fSampleFrame);
1474                    clientBuffer->mixedPosition.fLoopCount = loopCount;
1475                    clientBuffer->mixedPosition.fSampleFrame = firstSampleFrame;
1476                }
1477
1478                // Check to see if the first sample frame is more than one buffer behind the last mixed position
1479                // of all of the buffers.  We need to deal with the case where we didn't get any samples
1480                // for this buffer for more than a buffer cycle.  In that case, we need to jump to
1481                // the loop that the last buffer is on.  This assumes that a client never gets more than one
1482                // buffer cycle ahead of the playback head
1483                if ((clientBuffer != clientBufferListEnd) &&
1484                    (clientBufferListEnd != NULL) &&
1485                    ((clientBufferListEnd->mixedPosition.fLoopCount > (clientBuffer->mixedPosition.fLoopCount + 1)) ||
1486                     ((clientBufferListEnd->mixedPosition.fLoopCount == (clientBuffer->mixedPosition.fLoopCount + 1)) &&
1487                      (clientBufferListEnd->mixedPosition.fSampleFrame > clientBuffer->mixedPosition.fSampleFrame)))) {
1488                    // Adjust the loop count to be on the loop before the last mixed position
1489                    if (clientBuffer->mixedPosition.fSampleFrame > clientBufferListEnd->mixedPosition.fSampleFrame) {
1490                        clientBuffer->mixedPosition.fLoopCount = clientBufferListEnd->mixedPosition.fLoopCount - 1;
1491                    } else {
1492                        clientBuffer->mixedPosition.fLoopCount = clientBufferListEnd->mixedPosition.fLoopCount;
1493                    }
1494					audioDebugIOLog(6, "IOAudioStream[%p]::processOutputSamples(%p) - more than one buffer behind (%lx,%lx) adjusting to (%lx,%lx)\n",
1495										this,
1496										clientBuffer,
1497										(long unsigned int)clientBufferListEnd->mixedPosition.fLoopCount,
1498										(long unsigned int)clientBufferListEnd->mixedPosition.fSampleFrame,
1499										(long unsigned int)clientBuffer->mixedPosition.fLoopCount,
1500										(long unsigned int)firstSampleFrame);
1501					//dumpList(clientBufferListStart);
1502                }
1503            }
1504
1505            // If we've already clipped, we need to verify all of the samples are after the clipped position
1506            // Those that are not will be discarded - they can't be played
1507            if (!IOAUDIOENGINEPOSITION_IS_ZERO(&clippedPosition)) {
1508                if (clientBuffer->mixedPosition.fLoopCount == clippedPosition.fLoopCount) {
1509                    if (clientBuffer->mixedPosition.fSampleFrame < clippedPosition.fSampleFrame) {
1510                        audioEngine->resetClipPosition(this, clientBuffer->mixedPosition.fSampleFrame);
1511
1512#ifdef DEBUG
1513                        UInt32 samplesMissed;
1514                        samplesMissed = clippedPosition.fSampleFrame - clientBuffer->mixedPosition.fSampleFrame;
1515                        audioDebugIOLog(6, "IOAudioStream[%p]::processOutputSamples(%p) - Reset clip position (%lx,%lx)->(%lx,%lx) - %lx samples.\n",
1516										this,
1517										clientBuffer,
1518										(long unsigned int)clippedPosition.fLoopCount,
1519										(long unsigned int)clippedPosition.fSampleFrame,
1520										(long unsigned int)clientBuffer->mixedPosition.fLoopCount,
1521										(long unsigned int)clientBuffer->mixedPosition.fSampleFrame,
1522										(long unsigned int)samplesMissed);
1523#endif
1524
1525                        clippedPosition = clientBuffer->mixedPosition;
1526                    }
1527                } else if (clientBuffer->mixedPosition.fLoopCount < clippedPosition.fLoopCount) {
1528                    audioEngine->resetClipPosition(this, clientBuffer->mixedPosition.fSampleFrame);
1529
1530#ifdef DEBUG
1531                    UInt32 samplesMissed;
1532                    samplesMissed = (clippedPosition.fLoopCount - clientBuffer->mixedPosition.fLoopCount - 1) * numSampleFramesPerBuffer;
1533                    samplesMissed += clippedPosition.fSampleFrame + numSampleFramesPerBuffer - clientBuffer->mixedPosition.fSampleFrame;
1534                    audioDebugIOLog(6, "IOAudioStream[%p]::processOutputSamples(%p) - Reset clip position (%lx,%lx)->(%lx,%lx) - %lx samples.\n",
1535										this,
1536										clientBuffer,
1537										(long unsigned int)clippedPosition.fLoopCount,
1538										(long unsigned int)clippedPosition.fSampleFrame,
1539										(long unsigned int)clientBuffer->mixedPosition.fLoopCount,
1540										(long unsigned int)clientBuffer->mixedPosition.fSampleFrame,
1541										(long unsigned int)samplesMissed);
1542#endif
1543
1544                    clippedPosition = clientBuffer->mixedPosition;
1545                }
1546            }
1547
1548            // We only need to mix samples if there are samples available
1549            // If the watchdog timer was responsible for this call, then
1550            // there won't be any samples, so there's no point in mixing
1551            // or resetting the clip position
1552            if (samplesAvailable) {
1553                numSamplesToMix = clientBuffer->numSampleFrames;
1554            }
1555
1556            if (numSamplesToMix > 0) {
1557/*
1558#ifdef DEBUG
1559                UInt32 currentSampleFrame = audioEngine->getCurrentSampleFrame();
1560                if (currentSampleFrame > firstSampleFrame) {
1561                    if ((firstSampleFrame + clientBuffer->numSampleFrames) > currentSampleFrame) {
1562                        //audioDebugIOLog(6, "IOAudioStream[%p]::processOutputSamples(%p) - Error: Some samples already played: first=%lx num=%lx curr=%lx\n", this, clientBuffer, firstSampleFrame, clientBuffer->numSampleFrames, currentSampleFrame);
1563                        audioDebugIOLog(6, "mix() missed first=%lx num=%lx curr=%lx\n", firstSampleFrame, clientBuffer->numSampleFrames, currentSampleFrame);
1564                    }
1565                } else {
1566                    if ((clientBuffer->numSampleFrames + firstSampleFrame) > (currentSampleFrame + numSampleFramesPerBuffer)) {
1567                        //audioDebugIOLog(6, "IOAudioStream[%p]::processOutputSamples(%p) - Error: Some samples already played: first=%lx num=%lx curr=%lx\n", this, clientBuffer, firstSampleFrame, clientBuffer->numSampleFrames, currentSampleFrame);
1568                        audioDebugIOLog(6, "mix() missed first=%lx num=%lx curr=%lx\n", firstSampleFrame, clientBuffer->numSampleFrames, currentSampleFrame);
1569                    }
1570                }
1571#endif
1572*/
1573
1574				// Check if the buffer wraps
1575				if (numSampleFramesPerBuffer > (firstSampleFrame + numSamplesToMix)) {	// No wrap
1576					if (format.fIsMixable) {
1577						if (numClients == 1) {
1578							result = mixOutputSamples (clientBuffer->sourceBuffer, mixBuffer, firstSampleFrame, numSamplesToMix, &format, this);
1579						} else {
1580							result = audioEngine->mixOutputSamples(clientBuffer->sourceBuffer, mixBuffer, firstSampleFrame, numSamplesToMix, &format, this);
1581						}
1582					} else {
1583						result = kIOReturnSuccess;
1584					}
1585					nextSampleFrame = firstSampleFrame + numSamplesToMix;
1586				} else {	// Buffer wraps around
1587					mixBufferWrapped = true;
1588					if (format.fIsMixable) {
1589						if (numClients == 1) {
1590							result = mixOutputSamples (clientBuffer->sourceBuffer, mixBuffer, firstSampleFrame, numSampleFramesPerBuffer - firstSampleFrame, &format, this);
1591						} else {
1592							result = audioEngine->mixOutputSamples(clientBuffer->sourceBuffer, mixBuffer, firstSampleFrame, numSampleFramesPerBuffer - firstSampleFrame, &format, this);
1593						}
1594					} else {
1595						result = kIOReturnSuccess;
1596					}
1597					if (result != kIOReturnSuccess) {
1598						IOLog("IOAudioStream[%p]::processOutputSamples(%p) - Error: 0x%x returned from audioEngine->mixOutputSamples(%p, %p, 0x%lx, 0x%lx, %p, %p)\n", this, clientBuffer, result, clientBuffer->sourceBuffer, mixBuffer, (long unsigned int)firstSampleFrame,(long unsigned int) numSampleFramesPerBuffer - firstSampleFrame, &format, this);
1599					}
1600					nextSampleFrame = numSamplesToMix - (numSampleFramesPerBuffer - firstSampleFrame);
1601					if (format.fIsMixable) {
1602						if (numClients == 1) {
1603							result = mixOutputSamples (((float *)clientBuffer->sourceBuffer) + ((numSampleFramesPerBuffer - firstSampleFrame) * format.fNumChannels), mixBuffer, 0, nextSampleFrame, &format, this);
1604						} else {
1605							result = audioEngine->mixOutputSamples(((float *)clientBuffer->sourceBuffer) + ((numSampleFramesPerBuffer - firstSampleFrame) * format.fNumChannels), mixBuffer, 0, nextSampleFrame, &format, this);
1606						}
1607					} else {
1608						result = kIOReturnSuccess;
1609					}
1610				}
1611
1612                if (result == kIOReturnSuccess) {
1613                    // Reset startingSampleFrame and startingLoopCount if we haven't clipped
1614                    // anything yet and this buffer mixed samples before the previous
1615                    // starting frame
1616                    if (IOAUDIOENGINEPOSITION_IS_ZERO(&clippedPosition)) {
1617                        if (IOAUDIOENGINEPOSITION_IS_ZERO(&startingPosition) ||
1618                            (clientBuffer->mixedPosition.fLoopCount < startingPosition.fLoopCount) ||
1619                            ((clientBuffer->mixedPosition.fLoopCount == startingPosition.fLoopCount) && (firstSampleFrame < startingPosition.fSampleFrame))) {
1620
1621                            startingPosition.fLoopCount = clientBuffer->mixedPosition.fLoopCount;
1622                            startingPosition.fSampleFrame = firstSampleFrame;
1623                        }
1624                    }
1625                } else {
1626                    IOLog("IOAudioStream[%p]::processOutputSamples(%p) - Error: 0x%lx returned from audioEngine->mixOutputSamples(%p, %p, 0x%lx, 0x%lx, %p, %p)\n", this, clientBuffer, (long unsigned int)result, clientBuffer->sourceBuffer, mixBuffer, (long unsigned int)firstSampleFrame,(long unsigned int) numSampleFramesPerBuffer - firstSampleFrame, &format, this);
1627                }
1628
1629                if (mixBufferWrapped) {
1630                    clientBuffer->mixedPosition.fLoopCount++;
1631                }
1632                clientBuffer->mixedPosition.fSampleFrame = nextSampleFrame;
1633
1634            } else {	// We missed all of the samples
1635                clientBuffer->mixedPosition.fSampleFrame += clientBuffer->numSampleFrames;
1636                if (clientBuffer->mixedPosition.fSampleFrame >= numSampleFramesPerBuffer) {
1637                    clientBuffer->mixedPosition.fSampleFrame -= numSampleFramesPerBuffer;
1638                    clientBuffer->mixedPosition.fLoopCount++;
1639                }
1640            }
1641
1642            // If this buffer isn't in the list yet, then we look at the beginning of the list
1643            if ((clientBuffer->nextClip == NULL) && (clientBuffer->previousClip == NULL) && (clientBuffer != clientBufferListStart)) {
1644                // If the buffer has mixed past the first buffer in the list, then we can start at the beginning
1645                // If not, then tmpBuf is just NULL and we insert at the beginning
1646                if ((clientBufferListStart != NULL) && (CMP_IOAUDIOENGINEPOSITION(&clientBuffer->mixedPosition, &clientBufferListStart->mixedPosition) > 0)) {
1647                    tmpBuf = clientBufferListStart;
1648                }
1649            } else { // Otherwise, we look forward from the current position
1650                tmpBuf = clientBuffer;
1651            }
1652
1653            // Add it to the beginning if the buffer is new and has not mixed past any other buffers
1654            if (tmpBuf == NULL) {
1655                assert(clientBuffer->nextClip == NULL);
1656                assert(clientBuffer->previousClip == NULL);
1657
1658                clientBuffer->nextClip = clientBufferListStart;
1659                clientBufferListStart = clientBuffer;
1660
1661                if (clientBuffer->nextClip == NULL) {
1662                    clientBufferListEnd = clientBuffer;
1663                } else {
1664                    clientBuffer->nextClip->previousClip = clientBuffer;
1665                }
1666            } else {
1667                //Find the insertion point for the new location for this buffer
1668                while ((tmpBuf->nextClip != NULL) && (CMP_IOAUDIOENGINEPOSITION(&clientBuffer->mixedPosition, &tmpBuf->nextClip->mixedPosition) > 0)) {
1669                    tmpBuf = tmpBuf->nextClip;
1670                }
1671
1672                if (tmpBuf != clientBuffer) {
1673                    // If the buffer is to change position, move updated client buffer to its new sorted position
1674                    // First remove the client buffer from its current position
1675                    if (clientBuffer->previousClip != NULL) {
1676                        clientBuffer->previousClip->nextClip = clientBuffer->nextClip;
1677                    } else if (clientBuffer == clientBufferListStart) {	// If we don't have a previous clip set, we may be the starting entry
1678                        clientBufferListStart = clientBuffer->nextClip;
1679                    } // If we have don't have a previousClip set and are not the start, then this is the first time this buffer is being mixed
1680
1681                    if (clientBuffer->nextClip != NULL) {
1682                        clientBuffer->nextClip->previousClip = clientBuffer->previousClip;
1683                    } else if (clientBuffer == clientBufferListEnd) {	// If we don't have a next clip set, we may be the last entry
1684                        // We should never get here, because we only are moving this buffer forward
1685                        // and that is impossible if it is the last one
1686                        clientBufferListEnd = clientBuffer->previousClip;
1687                    } // If we don't have a next clip and are not the end, then this is the first time this buffer is being mixed
1688
1689                    // Insert it after tmpBuf
1690                    clientBuffer->nextClip = tmpBuf->nextClip;
1691                    clientBuffer->previousClip= tmpBuf;
1692                    tmpBuf->nextClip = clientBuffer;
1693                    if (clientBuffer->nextClip) {
1694                        clientBuffer->nextClip->previousClip = clientBuffer;
1695                    }
1696                    if (clientBuffer->nextClip == NULL) {
1697                        assert(clientBufferListEnd == tmpBuf);
1698                        clientBufferListEnd = clientBuffer;
1699                    }
1700
1701#ifdef DEBUG
1702                    validateList(clientBufferListStart);
1703#endif
1704                }
1705            }
1706
1707            // We should attempt to clip if we mixed some samples of if we
1708            // were called as a result of the watchdog timer (indicated
1709            // by samplesAvailable being false)
1710            if ((numSamplesToMix > 0) || !samplesAvailable) {
1711				if (!format.fIsMixable) {
1712					mixBuffer = clientBuffer->sourceBuffer;
1713				}
1714
1715				reserved->mClipOutputStatus = kIOReturnSuccess;
1716
1717				clipIfNecessary();
1718				if (!format.fIsMixable) {
1719					mixBuffer = NULL;
1720				}
1721
1722				// gets set based on IOAudioEngine::clipOutputSamples return value inside IOAudioStream::clipOutputSamples
1723				result = reserved->mClipOutputStatus;
1724            }
1725        } else {
1726            IOLog("IOAudioStream[%p]::processOutputSamples(%p) - Internal Error: No mix buffer\n", this, clientBuffer);
1727            result = kIOReturnError;
1728        }
1729    } else {
1730        result = kIOReturnBadArgument;
1731    }
1732
1733    return result;
1734}
1735
1736void IOAudioStream::resetClipInfo()
1737{
1738    startingPosition.fLoopCount = 0;
1739    startingPosition.fSampleFrame = 0;
1740    clippedPosition.fLoopCount = 0;
1741    clippedPosition.fSampleFrame = 0;
1742}
1743
1744void IOAudioStream::clipIfNecessary()
1745{
1746    //audioDebugIOLog(6, "IOAudioStream[%p]::clipIfNecessary()\n", this);
1747
1748    if (clientBufferListStart != NULL) {
1749        // Only try to clip if there is not an unmixed buffer
1750        if (!IOAUDIOENGINEPOSITION_IS_ZERO(&clientBufferListStart->mixedPosition)) {
1751
1752            // Check to see if we've clipped any samples yet
1753            if (IOAUDIOENGINEPOSITION_IS_ZERO(&clippedPosition)) {
1754                clippedPosition = startingPosition;
1755            }
1756
1757#ifdef DEBUG
1758            IOAudioClientBuffer *tmp;
1759
1760            tmp = clientBufferListStart->nextClip;
1761            while (tmp) {
1762                if ((tmp->mixedPosition.fLoopCount > (clippedPosition.fLoopCount + 1)) ||
1763                    ((tmp->mixedPosition.fLoopCount == clippedPosition.fLoopCount) &&
1764                     (tmp->mixedPosition.fSampleFrame > clippedPosition.fSampleFrame))) {
1765
1766                    if (clientBufferListStart->mixedPosition.fSampleFrame > clippedPosition.fSampleFrame) {
1767                        if ((tmp->mixedPosition.fSampleFrame > clippedPosition.fSampleFrame) &&
1768                            (clientBufferListStart->mixedPosition.fSampleFrame > tmp->mixedPosition.fSampleFrame)) {
1769                            audioDebugIOLog(6, "IOAudioStream[%p]::clipIfNecessary() - Error: Clipping across future buffer boundary - glitching! (%lx,%lx)->(%lx,%lx) buf=(%lx,%lx)\n",
1770											this,
1771											(long unsigned int)clippedPosition.fLoopCount,
1772											(long unsigned int)clippedPosition.fSampleFrame,
1773											(long unsigned int)clientBufferListStart->mixedPosition.fLoopCount,
1774											(long unsigned int)clientBufferListStart->mixedPosition.fSampleFrame,
1775											(long unsigned int)tmp->mixedPosition.fLoopCount,
1776											(long unsigned int)tmp->mixedPosition.fSampleFrame);
1777                            dumpList(clientBufferListStart);
1778                            break;
1779                        }
1780                    } else if (clippedPosition.fSampleFrame > clientBufferListStart->mixedPosition.fSampleFrame) {
1781                        if ((tmp->mixedPosition.fSampleFrame < clientBufferListStart->mixedPosition.fSampleFrame) ||
1782                            (tmp->mixedPosition.fSampleFrame > clippedPosition.fSampleFrame)) {
1783                            audioDebugIOLog(6, "IOAudioStream[%p]::clipIfNecessary() - Error: Clipping across future buffer boundary - glitching! (%lx,%lx)->(%lx,%lx) buf=(%lx,%lx)\n",
1784											this,
1785											(long unsigned int)clippedPosition.fLoopCount,
1786											(long unsigned int)clippedPosition.fSampleFrame,
1787											(long unsigned int)clientBufferListStart->mixedPosition.fLoopCount,
1788											(long unsigned int)clientBufferListStart->mixedPosition.fSampleFrame,
1789											(long unsigned int)tmp->mixedPosition.fLoopCount,
1790											(long unsigned int)tmp->mixedPosition.fSampleFrame);
1791                            dumpList(clientBufferListStart);
1792                            break;
1793                        }
1794                    }
1795                }
1796                tmp = tmp->nextClip;
1797            }
1798#endif
1799
1800            // Check to see if it is on the same loop as the starting position
1801            // If not, adjust it to the same loop
1802            if (((clientBufferListStart->mixedPosition.fLoopCount == (clippedPosition.fLoopCount + 1)) &&
1803                 (clientBufferListStart->mixedPosition.fSampleFrame >= clippedPosition.fSampleFrame)) ||
1804                (clientBufferListStart->mixedPosition.fLoopCount > (clippedPosition.fLoopCount + 1))) {
1805                IOLog("IOAudioStream[%p]::clipIfNecessary() - Error: attempting to clip to a position more than one buffer ahead of last clip position (%lx,%lx)->(%lx,%lx).\n", this, (long unsigned int)clippedPosition.fLoopCount, (long unsigned int)clippedPosition.fSampleFrame, (long unsigned int) clientBufferListStart->mixedPosition.fLoopCount,(long unsigned int) clientBufferListStart->mixedPosition.fSampleFrame);
1806                if (clientBufferListStart->mixedPosition.fSampleFrame >= clippedPosition.fSampleFrame) {
1807                    clippedPosition.fLoopCount = clientBufferListStart->mixedPosition.fLoopCount;
1808                } else {
1809                    clippedPosition.fLoopCount = clientBufferListStart->mixedPosition.fLoopCount - 1;
1810                }
1811                IOLog("IOAudioStream[%p]::clipIfNecessary() - adjusting clipped position to (%lx,%lx)\n", this, (long unsigned int) clippedPosition.fLoopCount,(long unsigned int) clippedPosition.fSampleFrame);
1812            }
1813
1814			// Add a test to see if we'd be clipping more samples than delivered because the HAL might skip some samples around a loop increment
1815			// If the HAL skipped samples around a loop increment, then just start from where it wants to
1816			if (clientBufferListStart->mixedPosition.fLoopCount + 1 == clippedPosition.fLoopCount && (clientBufferListStart->numSampleFrames < audioEngine->getNumSampleFramesPerBuffer() - clippedPosition.fSampleFrame)) {
1817				clientBufferListStart->mixedPosition.fLoopCount = clippedPosition.fLoopCount;
1818				IOLog ("clip position is off %ld < %ld - %ld \n",(long int) clientBufferListStart->numSampleFrames,(long int) audioEngine->getNumSampleFramesPerBuffer(),(long int) clippedPosition.fSampleFrame);
1819			}
1820/*
1821	static UInt32 lastSampleFrame;
1822	if (clippedPosition.fSampleFrame != lastSampleFrame) {
1823		audioDebugIOLog(3, "Family sample frames wrong %ld %ld\n", clippedPosition.fSampleFrame, lastSampleFrame);
1824	}
1825	lastSampleFrame = clippedPosition.fSampleFrame + (clientBufferListStart->mixedPosition.fSampleFrame - clippedPosition.fSampleFrame);
1826*/
1827			UInt32 numSamplesToClip;				//<rdar://problem/5994776>
1828
1829			if (clientBufferListStart->mixedPosition.fLoopCount == clippedPosition.fLoopCount) {
1830                if (clientBufferListStart->mixedPosition.fSampleFrame > clippedPosition.fSampleFrame)  {
1831					 numSamplesToClip = clientBufferListStart->mixedPosition.fSampleFrame - clippedPosition.fSampleFrame;
1832					if (!format.fIsMixable) {
1833						if ( numSamplesToClip <= kMixBufferMaxSize ) { 	// <rdar://problem/5994776>
1834							clipOutputSamples(clippedPosition.fSampleFrame, numSamplesToClip );
1835						} else {
1836							reserved->mClipOutputStatus = kIOReturnOverrun;
1837#ifdef DEBUG
1838							audioDebugIOLog(6,"IOAudioStream[%p]::clipIfNecessary() clipOutputSamples clip too large for source buffer numSamplesToClip=%lu clientBufferListStart->numSampleFrames %lu\n",
1839											this, (long unsigned int)numSamplesToClip, (long unsigned int)clientBufferListStart->numSampleFrames );
1840							IOLog("IOAudioStream[%p]::clipIfNecessary() clipOutputSamples clip too large for source buffer numSamplesToClip=%lu clientBufferListStart->numSampleFrames %lu\n",
1841											this, (long unsigned int)numSamplesToClip, (long unsigned int)clientBufferListStart->numSampleFrames );
1842#endif
1843						}
1844					} else {
1845						clipOutputSamples(clippedPosition.fSampleFrame, numSamplesToClip);
1846					}
1847                    clippedPosition.fSampleFrame = clientBufferListStart->mixedPosition.fSampleFrame;
1848                } else if (clientBufferListStart->mixedPosition.fSampleFrame < clippedPosition.fSampleFrame) {
1849                    IOLog("IOAudioStream[%p]::clipIfNecessary() - Error: already clipped to a position (0x%lx,0x%lx) past data to be clipped (0x%lx, 0x%lx) - data ignored.\n", this,(long unsigned int) clippedPosition.fLoopCount,(long unsigned int) clippedPosition.fSampleFrame,(long unsigned int) clientBufferListStart->mixedPosition.fLoopCount,(long unsigned int) clientBufferListStart->mixedPosition.fSampleFrame);
1850                    //clippedPosition.fSampleFrame = clientBufferListStart->mixedPosition.fSampleFrame;
1851                }
1852            } else {	// Clip wraps around
1853                UInt32 numSampleFramesPerBuffer;
1854
1855                assert(audioEngine);
1856
1857                numSampleFramesPerBuffer = audioEngine->getNumSampleFramesPerBuffer();
1858				numSamplesToClip = numSampleFramesPerBuffer - clippedPosition.fSampleFrame;
1859
1860				if (!format.fIsMixable) {
1861					if ( numSamplesToClip <= kMixBufferMaxSize) { // <rdar://problem/5994776>
1862						clipOutputSamples(clippedPosition.fSampleFrame, numSamplesToClip );
1863					} else {
1864						reserved->mClipOutputStatus = kIOReturnOverrun;
1865#ifdef DEBUG
1866						audioDebugIOLog(6,"IOAudioStream[%p]::clipIfNecessary() clipOutputSamples wrap clip too large for source buffer numSamplesToClip=%lu clientBufferListStart->numSampleFrames %lu\n",
1867									this, (long unsigned int)numSamplesToClip, (long unsigned int)clientBufferListStart->numSampleFrames );
1868						IOLog("IOAudioStream[%p]::clipIfNecessary() clipOutputSamples wrap clip too large for source buffer numSamplesToClip=%lu clientBufferListStart->numSampleFrames %lu\n",
1869									this, (long unsigned int)numSamplesToClip, (long unsigned int)clientBufferListStart->numSampleFrames );
1870#endif
1871					}
1872				} else {
1873					clipOutputSamples(clippedPosition.fSampleFrame, numSamplesToClip );
1874				}
1875
1876				if (!format.fIsMixable) {
1877					UInt32 remainingSamplesToClip = (numSampleFramesPerBuffer - clippedPosition.fSampleFrame);		//<rdar://problem/5994776>
1878
1879					// Move the mix buffer to where we left off because the clip routine always starts at the beginning of the source buffer,
1880					// but that's not the right place when we don't have a source buffer and are using the mixbuffer as a pseduo-source buffer.
1881					audioDebugIOLog(6,"IOAudioStream[%p]::clipIfNecessary() clipOutputSamples wrap  mixBuffer=%p remainingSamplesToClip=0x%lu clientBufferListStart->mixedPosition.fSampleFrame=%lu\n",
1882									this, mixBuffer, (long unsigned int)remainingSamplesToClip, (long unsigned int)clientBufferListStart->mixedPosition.fSampleFrame );
1883					if ( remainingSamplesToClip + clientBufferListStart->mixedPosition.fSampleFrame <= kMixBufferMaxSize) // <rdar://problem/5994776>
1884					{
1885						mixBuffer = (char *)mixBuffer + (remainingSamplesToClip * format.fNumChannels * (format.fBitWidth / 8));
1886						clipOutputSamples(0, clientBufferListStart->mixedPosition.fSampleFrame);
1887					} else {
1888						reserved->mClipOutputStatus = kIOReturnOverrun;
1889#ifdef DEBUG
1890						audioDebugIOLog(6,"IOAudioStream[%p]::clipIfNecessary() clipOutputSamples mixBufferOffset  too large for source buffer numSamplesToClip=%lu clientBufferListStart->numSampleFrames=%lu remainingSamplesToClip=%lu\n",
1891									this, (long unsigned int)clientBufferListStart->mixedPosition.fSampleFrame, (long unsigned int)clientBufferListStart->numSampleFrames, (long unsigned int)remainingSamplesToClip );
1892						IOLog("IOAudioStream[%p]::clipIfNecessary() clipOutputSamples mixBufferOffset  too large for source buffer numSamplesToClip=%lu clientBufferListStart->numSampleFrames=%lu remainingSamplesToClip=%lu\n",
1893									this, (long unsigned int)clientBufferListStart->mixedPosition.fSampleFrame, (long unsigned int)clientBufferListStart->numSampleFrames, (long unsigned int)remainingSamplesToClip );
1894#endif
1895					}
1896				} else {
1897					clipOutputSamples(0, clientBufferListStart->mixedPosition.fSampleFrame);
1898				}
1899                clippedPosition = clientBufferListStart->mixedPosition;
1900            }
1901        }
1902    }
1903}
1904
1905void IOAudioStream::clipOutputSamples(UInt32 firstSampleFrame, UInt32 numSampleFrames)
1906{
1907    IOReturn result = kIOReturnSuccess;
1908
1909    //audioDebugIOLog(6, "IOAudioStream[%p]::clipOutputSamples(0x%lx, 0x%lx)\n", this, firstSampleFrame, numSampleFrames);
1910    //audioDebugIOLog(6, "c(%lx,%lx) %lx\n", firstSampleFrame, numSampleFrames, audioEngine->getCurrentSampleFrame());
1911
1912    assert(direction == kIOAudioStreamDirectionOutput);
1913    assert(audioEngine);
1914    assert(reserved);
1915
1916    if (!mixBuffer || !sampleBuffer) {
1917        IOLog("IOAudioStream[%p]::clipOutputSamples(0x%lx, 0x%lx) - Internal Error: mixBuffer = %p - sampleBuffer = %p\n", this ,(long unsigned int) firstSampleFrame,(long unsigned int) numSampleFrames, mixBuffer, sampleBuffer);
1918        return;
1919    }
1920
1921/*
1922#ifdef DEBUG
1923    UInt32 currentSampleFrame = audioEngine->getCurrentSampleFrame();
1924
1925    if (currentSampleFrame > firstSampleFrame) {
1926        if ((firstSampleFrame + numSampleFrames) > currentSampleFrame) {
1927            //audioDebugIOLog(6, "IOAudioStream[%p]::clipOutputSamples(0x%lx, 0x%lx) - too late for some samples - current position = 0x%lx.\n", this, firstSampleFrame, numSampleFrames, currentSampleFrame);
1928            audioDebugIOLog(6, "clip(%lx,%lx) missed curr=%lx.\n", firstSampleFrame, numSampleFrames, currentSampleFrame);
1929        }
1930    } else {
1931        if ((numSampleFrames + firstSampleFrame) > (currentSampleFrame + audioEngine->getNumSampleFramesPerBuffer())) {
1932            //audioDebugIOLog(6, "IOAudioStream[%p]::clipOutputSamples(0x%lx, 0x%lx) - too late for some samples - current position = 0x%lx.\n", this, firstSampleFrame, numSampleFrames, currentSampleFrame);
1933            audioDebugIOLog(6, "clip(%lx,%lx) missed curr=%lx.\n", firstSampleFrame, numSampleFrames, currentSampleFrame);
1934        }
1935    }
1936#endif
1937*/
1938
1939    if (audioIOFunctions && (numIOFunctions != 0)) {
1940        UInt32 functionNum;
1941
1942        for (functionNum = 0; functionNum < numIOFunctions; functionNum++) {
1943            if (audioIOFunctions[functionNum]) {
1944                result = audioIOFunctions[functionNum](mixBuffer, sampleBuffer, firstSampleFrame, numSampleFrames, &format, this);
1945                if (result != kIOReturnSuccess) {
1946                    break;
1947                }
1948            }
1949        }
1950    } else {
1951        result = audioEngine->clipOutputSamples(mixBuffer, sampleBuffer, firstSampleFrame, numSampleFrames, &format, this);
1952    }
1953
1954    if (result != kIOReturnSuccess) {
1955        IOLog("IOAudioStream[%p]::clipOutputSamples(0x%lx, 0x%lx) - clipping function returned error: 0x%x\n", this,(long unsigned int) firstSampleFrame,(long unsigned int) numSampleFrames, result);
1956    }
1957	reserved->mClipOutputStatus = result;
1958}
1959
1960void IOAudioStream::lockStreamForIO()
1961{
1962    assert(streamIOLock);
1963
1964    IORecursiveLockLock(streamIOLock);
1965}
1966
1967void IOAudioStream::unlockStreamForIO()
1968{
1969    assert(streamIOLock);
1970
1971    IORecursiveLockUnlock(streamIOLock);
1972}
1973
1974void IOAudioStream::setStreamAvailable(bool available)
1975{
1976    if (streamAvailable != available) {
1977        streamAvailable = available;
1978        setProperty(kIOAudioStreamAvailableKey, available ? 1 : 0, sizeof(UInt8)*8);
1979
1980        assert(audioEngine);
1981        audioEngine->updateChannelNumbers();
1982    }
1983}
1984
1985bool IOAudioStream::getStreamAvailable()
1986{
1987    return streamAvailable;
1988}
1989
1990IOReturn IOAudioStream::addDefaultAudioControl(IOAudioControl *defaultAudioControl)
1991{
1992    IOReturn result = kIOReturnBadArgument;
1993
1994    if (defaultAudioControl) {
1995        UInt32 controlChannelID;
1996
1997        if (defaultAudioControl->getChannelID() == kIOAudioControlChannelIDAll) {
1998            if (((getDirection() == kIOAudioStreamDirectionOutput) && (defaultAudioControl->getUsage() == kIOAudioControlUsageInput)) ||
1999                ((getDirection() == kIOAudioStreamDirectionInput) && (defaultAudioControl->getUsage() == kIOAudioControlUsageOutput))) {
2000                result = kIOReturnError;
2001                IOLog("IOAudioStream[%p]::addDefaultAudioControl() - Error: invalid audio control - stream direction is opposite of control usage.\n", this);
2002                goto Done;
2003            }
2004
2005            controlChannelID = defaultAudioControl->getChannelID();
2006
2007            if ((controlChannelID != 0) && ((controlChannelID < startingChannelID) || (controlChannelID >= (startingChannelID + maxNumChannels)))) {
2008                result = kIOReturnError;
2009                IOLog("IOAudioStream[%p]::addDefaultAudioControl() - Error: audio control channel is not in this stream.\n", this);
2010                goto Done;
2011            }
2012
2013            if (defaultAudioControl->attachAndStart(this)) {
2014                if (!defaultAudioControls) {
2015                    defaultAudioControls = OSSet::withObjects((const OSObject **)&defaultAudioControl, 1, 1);
2016                } else {
2017                    defaultAudioControls->setObject(defaultAudioControl);
2018                }
2019            } else {
2020                result = kIOReturnError;
2021            }
2022        } else {	// Control for an individual channel - attach to audio engine instead
2023            assert(audioEngine);
2024            result = audioEngine->addDefaultAudioControl(defaultAudioControl);
2025        }
2026    }
2027
2028Done:
2029
2030    return result;
2031}
2032
2033void IOAudioStream::removeDefaultAudioControls()
2034{
2035    if (defaultAudioControls) {
2036        if (!isInactive()) {
2037            OSCollectionIterator *controlIterator;
2038
2039            controlIterator = OSCollectionIterator::withCollection(defaultAudioControls);
2040
2041            if (controlIterator) {
2042                IOAudioControl *control;
2043
2044                while ( (control = (IOAudioControl *)controlIterator->getNextObject()) ) {
2045                    if (control->getProvider() == this) {
2046                        control->terminate();
2047                    } else {
2048                        control->detach(this);
2049                    }
2050                }
2051
2052                controlIterator->release();
2053            }
2054        }
2055
2056        defaultAudioControls->flushCollection();
2057    }
2058}
2059