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