|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. ! 3: * ! 4: * @APPLE_LICENSE_HEADER_START@ ! 5: * ! 6: * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights ! 7: * Reserved. This file contains Original Code and/or Modifications of ! 8: * Original Code as defined in and that are subject to the Apple Public ! 9: * Source License Version 1.1 (the "License"). You may not use this file ! 10: * except in compliance with the License. Please obtain a copy of the ! 11: * License at http://www.apple.com/publicsource and read it before using ! 12: * this file. ! 13: * ! 14: * The Original Code and all software distributed under the License are ! 15: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER ! 16: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ! 17: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ! 18: * FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. Please see the ! 19: * License for the specific language governing rights and limitations ! 20: * under the License. ! 21: * ! 22: * @APPLE_LICENSE_HEADER_END@ ! 23: */ ! 24: /* ! 25: * AudioChannel.m ! 26: * ! 27: * Copyright (c) 1991, NeXT Computer, Inc. All rights reserved. ! 28: * ! 29: * Audio driver channel object. ! 30: * ! 31: * HISTORY ! 32: * 06/22/94/wmg HP modifications. ! 33: * 11/17/93/rkd Added XPRs. ! 34: * 07/14/92/mtm Original coding. ! 35: */ ! 36: ! 37: #import "AudioChannel.h" ! 38: #import "AudioStream.h" ! 39: #import "InputStream.h" ! 40: #import "OutputStream.h" ! 41: #import <driverkit/IOAudio.h> ! 42: #import <driverkit/IOAudioPrivate.h> ! 43: #import "AudioCommand.h" ! 44: #import "audio_peak.h" ! 45: #import "audio_msgs.h" ! 46: #import "audioLog.h" ! 47: #import "AudioCommand.h" ! 48: #import "audio_kern_server.h" ! 49: #import <mach/vm_param.h> // PAGE_SIZE ! 50: #import <driverkit/generalFuncs.h> ! 51: #import <driverkit/kernelDriver.h> // IOPhysicalFromVirtual / IOVmTaskSelf ! 52: #import <bsd/string.h> // bzero ! 53: ! 54: #if i386 ! 55: /* ! 56: * Temporary function prototype for alloc_cnvmem ! 57: * copied from <machdep/i386/i386_init.c) ! 58: */ ! 59: vm_offset_t alloc_cnvmem(vm_size_t size, vm_offset_t align); ! 60: #endif i386 ! 61: #if hppa ! 62: #import <machdep/hppa/pmap.h> ! 63: extern hpaudiobuffer; ! 64: extern hpaudiosilent; ! 65: #endif hppa ! 66: #if sparc ! 67: // ! 68: // set in device init routine ! 69: // ! 70: u_int AudioIn_dmaSize = 0; ! 71: u_int AudioIn_dmaCount = 0; ! 72: caddr_t AudioIn_dmaBuf = 0; ! 73: u_int AudioOut_dmaSize = 0; ! 74: u_int AudioOut_dmaCount = 0; ! 75: caddr_t AudioOut_dmaBuf = 0; ! 76: #endif sparc ! 77: ! 78: #if ppc ! 79: extern void *kernel_map; ! 80: #endif ! 81: ! 82: @implementation AudioChannel ! 83: ! 84: /* Factory variables */ ! 85: static id allStreams = nil; ! 86: ! 87: /* ! 88: * Both input and output channels share one buffer. ! 89: */ ! 90: static BOOL sharedChannelBuffer = YES; ! 91: static vm_offset_t sharedChannelBufferPtr = 0; ! 92: ! 93: /* ! 94: * Add a stream. ! 95: */ ! 96: + addStream:stream ! 97: { ! 98: if (!allStreams) ! 99: allStreams = [[List alloc] init]; ! 100: [allStreams addObject:stream]; ! 101: return self; ! 102: } ! 103: ! 104: /* ! 105: * Remove a stream. ! 106: */ ! 107: + removeStream:stream ! 108: { ! 109: [allStreams removeObject:stream]; ! 110: return self; ! 111: } ! 112: ! 113: /* ! 114: * Search for a stream given a user port. ! 115: */ ! 116: + streamForUserPort:(port_t)port ! 117: { ! 118: int i; ! 119: id stream; ! 120: ! 121: for (i = 0; i < [allStreams count]; i++) { ! 122: stream = [allStreams objectAt:i]; ! 123: if ([stream userPort] == port) ! 124: return stream; ! 125: } ! 126: return nil; ! 127: } ! 128: ! 129: /* ! 130: * Search for a stream given an owner port. ! 131: * Returns the FIRST such stream found. ! 132: */ ! 133: + streamForOwnerPort:(port_t)port ! 134: { ! 135: int i; ! 136: id stream; ! 137: ! 138: for (i = 0; i < [allStreams count]; i++) { ! 139: stream = [allStreams objectAt:i]; ! 140: if ([stream ownerPort] == port) ! 141: return stream; ! 142: } ! 143: return nil; ! 144: } ! 145: ! 146: /* ! 147: * Initialize. ! 148: */ ! 149: ! 150: - initOnDevice: device read: (BOOL)isRead ! 151: { ! 152: [super init]; ! 153: audioDevice = device; ! 154: ! 155: _isRead = isRead; ! 156: ! 157: if (isRead) ! 158: streamClass = [InputStream class]; ! 159: else ! 160: streamClass = [OutputStream class]; ! 161: ! 162: exclusiveUser = PORT_NULL; ! 163: streamList = [[List alloc] init]; ! 164: streamListLock = [[NXLock alloc] init]; ! 165: queue_init(&dmaQueue); ! 166: queue_init(&freeQueue); ! 167: #if hppa ! 168: queue_init(&devQueue); ! 169: queue_init(&dfreeQueue); ! 170: #endif hppa ! 171: peakHistory = 1; ! 172: ! 173: channelBufferPtr = 0; ! 174: /* ! 175: * Note: ! 176: * Until the DMA buffer can be reallocated, the dmaSize cannot be changed. ! 177: */ ! 178: #if i386 ! 179: if ([audioDevice isEISAPresent]) { ! 180: [self setDMASize: PAGE_SIZE * 16]; ! 181: (void) [self setDescriptorSize: PAGE_SIZE]; ! 182: } else { ! 183: [self setDMASize: PAGE_SIZE * 8]; // 64K limit ! 184: (void) [self setDescriptorSize: PAGE_SIZE]; ! 185: } ! 186: #elif hppa ! 187: // uses 64k too ! 188: dmaSize = PAGE_SIZE * 8; ! 189: dmaCount = 16; ! 190: (void) [self setDescriptorSize: (dmaSize/dmaCount)]; ! 191: #elif sparc ! 192: // dmaSize = PAGE_SIZE * 8; ! 193: // dmaCount = 16; ! 194: // 16 - 4K buffers ! 195: if (isRead) { ! 196: dmaSize = AudioIn_dmaSize; ! 197: dmaCount = AudioIn_dmaCount; ! 198: } else { ! 199: dmaSize = AudioOut_dmaSize; ! 200: dmaCount = AudioOut_dmaCount; ! 201: } ! 202: (void) [self setDescriptorSize: (dmaSize/dmaCount)]; ! 203: #elif ppc ! 204: dmaCount = 32; ! 205: dmaSize = PAGE_SIZE * dmaCount; ! 206: (void) [self setDescriptorSize: (dmaSize/dmaCount)]; ! 207: #else ! 208: dmaSize = PAGE_SIZE * 8; ! 209: dmaCount = 16; ! 210: #endif ! 211: ! 212: ! 213: return self; ! 214: } ! 215: ! 216: /* ! 217: * Currently cannot free, but if want to someday, worry about: ! 218: * destroyDMABuffers; and ! 219: * Free peak history buffers ! 220: */ ! 221: - free ! 222: { ! 223: IOLog("AudioChannel: -free not supported\n"); ! 224: return [super free]; ! 225: } ! 226: ! 227: /* ! 228: * ! 229: */ ! 230: - (u_int) descriptorSize ! 231: { ! 232: return descriptorSize; ! 233: } ! 234: ! 235: /* ! 236: * Returns the desciptorSize which may be different from the one requested. ! 237: */ ! 238: - (u_int) setDescriptorSize:(u_int) size ! 239: { ! 240: dmaCount = [self dmaSize] / size; ! 241: ! 242: #ifndef ppc ! 243: if (dmaCount < 4 || dmaCount > 16) { ! 244: dmaCount = 8; ! 245: size = [self dmaSize] / dmaCount; ! 246: } ! 247: #endif ! 248: ! 249: descriptorSize = size; ! 250: ! 251: return descriptorSize; ! 252: } ! 253: ! 254: - (u_int) dmaSize ! 255: { ! 256: return dmaSize; ! 257: } ! 258: ! 259: - (void) setDMASize:(u_int) size ! 260: { ! 261: dmaSize = size; ! 262: } ! 263: ! 264: - (u_int)dmaCount ! 265: { ! 266: return dmaCount; ! 267: } ! 268: ! 269: - (BOOL) isRead ! 270: { ! 271: return _isRead; ! 272: } ! 273: ! 274: /* ! 275: * Return number of outstanding (enqueued) dma descriptors on dmaQueue. ! 276: */ ! 277: - (u_int)enqueueCount ! 278: { ! 279: return enqueueCount; ! 280: } ! 281: ! 282: /* ! 283: * Create channel dma buffers. ! 284: * There must be no active streams when this is called. ! 285: */ ! 286: - (BOOL) createChannelBuffer ! 287: { ! 288: BOOL status; ! 289: int len; ! 290: #ifdef hppa ! 291: extern pmap_t audio_pmap; // defined in IOAudio.m ! 292: #endif ! 293: ! 294: /* ! 295: * To Do: Until better versions of IOMallocLow and IOFreeLow are available, ! 296: * the channel will use alloc_cnvmem (allocate conventional memory) which ! 297: * can allocate more than one physically contiguous page. The memory cannot ! 298: * be freed; therefore, the code checks to see if the channelBuffer has ! 299: * been created. ! 300: */ ! 301: if (channelBufferPtr) ! 302: return TRUE; ! 303: ! 304: #if i386 ! 305: if ((sharedChannelBuffer) && (sharedChannelBufferPtr)) { ! 306: channelBufferPtr = sharedChannelBufferPtr; ! 307: ! 308: channelBuffer = [audioDevice createDMABufferFor: &channelBufferPtr ! 309: length: dmaSize ! 310: read:(BOOL) _isRead ! 311: needsLowMemory: TRUE ! 312: limitSize: NO]; ! 313: ! 314: [self initializeFreeQueue]; ! 315: return TRUE; ! 316: } ! 317: ! 318: /* ! 319: * We treat ISA systems as special case since other systems do not have ! 320: * DMA memory restrictions like it. For ISA we assign memory using ! 321: * alloc_envmem() and for others we will use an IOBuffer object ! 322: * (eventually). ! 323: */ ! 324: if (![audioDevice isEISAPresent]) { ! 325: channelBufferPtr = alloc_cnvmem(dmaSize, 65536); // 64K align ! 326: if (!channelBufferPtr) { ! 327: IOLog("Audio: no memory for allocating buffers.\n"); ! 328: return FALSE; ! 329: } ! 330: } else if ([audioDevice isEISAPresent]) { ! 331: channelBufferPtr = alloc_cnvmem(dmaSize, PAGE_SIZE); ! 332: if (!channelBufferPtr) { ! 333: IOLog("Audio: no memory for allocating buffers.\n"); ! 334: return FALSE; ! 335: } ! 336: } ! 337: #elif hppa ! 338: if (_isRead) { ! 339: // if read it is read buffer ! 340: channelBufferPtr = (vm_address_t)(&hpaudiosilent); ! 341: } else { ! 342: channelBufferPtr = (vm_address_t)(&hpaudiobuffer); ! 343: } ! 344: #elif sparc ! 345: if (_isRead) ! 346: channelBufferPtr = (vm_offset_t)AudioIn_dmaBuf; ! 347: else ! 348: channelBufferPtr = (vm_offset_t)AudioOut_dmaBuf; ! 349: #elif ppc ! 350: { ! 351: int kr; ! 352: kr = kmem_alloc_wired( kernel_map, (vm_offset_t)&channelBufferPtr, dmaSize ); ! 353: if ( kr != KERN_SUCCESS ) ! 354: { ! 355: IOLog("Audio: no memory for allocating buffers.\n"); ! 356: return FALSE; ! 357: } ! 358: } ! 359: #else ! 360: #warning AudioChannel class only supports i386 , hppa or sparc ! 361: #endif ! 362: ! 363: sharedChannelBufferPtr = channelBufferPtr; ! 364: ! 365: #if i386 ! 366: channelBuffer = [audioDevice createDMABufferFor: &channelBufferPtr ! 367: length: dmaSize ! 368: read:(BOOL) _isRead ! 369: needsLowMemory: TRUE ! 370: limitSize: NO]; ! 371: #else ! 372: // for hppa and sparc there is no seperate setups for DMA ! 373: channelBuffer = (void *)channelBufferPtr; ! 374: #endif ! 375: ! 376: [self initializeFreeQueue]; ! 377: #if hppa ! 378: [self initializeDFreeQueue]; ! 379: #endif ! 380: return TRUE; ! 381: } ! 382: ! 383: - (void) initializeFreeQueue ! 384: { ! 385: dma_desc_t *ddp; ! 386: int i; ! 387: vm_address_t ptr; ! 388: ! 389: while (!queue_empty(&freeQueue)) { ! 390: queue_remove_first(&freeQueue, ddp, dma_desc_t *, link); ! 391: IOFree((void *)ddp, sizeof(dma_desc_t)); ! 392: } ! 393: ! 394: bzero((void *)channelBufferPtr, dmaSize); ! 395: ! 396: ptr = channelBufferPtr; ! 397: ! 398: for (i = 0; i < dmaCount; i++) { ! 399: ddp = (dma_desc_t *)IOMalloc(sizeof(dma_desc_t)); ! 400: ddp->size = 0; ! 401: ddp->mem = ptr; ! 402: ptr += descriptorSize; ! 403: queue_enter(&freeQueue, ddp, dma_desc_t *, link); ! 404: } ! 405: } ! 406: ! 407: #if hppa ! 408: - (void) initializeDFreeQueue ! 409: { ! 410: dma_desc_t *ddp; ! 411: int i; ! 412: vm_address_t ptr; ! 413: ! 414: while (!queue_empty(&dfreeQueue)) { ! 415: queue_remove_first(&dfreeQueue, ddp, dma_desc_t *, link); ! 416: IOFree((void *)ddp, sizeof(dma_desc_t)); ! 417: } ! 418: ! 419: bzero((void *)channelBufferPtr, dmaSize); ! 420: ! 421: pmap_flush_range(kernel_pmap, (vm_offset_t)channelBufferPtr, dmaSize); ! 422: ! 423: ! 424: ptr = channelBufferPtr; ! 425: ! 426: for (i = 0; i < dmaCount; i++) { ! 427: ddp = (dma_desc_t *)IOMalloc(sizeof(dma_desc_t)); ! 428: ddp->size = 0; ! 429: ddp->mem = ptr; ! 430: ptr += descriptorSize; ! 431: queue_enter(&dfreeQueue, ddp, dma_desc_t *, link); ! 432: } ! 433: } ! 434: ! 435: /* returns the device dma address also releases the queue ! 436: * ! 437: */ ! 438: ! 439: - (vm_offset_t) getDevDmaAddress ! 440: { ! 441: dma_desc_t *ddp_d; // for the dev queue ! 442: vm_offset_t dev_dma_addr = (vm_offset_t)NULL; ! 443: vm_offset_t addr; ! 444: extern pmap_t audio_pmap; // defined in IOAudio.m ! 445: ! 446: if (queue_empty(&devQueue)) return (vm_offset_t)NULL; ! 447: queue_remove_first(&devQueue, ddp_d, dma_desc_t *, link); ! 448: // now the buffer is a kernel buffer mapped 1 to 1 ! 449: // dev_dma_addr = ddp_d->mem; ! 450: dev_dma_addr = pmap_extract(kernel_pmap,ddp_d->mem); ! 451: ! 452: queue_enter(&dfreeQueue, ddp_d, dma_desc_t *, link); ! 453: return dev_dma_addr; ! 454: } ! 455: #endif hppa ! 456: ! 457: /* ! 458: * Destroy dma buffers. ! 459: * There must be no active streams when this is called. ! 460: */ ! 461: - (void) destroyChannelBuffer ! 462: { ! 463: ! 464: /* ! 465: * The channelBuffer cannot be freed until a better version ! 466: * of IOFreeLow is available. ! 467: */ ! 468: } ! 469: ! 470: /* ! 471: * enqueue a dma descriptor using the current device parameters. ! 472: */ ! 473: - (BOOL) enqueueDescriptor: (u_int *) rate ! 474: dataFormat: (IOAudioDataFormat *) format ! 475: channelCount: (u_int *) count ! 476: { ! 477: id stream; ! 478: int i; ! 479: u_int bufferSize = 0; ! 480: u_int streamCount; ! 481: u_int streamSize; ! 482: dma_desc_t *ddp; ! 483: #if hppa ! 484: dma_desc_t *ddp_d; // for the dev queue ! 485: #endif hppa ! 486: ! 487: xpr_audio_channel("AC: enqueueDescriptor: rate %d dataFormat %d " ! 488: "channelCount %d\n", rate, format, count, 4,5); ! 489: [streamListLock lock]; ! 490: streamCount = [streamList count]; ! 491: if (streamCount == 0 || queue_empty(&freeQueue)) { ! 492: [streamListLock unlock]; ! 493: return FALSE; ! 494: } ! 495: queue_remove_first(&freeQueue, ddp, dma_desc_t *, link); ! 496: for (i = 0; i < streamCount; i++) { ! 497: stream = [streamList objectAt:i]; ! 498: streamSize = [stream mixBuffer:ddp->mem maxCount:descriptorSize ! 499: rate:rate format:format ! 500: channelCount:count descriptor:ddp ! 501: virgin:(bufferSize == 0) ! 502: streamCount:streamCount]; ! 503: if (streamSize > bufferSize) ! 504: bufferSize = streamSize; ! 505: } ! 506: [streamListLock unlock]; ! 507: if (bufferSize == 0) { ! 508: queue_enter_first(&freeQueue, ddp, dma_desc_t *, link); ! 509: return(FALSE); ! 510: } ! 511: ! 512: ddp->size = bufferSize; ! 513: #ifdef sparc ! 514: vac_flush((caddr_t)ddp->mem, ddp->size); ! 515: #endif ! 516: #ifdef hppa ! 517: pmap_flush_range(kernel_pmap,(vm_offset_t)ddp->mem,ddp->size); ! 518: #endif ! 519: #ifdef ppc ! 520: flush_cache_v((vm_offset_t)ddp->mem,ddp->size); ! 521: #endif ! 522: queue_enter(&dmaQueue, ddp, dma_desc_t *, link); ! 523: #ifdef hppa ! 524: if (!queue_empty(&dfreeQueue)) { ! 525: queue_remove_first(&dfreeQueue, ddp_d, dma_desc_t *, link); ! 526: ddp_d->mem = ddp->mem; ! 527: ddp_d->size = ddp->size; ! 528: queue_enter(&devQueue, ddp_d, dma_desc_t *, link); ! 529: } ! 530: #endif ! 531: ! 532: enqueueCount++; ! 533: ! 534: xpr_audio_channel("AC: enqueueDescriptor done\n",1,2,3,4,5); ! 535: ! 536: return(TRUE); ! 537: } ! 538: ! 539: ! 540: /* ! 541: * dequeue a DMA descriptor ! 542: */ ! 543: - (void) dequeueDescriptor ! 544: { ! 545: dma_desc_t *ddp; ! 546: int i; ! 547: id stream; ! 548: u_int peak_left = 0, peak_right = 0; ! 549: u_int numStreams; ! 550: ! 551: xpr_audio_channel("AC: dequeueDescriptor\n",1,2,3,4,5); ! 552: ! 553: queue_remove_first(&dmaQueue, ddp, dma_desc_t *, link); ! 554: ! 555: [streamListLock lock]; ! 556: numStreams = [streamList count]; ! 557: if (numStreams > 0) { ! 558: if (peakEnabled) { ! 559: switch ([audioDevice dataEncoding]) { ! 560: case NX_SoundStreamDataEncoding_Linear16: ! 561: audio_linear16_peak([audioDevice channelCount], ! 562: (short *)ddp->mem, ddp->size/2, ! 563: &peak_left, &peak_right); ! 564: break; ! 565: ! 566: case NX_SoundStreamDataEncoding_Linear8: ! 567: audio_linear8_peak([audioDevice channelCount], ! 568: (char *)ddp->mem, ddp->size, ! 569: &peak_left, &peak_right); ! 570: break; ! 571: ! 572: case NX_SoundStreamDataEncoding_Mulaw8: ! 573: audio_mulaw8_peak([audioDevice channelCount], ! 574: (unsigned char *)ddp->mem, ! 575: ddp->size, &peak_left, &peak_right); ! 576: break; ! 577: ! 578: default: ! 579: /* FIXME: A-law and AES peak not supported */ ! 580: break; ! 581: } ! 582: audio_add_peak(peaksLeft, peak_left, ¤tPeak, peakHistory); ! 583: audio_add_peak(peaksRight, peak_right, ¤tPeak, peakHistory); ! 584: } ! 585: ! 586: for (i = 0; i < numStreams; i++) { ! 587: stream = [streamList objectAt:i]; ! 588: /* ! 589: * Note: transfer count is only valid for input channel ! 590: * (0 sent for output channel). ! 591: */ ! 592: [stream dmaCompleteDescriptor:ddp transfered:ddp->size]; ! 593: ! 594: /* ! 595: * In the original driver, the dequeueDMA operation would return ! 596: * the actually transfer count. We need to offer a similar ! 597: * solution at some point: ! 598: * [stream dmaCompleteDescriptor:ddp transfered:count]; ! 599: */ ! 600: } ! 601: } ! 602: [streamListLock unlock]; ! 603: ! 604: bzero((void *)ddp->mem, descriptorSize); ! 605: ! 606: #ifdef ppc ! 607: flush_cache_v((vm_offset_t)ddp->mem,descriptorSize); ! 608: #endif ! 609: ! 610: queue_enter(&freeQueue, ddp, dma_desc_t *, link); ! 611: ! 612: --enqueueCount; ! 613: xpr_audio_channel("AC: dequeueDescriptor done\n",1,2,3,4,5); ! 614: } ! 615: ! 616: ! 617: /* ! 618: * returns the channel buffer as a void * ! 619: */ ! 620: - (void *) channelBuffer ! 621: { ! 622: return channelBuffer; ! 623: } ! 624: ! 625: - (vm_address_t) channelBufferAddress ! 626: { ! 627: return channelBufferPtr; ! 628: } ! 629: ! 630: - (void) freeDescriptors ! 631: { ! 632: /* ! 633: * When a DMA operation is aborted, descriptors might still remain on ! 634: * the DMA queue. ! 635: */ ! 636: while (!queue_empty(&dmaQueue)) ! 637: [self dequeueDescriptor]; ! 638: ! 639: [self initializeFreeQueue]; ! 640: } ! 641: ! 642: - (void) setLocalChannel:(u_int) channel ! 643: { ! 644: localChannel = channel; ! 645: } ! 646: ! 647: - (u_int) localChannel ! 648: { ! 649: return localChannel; ! 650: } ! 651: ! 652: /* ! 653: * Get and set user channel and snd ports. ! 654: */ ! 655: - setUserChannelPort:(port_t)port ! 656: { ! 657: userChannelPort = port; ! 658: return self; ! 659: } ! 660: - (port_t)userChannelPort ! 661: { ! 662: return userChannelPort; ! 663: } ! 664: - setUserSndPort:(port_t)port ! 665: { ! 666: userSndPort = port; ! 667: return self; ! 668: } ! 669: - (port_t)userSndPort ! 670: { ! 671: return userSndPort; ! 672: } ! 673: ! 674: /* ! 675: * Search for the FIRST stream with the given owner port ! 676: * (used by the snd interface, which has one stream per channel). ! 677: * Returns the stream's user port. ! 678: */ ! 679: - (port_t)streamUserForOwnerPort:(port_t)port ! 680: { ! 681: int i; ! 682: id stream; ! 683: ! 684: for (i = 0; i < [streamList count]; i++) { ! 685: stream = [streamList objectAt:i]; ! 686: if ([stream ownerPort] == port) ! 687: return [stream userPort]; ! 688: } ! 689: return PORT_NULL; ! 690: } ! 691: ! 692: /* ! 693: * Remove all snd type streams. ! 694: */ ! 695: - removeSndStreams ! 696: { ! 697: id stream; ! 698: List *remList = [[List alloc] init]; ! 699: int i; ! 700: ! 701: [streamListLock lock]; ! 702: for (i = 0; i < [streamList count]; i++) { ! 703: stream = [streamList objectAt:i]; ! 704: if ([stream type] != AS_TypeUser) ! 705: [remList addObject:stream]; ! 706: } ! 707: [streamListLock unlock]; ! 708: ! 709: for (i = 0; i < [remList count]; i++) ! 710: [self removeStream:[remList objectAt:i]]; ! 711: ! 712: [remList free]; ! 713: return self; ! 714: } ! 715: ! 716: /* ! 717: * Get and set exclusive user. ! 718: */ ! 719: - (void)setExclusiveUser:(port_t)streamPort ! 720: { ! 721: int streamCount, i; ! 722: ! 723: exclusiveUser = streamPort; ! 724: /* ! 725: * Cause other owner's streams to abort with excluded messages. ! 726: */ ! 727: [streamListLock lock]; ! 728: streamCount = [streamList count]; ! 729: if (streamCount == 0) { ! 730: [streamListLock unlock]; ! 731: return; ! 732: } ! 733: for (i = 0; i < streamCount; i++) ! 734: [[streamList objectAt:i] control:AC_ControlExclude]; ! 735: [streamListLock unlock]; ! 736: } ! 737: - (port_t)exclusiveUser ! 738: { ! 739: return exclusiveUser; ! 740: } ! 741: ! 742: /* ! 743: * Check prospective owner port against current exclusive user port. ! 744: */ ! 745: - (BOOL)checkOwner:(port_t)owner ! 746: { ! 747: if (exclusiveUser != PORT_NULL && owner != exclusiveUser) ! 748: return NO; ! 749: else ! 750: return YES; ! 751: } ! 752: ! 753: /* ! 754: * ! 755: */ ! 756: - streamClass ! 757: { ! 758: return streamClass; ! 759: } ! 760: ! 761: /* ! 762: * Return number of streams ! 763: */ ! 764: - (u_int)streamCount ! 765: { ! 766: u_int count; ! 767: ! 768: [streamListLock lock]; ! 769: count = [streamList count]; ! 770: [streamListLock unlock]; ! 771: return count; ! 772: } ! 773: ! 774: /* ! 775: * When a stream is added, its user port must be registered with the ! 776: * audio loadable kernel server. ! 777: */ ! 778: - (BOOL)addStreamTag:(int)tag user:(port_t *)userPort ! 779: owner:(port_t)owner type:(u_int)type ! 780: { ! 781: id aStream; ! 782: ! 783: xpr_audio_channel("AC: addStreamTag tag=%d user=%x owner=%x" ! 784: " type=%d\n", tag, userPort, owner, type, 5); ! 785: ! 786: if (![audioDevice _channelWillAddStream]) { ! 787: xpr_audio_channel("AC: audioDevice can not add stream.\n",1,2,3,4,5); ! 788: return NO; ! 789: } ! 790: ! 791: aStream = [[[self streamClass] alloc] initChannel:self tag:tag ! 792: user:userPort ! 793: owner:owner type:type]; ! 794: if (!aStream) { ! 795: xpr_audio_channel("AC: addStreamTag: can not add stream.\n",1,2,3,4,5); ! 796: return NO; ! 797: } ! 798: ! 799: [streamListLock lock]; ! 800: ! 801: if ([streamList count] == 0) { ! 802: if (![self createChannelBuffer]) { ! 803: [streamListLock unlock]; ! 804: xpr_audio_channel("AC: addStreamTag: can not create" ! 805: " channel buffer.\n",1,2,3,4,5); ! 806: return NO; ! 807: } ! 808: } ! 809: ! 810: [streamList addObject:aStream]; ! 811: [streamListLock unlock]; ! 812: [AudioChannel addStream:aStream]; ! 813: ! 814: return audio_enroll_stream_port(*userPort, TRUE); ! 815: } ! 816: ! 817: /* ! 818: * Remove a stream. ! 819: */ ! 820: - (void)removeStream:stream ! 821: { ! 822: unsigned int count; ! 823: ! 824: audio_enroll_stream_port([stream userPort], FALSE); ! 825: [streamListLock lock]; ! 826: count = [streamList count]; ! 827: ! 828: /* ! 829: * When only one stream remains, DMA is aborted when the stream is removed. ! 830: */ ! 831: if (count == 1) { ! 832: ! 833: /* ! 834: * The streamListLock needs to be unlocked to prevent deadlock. When ! 835: * the abort command is sent to the IO thread, the dequeueDescriptor ! 836: * method will be executed. This method needs to acquire the lock. ! 837: */ ! 838: [streamListLock unlock]; ! 839: ! 840: if ([self isRead]) ! 841: [[audioDevice _audioCommand] send: abortInputChannel]; ! 842: else ! 843: [[audioDevice _audioCommand] send: abortOutputChannel]; ! 844: ! 845: [streamListLock lock]; ! 846: ! 847: if (peaksLeft) ! 848: audio_clear_peaks(peaksLeft, MAX_PEAK_HISTORY); ! 849: if (peaksRight) ! 850: audio_clear_peaks(peaksRight, MAX_PEAK_HISTORY); ! 851: clipCount = 0; ! 852: ! 853: } ! 854: ! 855: [streamList removeObject:stream]; ! 856: [AudioChannel removeStream:stream]; ! 857: [stream free]; ! 858: [streamListLock unlock]; ! 859: ! 860: } ! 861: ! 862: ! 863: /* ! 864: * Send stream control to all streams. ! 865: */ ! 866: - (void)controlStreams:(ACStreamControl)action ! 867: { ! 868: int streamCount, i; ! 869: ! 870: [streamListLock lock]; ! 871: streamCount = [streamList count]; ! 872: if (streamCount == 0) { ! 873: [streamListLock unlock]; ! 874: return; ! 875: } ! 876: for (i = 0; i < streamCount; i++) ! 877: [[streamList objectAt:i] control:action]; ! 878: [streamListLock unlock]; ! 879: } ! 880: ! 881: - (BOOL)isDetectingPeaks ! 882: { ! 883: return peakEnabled; ! 884: } ! 885: ! 886: - (void)setDetectPeaks:(BOOL)flag; ! 887: { ! 888: /* ! 889: * FIXME: unsupport history. ! 890: */ ! 891: peakEnabled = flag; ! 892: if (peakEnabled && !peaksLeft) { ! 893: peaksLeft = (u_int *)IOMalloc(MAX_PEAK_HISTORY*sizeof(u_int)); ! 894: peaksRight = (u_int *)IOMalloc(MAX_PEAK_HISTORY*sizeof(u_int)); ! 895: audio_clear_peaks(peaksLeft, MAX_PEAK_HISTORY); ! 896: audio_clear_peaks(peaksRight, MAX_PEAK_HISTORY); ! 897: } ! 898: } ! 899: ! 900: /* ! 901: * Get peaks and clip count. ! 902: */ ! 903: - (void)getPeakLeft:(u_int *)leftPeak right:(u_int *)rightPeak ! 904: { ! 905: if (peakEnabled) { ! 906: *leftPeak = audio_max_peak(peaksLeft, peakHistory); ! 907: *rightPeak = audio_max_peak(peaksRight, peakHistory); ! 908: } else ! 909: *leftPeak = *rightPeak = 0; ! 910: } ! 911: - (u_int)clipCount ! 912: { ! 913: return clipCount; ! 914: } ! 915: - incrementClipCount:(u_int)count ! 916: { ! 917: clipCount += count; ! 918: return self; ! 919: } ! 920: ! 921: /* ! 922: * Return device. ! 923: */ ! 924: - audioDevice ! 925: { ! 926: return audioDevice; ! 927: } ! 928: ! 929: @end
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.