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