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 "IOAudioEngineUserClient.h" 25#include "IOAudioEngine.h" 26#include "IOAudioTypes.h" 27#include "IOAudioStream.h" 28#include "IOAudioDebug.h" 29#include "IOAudioDefines.h" 30 31#include <IOKit/IOLib.h> 32#include <IOKit/IOMemoryDescriptor.h> 33#include <IOKit/IOWorkLoop.h> 34#include <IOKit/IOCommandGate.h> 35#include <IOKit/IOKitKeys.h> 36 37// <rdar://8518215> 38enum 39{ 40 kCommandGateStatus_Normal = 0, 41 kCommandGateStatus_RemovalPending, 42 kCommandGateStatus_Invalid 43}; 44 45// <rdar://15277619> 46enum 47{ 48 kLoopCountMaximumDifference = 5 49}; 50 51#define super OSObject 52 53class IOAudioClientBufferSet : public OSObject 54{ 55 OSDeclareDefaultStructors(IOAudioClientBufferSet); 56 57public: 58 UInt32 bufferSetID; 59 IOAudioEngineUserClient * userClient; 60 IOAudioClientBuffer64 * outputBufferList; 61 IOAudioClientBuffer64 * inputBufferList; 62 IOAudioEnginePosition nextOutputPosition; 63 AbsoluteTime outputTimeout; 64 AbsoluteTime sampleInterval; 65 IOAudioClientBufferSet * mNextBufferSet; 66 thread_call_t watchdogThreadCall; 67 UInt32 generationCount; 68 bool timerPending; 69 70 bool init(UInt32 setID, IOAudioEngineUserClient *client); 71 void free(); 72 73#ifdef DEBUG 74 void retain() const; 75 void release() const; 76#endif 77 78 void resetNextOutputPosition(); 79 80 void allocateWatchdogTimer(); 81 void freeWatchdogTimer(); 82 83 void setWatchdogTimeout(AbsoluteTime *timeout); 84 void cancelWatchdogTimer(); 85 86 static void watchdogTimerFired(IOAudioClientBufferSet *clientBufferSet, UInt32 generationCount); 87}; 88 89OSDefineMetaClassAndStructors(IOAudioClientBufferSet, OSObject) 90 91// <rdar://8121989> Restructured for single point of entry and single point of exit so that 92// the indentifier post processing tool can properly insert scope when post processing a log file 93// obtained via fwkpfv. 94 95bool IOAudioClientBufferSet::init(UInt32 setID, IOAudioEngineUserClient *client) 96{ 97 bool result = false; 98 99 audioDebugIOLog(3, "+ IOAudioClientBufferSet[%p]::init(%lx, %p)\n", this, (long unsigned int)setID, client); 100 101 if ( super::init () ) 102 { 103 if ( 0 != client ) 104 { 105 bufferSetID = setID; 106 client->retain(); 107 userClient = client; 108 109 outputBufferList = NULL; 110 inputBufferList = NULL; 111 mNextBufferSet = NULL; 112 watchdogThreadCall = NULL; 113 generationCount = 0; 114 timerPending = false; 115 116 resetNextOutputPosition(); 117 result = true; 118 } 119 } 120 121 audioDebugIOLog(3, "- IOAudioClientBufferSet[%p]::init(%lx, %p) returns %d\n", this, (long unsigned int)setID, client, result ); 122 return result; 123} 124 125void IOAudioClientBufferSet::free() 126{ 127 audioDebugIOLog(3, "+ IOAudioClientBufferSet[%p]::free()\n", this); 128 129 if (watchdogThreadCall) { 130 freeWatchdogTimer(); 131 } 132 133 if (userClient != NULL) { 134 userClient->release(); 135 userClient = NULL; 136 } 137 138 super::free(); 139 140 audioDebugIOLog(3, "- IOAudioClientBufferSet[%p]::free()\n", this); 141 return; 142} 143 144#ifdef DEBUG 145void IOAudioClientBufferSet::retain() const 146{ 147 super::retain(); 148} 149 150void IOAudioClientBufferSet::release() const 151{ 152 super::release(); 153} 154#endif 155 156void IOAudioClientBufferSet::resetNextOutputPosition() 157{ 158 nextOutputPosition.fLoopCount = 0; 159 nextOutputPosition.fSampleFrame = 0; 160} 161 162void IOAudioClientBufferSet::allocateWatchdogTimer() 163{ 164 audioDebugIOLog(3, "+ IOAudioClientBufferSet[%p]::allocateWatchdogTimer()\n", this); 165 166 if (watchdogThreadCall == NULL) { 167 watchdogThreadCall = thread_call_allocate((thread_call_func_t)IOAudioClientBufferSet::watchdogTimerFired, (thread_call_param_t)this); 168 } 169 170 audioDebugIOLog(3, "- IOAudioClientBufferSet[%p]::allocateWatchdogTimer()\n", this); 171 return; 172} 173 174void IOAudioClientBufferSet::freeWatchdogTimer() 175{ 176 audioDebugIOLog(3, "+ IOAudioClientBufferSet[%p]::freeWatchdogTimer()\n", this); 177 178 if (watchdogThreadCall != NULL) { 179 cancelWatchdogTimer(); 180 thread_call_free(watchdogThreadCall); 181 watchdogThreadCall = NULL; 182 } 183 184 audioDebugIOLog(3, "- IOAudioClientBufferSet[%p]::freeWatchdogTimer()\n", this); 185 return; 186} 187 188void IOAudioClientBufferSet::setWatchdogTimeout(AbsoluteTime *timeout) 189{ 190 bool result; 191 192 if (watchdogThreadCall == NULL) { 193 // allocate it here 194 IOLog("IOAudioClientBufferSet[%p]::setWatchdogTimeout() - no thread call.\n", this); 195 } 196 197 assert(watchdogThreadCall); 198 199 outputTimeout = *timeout; 200 201 generationCount++; 202 203 userClient->lockBuffers(); 204 205 retain(); 206 207 timerPending = true; 208 209 result = thread_call_enter1_delayed(watchdogThreadCall, (thread_call_param_t)(uintptr_t)generationCount, outputTimeout); 210 if (result) { 211 release(); // canceled the previous call 212 } 213 214 userClient->unlockBuffers(); 215} 216 217void IOAudioClientBufferSet::cancelWatchdogTimer() 218{ 219 audioDebugIOLog(3, "+ IOAudioClientBufferSet[%p]::cancelWatchdogTimer()\n", this); 220 221 if (NULL != userClient) { 222 userClient->retain(); 223 userClient->lockBuffers(); 224 if (timerPending) { 225 timerPending = false; 226 if (thread_call_cancel(watchdogThreadCall)) 227 release(); 228 } 229 userClient->unlockBuffers(); 230 userClient->release(); 231 } 232 233 audioDebugIOLog(3, "- IOAudioClientBufferSet[%p]::cancelWatchdogTimer()\n", this); 234 return; 235} 236 237void IOAudioClientBufferSet::watchdogTimerFired(IOAudioClientBufferSet *clientBufferSet, UInt32 generationCount) 238{ 239 IOAudioEngineUserClient *userClient; 240 241 assert(clientBufferSet); 242 assert(clientBufferSet->userClient); 243 244 if (clientBufferSet) { 245#ifdef DEBUG 246 AbsoluteTime now; 247 clock_get_uptime(&now); 248 249#ifdef __LP64__ 250 audioDebugIOLog(3, "+ IOAudioClientBufferSet[%p]::watchdogTimerFired(%ld):(%llu)(%llu)(%lx,%lx)\n", 251 clientBufferSet, 252 (long int)generationCount, 253 now, 254 clientBufferSet->outputTimeout, 255 (long unsigned int)clientBufferSet->nextOutputPosition.fLoopCount, 256 (long unsigned int)clientBufferSet->nextOutputPosition.fSampleFrame); 257#else /* __LP64__ */ 258 audioDebugIOLog(3, "+ IOAudioClientBufferSet[%p]::watchdogTimerFired(%ld):(%lx,%lx)(%lx,%lx)(%lx,%lx)\n", 259 clientBufferSet, 260 (long int)generationCount, 261 now.hi, 262 now.lo, 263 clientBufferSet->outputTimeout.hi, 264 clientBufferSet->outputTimeout.lo, 265 clientBufferSet->nextOutputPosition.fLoopCount, 266 clientBufferSet->nextOutputPosition.fSampleFrame); 267#endif /* __LP64__ */ 268 269#endif /* DEBUG */ 270 271 userClient = clientBufferSet->userClient; 272 if (userClient) { 273 userClient->retain(); 274 userClient->lockBuffers(); 275 276 if(clientBufferSet->timerPending != false) { 277 userClient->performWatchdogOutput(clientBufferSet, generationCount); 278 } 279 280 clientBufferSet->release(); 281 282 userClient->unlockBuffers(); 283 userClient->release(); 284 } 285 286 // clientBufferSet->release code was down here... 287 288#ifdef DEBUG 289#ifdef __LP64__ 290 audioDebugIOLog(3, "- IOAudioClientBufferSet[%p]::watchdogTimerFired(%ld):(%llu)(%llu)(%lx,%lx)\n", 291 clientBufferSet, 292 (long int)generationCount, 293 now, 294 clientBufferSet->outputTimeout, 295 (long unsigned int)clientBufferSet->nextOutputPosition.fLoopCount, 296 (long unsigned int)clientBufferSet->nextOutputPosition.fSampleFrame); 297#else /* __LP64__ */ 298 audioDebugIOLog(3, "- IOAudioClientBufferSet[%p]::watchdogTimerFired(%ld):(%lx,%lx)(%lx,%lx)(%lx,%lx)\n", 299 clientBufferSet, 300 (long int)generationCount, 301 now.hi, 302 now.lo, 303 clientBufferSet->outputTimeout.hi, 304 clientBufferSet->outputTimeout.lo, 305 clientBufferSet->nextOutputPosition.fLoopCount, 306 clientBufferSet->nextOutputPosition.fSampleFrame); 307#endif /* __LP64__ */ 308#endif /* DEBUG */ 309 } else { 310 IOLog ("IOAudioClientBufferSet::watchdogTimerFired assert (clientBufferSet == NULL) failed\n"); 311 } 312 return; 313} 314 315#undef super 316#define super IOUserClient 317 318OSDefineMetaClassAndStructors(IOAudioEngineUserClient, IOUserClient) 319 320OSMetaClassDefineReservedUsed(IOAudioEngineUserClient, 0); 321OSMetaClassDefineReservedUsed(IOAudioEngineUserClient, 1); 322OSMetaClassDefineReservedUsed(IOAudioEngineUserClient, 2); 323OSMetaClassDefineReservedUsed(IOAudioEngineUserClient, 3); 324OSMetaClassDefineReservedUsed(IOAudioEngineUserClient, 4); 325OSMetaClassDefineReservedUsed(IOAudioEngineUserClient, 5); 326OSMetaClassDefineReservedUsed(IOAudioEngineUserClient, 6); 327OSMetaClassDefineReservedUsed(IOAudioEngineUserClient, 7); 328OSMetaClassDefineReservedUsed(IOAudioEngineUserClient, 8); 329OSMetaClassDefineReservedUsed(IOAudioEngineUserClient, 9); 330OSMetaClassDefineReservedUsed(IOAudioEngineUserClient, 10); 331OSMetaClassDefineReservedUsed(IOAudioEngineUserClient, 11); 332 333 334OSMetaClassDefineReservedUnused(IOAudioEngineUserClient, 12); 335OSMetaClassDefineReservedUnused(IOAudioEngineUserClient, 13); 336OSMetaClassDefineReservedUnused(IOAudioEngineUserClient, 14); 337OSMetaClassDefineReservedUnused(IOAudioEngineUserClient, 15); 338OSMetaClassDefineReservedUnused(IOAudioEngineUserClient, 16); 339OSMetaClassDefineReservedUnused(IOAudioEngineUserClient, 17); 340OSMetaClassDefineReservedUnused(IOAudioEngineUserClient, 18); 341OSMetaClassDefineReservedUnused(IOAudioEngineUserClient, 19); 342OSMetaClassDefineReservedUnused(IOAudioEngineUserClient, 20); 343OSMetaClassDefineReservedUnused(IOAudioEngineUserClient, 21); 344OSMetaClassDefineReservedUnused(IOAudioEngineUserClient, 22); 345OSMetaClassDefineReservedUnused(IOAudioEngineUserClient, 23); 346OSMetaClassDefineReservedUnused(IOAudioEngineUserClient, 24); 347OSMetaClassDefineReservedUnused(IOAudioEngineUserClient, 25); 348OSMetaClassDefineReservedUnused(IOAudioEngineUserClient, 26); 349OSMetaClassDefineReservedUnused(IOAudioEngineUserClient, 27); 350OSMetaClassDefineReservedUnused(IOAudioEngineUserClient, 28); 351OSMetaClassDefineReservedUnused(IOAudioEngineUserClient, 29); 352OSMetaClassDefineReservedUnused(IOAudioEngineUserClient, 30); 353OSMetaClassDefineReservedUnused(IOAudioEngineUserClient, 31); 354 355// New code added here 356 357// OSMetaClassDefineReservedUsed(IOAudioEngineUserClient, 5); 358// <rdar://8121989> Restructured for single point of entry and single point of exit so that 359// the indentifier post processing tool can properly insert scope when post processing a log file 360// obtained via fwkpfv. 361 362bool IOAudioEngineUserClient::initWithAudioEngine(IOAudioEngine *engine, task_t task, void *securityToken, UInt32 type, OSDictionary* properties) 363{ 364 bool result = false; 365 366 audioDebugIOLog(3, "+ IOAudioEngineUserClient[%p]::initWithAudioEngine(%p, 0x%lx, %p, 0x%lx, %p)\n", this, engine, (long unsigned int)task, securityToken, (long unsigned int)type, properties); 367 368 // Declare Rosetta compatibility 369 if ( properties ) 370 { 371 properties->setObject ( kIOUserClientCrossEndianCompatibleKey, kOSBooleanTrue ); 372 } 373 374 if ( initWithTask ( task, securityToken, type, properties ) ) 375 { 376 if ( engine && task ) 377 { 378 clientTask = task; 379 audioEngine = engine; 380 381 setOnline(false); 382 383 clientBufferSetList = NULL; 384 385 clientBufferLock = IORecursiveLockAlloc(); 386 if ( clientBufferLock ) 387 { 388 workLoop = audioEngine->getWorkLoop(); 389 if ( workLoop ) 390 { 391 workLoop->retain(); 392 393 commandGate = IOCommandGate::commandGate(this); 394 if ( commandGate ) 395 { 396 reserved = (ExpansionData *)IOMalloc (sizeof(struct ExpansionData)); 397 if ( reserved ) 398 { 399 reserved->extendedInfo = NULL; 400 reserved->classicMode = 0; 401 reserved->commandGateStatus = kCommandGateStatus_Normal; // <rdar://8518215> 402 reserved->commandGateUsage = 0; // <rdar://8518215> 403 404 workLoop->addEventSource(commandGate); 405 406 reserved->methods[kIOAudioEngineCallRegisterClientBuffer].object = this; 407 reserved->methods[kIOAudioEngineCallRegisterClientBuffer].func = (IOMethod) &IOAudioEngineUserClient::registerBuffer64; 408 reserved->methods[kIOAudioEngineCallRegisterClientBuffer].count0 = 4; 409 reserved->methods[kIOAudioEngineCallRegisterClientBuffer].count1 = 0; 410 reserved->methods[kIOAudioEngineCallRegisterClientBuffer].flags = kIOUCScalarIScalarO; 411 412 reserved->methods[kIOAudioEngineCallUnregisterClientBuffer].object = this; 413 reserved->methods[kIOAudioEngineCallUnregisterClientBuffer].func = (IOMethod) &IOAudioEngineUserClient::unregisterBuffer64; 414 reserved->methods[kIOAudioEngineCallUnregisterClientBuffer].count0 = 2; 415 reserved->methods[kIOAudioEngineCallUnregisterClientBuffer].count1 = 0; 416 reserved->methods[kIOAudioEngineCallUnregisterClientBuffer].flags = kIOUCScalarIScalarO; 417 418 reserved->methods[kIOAudioEngineCallGetConnectionID].object = this; 419 reserved->methods[kIOAudioEngineCallGetConnectionID].func = (IOMethod) &IOAudioEngineUserClient::getConnectionID; 420 reserved->methods[kIOAudioEngineCallGetConnectionID].count0 = 0; 421 reserved->methods[kIOAudioEngineCallGetConnectionID].count1 = 1; 422 reserved->methods[kIOAudioEngineCallGetConnectionID].flags = kIOUCScalarIScalarO; 423 424 reserved->methods[kIOAudioEngineCallStart].object = this; 425 reserved->methods[kIOAudioEngineCallStart].func = (IOMethod) &IOAudioEngineUserClient::clientStart; 426 reserved->methods[kIOAudioEngineCallStart].count0 = 0; 427 reserved->methods[kIOAudioEngineCallStart].count1 = 0; 428 reserved->methods[kIOAudioEngineCallStart].flags = kIOUCScalarIScalarO; 429 430 reserved->methods[kIOAudioEngineCallStop].object = this; 431 reserved->methods[kIOAudioEngineCallStop].func = (IOMethod) &IOAudioEngineUserClient::clientStop; 432 reserved->methods[kIOAudioEngineCallStop].count0 = 0; 433 reserved->methods[kIOAudioEngineCallStop].count1 = 0; 434 reserved->methods[kIOAudioEngineCallStop].flags = kIOUCScalarIScalarO; 435 436 reserved->methods[kIOAudioEngineCallGetNearestStartTime].object = this; 437 reserved->methods[kIOAudioEngineCallGetNearestStartTime].func = (IOMethod) &IOAudioEngineUserClient::getNearestStartTime; 438 reserved->methods[kIOAudioEngineCallGetNearestStartTime].count0 = 3; 439 reserved->methods[kIOAudioEngineCallGetNearestStartTime].count1 = 0; 440 reserved->methods[kIOAudioEngineCallGetNearestStartTime].flags = kIOUCScalarIScalarO; 441 442 trap.object = this; 443 trap.func = (IOTrap) &IOAudioEngineUserClient::performClientIO; 444 result = true; 445 } 446 } 447 } 448 } 449 } 450 } 451 452 audioDebugIOLog(3, "- IOAudioEngineUserClient[%p]::initWithAudioEngine(%p, 0x%lx, %p, 0x%lx, %p) returns %d\n", this, engine, (long unsigned int)task, securityToken, (long unsigned int)type, properties, result); 453 return result; 454} 455 456// Used so that a pointer to a kernel IOAudioStream isn't passed out of the kernel ( 32 bit version ) 457// <rdar://8121989> Restructured for single point of entry and single point of exit so that 458// the indentifier post processing tool can properly insert scope when post processing a log file 459// obtained via fwkpfv. 460 461IOReturn IOAudioEngineUserClient::safeRegisterClientBuffer(UInt32 audioStreamIndex, void * sourceBuffer, UInt32 bufSizeInBytes, UInt32 bufferSetID) { 462 463 audioDebugIOLog(3, "IOAudioEngineUserClient::safeRegisterClientBuffer deprecated for 32 bit %p \n", sourceBuffer); 464 IOAudioStream * audioStream; 465 IOReturn result = kIOReturnBadArgument; 466 467 audioDebugIOLog(3, "+ IOAudioEngineUserClient::safeRegisterClientBuffer32 %p \n", sourceBuffer); 468 469 audioStream = audioEngine->getStreamForID(audioStreamIndex); 470 if (!audioStream) 471 { 472 audioDebugIOLog(3, "no stream associated with audioStreamIndex 0x%lx \n", (long unsigned int)audioStreamIndex); 473 } 474 else 475 { 476 result = registerClientBuffer(audioStream, sourceBuffer, bufSizeInBytes, bufferSetID); 477 } 478 479 audioDebugIOLog(3, "- IOAudioEngineUserClient::safeRegisterClientBuffer32 %p returns 0x%lX\n", sourceBuffer, (long unsigned int)result ); 480 return result; 481 482} 483 484// Used so that a pointer to a kernel IOAudioStream isn't passed out of the kernel ( 64 bit version ) <rdar://problems/5321701> 485// New method added for 64 bit support <rdar://problems/5321701> 486IOReturn IOAudioEngineUserClient::safeRegisterClientBuffer64(UInt32 audioStreamIndex, mach_vm_address_t * sourceBuffer, UInt32 bufSizeInBytes, UInt32 bufferSetID) 487{ 488 IOReturn retVal = kIOReturnBadArgument; 489 IOAudioStream * audioStream; 490 audioDebugIOLog(3, "+ IOAudioEngineUserClient::safeRegisterClientBuffer64 %p \n", sourceBuffer); 491 492 audioStream = audioEngine->getStreamForID(audioStreamIndex); 493 if (!audioStream) { 494 audioDebugIOLog(3, " no stream associated with audioStreamIndex 0x%lx \n", (long unsigned int)audioStreamIndex); 495 } 496 else 497 { 498 retVal = registerClientBuffer64(audioStream, * sourceBuffer, bufSizeInBytes, bufferSetID); 499 } 500 audioDebugIOLog(3, "- IOAudioEngineUserClient::safeRegisterClientBuffer64 returns 0x%lX\n", (long unsigned int)retVal ); 501 return retVal; 502} 503// Used to pass extra information about how many samples are actually in a buffer and other things related to interesting non-mixable audio formats. 504IOReturn IOAudioEngineUserClient::registerClientParameterBuffer (void * paramBuffer, UInt32 bufferSetID) 505{ 506 IOReturn result = kIOReturnSuccess; 507 IOAudioClientBufferSet *bufferSet = NULL; 508 IOAudioClientBufferExtendedInfo64 *extendedInfo; 509 510 audioDebugIOLog(3, "+ IOAudioEngineUserClient::registerClientParameterBuffer() - result = 0x%x\n", result); 511 512 if (!isInactive()) { 513 if (!paramBuffer || ((IOAudioStreamDataDescriptor *)paramBuffer)->fVersion > kStreamDataDescriptorCurrentVersion) { 514 return kIOReturnBadArgument; 515 } 516 517 lockBuffers(); // added here because it was turned off in findBufferSet // MPC 518 519 // this buffer set can't have already been registered with extended info 520 extendedInfo = findExtendedInfo64 (bufferSetID); 521 if (extendedInfo) 522 { 523 unlockBuffers(); 524 return kIOReturnBadArgument; 525 } 526 527 // make sure that this buffer set has already been registered for output 528 bufferSet = findBufferSet(bufferSetID); 529 530 unlockBuffers(); 531 532 if (bufferSet) { 533 IOAudioClientBufferExtendedInfo64 *info; 534 535 extendedInfo = (IOAudioClientBufferExtendedInfo64*)IOMalloc (sizeof (IOAudioClientBufferExtendedInfo64)); 536 if (!extendedInfo) { 537 return kIOReturnError; 538 } 539 540 // Can only be for output buffers, so always kIODirectionIn 541 extendedInfo->mAudioClientBufferExtended32.paramBufferDescriptor = IOMemoryDescriptor::withAddressRange(* (mach_vm_address_t*)paramBuffer, (((IOAudioStreamDataDescriptor *)paramBuffer)->fNumberOfStreams * 4) + 8, kIODirectionIn, clientTask); 542 if (!extendedInfo->mAudioClientBufferExtended32.paramBufferDescriptor) 543 { 544 result = kIOReturnInternalError; 545 goto Exit; 546 } 547 548 if ((result = extendedInfo->mAudioClientBufferExtended32.paramBufferDescriptor->prepare()) != kIOReturnSuccess) 549 { 550 goto Exit; 551 } 552 553 extendedInfo->mAudioClientBufferExtended32.paramBufferMap = extendedInfo->mAudioClientBufferExtended32.paramBufferDescriptor->map(); 554 555 if (extendedInfo->mAudioClientBufferExtended32.paramBufferMap == NULL) 556 { 557 IOLog("IOAudioEngineUserClient<0x%p>::registerClientParameterBuffer() - error mapping memory.\n", this); 558 result = kIOReturnVMError; 559 goto Exit; 560 } 561 562 extendedInfo->mAudioClientBufferExtended32.paramBuffer = (void *)extendedInfo->mAudioClientBufferExtended32.paramBufferMap->getVirtualAddress(); 563 if (extendedInfo->mAudioClientBufferExtended32.paramBuffer == NULL) 564 { 565 result = kIOReturnVMError; 566 goto Exit; 567 } 568 569 extendedInfo->mUnmappedParamBuffer64 = * (mach_vm_address_t*)paramBuffer; 570 extendedInfo->mNextExtended64 = NULL; 571 572 if (reserved->extendedInfo) 573 { 574 // Get to the end of the linked list of extended info and add this new entry there 575 info = reserved->extendedInfo; 576 if (info) 577 { 578 while (info->mNextExtended64) 579 { 580 info = info->mNextExtended64; 581 } 582 583 info->mNextExtended64 = extendedInfo; 584 } 585 } 586 else 587 { 588 // The list is empty, so this the start of the list 589 reserved->extendedInfo = extendedInfo; 590 } 591 } 592 } 593 else 594 { 595 result = kIOReturnNoDevice; 596 } 597 598Exit: 599 audioDebugIOLog(3, "- IOAudioEngineUserClient::registerClientParameterBuffer() - result = 0x%lX\n", (long unsigned int)result); 600 return result; 601} 602 603IOAudioClientBufferExtendedInfo *IOAudioEngineUserClient::findExtendedInfo(UInt32 bufferSetID) 604{ 605 IOAudioClientBufferExtendedInfo64 *extendedInfo; // <rdar://problems/5321701> 606 607IOAudioClientBufferExtendedInfo * retVal = NULL; 608 extendedInfo = reserved->extendedInfo; 609 while (extendedInfo && (extendedInfo->mAudioClientBufferExtended32.bufferSetID != bufferSetID)) 610 { 611 extendedInfo = extendedInfo->mNextExtended64; 612 } 613 if ( extendedInfo) 614 { 615 retVal = &(extendedInfo->mAudioClientBufferExtended32); 616 } 617 return retVal; 618} 619 620// New method added for 64 bit support <rdar://problems/5321701> 621IOAudioClientBufferExtendedInfo64 *IOAudioEngineUserClient::findExtendedInfo64(UInt32 bufferSetID) 622{ 623 IOAudioClientBufferExtendedInfo64 *extendedInfo; // <rdar://problems/5321701> 624 625 extendedInfo = reserved->extendedInfo; 626 while (extendedInfo && (extendedInfo->mAudioClientBufferExtended32.bufferSetID != bufferSetID)) { 627 extendedInfo = extendedInfo->mNextExtended64; 628 } 629 630 return extendedInfo; 631} 632IOReturn IOAudioEngineUserClient::getNearestStartTime(IOAudioStream *audioStream, IOAudioTimeStamp *ioTimeStamp, UInt32 isInput) 633{ 634 IOReturn ret = kIOReturnError; 635 636 // <rdar://7363756>, <rdar://7529580> 637 if ( workLoop ) 638 { 639 ret = workLoop->runAction(_getNearestStartTimeAction, this, (void *)audioStream, (void *)ioTimeStamp, (void *)(uintptr_t)isInput); // <rdar://7529580> 640 } 641 642 return ret; 643} 644 645// <rdar://7529580> 646IOReturn IOAudioEngineUserClient::_getNearestStartTimeAction(OSObject *target, void *arg0, void *arg1, void *arg2, void *arg3) 647{ 648 IOReturn result = kIOReturnBadArgument; 649 650 if (target) { 651 IOAudioEngineUserClient *userClient = OSDynamicCast(IOAudioEngineUserClient, target); 652 if (userClient) { 653 if (userClient->commandGate) { 654 setCommandGateUsage(userClient, true); // <rdar://8518215> 655 result = userClient->commandGate->runAction(getNearestStartTimeAction, arg0, arg1, arg2, arg3); 656 setCommandGateUsage(userClient, false); // <rdar://8518215> 657 } else { 658 result = kIOReturnError; 659 } 660 } 661 } 662 663 return result; 664} 665 666IOReturn IOAudioEngineUserClient::getNearestStartTimeAction(OSObject *owner, void *arg1, void *arg2, void *arg3, void *arg4) 667{ 668 IOReturn result = kIOReturnBadArgument; 669 670 if (owner) { 671 IOAudioEngineUserClient *userClient = OSDynamicCast(IOAudioEngineUserClient, owner); 672 673 if (userClient) { 674 675#if __LP64__ 676 UInt32 tempBoolArgument = (UInt64)arg4; 677#else 678 UInt32 tempBoolArgument = (UInt32)arg4; 679#endif 680 681 result = userClient->getClientNearestStartTime((IOAudioStream *)arg1, (IOAudioTimeStamp *)arg2, tempBoolArgument); 682 } 683 } 684 685 return result; 686} 687 688IOReturn IOAudioEngineUserClient::getClientNearestStartTime(IOAudioStream *audioStream, IOAudioTimeStamp *ioTimeStamp, UInt32 isInput) 689{ 690 IOReturn result = kIOReturnSuccess; 691 692 if (audioEngine && !isInactive()) { 693 result = audioEngine->getNearestStartTime(audioStream, ioTimeStamp, isInput); 694 } 695 696 return result; 697} 698 699IOAudioEngineUserClient *IOAudioEngineUserClient::withAudioEngine(IOAudioEngine *engine, task_t clientTask, void *securityToken, UInt32 type, OSDictionary *properties) 700{ 701 IOAudioEngineUserClient *client; 702 703 audioDebugIOLog(3, "+ IOAudioEngineUserClient::withAudioEngine(%p, 0x%lx, %p, 0x%lx, %p)\n", engine, (long unsigned int)clientTask, securityToken, (long unsigned int)type, properties); 704 705 client = new IOAudioEngineUserClient; 706 707 if (client) { 708 if (!client->initWithAudioEngine(engine, clientTask, securityToken, type, properties)) { 709 client->release(); 710 client = NULL; 711 } 712 } 713 714 audioDebugIOLog(3, "- IOAudioEngineUserClient::withAudioEngine(%p, 0x%lx, %p, 0x%lx, %p) returns %p\n", engine, (long unsigned int)clientTask, securityToken, (long unsigned int)type, properties, client ); 715 return client; 716} 717 718// Original code 719IOAudioEngineUserClient *IOAudioEngineUserClient::withAudioEngine(IOAudioEngine *engine, task_t clientTask, void *securityToken, UInt32 type) 720{ 721 IOAudioEngineUserClient *client; 722 723 audioDebugIOLog(3, "+ IOAudioEngineUserClient::withAudioEngine(%p, 0x%lx, %p, 0x%lx)\n", engine, (long unsigned int)clientTask, securityToken, (long unsigned int)type); 724 725 client = new IOAudioEngineUserClient; 726 727 if (client) { 728 if (!client->initWithAudioEngine(engine, clientTask, securityToken, type)) { 729 client->release(); 730 client = NULL; 731 } 732 } 733 734 audioDebugIOLog(3, "- IOAudioEngineUserClient::withAudioEngine(%p, 0x%lx, %p, 0x%lx) returns %p\n", engine, (long unsigned int)clientTask, securityToken, (long unsigned int)type, client); 735 return client; 736} 737 738// <rdar://8121989> Restructured for single point of entry and single point of exit so that 739// the indentifier post processing tool can properly insert scope when post processing a log file 740// obtained via fwkpfv. 741 742bool IOAudioEngineUserClient::initWithAudioEngine(IOAudioEngine *engine, task_t task, void *securityToken, UInt32 type) 743{ 744 bool result = false; 745 746 audioDebugIOLog(3, "+ IOAudioEngineUserClient[%p]::initWithAudioEngine(%p, 0x%lx, %p, 0x%lx)\n", this, engine, (long unsigned int)task, securityToken, (long unsigned int)type); 747 748 if ( initWithTask( task, securityToken, type ) ) 749 { 750 if ( engine && task ) 751 { 752 clientTask = task; 753 audioEngine = engine; 754 755 setOnline(false); 756 757 clientBufferSetList = NULL; 758 759 clientBufferLock = IORecursiveLockAlloc(); 760 if ( clientBufferLock ) 761 { 762 workLoop = audioEngine->getWorkLoop(); 763 if ( workLoop ) 764 { 765 workLoop->retain(); 766 767 commandGate = IOCommandGate::commandGate(this); 768 if ( commandGate ) 769 { 770 reserved = (ExpansionData *)IOMalloc (sizeof(struct ExpansionData)); 771 if ( reserved ) 772 { 773 reserved->extendedInfo = NULL; 774 reserved->classicMode = 0; 775 reserved->commandGateStatus = kCommandGateStatus_Normal; // <rdar://8518215> 776 reserved->commandGateUsage = 0; // <rdar://8518215> 777 778 workLoop->addEventSource(commandGate); 779 780 reserved->methods[kIOAudioEngineCallRegisterClientBuffer].object = this; 781 reserved->methods[kIOAudioEngineCallRegisterClientBuffer].func = (IOMethod) &IOAudioEngineUserClient::registerBuffer64; 782 reserved->methods[kIOAudioEngineCallRegisterClientBuffer].count0 = 4; 783 reserved->methods[kIOAudioEngineCallRegisterClientBuffer].count1 = 0; 784 reserved->methods[kIOAudioEngineCallRegisterClientBuffer].flags = kIOUCScalarIScalarO; 785 786 reserved->methods[kIOAudioEngineCallUnregisterClientBuffer].object = this; 787 reserved->methods[kIOAudioEngineCallUnregisterClientBuffer].func = (IOMethod) &IOAudioEngineUserClient::unregisterBuffer64; 788 reserved->methods[kIOAudioEngineCallUnregisterClientBuffer].count0 = 2; 789 reserved->methods[kIOAudioEngineCallUnregisterClientBuffer].count1 = 0; 790 reserved->methods[kIOAudioEngineCallUnregisterClientBuffer].flags = kIOUCScalarIScalarO; 791 792 reserved->methods[kIOAudioEngineCallGetConnectionID].object = this; 793 reserved->methods[kIOAudioEngineCallGetConnectionID].func = (IOMethod) &IOAudioEngineUserClient::getConnectionID; 794 reserved->methods[kIOAudioEngineCallGetConnectionID].count0 = 0; 795 reserved->methods[kIOAudioEngineCallGetConnectionID].count1 = 1; 796 reserved->methods[kIOAudioEngineCallGetConnectionID].flags = kIOUCScalarIScalarO; 797 798 reserved->methods[kIOAudioEngineCallStart].object = this; 799 reserved->methods[kIOAudioEngineCallStart].func = (IOMethod) &IOAudioEngineUserClient::clientStart; 800 reserved->methods[kIOAudioEngineCallStart].count0 = 0; 801 reserved->methods[kIOAudioEngineCallStart].count1 = 0; 802 reserved->methods[kIOAudioEngineCallStart].flags = kIOUCScalarIScalarO; 803 804 reserved->methods[kIOAudioEngineCallStop].object = this; 805 reserved->methods[kIOAudioEngineCallStop].func = (IOMethod) &IOAudioEngineUserClient::clientStop; 806 reserved->methods[kIOAudioEngineCallStop].count0 = 0; 807 reserved->methods[kIOAudioEngineCallStop].count1 = 0; 808 reserved->methods[kIOAudioEngineCallStop].flags = kIOUCScalarIScalarO; 809 810 reserved->methods[kIOAudioEngineCallGetNearestStartTime].object = this; 811 reserved->methods[kIOAudioEngineCallGetNearestStartTime].func = (IOMethod) &IOAudioEngineUserClient::getNearestStartTime; 812 reserved->methods[kIOAudioEngineCallGetNearestStartTime].count0 = 3; 813 reserved->methods[kIOAudioEngineCallGetNearestStartTime].count1 = 0; 814 reserved->methods[kIOAudioEngineCallGetNearestStartTime].flags = kIOUCScalarIScalarO; 815 816 trap.object = this; 817 trap.func = (IOTrap) &IOAudioEngineUserClient::performClientIO; 818 result = true; 819 } 820 } 821 } 822 } 823 } 824 } 825 826 audioDebugIOLog(3, "- IOAudioEngineUserClient[%p]::initWithAudioEngine(%p, 0x%lx, %p, 0x%lx) returns %d\n", this, engine, (long unsigned int)task, securityToken, (long unsigned int)type, result ); 827 return result; 828} 829 830void IOAudioEngineUserClient::free() 831{ 832 IOAudioClientBufferExtendedInfo64 * cur; 833 IOAudioClientBufferExtendedInfo64 * prev; 834 835 audioDebugIOLog(3, "+ IOAudioEngineUserClient[%p]::free()\n", this); 836 837 freeClientBufferSetList(); // Moved above clientBufferLock code below 838 839 if (clientBufferLock) { 840 IORecursiveLockFree(clientBufferLock); 841 clientBufferLock = NULL; 842 } 843 844 if (notificationMessage) { 845 IOFreeAligned(notificationMessage, sizeof(IOAudioNotificationMessage)); 846 notificationMessage = NULL; 847 } 848 849 if (commandGate) { 850 if (workLoop) { 851 workLoop->removeEventSource(commandGate); 852 } 853 854 commandGate->release(); 855 commandGate = NULL; 856 } 857 858 if (workLoop) { 859 workLoop->release(); 860 workLoop = NULL; 861 } 862 863 if (reserved) { 864 if (NULL != reserved->extendedInfo) { 865 cur = reserved->extendedInfo; 866 while (cur) { 867 prev = cur; 868 if (NULL != prev) { 869 IOFree (prev, sizeof (IOAudioClientBufferExtendedInfo64)); 870 } 871 cur = cur->mNextExtended64; 872 } 873 } 874 IOFree (reserved, sizeof(struct ExpansionData)); 875 } 876 877 super::free(); 878 879 audioDebugIOLog(3, "- IOAudioEngineUserClient[%p]::free()\n", this); 880 return; 881} 882 883void IOAudioEngineUserClient::freeClientBufferSetList() 884{ 885 // <rdar://9180891> Lock the buffers to synchronize access to the client buffer list. 886 // This is to prevent race condition between freeClientBufferList, unregisterClientBuffer64 887 // & stopClient when calling IOAudioStream::removeClient(). 888 lockBuffers(); 889 890 while (clientBufferSetList) { 891 IOAudioClientBufferSet *nextSet; 892 893 // Move call up here to fix 3472373 894 clientBufferSetList->cancelWatchdogTimer(); 895 896 while (clientBufferSetList->outputBufferList) { 897 IOAudioClientBuffer64 *nextBuffer = clientBufferSetList->outputBufferList->mNextBuffer64; 898 899 freeClientBuffer(clientBufferSetList->outputBufferList); 900 901 clientBufferSetList->outputBufferList = nextBuffer; 902 } 903 904 while (clientBufferSetList->inputBufferList) { 905 IOAudioClientBuffer64 *next = clientBufferSetList->inputBufferList->mNextBuffer64; 906 907 freeClientBuffer(clientBufferSetList->inputBufferList); 908 909 clientBufferSetList->inputBufferList = next; 910 } 911 912 nextSet = clientBufferSetList->mNextBufferSet; 913 914 clientBufferSetList->release(); 915 916 clientBufferSetList = nextSet; 917 } 918 919 unlockBuffers(); // <rdar://9180891> 920} 921 922void IOAudioEngineUserClient::freeClientBuffer(IOAudioClientBuffer64 *clientBuffer) 923{ 924 if (clientBuffer) { 925 if (clientBuffer->mAudioClientBuffer32.audioStream) { 926 clientBuffer->mAudioClientBuffer32.audioStream->removeClient(&(clientBuffer->mAudioClientBuffer32) ); 927 clientBuffer->mAudioClientBuffer32.audioStream->release(); 928 clientBuffer->mAudioClientBuffer32.audioStream = NULL; 929 } 930 931 if (clientBuffer->mAudioClientBuffer32.sourceBufferDescriptor != NULL) { 932 clientBuffer->mAudioClientBuffer32.sourceBufferDescriptor->complete(); 933 clientBuffer->mAudioClientBuffer32.sourceBufferDescriptor->release(); 934 clientBuffer->mAudioClientBuffer32.sourceBufferDescriptor = NULL; 935 } 936 937 if (clientBuffer->mAudioClientBuffer32.sourceBufferMap != NULL) { 938 clientBuffer->mAudioClientBuffer32.sourceBufferMap->release(); 939 clientBuffer->mAudioClientBuffer32.sourceBufferMap = NULL; 940 } 941 942 IOFreeAligned(clientBuffer, sizeof(IOAudioClientBuffer64)); 943 clientBuffer = NULL; 944 } 945} 946 947void IOAudioEngineUserClient::stop(IOService *provider) 948{ 949 audioDebugIOLog(3, "+ IOAudioEngineUserClient[%p]::stop(%p)\n", this, provider); 950 951 952 // <rdar://7363756> 953 if ( commandGate ) 954 { 955 commandGate->runAction(stopClientAction); 956 } 957 958 // We should be both inactive and offline at this point, 959 // so it is safe to free the client buffer set list without holding the lock 960 961 freeClientBufferSetList(); 962 963 // <rdar://7233118>, <rdar://7029696> Remove the event source here as performing heavy workloop operation in free() could lead 964 // to deadlock since the context which free() is called is not known. stop() is called on the workloop, so it is safe to remove 965 // the event source here. 966 if (reserved->commandGateUsage == 0) { // <rdar://8518215> 967 reserved->commandGateStatus = kCommandGateStatus_Invalid; // <rdar://8518215> 968 969 if (commandGate) { 970 if (workLoop) { 971 workLoop->removeEventSource(commandGate); 972 } 973 974 commandGate->release(); 975 commandGate = NULL; 976 } 977 } 978 else { // <rdar://8518215> 979 reserved->commandGateStatus = kCommandGateStatus_RemovalPending; 980 } 981 982 super::stop(provider); 983 984 audioDebugIOLog(3, "- IOAudioEngineUserClient[%p]::stop(%p)\n", this, provider); 985 return; 986} 987 988IOReturn IOAudioEngineUserClient::clientClose() 989{ 990 IOReturn result = kIOReturnSuccess; 991 992 audioDebugIOLog(3, "+ IOAudioEngineUserClient[%p]::clientClose()\n", this); 993 994 // <rdar://7363756> 995 if (audioEngine && workLoop && !isInactive()) { // <rdar://7529580> 996 result = workLoop->runAction(_closeClientAction, this); // <rdar://7529580> 997 } 998 999 audioDebugIOLog(3, "- IOAudioEngineUserClient[%p]::clientClose() returns 0x%lX\n", this, (long unsigned int)result ); 1000 return result; 1001} 1002 1003// <rdar://8121989> Restructured for single point of entry and single point of exit so that 1004// the indentifier post processing tool can properly insert scope when post processing a log file 1005// obtained via fwkpfv. 1006 1007IOReturn IOAudioEngineUserClient::clientDied() 1008{ 1009 IOReturn result; 1010 1011 audioDebugIOLog(3, "+ IOAudioEngineUserClient[%p]::clientDied()\n", this); 1012 1013 result = clientClose(); 1014 1015 audioDebugIOLog(3, "- IOAudioEngineUserClient[%p]::clientDied() returns 0x%lX\n", this, (long unsigned int)result); 1016 return result; 1017} 1018 1019// <rdar://7529580> 1020IOReturn IOAudioEngineUserClient::_closeClientAction(OSObject *target, void *arg0, void *arg1, void *arg2, void *arg3) 1021{ 1022 IOReturn result = kIOReturnBadArgument; 1023 1024 if (target) { 1025 IOAudioEngineUserClient *userClient = OSDynamicCast(IOAudioEngineUserClient, target); 1026 if (userClient) { 1027 if (userClient->commandGate) { 1028 setCommandGateUsage(userClient, true); // <rdar://8518215> 1029 result = userClient->commandGate->runAction(closeClientAction, arg0, arg1, arg2, arg3); 1030 setCommandGateUsage(userClient, false); // <rdar://8518215> 1031 } else { 1032 result = kIOReturnError; 1033 } 1034 } 1035 } 1036 1037 return result; 1038} 1039 1040IOReturn IOAudioEngineUserClient::closeClientAction(OSObject *owner, void *arg1, void *arg2, void *arg3, void *arg4) 1041{ 1042 IOReturn result = kIOReturnBadArgument; 1043 1044 if (owner) { 1045 IOAudioEngineUserClient *userClient = OSDynamicCast(IOAudioEngineUserClient, owner); 1046 if (userClient) { 1047 result = userClient->closeClient(); 1048 } 1049 } 1050 1051 return result; 1052} 1053 1054IOReturn IOAudioEngineUserClient::closeClient() 1055{ 1056 audioDebugIOLog(3, "+ IOAudioEngineUserClient[%p]::closeClient()\n", this); 1057 1058 if (audioEngine && !isInactive()) { 1059 if (isOnline()) { 1060 stopClient(); 1061 } 1062 audioEngine->clientClosed(this); 1063 audioEngine = NULL; 1064 } 1065 1066 audioDebugIOLog(3, "- IOAudioEngineUserClient[%p]::closeClient() returns 0x%lX\n", this, (long unsigned int)kIOReturnSuccess ); 1067 return kIOReturnSuccess; 1068} 1069 1070void IOAudioEngineUserClient::setOnline(bool newOnline) 1071{ 1072 audioDebugIOLog(3, "+ IOAudioEngineUserClient[%p]::setOnline(%d)\n", this, newOnline); 1073 1074 if (online != newOnline) { 1075 online = newOnline; 1076 setProperty(kIOAudioEngineUserClientActiveKey, (unsigned long long)(online ? 1 : 0), sizeof(unsigned long long)*8); 1077 } 1078 1079 audioDebugIOLog(3, "- IOAudioEngineUserClient[%p]::setOnline(%d)\n", this, newOnline); 1080 return; 1081} 1082 1083bool IOAudioEngineUserClient::isOnline() 1084{ 1085 return online; 1086} 1087 1088void IOAudioEngineUserClient::lockBuffers() 1089{ 1090 assert(clientBufferLock); 1091 1092 IORecursiveLockLock(clientBufferLock); 1093} 1094 1095void IOAudioEngineUserClient::unlockBuffers() 1096{ 1097 assert(clientBufferLock); 1098 1099 IORecursiveLockUnlock(clientBufferLock); 1100} 1101 1102IOReturn IOAudioEngineUserClient::clientMemoryForType(UInt32 type, UInt32 *flags, IOMemoryDescriptor **memory) 1103{ 1104 IOReturn result = kIOReturnSuccess; 1105 IOBufferMemoryDescriptor *theMemoryDescriptor = NULL; 1106 1107 audioDebugIOLog(3, "+ IOAudioEngineUserClient[%p]::clientMemoryForType(0x%lx, 0x%lx, %p)\n", this, (long unsigned int)type, (long unsigned int)*flags, memory); 1108 1109 assert(audioEngine); 1110 1111 switch(type) { 1112 case kIOAudioStatusBuffer: 1113 theMemoryDescriptor = audioEngine->getStatusDescriptor(); 1114 break; 1115 case kIOAudioBytesInInputBuffer: 1116 theMemoryDescriptor = audioEngine->getBytesInInputBufferArrayDescriptor(); 1117 break; 1118 case kIOAudioBytesInOutputBuffer: 1119 theMemoryDescriptor = audioEngine->getBytesInOutputBufferArrayDescriptor(); 1120 break; 1121 default: 1122 result = kIOReturnUnsupported; 1123 break; 1124 } 1125 1126 if (!result && theMemoryDescriptor) { 1127 theMemoryDescriptor->retain(); // Don't release it, it will be released by mach-port automatically 1128 *memory = theMemoryDescriptor; 1129 *flags = kIOMapReadOnly; 1130 } else { 1131 result = kIOReturnError; 1132 } 1133 1134 audioDebugIOLog(3, "- IOAudioEngineUserClient[%p]::clientMemoryForType(0x%lx, 0x%lx, %p) returns 0x%lX\n", this, (long unsigned int)type, (long unsigned int)*flags, memory, (long unsigned int)result ); 1135 return result; 1136} 1137 1138IOExternalMethod *IOAudioEngineUserClient::getExternalMethodForIndex(UInt32 index) 1139{ 1140 IOExternalMethod *method = 0; 1141 1142 if (index < kIOAudioEngineNumCalls) { 1143 method = &reserved->methods[index]; 1144 } 1145 1146 return method; 1147} 1148 1149IOExternalTrap *IOAudioEngineUserClient::getExternalTrapForIndex( UInt32 index ) 1150{ 1151 IOExternalTrap *result = NULL; 1152 1153 if (index == kIOAudioEngineTrapPerformClientIO) { 1154 result = &trap; 1155 } else if (index == (0x1000 | kIOAudioEngineTrapPerformClientIO)) { 1156 reserved->classicMode = 1; 1157 result = &trap; 1158 } 1159 1160 return result; 1161} 1162 1163IOReturn IOAudioEngineUserClient::registerNotificationPort(mach_port_t port, UInt32 type, UInt32 refCon) 1164{ 1165 IOReturn result = kIOReturnSuccess; 1166 1167 audioDebugIOLog(3, "+ IOAudioEngineUserClient[%p]::registerNotificationPort(0x%lx, 0x%lx, 0x%lx)\n", this, (long unsigned int)port, (long unsigned int)type, (long unsigned int)refCon); 1168 1169 switch (type) { 1170 case kIOAudioEngineAllNotifications: 1171 // <rdar://7363756>, <rdar://7529580> 1172 if ( workLoop ) 1173 { 1174 result = workLoop->runAction(_registerNotificationAction, this, (void *)port, (void *)(uintptr_t)refCon); // <rdar://7529580> 1175 } 1176 else 1177 { 1178 result = kIOReturnError; 1179 } 1180 1181 break; 1182 default: 1183 IOLog("IOAudioEngineUserClient[%p]::registerNotificationPort() - ERROR: invalid notification type specified - no notifications will be sent.\n", this); 1184 result = kIOReturnBadArgument; 1185 break; 1186 } 1187 // Create a single message, but keep a dict or something of all of the IOAudioStreams registered for 1188 // refCon is IOAudioStream * 1189 1190 audioDebugIOLog(3, "- IOAudioEngineUserClient[%p]::registerNotificationPort(0x%lx, 0x%lx, 0x%lx) returns 0x%lX\n", this, (long unsigned int)port, (long unsigned int)type, (long unsigned int)refCon, (long unsigned int)result ); 1191 return result; 1192} 1193 1194// <rdar://7529580> 1195IOReturn IOAudioEngineUserClient::_registerNotificationAction(OSObject *target, void *arg0, void *arg1, void *arg2, void *arg3) 1196{ 1197 IOReturn result = kIOReturnBadArgument; 1198 1199 if (target) { 1200 IOAudioEngineUserClient *userClient = OSDynamicCast(IOAudioEngineUserClient, target); 1201 if (userClient) { 1202 if (userClient->commandGate) { 1203 setCommandGateUsage(userClient, true); // <rdar://8518215> 1204 result = userClient->commandGate->runAction(registerNotificationAction, arg0, arg1, arg2, arg3); 1205 setCommandGateUsage(userClient, false); // <rdar://8518215> 1206 } else { 1207 result = kIOReturnError; 1208 } 1209 } 1210 } 1211 1212 return result; 1213} 1214 1215IOReturn IOAudioEngineUserClient::registerNotificationAction(OSObject *owner, void *arg1, void *arg2, void *arg3, void *arg4) 1216{ 1217 IOReturn result = kIOReturnBadArgument; 1218 1219 audioDebugIOLog(3, "+ IOAudioEngineUserClient::registerNotificationAction(%p, %p)\n", owner, arg1); 1220 1221 if (owner) { 1222 IOAudioEngineUserClient *userClient = OSDynamicCast(IOAudioEngineUserClient, owner); 1223 1224 if (userClient) { 1225#if __LP64__ 1226 UInt64 refCon = (UInt64) arg2; 1227#else 1228 UInt32 refCon = (UInt32) arg2; 1229#endif 1230 1231 result = userClient->registerNotification((mach_port_t)arg1, refCon); 1232 } 1233 } 1234 1235 audioDebugIOLog(3, "- IOAudioEngineUserClient::registerNotificationAction(%p, %p) returns 0x%lX\n", owner, arg1, (long unsigned int)result ); 1236 return result; 1237} 1238 1239IOReturn IOAudioEngineUserClient::registerNotification(mach_port_t port, UInt32 refCon) 1240{ 1241 IOReturn result = kIOReturnSuccess; 1242 1243 audioDebugIOLog(3, "+ IOAudioEngineUserClient[%p]::registerFormatNotification(0x%lx, 0x%lx)\n", this, (long unsigned int)port, (long unsigned int)refCon); 1244 1245 if (!isInactive()) { 1246 if (port == MACH_PORT_NULL) { // We need to remove this notification 1247 if (notificationMessage != NULL) { 1248 notificationMessage->messageHeader.msgh_remote_port = MACH_PORT_NULL; 1249 } 1250 } else { 1251 if (notificationMessage == NULL) { 1252 notificationMessage = (IOAudioNotificationMessage *)IOMallocAligned(sizeof(IOAudioNotificationMessage), sizeof (IOAudioNotificationMessage *)); 1253 1254 if (notificationMessage) { 1255 notificationMessage->messageHeader.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0); 1256 notificationMessage->messageHeader.msgh_size = sizeof(IOAudioNotificationMessage); 1257 notificationMessage->messageHeader.msgh_local_port = MACH_PORT_NULL; 1258 notificationMessage->messageHeader.msgh_reserved = 0; 1259 notificationMessage->messageHeader.msgh_id = 0; 1260 notificationMessage->messageHeader.msgh_remote_port = port; 1261 notificationMessage->ref = refCon; 1262 } else { 1263 result = kIOReturnNoMemory; 1264 } 1265 } else { 1266 notificationMessage->messageHeader.msgh_remote_port = port; 1267 notificationMessage->ref = refCon; 1268 } 1269 } 1270 } else { 1271 result = kIOReturnNoDevice; 1272 } 1273 1274 audioDebugIOLog(3, "- IOAudioEngineUserClient[%p]::registerFormatNotification(0x%lx, 0x%lx) returns 0x%lX\n", this, (long unsigned int)port, (long unsigned int)refCon, (long unsigned int)result ); 1275 return result; 1276} 1277 1278 1279IOReturn IOAudioEngineUserClient::externalMethod ( uint32_t selector, IOExternalMethodArguments * arguments, 1280 IOExternalMethodDispatch * dispatch, OSObject * target, void * reference) 1281{ 1282 IOReturn result = kIOReturnBadArgument; 1283 audioDebugIOLog(3, "+ IOAudioEngineUserClient::externalMethod, selector=0x%x, arg0 0x%llX, arg1 0x%llx, arg2 0x%llx arg3 0x%llx \n", 1284 selector, arguments->scalarInput[0], arguments->scalarInput[1], arguments->scalarInput[2], arguments->scalarInput[3]); 1285 audioDebugIOLog(3, " scalarInputCount=0x%x structureInputSize 0x%x, scalarOutputCount 0x%x, structureOutputSize 0x%x \n", 1286 arguments->scalarInputCount, arguments->structureInputSize, arguments->scalarOutputCount, arguments->structureOutputSize ); 1287 1288 // Dispatch the method call 1289 switch (selector) 1290 { 1291 case kIOAudioEngineCallRegisterClientBuffer: 1292 if (arguments != 0) 1293 { 1294 if ( arguments->scalarInputCount >= 4 ) // <rdar://9204853> 1295 { 1296 result = registerBuffer64((IOAudioStream *)arguments->scalarInput[0], (mach_vm_address_t)arguments->scalarInput[1], (UInt32)arguments->scalarInput[2], (UInt32)arguments->scalarInput[3] ); 1297 } 1298 else 1299 { 1300 audioDebugIOLog(3, " kIOAudioEngineCallRegisterClientBuffer: invalid input argument count %d. Need at least 4.\n", arguments->scalarInputCount); 1301 } 1302 } 1303 break; 1304 case kIOAudioEngineCallUnregisterClientBuffer: 1305 if (arguments != 0) 1306 { 1307 if ( arguments->scalarInputCount >= 2 ) // <rdar://9204853> 1308 { 1309 result = unregisterBuffer64((mach_vm_address_t)arguments->scalarInput[0], (UInt32)arguments->scalarInput[1] ); 1310 } 1311 else 1312 { 1313 audioDebugIOLog(3, " kIOAudioEngineCallUnregisterClientBuffer: invalid input argument count %d. Need at least 2.\n", arguments->scalarInputCount); 1314 } 1315 } 1316 break; default: 1317 result = super::externalMethod(selector, arguments, dispatch, target, reference ); 1318 break; 1319 } 1320 audioDebugIOLog(3, "- IOAudioEngineUserClient::externalMethod returns 0x%lX\n", (long unsigned int)result ); 1321 return result; 1322} 1323 1324// 32 bit version <rdar://problems/5321701> 1325IOReturn IOAudioEngineUserClient::registerBuffer(IOAudioStream *audioStream, void * sourceBuffer, UInt32 bufSizeInBytes, UInt32 bufferSetID) 1326{ 1327 audioDebugIOLog(3, "+-IOAudioEngineUserClient::registerBuffer Deprecated 0x%llx %p 0x%lx 0x%lx\n", (unsigned long long )audioStream, sourceBuffer, (long unsigned int)bufSizeInBytes, (long unsigned int)bufferSetID); 1328 1329 return kIOReturnUnsupported; 1330} 1331 1332// 64 bit version <rdar://problems/5321701> 1333IOReturn IOAudioEngineUserClient::registerBuffer64(IOAudioStream *audioStream, mach_vm_address_t sourceBuffer, UInt32 bufSizeInBytes, UInt32 bufferSetID) 1334{ 1335 IOReturn ret = kIOReturnError; 1336 1337 audioDebugIOLog(3, "+ IOAudioEngineUserClient::registerBuffer64 0x%llx 0x%llx 0x%lx 0x%lx\n", (unsigned long long )audioStream, sourceBuffer, (long unsigned int)bufSizeInBytes, (long unsigned int)bufferSetID); 1338 1339 // <rdar://7363756>, <rdar://7529580> 1340 if ( workLoop ) 1341 { 1342 ret = workLoop->runAction(_registerBufferAction, this, audioStream, &sourceBuffer, (void *)(uintptr_t)bufSizeInBytes, (void *)(uintptr_t)bufferSetID); // <rdar://7529580> 1343 } 1344 1345 audioDebugIOLog(3, "- IOAudioEngineUserClient::registerBuffer64 0x%llx 0x%llx 0x%lx 0x%lx returns 0x%lX\n", (unsigned long long )audioStream, sourceBuffer, (long unsigned int)bufSizeInBytes, (long unsigned int)bufferSetID, (long unsigned int)ret ); 1346 return ret; 1347} 1348 1349// 32 bit version <rdar://problems/5321701> 1350IOReturn IOAudioEngineUserClient::unregisterBuffer( void * sourceBuffer, UInt32 bufferSetID) 1351{ 1352 audioDebugIOLog(3, "+-IOAudioEngineUserClient::unregisterBuffer 32 bit version NOT SUPPORTED \n" ); 1353 return kIOReturnUnsupported; 1354} 1355 1356// 64 bit version <rdar://problems/5321701> 1357IOReturn IOAudioEngineUserClient::unregisterBuffer64( mach_vm_address_t sourceBuffer, UInt32 bufferSetID) 1358{ 1359 IOReturn ret = kIOReturnError; 1360 1361 // <rdar://7363756>, <rdar://7529580> 1362 if ( workLoop ) 1363 { 1364 ret = workLoop->runAction(_unregisterBufferAction, this, ( void * ) &sourceBuffer, (void *)(uintptr_t)bufferSetID); // <rdar://7529580> 1365 } 1366 1367 return ret; 1368} 1369 1370// <rdar://7529580> 1371IOReturn IOAudioEngineUserClient::_registerBufferAction(OSObject *target, void *arg0, void *arg1, void *arg2, void *arg3) 1372{ 1373 IOReturn result = kIOReturnBadArgument; 1374 1375 if (target) { 1376 IOAudioEngineUserClient *userClient = OSDynamicCast(IOAudioEngineUserClient, target); 1377 if (userClient) { 1378 if (userClient->commandGate) { 1379 setCommandGateUsage(userClient, true); // <rdar://8518215> 1380 result = userClient->commandGate->runAction(registerBufferAction, arg0, arg1, arg2, arg3); 1381 setCommandGateUsage(userClient, false); // <rdar://8518215> 1382 } else { 1383 result = kIOReturnError; 1384 } 1385 } 1386 } 1387 1388 return result; 1389} 1390 1391IOReturn IOAudioEngineUserClient::registerBufferAction(OSObject *owner, void *arg1, void *arg2, void *arg3, void *arg4) 1392{ 1393 IOReturn result = kIOReturnBadArgument; 1394 1395 audioDebugIOLog(3, "+ IOAudioEngineUserClient::registerBufferAction %p \n", arg1 ); 1396 1397 if (owner) { 1398 IOAudioEngineUserClient *userClient = OSDynamicCast(IOAudioEngineUserClient, owner); 1399 1400 if (userClient) { 1401#if __LP64__ 1402 UInt32 bufSizeInBytes = (UInt32)((UInt64)arg3 & 0x00000000FFFFFFFFLLU); 1403 UInt32 bufferSetID = (UInt32)((UInt64)arg4 & 0x00000000FFFFFFFFLLU); 1404 UInt32 audioStreamIndex = (UInt32)((UInt64)arg1 & 0x00000000FFFFFFFFLLU); 1405#else 1406 UInt32 bufSizeInBytes = (UInt32) arg3; 1407 UInt32 bufferSetID = (UInt32) arg4; 1408 UInt32 audioStreamIndex = (UInt32) arg1; 1409#endif 1410 1411 result = userClient->safeRegisterClientBuffer64( audioStreamIndex, ( mach_vm_address_t * ) arg2, bufSizeInBytes, bufferSetID); 1412 } 1413 } 1414 1415 audioDebugIOLog(3, "- IOAudioEngineUserClient::registerBufferAction %p returns 0x%lX\n", arg1, (long unsigned int)result ); 1416 return result; 1417} 1418 1419// <rdar://7529580> 1420IOReturn IOAudioEngineUserClient::_unregisterBufferAction(OSObject *target, void *arg0, void *arg1, void *arg2, void *arg3) 1421{ 1422 IOReturn result = kIOReturnBadArgument; 1423 1424 if (target) { 1425 IOAudioEngineUserClient *userClient = OSDynamicCast(IOAudioEngineUserClient, target); 1426 if (userClient) { 1427 if (userClient->commandGate) { 1428 setCommandGateUsage(userClient, true); // <rdar://8518215> 1429 result = userClient->commandGate->runAction(unregisterBufferAction, arg0, arg1, arg2, arg3); 1430 setCommandGateUsage(userClient, false); // <rdar://8518215> 1431 } else { 1432 result = kIOReturnError; 1433 } 1434 } 1435 } 1436 1437 return result; 1438} 1439 1440IOReturn IOAudioEngineUserClient::unregisterBufferAction(OSObject *owner, void *arg1, void *arg2, void *arg3, void *arg4) 1441{ 1442 IOReturn result = kIOReturnBadArgument; 1443 1444 if (owner) { 1445 IOAudioEngineUserClient *userClient = OSDynamicCast(IOAudioEngineUserClient, owner); 1446 1447 if (userClient) { 1448#if __LP64__ 1449 UInt32 bufferSetID = (UInt32)((UInt64)arg2 & 0x00000000FFFFFFFFLLU); 1450#else 1451 UInt32 bufferSetID = (UInt32) arg2; 1452#endif 1453 result = userClient->unregisterClientBuffer64( ( mach_vm_address_t * )arg1, bufferSetID); 1454 } 1455 } 1456 1457 return result; 1458} 1459// 32 bit version <rdar://problems/5321701> 1460IOReturn IOAudioEngineUserClient::registerClientBuffer(IOAudioStream *audioStream, void * sourceBuffer, UInt32 bufSizeInBytes, UInt32 bufferSetID) 1461{ 1462 audioDebugIOLog(3, "+-IOAudioEngineUserClient[%p]::registerClientBuffer 32 bit version Deprecated (%p[%ld], %p, 0x%lx, 0x%lx)\n", this, audioStream, (long int)audioStream->getStartingChannelID(), sourceBuffer, (long unsigned int)bufSizeInBytes, (long unsigned int)bufferSetID); 1463 return kIOReturnUnsupported; 1464} 1465// 64 bit version <rdar://problems/5321701> 1466IOReturn IOAudioEngineUserClient::registerClientBuffer64(IOAudioStream *audioStream, mach_vm_address_t sourceBuffer, UInt32 bufSizeInBytes, UInt32 bufferSetID) 1467{ 1468 IOReturn result = kIOReturnSuccess; 1469 IOAudioClientBuffer64 *clientBuffer; 1470 IODirection bufferDirection; 1471 const IOAudioStreamFormat *streamFormat; 1472 1473 audioDebugIOLog(3, "+ IOAudioEngineUserClient[%p]::registerClientBuffer64 (%p[%ld], 0x%llx, 0x%lx, 0x%lx)\n", this, audioStream, (long int)audioStream->getStartingChannelID(), sourceBuffer, (long unsigned int)bufSizeInBytes, (long unsigned int)bufferSetID); 1474 if (!isInactive()) 1475 { 1476 IOAudioClientBufferSet *clientBufferSet; 1477 IOAudioClientBuffer64 **clientBufferList; 1478 1479 if (!sourceBuffer || !audioStream || (bufSizeInBytes == 0) ) 1480 { 1481 audioDebugIOLog(3, " bad argument\n"); 1482 return kIOReturnBadArgument; 1483 } 1484 1485 streamFormat = audioStream->getFormat(); 1486 if (!streamFormat) 1487 { 1488 audioDebugIOLog(3, " no format\n"); 1489 return kIOReturnError; 1490 } 1491 1492 // Return an error if this is an unmixable stream and it already has a client 1493 if (!streamFormat->fIsMixable && (audioStream->getNumClients() != 0)) 1494 { 1495 audioDebugIOLog(3, " mix problem or client exists\n"); 1496 return kIOReturnExclusiveAccess; 1497 } 1498 1499 // <rdar://10282154> Check if the source buffer is already registered in the 1500 // buffer set. If it is already registered, unregister the existing source 1501 // buffer from the buffer set. 1502 lockBuffers(); 1503 1504 clientBufferSet = findBufferSet(bufferSetID); 1505 if (clientBufferSet) { 1506 if (audioStream->getDirection() == kIOAudioStreamDirectionOutput) { 1507 clientBufferList = &clientBufferSet->outputBufferList; 1508 } else { 1509 clientBufferList = &clientBufferSet->inputBufferList; 1510 } 1511 1512 assert(clientBufferList); 1513 1514 if (*clientBufferList != NULL) { 1515 IOAudioClientBuffer64 *clientBufPtr = *clientBufferList; 1516 while (clientBufPtr != NULL) { 1517 if (clientBufPtr->mUnmappedSourceBuffer64 == sourceBuffer) { 1518 audioDebugIOLog(3, " source buffer (0x%llx) already registered in buffer set 0x%lx. Unregister existing source buffer...\n", sourceBuffer, (long unsigned int)bufferSetID); 1519 unregisterClientBuffer64(&sourceBuffer, bufferSetID); 1520 break; 1521 } 1522 clientBufPtr = clientBufPtr->mNextBuffer64; 1523 } 1524 } 1525 } 1526 1527 unlockBuffers(); 1528 1529 // allocate IOAudioClientBuffer to hold buffer descriptor, etc... 1530 clientBuffer = (IOAudioClientBuffer64 *)IOMallocAligned(sizeof(IOAudioClientBuffer64), sizeof (IOAudioClientBuffer64 *)); 1531 if (!clientBuffer) 1532 { 1533 audioDebugIOLog(3, " no clientbuffer\n"); 1534 result = kIOReturnNoMemory; 1535 goto Exit; 1536 } 1537 1538 // make sure everthing is set to NULL [2851917] 1539 bzero(clientBuffer,sizeof(IOAudioClientBuffer64)); 1540 1541 clientBuffer->mAudioClientBuffer32.userClient = this; 1542 1543 bufferDirection = audioStream->getDirection() == kIOAudioStreamDirectionOutput ? kIODirectionIn : kIODirectionOut; 1544 1545 audioStream->retain(); 1546 clientBuffer->mAudioClientBuffer32.audioStream = audioStream; 1547 1548 clientBuffer->mAudioClientBuffer32.sourceBufferDescriptor = IOMemoryDescriptor::withAddressRange((mach_vm_address_t)sourceBuffer, (mach_vm_size_t)bufSizeInBytes, kIODirectionNone, clientTask); 1549 if (!clientBuffer->mAudioClientBuffer32.sourceBufferDescriptor) 1550 { 1551 audioDebugIOLog(3, " no sourcebufferdescriptor\n"); 1552 result = kIOReturnInternalError; 1553 goto Exit; 1554 } 1555 1556 if ( kIOReturnSuccess != (result = clientBuffer->mAudioClientBuffer32.sourceBufferDescriptor->prepare( kIODirectionOutIn ) ) ) 1557 { 1558 audioDebugIOLog(3, " prepare error \n"); 1559 goto Exit; 1560 } 1561 1562 clientBuffer->mAudioClientBuffer32.sourceBufferMap = clientBuffer->mAudioClientBuffer32.sourceBufferDescriptor->map(); 1563 1564 1565 if (clientBuffer->mAudioClientBuffer32.sourceBufferMap == NULL) 1566 { 1567 IOLog("IOAudioEngineUserClient<0x%p>::registerClientBuffer64() - error mapping memory.\n", this); 1568 result = kIOReturnVMError; 1569 goto Exit; 1570 } 1571 1572 clientBuffer->mAudioClientBuffer32.sourceBuffer = (void *)clientBuffer->mAudioClientBuffer32.sourceBufferMap->getVirtualAddress(); 1573 if (clientBuffer->mAudioClientBuffer32.sourceBuffer == NULL) 1574 { 1575 result = kIOReturnVMError; 1576 goto Exit; 1577 } 1578 // offset past per buffer info 1579 audioDebugIOLog(3, " clientBuffer->mAudioClientBuffer32.sourceBuffer before offset: %p, offset size: %ld\n", clientBuffer->mAudioClientBuffer32.sourceBuffer, offsetof(IOAudioBufferDataDescriptor, fData)); 1580 clientBuffer->mAudioClientBuffer32.bufferDataDescriptor = (IOAudioBufferDataDescriptor *)(clientBuffer->mAudioClientBuffer32.sourceBuffer); 1581 clientBuffer->mAudioClientBuffer32.sourceBuffer = (UInt8 *)(clientBuffer->mAudioClientBuffer32.sourceBuffer) + offsetof(IOAudioBufferDataDescriptor, fData); 1582 audioDebugIOLog(3, " clientBuffer->mAudioClientBuffer32.sourceBuffer after offset: %p\n", clientBuffer->mAudioClientBuffer32.sourceBuffer); 1583 1584 numSampleFrames = bufSizeInBytes; 1585 if (streamFormat->fIsMixable) { 1586 // If it's mixable the data is floats, so that's the size of each sample 1587 clientBuffer->mAudioClientBuffer32.numSampleFrames = ( bufSizeInBytes - offsetof(IOAudioBufferDataDescriptor, fData) ) / (kIOAudioEngineDefaultMixBufferSampleSize * streamFormat->fNumChannels); 1588 } else { 1589 // If it's not mixable then the size is whatever the bitwidth is 1590 clientBuffer->mAudioClientBuffer32.numSampleFrames = ( bufSizeInBytes - offsetof(IOAudioBufferDataDescriptor, fData) ) / ((streamFormat->fBitWidth / 8) * streamFormat->fNumChannels); 1591 } 1592 clientBuffer->mAudioClientBuffer32.numChannels = streamFormat->fNumChannels; 1593 clientBuffer->mUnmappedSourceBuffer64 = sourceBuffer; 1594 clientBuffer->mAudioClientBuffer32.unmappedSourceBuffer = (void *)sourceBuffer; 1595 clientBuffer->mNextBuffer64 = NULL; 1596 clientBuffer->mAudioClientBuffer32.mNextBuffer32 = NULL; 1597 clientBuffer->mAudioClientBuffer32.nextClip = NULL; 1598 clientBuffer->mAudioClientBuffer32.previousClip = NULL; 1599 clientBuffer->mAudioClientBuffer32.nextClient = NULL; 1600 1601 lockBuffers(); 1602 1603 clientBufferSet = findBufferSet(bufferSetID); 1604 if (clientBufferSet == NULL) { 1605 audioDebugIOLog(3, " creating new IOAudioClientBufferSet \n" ); 1606 clientBufferSet = new IOAudioClientBufferSet; 1607 1608 if (clientBufferSet == NULL) { 1609 result = kIOReturnNoMemory; 1610 unlockBuffers(); 1611 goto Exit; 1612 } 1613 1614 if (!clientBufferSet->init(bufferSetID, this)) { 1615 result = kIOReturnError; 1616 unlockBuffers(); 1617 goto Exit; 1618 } 1619 1620 clientBufferSet->mNextBufferSet = clientBufferSetList; 1621 1622 clientBufferSetList = clientBufferSet; 1623 } 1624 1625 if (audioStream->getDirection() == kIOAudioStreamDirectionOutput) { 1626 audioDebugIOLog(3, " output \n" ); 1627 clientBufferList = &clientBufferSet->outputBufferList; 1628 if (clientBufferSet->watchdogThreadCall == NULL) { 1629 clientBufferSet->allocateWatchdogTimer(); 1630 if (clientBufferSet->watchdogThreadCall == NULL) { 1631 result = kIOReturnNoMemory; 1632 unlockBuffers(); 1633 goto Exit; 1634 } 1635 } 1636 } else { 1637 audioDebugIOLog(3, " input \n" ); 1638 clientBufferList = &clientBufferSet->inputBufferList; 1639 } 1640 1641 assert(clientBufferList); 1642 1643 if (*clientBufferList == NULL) { 1644 *clientBufferList = clientBuffer; 1645 } else { 1646 IOAudioClientBuffer64 *clientBufPtr = *clientBufferList; 1647 while (clientBufPtr->mNextBuffer64 != NULL) { 1648 clientBufPtr = clientBufPtr->mNextBuffer64; 1649 } 1650 audioDebugIOLog(3, " assigning clientBufPtr->mAudioClientBuffer32.mNextBuffer32 %p \n", &clientBuffer->mAudioClientBuffer32 ); 1651 clientBufPtr->mNextBuffer64 = clientBuffer; 1652 clientBufPtr->mAudioClientBuffer32.mNextBuffer32 = &clientBuffer->mAudioClientBuffer32; 1653 } 1654 1655 // <rdar://11731381> Add the client while holding the buffers lock to avoid race conditions. 1656 if (isOnline()) { 1657 audioDebugIOLog(3, " isOnline adding client \n" ); 1658 1659 result = audioStream->addClient( &clientBuffer->mAudioClientBuffer32 ); 1660 1661 // Clean up the client buffer list in the event of failure. 1662 if (kIOReturnSuccess != result) { 1663 if (*clientBufferList == clientBuffer) { 1664 *clientBufferList = NULL; 1665 } else { 1666 IOAudioClientBuffer64 *clientBufPtr = *clientBufferList; 1667 while ((NULL != clientBufPtr) && (clientBufPtr->mNextBuffer64 != clientBuffer)) { 1668 clientBufPtr = clientBufPtr->mNextBuffer64; 1669 } 1670 clientBufPtr->mNextBuffer64 = NULL; 1671 clientBufPtr->mAudioClientBuffer32.mNextBuffer32 = NULL; 1672 } 1673 } 1674 } 1675 else { 1676 audioDebugIOLog(3, " !isOnline \n" ); 1677 } 1678 1679 unlockBuffers(); 1680 1681 Exit: 1682 1683 if (result != kIOReturnSuccess) { 1684 audioDebugIOLog(3, " result (0x%x) != kIOReturnSuccess \n", result ); 1685 if (clientBuffer != NULL) { 1686 if (clientBuffer->mAudioClientBuffer32.sourceBufferDescriptor != NULL) { 1687 clientBuffer->mAudioClientBuffer32.sourceBufferDescriptor->release(); 1688 clientBuffer->mAudioClientBuffer32.sourceBufferDescriptor = NULL; 1689 } 1690 if (clientBuffer->mAudioClientBuffer32.sourceBufferMap != NULL) { 1691 clientBuffer->mAudioClientBuffer32.sourceBufferMap->release(); 1692 clientBuffer->mAudioClientBuffer32.sourceBufferMap = NULL; 1693 } 1694 if (clientBuffer->mAudioClientBuffer32.audioStream) { 1695 clientBuffer->mAudioClientBuffer32.audioStream->release(); 1696 clientBuffer->mAudioClientBuffer32.audioStream = NULL; 1697 } 1698 IOFreeAligned(clientBuffer, sizeof(IOAudioClientBuffer64)); 1699 clientBuffer = NULL; 1700 } 1701 } 1702 1703 } else { 1704 audioDebugIOLog(3, " !isActive - no Device \n" ); 1705 result = kIOReturnNoDevice; 1706 } 1707 audioDebugIOLog(3, "- IOAudioEngineUserClient::registerClientBuffer64() result 0x%lX\n", (long unsigned int)result); 1708 1709 return result; 1710} 1711// 32 bit version <rdar://problems/5321701> 1712IOReturn IOAudioEngineUserClient::unregisterClientBuffer( void * sourceBuffer, UInt32 bufferSetID) 1713{ 1714 IOReturn result = kIOReturnUnsupported; 1715 audioDebugIOLog(3, "+-IOAudioEngineUserClient[%p]::unregisterClientBuffer NOT SUPPORTED for 32 bit buffer( %p, 0x%lx)\n", this, sourceBuffer, (long unsigned int)bufferSetID); 1716 return result; 1717} 1718// 64 bit version <rdar://problems/5321701> 1719IOReturn IOAudioEngineUserClient::unregisterClientBuffer64( mach_vm_address_t * sourceBuffer, UInt32 bufferSetID) 1720{ 1721 IOReturn result = kIOReturnBadArgument; 1722 1723 audioDebugIOLog(3, "+ IOAudioEngineUserClient[%p]::unregisterClientBuffer64(0x%p, 0x%lx)\n", this, sourceBuffer, (long unsigned int)bufferSetID); 1724 1725 if (sourceBuffer) { 1726 IOAudioClientBufferSet *bufferSet; 1727 1728 lockBuffers(); 1729 1730 bufferSet = findBufferSet(bufferSetID); 1731 1732 if (bufferSet) { 1733 IOAudioClientBuffer64 *clientBuf = NULL, *previousBuf = NULL; 1734 IOAudioClientBuffer64 **clientBufferList = NULL; 1735 1736 if (bufferSet->outputBufferList) 1737 { 1738 clientBufferList = &bufferSet->outputBufferList; 1739 audioDebugIOLog(3, " searching for sourceBuffer 0x%llx \n", *sourceBuffer); 1740 clientBuf = bufferSet->outputBufferList; 1741 previousBuf = NULL; 1742 1743 while (clientBuf && (clientBuf->mUnmappedSourceBuffer64 != *sourceBuffer)) 1744 { 1745 audioDebugIOLog(3, " checking against 0x%llx \n", clientBuf->mUnmappedSourceBuffer64); 1746 previousBuf = clientBuf; 1747 clientBuf = clientBuf->mNextBuffer64; 1748 } 1749 } 1750 else 1751 { 1752 audioDebugIOLog(3, " clientBuf for output not found \n"); 1753 } 1754 1755 // If we didn't find the buffer in the output list, check the input list 1756 if (!clientBuf && bufferSet->inputBufferList) { 1757 audioDebugIOLog(3, " checking input \n"); 1758 clientBufferList = &bufferSet->inputBufferList; 1759 clientBuf = bufferSet->inputBufferList; 1760 previousBuf = NULL; 1761 while (clientBuf && (clientBuf->mUnmappedSourceBuffer64 != *sourceBuffer)) { 1762 previousBuf = clientBuf; 1763 clientBuf = clientBuf->mNextBuffer64; 1764 } 1765 } 1766 1767 if (clientBuf) { 1768 1769 assert(clientBuf->mUnmappedSourceBuffer64 == *sourceBuffer); 1770 1771 if (previousBuf) { 1772 previousBuf->mNextBuffer64 = clientBuf->mNextBuffer64; 1773 } else { 1774 assert(clientBufferList); 1775 *clientBufferList = clientBuf->mNextBuffer64; 1776 } 1777 1778 if (bufferSet->outputBufferList == NULL) { 1779 if (bufferSet->inputBufferList == NULL) { 1780 removeBufferSet(bufferSet); 1781 } else if (bufferSet->watchdogThreadCall != NULL) { 1782 bufferSet->freeWatchdogTimer(); 1783 } 1784 } 1785 1786 freeClientBuffer(clientBuf); // Moved below above if statement 1787 1788 result = kIOReturnSuccess; 1789 } else 1790 { 1791 audioDebugIOLog(3, " no clientbuffer found \n" ); 1792 result = kIOReturnNotFound; 1793 } 1794 } else 1795 { 1796 audioDebugIOLog(3, " no bufferSet found for id 0x%lx \n", (long unsigned int)bufferSetID); 1797 result = kIOReturnNotFound; 1798 } 1799 1800 unlockBuffers(); 1801 } 1802 else 1803 { 1804 audioDebugIOLog(3, " no sourcebuffer \n" ); 1805 } 1806 audioDebugIOLog(3, "- IOAudioEngineUserClient::unregisterClientBuffer64 no sourcebuffer returns 0x%lX\n", (long unsigned int)result ); 1807 return result; 1808} 1809 1810IOAudioClientBufferSet *IOAudioEngineUserClient::findBufferSet(UInt32 bufferSetID) 1811{ 1812 IOAudioClientBufferSet *bufferSet = NULL; 1813 1814 audioDebugIOLog(7, "+ IOAudioEngineUserClient::findBufferSet ( bufferSetID %ld )\n", (long int)bufferSetID ); // <rdar://9725460> 1815 1816 if (0 == clientBufferSetList) 1817 { 1818 audioDebugIOLog(3, " null clientBufferSetList\n"); 1819 } 1820 bufferSet = clientBufferSetList; 1821 while (bufferSet && (bufferSet->bufferSetID != bufferSetID)) { 1822 bufferSet = bufferSet->mNextBufferSet; 1823 } 1824 if ( !bufferSet || ( bufferSet->bufferSetID != bufferSetID ) ) 1825 { 1826 audioDebugIOLog(3, " did not find clientBufferSetList for ID 0x%lx \n", (long unsigned int)bufferSetID); 1827 } 1828 audioDebugIOLog(7, "- IOAudioEngineUserClient::findBufferSet ( bufferSetID %ld ) returns %p\n", (long int)bufferSetID, bufferSet ); // <rdar://9725460> 1829 return bufferSet; 1830} 1831 1832void IOAudioEngineUserClient::removeBufferSet(IOAudioClientBufferSet *bufferSet) 1833{ 1834 IOAudioClientBufferSet *prevSet, *nextSet; 1835 1836 audioDebugIOLog(3, "+ IOAudioEngineUserClient[%p]::removeBufferSet(%p)\n", this, bufferSet); 1837 1838 lockBuffers(); 1839 1840 nextSet = clientBufferSetList; 1841 prevSet = NULL; 1842 while (nextSet && (nextSet != bufferSet)) { 1843 prevSet = nextSet; 1844 nextSet = nextSet->mNextBufferSet; 1845 } 1846 1847 if (nextSet) { 1848 assert(nextSet == bufferSet); 1849 1850 nextSet->cancelWatchdogTimer(); 1851 1852 if (prevSet) { 1853 prevSet->mNextBufferSet = nextSet->mNextBufferSet; 1854 } else { 1855 clientBufferSetList = nextSet->mNextBufferSet; 1856 } 1857 1858 nextSet->release(); 1859 } 1860 1861 unlockBuffers(); 1862 1863 audioDebugIOLog(3, "- IOAudioEngineUserClient[%p]::removeBufferSet(%p)\n", this, bufferSet); 1864 return; 1865} 1866 1867IOReturn IOAudioEngineUserClient::performClientIO(UInt32 firstSampleFrame, UInt32 loopCount, bool inputIO, UInt32 bufferSetID, UInt32 sampleIntervalHi, UInt32 sampleIntervalLo) 1868{ 1869 IOReturn result = kIOReturnSuccess; 1870 1871 audioDebugIOLog(7, "+ IOAudioEngineUserClient[%p]::performClientIO(0x%lx, 0x%lx, %d, 0x%lx, 0x%lx, 0x%lx )\n", 1872 this, 1873 (long unsigned int)firstSampleFrame, 1874 (long unsigned int)loopCount, inputIO, 1875 (long unsigned int)bufferSetID, 1876 (long unsigned int)sampleIntervalHi, 1877 (long unsigned int)sampleIntervalLo ); 1878 assert(audioEngine); 1879 1880 if (!isInactive()) 1881 { 1882 lockBuffers(); 1883 1884 if (isOnline() && (audioEngine->getState() == kIOAudioEngineRunning) && audioEngine->status && ( audioEngine->status->fCurrentLoopCount || audioEngine->status->fLastLoopTime ) ) // <rdar://12879939> Wait for first takeTimeStamp call before allowing audio 1885 { 1886 if (firstSampleFrame < audioEngine->numSampleFramesPerBuffer) 1887 { 1888 IOAudioClientBufferSet *bufferSet; 1889 1890 bufferSet = findBufferSet(bufferSetID); 1891 if (bufferSet) 1892 { 1893 1894 if (inputIO) 1895 { 1896 result = performClientInput(firstSampleFrame, bufferSet); 1897 } else 1898 { 1899 result = performClientOutput(firstSampleFrame, loopCount, bufferSet, sampleIntervalHi, sampleIntervalLo); 1900 } 1901 } 1902 else 1903 { 1904 audioDebugIOLog(3, " no bufferset\n"); 1905 } 1906 } 1907 else 1908 { 1909 audioDebugIOLog(3, " firstSampleFrame ( 0x%lx) is out of range - 0x%lx frames per buffer.\n", (long unsigned int)firstSampleFrame, (long unsigned int)audioEngine->numSampleFramesPerBuffer); 1910 result = kIOReturnBadArgument; 1911 } 1912 } 1913 else 1914 { 1915 audioDebugIOLog(3, "IOAudioEngineUserClient[%p] - AUDIO OFFLINE. online=%d. state=%d. loopCount=%d, lastLoopTime=%d\n", this, isOnline(), audioEngine->getState(), audioEngine->status->fCurrentLoopCount, (unsigned int)audioEngine->status->fLastLoopTime); 1916 result = kIOReturnOffline; 1917 } 1918 1919 unlockBuffers(); 1920 } else 1921 { 1922 result = kIOReturnNoDevice; 1923 } 1924 1925 audioDebugIOLog(7, "- IOAudioEngineUserClient::performClientIO result = 0x%lX\n", (long unsigned int)result); // <rdar://9725460> 1926 return result; 1927} 1928 1929// model a SwapFloat32 after CF 1930inline uint32_t CFSwapInt32(uint32_t arg) { 1931#if defined(__i386__) && defined(__GNUC__) 1932 __asm__("bswap %0" : "+r" (arg)); 1933 return arg; 1934#elif defined(__x86_64__) && defined(__GNUC__) // <rdar://6612182> 1935 __asm__("bswap %0" : "+r" (arg)); 1936 return arg; 1937#elif defined(__ppc__) && defined(__GNUC__) 1938 uint32_t result; 1939 __asm__("lwbrx %0,0,%1" : "=r" (result) : "r" (&arg), "m" (arg)); 1940 return result; 1941#else 1942 uint32_t result; 1943 result = ((arg & 0xFF) << 24) | ((arg & 0xFF00) << 8) | ((arg >> 8) & 0xFF00) | ((arg >> 24) & 0xFF); 1944 return result; 1945#endif 1946} 1947 1948 1949void FlipFloats(void *p, long fcnt) 1950{ 1951 UInt32 *ip = (UInt32 *)p; 1952 1953 while (fcnt--) { 1954 *ip = CFSwapInt32(*ip); 1955 ip++; 1956 } 1957} 1958 1959static inline IOAudioBufferDataDescriptor * FlipBufferDataDescriptor(IOAudioBufferDataDescriptor *in, IOAudioBufferDataDescriptor *tmp, UInt32 doFlip) 1960{ 1961 if (in && doFlip) { 1962 tmp->fActualDataByteSize = CFSwapInt32(in->fActualDataByteSize); 1963 tmp->fActualNumSampleFrames = CFSwapInt32(in->fActualNumSampleFrames); 1964 tmp->fTotalDataByteSize = CFSwapInt32(in->fTotalDataByteSize); 1965 tmp->fNominalDataByteSize = CFSwapInt32(in->fNominalDataByteSize); 1966 return tmp; 1967 } 1968 return in; 1969} 1970 1971IOReturn IOAudioEngineUserClient::performClientOutput(UInt32 firstSampleFrame, UInt32 loopCount, IOAudioClientBufferSet *bufferSet, UInt32 sampleIntervalHi, UInt32 sampleIntervalLo) 1972{ 1973 IOReturn tmpResult, result = kIOReturnSuccess; 1974 1975 // <rdar://9725460> 1976 audioDebugIOLog ( 4, "+ IOAudioEngineUserClient[%p]::performClientOutput ( firstSampleFrame %ld, loopCount %ld, bufferSet %p, sampleIntervalHi %ld, sampleIntervalLo %ld )\n", 1977 this, 1978 (long int)firstSampleFrame, 1979 (long int)loopCount, 1980 bufferSet, 1981 (long int)sampleIntervalHi, 1982 (long int)sampleIntervalLo ); 1983 1984 assert(audioEngine != NULL); 1985 1986 // <rdar://10145205,15277619> Sanity check the loop count 1987 if ( ( loopCount >= audioEngine->status->fCurrentLoopCount ) && 1988 ( loopCount <= audioEngine->status->fCurrentLoopCount + kLoopCountMaximumDifference ) ) 1989 { 1990#if __LP64__ 1991 UInt64 tempHI = sampleIntervalHi; 1992 bufferSet->sampleInterval = tempHI << 32 | sampleIntervalLo; 1993#else 1994 bufferSet->sampleInterval.hi = sampleIntervalHi; 1995 bufferSet->sampleInterval.lo = sampleIntervalLo; 1996#endif 1997 1998 if (bufferSet->outputBufferList != NULL) { 1999 IOAudioEnginePosition outputEndingPosition; 2000 IOAudioClientBuffer64 *clientBuf; 2001 UInt32 sampleFrames, numSampleFramesPerBuffer; 2002 UInt32 clientIndex; 2003 2004 clientIndex = 0; 2005 2006 clientBuf = bufferSet->outputBufferList; 2007 2008 IOAudioBufferDataDescriptor localBufferDataDescriptor; 2009 IOAudioBufferDataDescriptor * localBufferDataDescriptorPtr = FlipBufferDataDescriptor ( clientBuf->mAudioClientBuffer32.bufferDataDescriptor, &localBufferDataDescriptor, reserved->classicMode ); 2010 2011 if (NULL != localBufferDataDescriptorPtr) { 2012 audioDebugIOLog(6, " performClientOutput -------------%ld-----------------\n", (long int)clientIndex); 2013 audioDebugIOLog ( 6, " actual frames = %ld, actual bytes = %ld, nominal bytes = %ld, total bytes = %ld\n", 2014 (long int)localBufferDataDescriptorPtr->fActualNumSampleFrames, 2015 (long int)localBufferDataDescriptorPtr->fActualDataByteSize, 2016 (long int)localBufferDataDescriptorPtr->fNominalDataByteSize, 2017 (long int)localBufferDataDescriptorPtr->fTotalDataByteSize ); 2018 sampleFrames = localBufferDataDescriptorPtr->fActualNumSampleFrames; 2019 } else { 2020 audioDebugIOLog(6, " no buffer descriptor found, using bufferSet->outputBufferList->numSampleFrames\n"); 2021 sampleFrames = bufferSet->outputBufferList->mAudioClientBuffer32.numSampleFrames; 2022 } 2023 2024 numSampleFramesPerBuffer = audioEngine->getNumSampleFramesPerBuffer(); 2025 2026 outputEndingPosition.fLoopCount = loopCount; 2027 outputEndingPosition.fSampleFrame = firstSampleFrame + sampleFrames; 2028 2029 if (outputEndingPosition.fSampleFrame >= numSampleFramesPerBuffer) { 2030 outputEndingPosition.fSampleFrame -= numSampleFramesPerBuffer; 2031 outputEndingPosition.fLoopCount++; 2032 } 2033 2034 // We only want to do output if we haven't already gone past the new samples 2035 // If the samples are late, the watchdog will already have skipped them 2036 if (CMP_IOAUDIOENGINEPOSITION(&outputEndingPosition, &bufferSet->nextOutputPosition) >= 0) { 2037 AbsoluteTime outputTimeout; 2038 2039 audioDebugIOLog(6, " CMP_IOAUDIOENGINEPOSITION >= 0 \n"); 2040 clientBuf = bufferSet->outputBufferList; 2041 2042 while (clientBuf) { 2043 IOAudioStream * audioStream; 2044 UInt32 maxNumSampleFrames; 2045 2046 audioStream = clientBuf->mAudioClientBuffer32.audioStream; 2047 2048 assert(audioStream); 2049 assert(audioStream->getDirection() == kIOAudioStreamDirectionOutput); 2050 assert(clientBuf->mAudioClientBuffer32.sourceBuffer != NULL); 2051 2052 audioStream->lockStreamForIO(); 2053 2054 maxNumSampleFrames = clientBuf->mAudioClientBuffer32.numSampleFrames; 2055 // <rdar://6865619>, <rdar://6917678> Validate the parameters passed in IOAudioBufferDataDescriptor vs the maximum buffer size. 2056 if ( sampleFrames > maxNumSampleFrames ) { 2057 audioDebugIOLog ( 1, " **** VBR OUTPUT ERROR! - actual sample frames (%ld) is larger than max sample frames (%ld)\n", (long int)sampleFrames, (long int)maxNumSampleFrames); 2058 audioStream->unlockStreamForIO(); 2059 result = kIOReturnBadArgument; 2060 goto Exit; 2061 } 2062 // get the per buffer info 2063 if (NULL != localBufferDataDescriptorPtr) { 2064 audioDebugIOLog ( 6, " clientBuffer = %p: actual frames = %lu, actual bytes = %lu, nominal bytes = %lu, total bytes = %lu, source buffer size = %lu\n", 2065 clientBuf, 2066 (long unsigned int)localBufferDataDescriptorPtr->fActualNumSampleFrames, 2067 (long unsigned int)localBufferDataDescriptorPtr->fActualDataByteSize, 2068 (long unsigned int)localBufferDataDescriptorPtr->fNominalDataByteSize, 2069 (long unsigned int)localBufferDataDescriptorPtr->fTotalDataByteSize, 2070 (long unsigned int)clientBuf->mAudioClientBuffer32.sourceBufferDescriptor->getLength () - offsetof ( IOAudioBufferDataDescriptor, fData ) ); 2071 2072 clientBuf->mAudioClientBuffer32.numSampleFrames = sampleFrames; 2073 2074 if ((localBufferDataDescriptorPtr->fActualDataByteSize > (clientBuf->mAudioClientBuffer32.sourceBufferDescriptor->getLength () - offsetof(IOAudioBufferDataDescriptor, fData))) || 2075 (localBufferDataDescriptorPtr->fActualDataByteSize > localBufferDataDescriptorPtr->fTotalDataByteSize) || 2076 (localBufferDataDescriptorPtr->fNominalDataByteSize > localBufferDataDescriptorPtr->fTotalDataByteSize)) { 2077 audioDebugIOLog ( 1, " **** VBR OUTPUT ERROR! clientBuffer = %p: actual frames = %ld, actual bytes = %ld, nominal bytes = %ld, total bytes = %ld, source buffer size = %ld\n", 2078 clientBuf, 2079 (long unsigned int)localBufferDataDescriptorPtr->fActualNumSampleFrames, 2080 (long unsigned int)localBufferDataDescriptorPtr->fActualDataByteSize, 2081 (long unsigned int)localBufferDataDescriptorPtr->fNominalDataByteSize, 2082 (long unsigned int)localBufferDataDescriptorPtr->fTotalDataByteSize, 2083 (long unsigned int)clientBuf->mAudioClientBuffer32.sourceBufferDescriptor->getLength () - offsetof(IOAudioBufferDataDescriptor, fData ) ); 2084 audioStream->unlockStreamForIO(); 2085 result = kIOReturnBadArgument; 2086 goto Exit; 2087 } 2088#ifdef DEBUG 2089 if (clientBuf->mAudioClientBuffer32.numSampleFrames != localBufferDataDescriptorPtr->fActualDataByteSize / (audioStream->format.fNumChannels * sizeof(float))) { 2090 audioDebugIOLog ( 6, " DEBUGGING - calculated sample frames (%ld) does not match actual sample frames (%ld)\n", 2091 (long unsigned int)localBufferDataDescriptorPtr->fActualDataByteSize / (audioStream->format.fNumChannels * sizeof(float)), 2092 (long unsigned int)clientBuf->mAudioClientBuffer32.numSampleFrames); 2093 } 2094#endif 2095 } 2096 2097 #if __i386__ || __x86_64__ // <rdar://6612182> 2098 if (reserved->classicMode && clientBuf->mAudioClientBuffer32.sourceBuffer != NULL) { 2099 const IOAudioStreamFormat *fmt = audioStream->getFormat(); 2100 if (fmt->fIsMixable && fmt->fSampleFormat == kIOAudioStreamSampleFormatLinearPCM) { 2101 FlipFloats(clientBuf->mAudioClientBuffer32.sourceBuffer, clientBuf->mAudioClientBuffer32.numSampleFrames * clientBuf->mAudioClientBuffer32.numChannels); 2102 } 2103 } 2104#endif 2105 2106 tmpResult = audioStream->processOutputSamples( &( clientBuf->mAudioClientBuffer32 ), firstSampleFrame, loopCount, true); 2107 2108 clientBuf->mAudioClientBuffer32.numSampleFrames = maxNumSampleFrames; 2109 2110 audioStream->unlockStreamForIO(); 2111 2112 if (tmpResult != kIOReturnSuccess) { 2113 audioDebugIOLog ( 3, " processOutputSamples failed - result 0x%x\n", tmpResult ); 2114 result = tmpResult; 2115 } 2116 2117 clientBuf = clientBuf->mNextBuffer64; 2118 2119 if (clientBuf) { // need to update localBufferDataDescriptor for the current client buffer 2120 localBufferDataDescriptorPtr = FlipBufferDataDescriptor ( clientBuf->mAudioClientBuffer32.bufferDataDescriptor, &localBufferDataDescriptor, reserved->classicMode ); 2121 2122 if (NULL != localBufferDataDescriptorPtr) { 2123 sampleFrames = localBufferDataDescriptorPtr->fActualNumSampleFrames; 2124 } else { 2125 sampleFrames = clientBuf->mAudioClientBuffer32.numSampleFrames; 2126 } 2127 } 2128 2129 clientIndex++; 2130 } 2131 2132 bufferSet->nextOutputPosition = outputEndingPosition; 2133 2134 tmpResult = audioEngine->calculateSampleTimeout(&bufferSet->sampleInterval, sampleFrames, &bufferSet->nextOutputPosition, &outputTimeout); 2135 2136 if (tmpResult == kIOReturnSuccess) { 2137 assert(bufferSet->watchdogThreadCall != NULL); // We better have a thread call if we are doing output 2138 2139 bufferSet->setWatchdogTimeout(&outputTimeout); 2140 } else { 2141 audioDebugIOLog ( 3, " calculateSampleTimeout failed - result 0x%x\n", tmpResult ); 2142 result = tmpResult; 2143 } 2144 } else { 2145 audioDebugIOLog(3, " performClientOutput(%lx,%lx) - missed samples (%lx,%lx)\n", 2146 (long unsigned int)loopCount, 2147 (long unsigned int)firstSampleFrame, 2148 (long unsigned int)bufferSet->nextOutputPosition.fLoopCount, 2149 (long unsigned int)bufferSet->nextOutputPosition.fSampleFrame); 2150 result = kIOReturnIsoTooOld; 2151 } 2152 } 2153 } else { 2154 audioDebugIOLog(3, " performClientOutput(%lx,%lx) - missed samples (%lx,%lx). fCurrentLoopCount=%lx\n", 2155 (long unsigned int)loopCount, 2156 (long unsigned int)firstSampleFrame, 2157 (long unsigned int)bufferSet->nextOutputPosition.fLoopCount, 2158 (long unsigned int)bufferSet->nextOutputPosition.fSampleFrame, 2159 (long unsigned int)audioEngine->status->fCurrentLoopCount); 2160 result = kIOReturnIsoTooOld; 2161 } 2162 2163Exit: 2164 // <rdar://9725460> 2165 audioDebugIOLog ( 4, "- IOAudioEngineUserClient[%p]::performClientOutput ( firstSampleFrame %ld, loopCount %ld, bufferSet %p, sampleIntervalHi %ld, sampleIntervalLo %ld ) returns 0x%lX\n", 2166 this, 2167 (long int)firstSampleFrame, 2168 (long int)loopCount, 2169 bufferSet, 2170 (long int)sampleIntervalHi, 2171 (long int)sampleIntervalLo, 2172 (long unsigned int)result ); 2173 return result; 2174} 2175 2176IOReturn IOAudioEngineUserClient::performClientInput(UInt32 firstSampleFrame, IOAudioClientBufferSet *bufferSet) 2177{ 2178 IOReturn result = kIOReturnSuccess; 2179 IOAudioClientBuffer64 *clientBuf; 2180 UInt32 sampleFrames = 0; 2181 2182 audioDebugIOLog ( 4, "+ IOAudioEngineUserClient[%p]::performClientInput ( firstSampleFrame %ld, bufferSet %p)\n", this, (long int)firstSampleFrame, bufferSet ); // <rdar://problem/9725460> 2183 2184 clientBuf = bufferSet->inputBufferList; 2185 2186 IOAudioBufferDataDescriptor localBufferDataDescriptor; 2187 IOAudioBufferDataDescriptor * localBufferDataDescriptorPtr = 0; 2188 2189 if (NULL != clientBuf) { 2190 localBufferDataDescriptorPtr = FlipBufferDataDescriptor ( clientBuf->mAudioClientBuffer32.bufferDataDescriptor, &localBufferDataDescriptor, reserved->classicMode ); 2191 if (NULL != localBufferDataDescriptorPtr) { 2192 audioDebugIOLog(6, " performClientInput ------------------------------\n"); 2193 audioDebugIOLog ( 6, " found buffer descriptor, using actual frames = %ld\n", 2194 (long int)localBufferDataDescriptorPtr->fActualNumSampleFrames); 2195 sampleFrames = localBufferDataDescriptorPtr->fActualNumSampleFrames; 2196 } else { 2197 audioDebugIOLog(6, " no buffer descriptor found, using bufferSet->inputBufferList->numSampleFrames\n"); 2198 sampleFrames = bufferSet->inputBufferList->mAudioClientBuffer32.numSampleFrames; 2199 } 2200 } 2201 2202 while (clientBuf) { 2203 IOAudioStream * audioStream; 2204 UInt32 maxNumSampleFrames; 2205 UInt32 numSampleFramesRead; 2206 IOReturn tmpResult; 2207 2208 audioStream = clientBuf->mAudioClientBuffer32.audioStream; 2209 2210 assert(audioStream); 2211 assert(audioStream->getDirection() == kIOAudioStreamDirectionInput); 2212 assert(clientBuf->mAudioClientBuffer32.sourceBuffer != NULL); 2213 2214 audioStream->lockStreamForIO(); 2215 2216 maxNumSampleFrames = clientBuf->mAudioClientBuffer32.numSampleFrames; 2217 // <rdar://6865619>, <rdar://6917678> Validate the parameters passed in IOAudioBufferDataDescriptor vs the maximum buffer size. 2218 if ( sampleFrames > maxNumSampleFrames ) 2219 { 2220 audioDebugIOLog ( 6, " **** VBR INPUT ERROR! - actual sample frames (%ld) is larger than max sample frames (%ld)\n", (long int)sampleFrames, (long int)maxNumSampleFrames); 2221 audioStream->unlockStreamForIO(); 2222 result = kIOReturnBadArgument; 2223 goto Exit; 2224 } 2225 2226 if (NULL != localBufferDataDescriptorPtr) { 2227 2228 clientBuf->mAudioClientBuffer32.numSampleFrames = sampleFrames; 2229 2230 audioDebugIOLog ( 6, " clientBuffer = %p: actual frames = %lu, actual bytes = %lu, nominal bytes = %lu, total bytes = %lu, source buffer size = %lu\n", 2231 clientBuf, 2232 (long unsigned int)clientBuf->mAudioClientBuffer32.numSampleFrames, 2233 (long unsigned int)localBufferDataDescriptorPtr->fActualDataByteSize, 2234 (long unsigned int)localBufferDataDescriptorPtr->fNominalDataByteSize, 2235 (long unsigned int)localBufferDataDescriptorPtr->fTotalDataByteSize, 2236 (long unsigned int)clientBuf->mAudioClientBuffer32.sourceBufferDescriptor->getLength () - offsetof ( IOAudioBufferDataDescriptor, fData ) ); 2237 2238 #ifdef DEBUG 2239 if (clientBuf->mAudioClientBuffer32.numSampleFrames != localBufferDataDescriptorPtr->fActualDataByteSize / (audioStream->format.fNumChannels * sizeof(float))) { 2240 audioDebugIOLog ( 6, " DEBUGGING - calculated sample frames (%ld) does not match actual sample frames (%ld)\n", 2241 localBufferDataDescriptorPtr->fActualDataByteSize / (audioStream->format.fNumChannels * sizeof(float)), 2242 (long int)clientBuf->mAudioClientBuffer32.numSampleFrames); 2243 } 2244 #endif 2245 if ((localBufferDataDescriptorPtr->fActualDataByteSize > (clientBuf->mAudioClientBuffer32.sourceBufferDescriptor->getLength () - offsetof(IOAudioBufferDataDescriptor, fData))) || 2246 (localBufferDataDescriptorPtr->fActualDataByteSize > localBufferDataDescriptorPtr->fTotalDataByteSize)) { 2247 audioDebugIOLog (1, " *** VBR INPUT ERROR! clientBuffer = %p: actual frames = %ld, actual bytes = %ld, nominal bytes = %ld, total bytes = %ld, source buffer size = %ld\n", 2248 clientBuf, 2249 (long unsigned int)clientBuf->mAudioClientBuffer32.numSampleFrames, 2250 (long unsigned int)localBufferDataDescriptorPtr->fActualDataByteSize, 2251 (long unsigned int)localBufferDataDescriptorPtr->fNominalDataByteSize, 2252 (long unsigned int)localBufferDataDescriptorPtr->fTotalDataByteSize, 2253 (long unsigned int)clientBuf->mAudioClientBuffer32.sourceBufferDescriptor->getLength () - offsetof ( IOAudioBufferDataDescriptor, fData ) ); 2254 audioStream->unlockStreamForIO(); 2255 result = kIOReturnBadArgument; 2256 goto Exit; 2257 } 2258 } 2259 2260 // set the default number of frames read. This allows drivers to override readInputSamples and still work in the VBR world 2261 audioStream->setDefaultNumSampleFramesRead(sampleFrames); 2262 2263 tmpResult = audioStream->readInputSamples( &( clientBuf->mAudioClientBuffer32 ), firstSampleFrame); 2264 2265#if __i386__ || __x86_64__ // <rdar://6612182> 2266 if (reserved->classicMode && clientBuf->mAudioClientBuffer32.sourceBuffer != NULL) { 2267 const IOAudioStreamFormat *fmt = audioStream->getFormat(); 2268 if (fmt->fIsMixable && fmt->fSampleFormat == kIOAudioStreamSampleFormatLinearPCM) 2269 { 2270 FlipFloats(clientBuf->mAudioClientBuffer32.sourceBuffer, clientBuf->mAudioClientBuffer32.numSampleFrames * clientBuf->mAudioClientBuffer32.numChannels); 2271 } 2272 } 2273#endif 2274 2275 // get how many samples the driver actually read & update the rest of the structures 2276 numSampleFramesRead = audioStream->getNumSampleFramesRead(); 2277 localBufferDataDescriptorPtr->fActualDataByteSize = numSampleFramesRead * audioStream->format.fNumChannels * sizeof(float); 2278 localBufferDataDescriptorPtr->fActualNumSampleFrames = numSampleFramesRead; 2279 FlipBufferDataDescriptor(localBufferDataDescriptorPtr, clientBuf->mAudioClientBuffer32.bufferDataDescriptor, reserved->classicMode); // save changes back to clientBuf 2280 2281 audioDebugIOLog ( 5, " numSampleFramesRead = %ld, fActualNumSampleFrames = %ld, fActualDataByteSize = %ld\n", 2282 (long int)numSampleFramesRead, 2283 (long int)localBufferDataDescriptorPtr->fActualNumSampleFrames, 2284 (long int)localBufferDataDescriptorPtr->fActualDataByteSize ); 2285 2286 clientBuf->mAudioClientBuffer32.numSampleFrames = maxNumSampleFrames; 2287 2288 audioStream->unlockStreamForIO(); 2289 2290 if (tmpResult != kIOReturnSuccess) { 2291 audioDebugIOLog ( 3, " readInputSamples failed - result 0x%x\n", tmpResult ); 2292 result = tmpResult; 2293 } 2294 2295 audioDebugIOLog ( 7, " next clientBuf \n" ); 2296 clientBuf = clientBuf->mNextBuffer64; 2297 2298 if (clientBuf) { // need to update localBufferDataDescriptor for the current client buffer 2299 localBufferDataDescriptorPtr = FlipBufferDataDescriptor ( clientBuf->mAudioClientBuffer32.bufferDataDescriptor, &localBufferDataDescriptor, reserved->classicMode ); 2300 2301 if (NULL != localBufferDataDescriptorPtr) { 2302 sampleFrames = localBufferDataDescriptorPtr->fActualNumSampleFrames; 2303 } else { 2304 sampleFrames = clientBuf->mAudioClientBuffer32.numSampleFrames; 2305 } 2306 } 2307 } 2308 2309Exit: 2310 audioDebugIOLog ( 4, "- IOAudioEngineUserClient[%p]::performClientInput ( firstSampleFrame %ld, bufferSet %p) returns 0x%lX\n", this, (long int)firstSampleFrame, bufferSet, (long unsigned int)result ); 2311 return result; 2312} 2313 2314void IOAudioEngineUserClient::performWatchdogOutput(IOAudioClientBufferSet *clientBufferSet, UInt32 generationCount) 2315{ 2316 IOReturn tmpResult; 2317 2318 audioDebugIOLog(3, "+ IOAudioEngineUserClient[%p]::performWatchdogOutput(%p, %ld) - (%lx,%lx)\n", 2319 this, clientBufferSet, 2320 (long int)generationCount, 2321 (long unsigned int)clientBufferSet->nextOutputPosition.fLoopCount, 2322 (long unsigned int)clientBufferSet->nextOutputPosition.fSampleFrame); 2323 2324 lockBuffers(); 2325 2326 if (!isInactive() && isOnline()) { 2327 if (clientBufferSet->timerPending) { 2328 // If the generation count of the clientBufferSet is different than the 2329 // generation count passed in, then a new client IO was received just before 2330 // the timer fired, and we don't need to do the fake IO 2331 // We just leave the timerPending field set 2332 if (clientBufferSet->generationCount == generationCount) { 2333 IOAudioClientBuffer64 *clientBuffer; 2334 IOAudioBufferDataDescriptor localBufferDataDescriptor; // <rdar://8500809> 2335 IOAudioBufferDataDescriptor * localBufferDataDescriptorPtr; // <rdar://8500809> 2336 UInt32 sampleFrames, numSampleFramesPerBuffer; // <rdar://8500809> 2337 2338 clientBuffer = clientBufferSet->outputBufferList; 2339 2340 while (clientBuffer) { 2341 IOAudioStream * audioStream; 2342 UInt32 maxNumSampleFrames; // <rdar://8500809> 2343 2344 audioStream = clientBuffer->mAudioClientBuffer32.audioStream; 2345 2346 assert(audioStream); 2347 assert(audioStream->getDirection() == kIOAudioStreamDirectionOutput); 2348 2349 // <rdar://8500809> Similar to performClientOutput, look at the buffer data descriptor to find the number of 2350 // sample frames to process. 2351 localBufferDataDescriptorPtr = FlipBufferDataDescriptor ( clientBuffer->mAudioClientBuffer32.bufferDataDescriptor, &localBufferDataDescriptor, reserved->classicMode ); 2352 2353 if (NULL != localBufferDataDescriptorPtr) { 2354 audioDebugIOLog(6, " performWatchdogOutput ------------------------------\n"); 2355 audioDebugIOLog ( 6, " actual frames = %ld, actual bytes = %ld, nominal bytes = %ld, total bytes = %ld\n", 2356 (long int)localBufferDataDescriptorPtr->fActualNumSampleFrames, 2357 (long int)localBufferDataDescriptorPtr->fActualDataByteSize, 2358 (long int)localBufferDataDescriptorPtr->fNominalDataByteSize, 2359 (long int)localBufferDataDescriptorPtr->fTotalDataByteSize ); 2360 sampleFrames = localBufferDataDescriptorPtr->fNominalDataByteSize / ( clientBuffer->mAudioClientBuffer32.numChannels * sizeof(float) ); 2361 } else { 2362 audioDebugIOLog(6, " no buffer descriptor found, using bufferSet->outputBufferList->numSampleFrames\n"); 2363 sampleFrames = clientBuffer->mAudioClientBuffer32.numSampleFrames; 2364 } 2365 2366 audioStream->lockStreamForIO(); 2367 2368 // <rdar://8500809> Make sure that the number of sample frames to process is less than the total number of sample frames 2369 // in the buffer. 2370 maxNumSampleFrames = clientBuffer->mAudioClientBuffer32.numSampleFrames; 2371 2372 if (sampleFrames <= maxNumSampleFrames) { // <rdar://10320402> 2373 // Update the client buffer's numSampleFrames field if there is data descriptor. 2374 if (NULL != localBufferDataDescriptorPtr) { 2375 clientBuffer->mAudioClientBuffer32.numSampleFrames = sampleFrames; 2376 } 2377 2378 audioStream->processOutputSamples( &(clientBuffer->mAudioClientBuffer32), clientBufferSet->nextOutputPosition.fSampleFrame, clientBufferSet->nextOutputPosition.fLoopCount, false); 2379 2380 // Restore the client buffer's numSampleFrames field. 2381 clientBuffer->mAudioClientBuffer32.numSampleFrames = maxNumSampleFrames; 2382 } 2383 2384 audioStream->unlockStreamForIO(); 2385 2386 clientBuffer = clientBuffer->mNextBuffer64; 2387 } 2388 2389 if (clientBufferSet->outputBufferList != NULL) { 2390 AbsoluteTime outputTimeout; 2391 2392 // <rdar://8101171> Use the nominal number of sample frames in client buffer if it is available. Don't use 2393 // fActualNumSampleFrames as it will vary (due to cadence) in the case of device aggregation. 2394 localBufferDataDescriptorPtr = FlipBufferDataDescriptor ( clientBufferSet->outputBufferList->mAudioClientBuffer32.bufferDataDescriptor, &localBufferDataDescriptor, reserved->classicMode ); // <rdar://8500809> 2395 2396 if (NULL != localBufferDataDescriptorPtr) { 2397 audioDebugIOLog(6, " performWatchdogOutput ------------------------------\n"); 2398 audioDebugIOLog ( 6, " actual frames = %ld, actual bytes = %ld, nominal bytes = %ld, total bytes = %ld\n", 2399 (long int)localBufferDataDescriptorPtr->fActualNumSampleFrames, 2400 (long int)localBufferDataDescriptorPtr->fActualDataByteSize, 2401 (long int)localBufferDataDescriptorPtr->fNominalDataByteSize, 2402 (long int)localBufferDataDescriptorPtr->fTotalDataByteSize ); 2403 sampleFrames = localBufferDataDescriptorPtr->fNominalDataByteSize / ( clientBufferSet->outputBufferList->mAudioClientBuffer32.numChannels * sizeof(float) ); 2404 } else { 2405 audioDebugIOLog(6, " no buffer descriptor found, using bufferSet->outputBufferList->numSampleFrames\n"); 2406 sampleFrames = clientBufferSet->outputBufferList->mAudioClientBuffer32.numSampleFrames; 2407 } 2408 2409 numSampleFramesPerBuffer = audioEngine->getNumSampleFramesPerBuffer(); 2410 2411 audioDebugIOLog(6, "numSampleFrames = %u, numSampleFramesPerBuffer = %u\n", (unsigned int)sampleFrames, (unsigned int)numSampleFramesPerBuffer); 2412 2413 clientBufferSet->nextOutputPosition.fSampleFrame += sampleFrames; 2414 2415 if (clientBufferSet->nextOutputPosition.fSampleFrame >= numSampleFramesPerBuffer) { 2416 clientBufferSet->nextOutputPosition.fSampleFrame -= numSampleFramesPerBuffer; 2417 clientBufferSet->nextOutputPosition.fLoopCount++; 2418 } 2419 2420 // <rdar://10145205> Sanity check the calculated timeout value 2421 tmpResult = audioEngine->calculateSampleTimeout(&clientBufferSet->sampleInterval, sampleFrames, &clientBufferSet->nextOutputPosition, &outputTimeout); 2422 if ( kIOReturnSuccess == tmpResult ) { 2423 clientBufferSet->setWatchdogTimeout(&outputTimeout); 2424 } 2425 else { 2426 audioDebugIOLog(3, "IOAudioEngineUserClient[%p]::performWatchdogOutput failed to calculateSampleTimeout (returned %#x)\n", this, tmpResult); 2427 2428 clientBufferSet->timerPending = false; 2429 } 2430 } else { 2431 clientBufferSet->timerPending = false; 2432 } 2433 } 2434 } 2435 } else { 2436 clientBufferSet->timerPending = false; 2437 } 2438 2439 unlockBuffers(); 2440 2441 audioDebugIOLog(3, "- IOAudioEngineUserClient[%p]::performWatchdogOutput(%p, %ld) - (%lx,%lx)\n", 2442 this, clientBufferSet, 2443 (long int)generationCount, 2444 (long unsigned int)clientBufferSet->nextOutputPosition.fLoopCount, 2445 (long unsigned int)clientBufferSet->nextOutputPosition.fSampleFrame); 2446 return; 2447} 2448 2449IOReturn IOAudioEngineUserClient::getConnectionID(UInt32 *connectionID) 2450{ 2451 audioDebugIOLog(3, "+-IOAudioEngineUserClient[%p]::getConnectionID(%p)\n", this, connectionID); 2452 2453 *connectionID = (UInt32) (((UInt64)this >> 8) & 0x00000000FFFFFFFFLLU) ; 2454 return kIOReturnSuccess; 2455} 2456 2457IOReturn IOAudioEngineUserClient::clientStart() 2458{ 2459 IOReturn ret = kIOReturnError; 2460 2461 // <rdar://7363756>, <rdar://7529580> 2462 if ( workLoop ) 2463 { 2464 ret = workLoop->runAction(_startClientAction, this); // <rdar://7529580> 2465 } 2466 2467 return ret; 2468} 2469 2470IOReturn IOAudioEngineUserClient::clientStop() 2471{ 2472 IOReturn ret = kIOReturnError; 2473 2474 // <rdar://7363756>, <rdar://7529580> 2475 if ( workLoop ) 2476 { 2477 ret = workLoop->runAction(_stopClientAction, this); // <rdar://7529580> 2478 } 2479 2480 return ret; 2481} 2482 2483// <rdar://7529580> 2484IOReturn IOAudioEngineUserClient::_startClientAction(OSObject *target, void *arg0, void *arg1, void *arg2, void *arg3) 2485{ 2486 IOReturn result = kIOReturnBadArgument; 2487 2488 if (target) { 2489 IOAudioEngineUserClient *userClient = OSDynamicCast(IOAudioEngineUserClient, target); 2490 if (userClient) { 2491 if (userClient->commandGate) { 2492 setCommandGateUsage(userClient, true); // <rdar://8518215> 2493 result = userClient->commandGate->runAction(startClientAction, arg0, arg1, arg2, arg3); 2494 setCommandGateUsage(userClient, false); // <rdar://8518215> 2495 } else { 2496 result = kIOReturnError; 2497 } 2498 } 2499 } 2500 2501 return result; 2502} 2503 2504IOReturn IOAudioEngineUserClient::startClientAction(OSObject *owner, void *arg1, void *arg2, void *arg3, void *arg4) 2505{ 2506 IOReturn result = kIOReturnBadArgument; 2507 2508 if (owner) { 2509 IOAudioEngineUserClient *userClient = OSDynamicCast(IOAudioEngineUserClient, owner); 2510 if (userClient) { 2511 result = userClient->startClient(); 2512 } 2513 } 2514 2515 return result; 2516} 2517 2518// <rdar://7529580> 2519IOReturn IOAudioEngineUserClient::_stopClientAction(OSObject *target, void *arg0, void *arg1, void *arg2, void *arg3) 2520{ 2521 IOReturn result = kIOReturnBadArgument; 2522 2523 if (target) { 2524 IOAudioEngineUserClient *userClient = OSDynamicCast(IOAudioEngineUserClient, target); 2525 if (userClient) { 2526 if (userClient->commandGate) { 2527 setCommandGateUsage(userClient, true); // <rdar://8518215> 2528 result = userClient->commandGate->runAction(stopClientAction, arg0, arg1, arg2, arg3); 2529 setCommandGateUsage(userClient, false); // <rdar://8518215> 2530 } else { 2531 result = kIOReturnError; 2532 } 2533 } 2534 } 2535 2536 return result; 2537} 2538 2539IOReturn IOAudioEngineUserClient::stopClientAction(OSObject *owner, void *arg1, void *arg2, void *arg3, void *arg4) 2540{ 2541 IOReturn result = kIOReturnBadArgument; 2542 2543 if (owner) { 2544 IOAudioEngineUserClient *userClient = OSDynamicCast(IOAudioEngineUserClient, owner); 2545 if (userClient) { 2546 result = userClient->stopClient(); 2547 } 2548 } 2549 2550 return result; 2551} 2552 2553IOReturn IOAudioEngineUserClient::startClient() 2554{ 2555 IOReturn result = kIOReturnNoDevice; 2556 bool engineStillPaused = false; 2557 2558 audioDebugIOLog(3, "+ IOAudioEngineUserClient[%p]::startClient() - %ld\n", this, (long int)( audioEngine ? audioEngine->numActiveUserClients : 0 ) ); 2559 2560 retain(); 2561 2562 if (audioEngine && !isInactive()) { 2563 audioDebugIOLog(3, " audioEngine && !isInactive(). State = %d \n", audioEngine->getState()); 2564 2565 // <rdar://15485249> Pause here until the engine is no longer paused 2566 if (audioEngine->getState() == kIOAudioEnginePaused) { 2567 audioDebugIOLog(3, "Will need to wait for engine to resume\n"); 2568 result = audioEngine->waitForEngineResume (); 2569 2570 if ( result != kIOReturnSuccess ) { 2571 engineStillPaused = true; 2572 } 2573 } 2574 2575 // We only need to start things up if we're not already online 2576 if (!engineStillPaused && !isInactive()) { 2577 audioDebugIOLog(3, " audioEngine->getState() != kIOAudioEnginePaused \n"); 2578 2579 if (!isOnline()) { 2580 setOnline(true); 2581 audioDebugIOLog(3, " !isOnline() setting online \n"); 2582 result = audioEngine->startClient(this); 2583 2584 if (result == kIOReturnSuccess) { 2585 audioDebugIOLog(3, " engine started \n"); 2586 IOAudioClientBufferSet *bufferSet; 2587 2588 lockBuffers(); 2589 2590 // add buffers to streams 2591 bufferSet = clientBufferSetList; 2592 while (bufferSet) { 2593 IOAudioClientBuffer64 *clientBuffer; 2594 audioDebugIOLog(3, " bufferSet %p \n", bufferSet); 2595 2596 clientBuffer = bufferSet->outputBufferList; 2597 while (clientBuffer) { 2598 if (clientBuffer->mAudioClientBuffer32.audioStream) { 2599 audioDebugIOLog(3, " output clientBuffer %p \n", clientBuffer); 2600 result = clientBuffer->mAudioClientBuffer32.audioStream->addClient( &clientBuffer->mAudioClientBuffer32 ); 2601 if (result != kIOReturnSuccess) { 2602 audioEngine->stopClient(this); // <rdar://13412666> stopClient on failure 2603 break; 2604 } 2605 } 2606 clientBuffer = clientBuffer->mNextBuffer64; 2607 } 2608 2609 if (result == kIOReturnSuccess) { 2610 clientBuffer = bufferSet->inputBufferList; 2611 while (clientBuffer) { 2612 audioDebugIOLog(3, " input clientBuffer %p \n", clientBuffer); 2613 if (clientBuffer->mAudioClientBuffer32.audioStream) { 2614 result = clientBuffer->mAudioClientBuffer32.audioStream->addClient( &( clientBuffer->mAudioClientBuffer32 ) ); 2615 if (result != kIOReturnSuccess) { 2616 audioEngine->stopClient(this); // <rdar://13412666> stopClient on failure 2617 break; 2618 } 2619 } 2620 clientBuffer = clientBuffer->mNextBuffer64; 2621 } 2622 } 2623 2624 bufferSet->resetNextOutputPosition(); 2625 2626 bufferSet = bufferSet->mNextBufferSet; 2627 } 2628 2629 unlockBuffers(); 2630 } 2631 else 2632 { 2633 audioDebugIOLog(3, " engine NOT started \n"); 2634 } 2635 } 2636 else { 2637 result = kIOReturnSuccess; 2638 } 2639 } 2640 2641 if ( isInactive() ) 2642 { 2643 audioDebugIOLog(3, "Device no longer exists\n"); 2644 result = kIOReturnNoDevice; 2645 } 2646 } 2647 2648 if (kIOReturnSuccess != result) { 2649 audioDebugIOLog(3, " error (0x%x) - setting offline \n", result ); 2650 setOnline(false); 2651 } 2652 2653 release(); 2654 2655 audioDebugIOLog(3, "- IOAudioEngineUserClient[%p]::startClient() - %ld returns 0x%lX\n", this, (long int)( audioEngine ? audioEngine->numActiveUserClients : 0 ), (long unsigned int)result ); 2656 return result; 2657} 2658 2659IOReturn IOAudioEngineUserClient::stopClient() 2660{ 2661 IOReturn result = kIOReturnSuccess; 2662 2663 audioDebugIOLog(3, "+ IOAudioEngineUserClient[%p]::stopClient() - %ld\n", this, (long int)( audioEngine ? audioEngine->numActiveUserClients : 0 )); 2664 2665 if (isOnline()) { 2666 IOAudioClientBufferSet *bufferSet; 2667 2668 lockBuffers(); 2669 2670 bufferSet = clientBufferSetList; 2671 while (bufferSet) { 2672 IOAudioClientBuffer64 *clientBuffer; 2673 2674 bufferSet->cancelWatchdogTimer(); 2675 2676 clientBuffer = bufferSet->outputBufferList; 2677 while (clientBuffer) { 2678 if (clientBuffer->mAudioClientBuffer32.audioStream) { 2679 clientBuffer->mAudioClientBuffer32.audioStream->removeClient( &( clientBuffer->mAudioClientBuffer32 ) ); 2680 } 2681 clientBuffer = clientBuffer->mNextBuffer64; 2682 } 2683 2684 clientBuffer = bufferSet->inputBufferList; 2685 while (clientBuffer) { 2686 if (clientBuffer->mAudioClientBuffer32.audioStream) { 2687 clientBuffer->mAudioClientBuffer32.audioStream->removeClient( &(clientBuffer->mAudioClientBuffer32 )); 2688 } 2689 clientBuffer = clientBuffer->mNextBuffer64; 2690 } 2691 2692 bufferSet = bufferSet->mNextBufferSet; 2693 } 2694 2695 unlockBuffers(); 2696 2697 if (audioEngine) { 2698 result = audioEngine->stopClient(this); 2699 } 2700 2701 setOnline(false); 2702 } 2703 2704 audioDebugIOLog(3, "- IOAudioEngineUserClient[%p]::stopClient() - %ld returns 0x%lX\n", this, (long int)( audioEngine ? audioEngine->numActiveUserClients : 0 ), (long unsigned int)result ); 2705 return result; 2706} 2707 2708// Must be done on workLoop 2709void IOAudioEngineUserClient::sendFormatChangeNotification(IOAudioStream *audioStream) 2710{ 2711 audioDebugIOLog(3, "+ IOAudioEngineUserClient[%p]::sendFormatChangeNotification(%p)\n", this, audioStream); 2712 2713 // <rdar://problems/6674310&6687920> 2714 if ( ( !isInactive () ) && audioStream && notificationMessage && ( notificationMessage->messageHeader.msgh_remote_port != MACH_PORT_NULL ) ) { 2715 io_object_t clientStreamRef; 2716 2717 audioStream->retain(); 2718 if (exportObjectToClient(clientTask, audioStream, &clientStreamRef) == kIOReturnSuccess) { 2719 kern_return_t kr; 2720 2721 notificationMessage->type = kIOAudioEngineStreamFormatChangeNotification; 2722 notificationMessage->sender = clientStreamRef; 2723 2724 kr = mach_msg_send_from_kernel(¬ificationMessage->messageHeader, notificationMessage->messageHeader.msgh_size); 2725 if (kr != MACH_MSG_SUCCESS) { 2726 IOLog("IOAudioEngineUserClient::sendFormatChangeNotification() failed - msg_send returned: %d\n", kr); 2727 // Should also release the clientStreamRef here... 2728 } 2729 } else { 2730 IOLog("IOAudioEngineUserClient[%p]::sendFormatChangeNotification() - ERROR - unable to export stream object for notification - notification not sent\n", this); 2731 } 2732 } else { 2733 if (notificationMessage) { 2734 audioDebugIOLog(5, "IOAudioEngineUserClient[%p]::sendFormatChangeNotification() - ERROR - notification not sent - audioStream = %p - notificationMessage = %p - port = %p\n", this, audioStream, notificationMessage, notificationMessage->messageHeader.msgh_remote_port); 2735 } else { 2736 audioDebugIOLog(4, "IOAudioEngineUserClient[%p]::sendFormatChangeNotification() - ERROR - notification not sent - audioStream = %p - notificationMessage = %p\n", this, audioStream, notificationMessage); 2737 } 2738 } 2739 2740 audioDebugIOLog(3, "- IOAudioEngineUserClient[%p]::sendFormatChangeNotification(%p)\n", this, audioStream); 2741 return; 2742} 2743 2744IOReturn IOAudioEngineUserClient::sendNotification(UInt32 notificationType) 2745{ 2746 IOReturn result = kIOReturnSuccess; 2747 2748 audioDebugIOLog(3, "+ IOAudioEngineUserClient[%p]::sendNotification(%ld)\n", this, (long int)notificationType); 2749 2750 if (notificationType == kIOAudioEnginePausedNotification) { 2751 stopClient(); 2752 } 2753 2754 if (notificationMessage && (notificationMessage->messageHeader.msgh_remote_port != MACH_PORT_NULL)) { 2755 kern_return_t kr; 2756 2757 notificationMessage->type = notificationType; 2758 notificationMessage->sender = NULL; 2759 2760 kr = mach_msg_send_from_kernel(¬ificationMessage->messageHeader, notificationMessage->messageHeader.msgh_size); 2761 if (kr != MACH_MSG_SUCCESS) { 2762 result = kIOReturnError; 2763 } 2764 } 2765 2766 audioDebugIOLog(3, "- IOAudioEngineUserClient[%p]::sendNotification(%ld) returns 0x%lX\n", this, (long int)notificationType, (long unsigned int)result ); 2767 return result; 2768} 2769 2770// <rdar://8518215> 2771void IOAudioEngineUserClient::setCommandGateUsage(IOAudioEngineUserClient *userClient, bool increment) 2772{ 2773 if (userClient->reserved) { 2774 if (increment) { 2775 switch (userClient->reserved->commandGateStatus) 2776 { 2777 case kCommandGateStatus_Normal: 2778 case kCommandGateStatus_RemovalPending: 2779 userClient->reserved->commandGateUsage++; 2780 break; 2781 case kCommandGateStatus_Invalid: 2782 // Should never be here. If so, something went bad... 2783 break; 2784 } 2785 } 2786 else { 2787 switch (userClient->reserved->commandGateStatus) 2788 { 2789 case kCommandGateStatus_Normal: 2790 if (userClient->reserved->commandGateUsage > 0) { 2791 userClient->reserved->commandGateUsage--; 2792 } 2793 break; 2794 case kCommandGateStatus_RemovalPending: 2795 if (userClient->reserved->commandGateUsage > 0) { 2796 userClient->reserved->commandGateUsage--; 2797 2798 if (userClient->reserved->commandGateUsage == 0) { 2799 userClient->reserved->commandGateStatus = kCommandGateStatus_Invalid; 2800 2801 if (userClient->commandGate) { 2802 if (userClient->workLoop) { 2803 userClient->workLoop->removeEventSource(userClient->commandGate); 2804 } 2805 2806 userClient->commandGate->release(); 2807 userClient->commandGate = NULL; 2808 } 2809 } 2810 } 2811 break; 2812 case kCommandGateStatus_Invalid: 2813 // Should never be here. If so, something went bad... 2814 break; 2815 } 2816 } 2817 } 2818} 2819