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