|
|
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: * OutputStream.m ! 26: * ! 27: * Copyright (c) 1991, NeXT Computer, Inc. All rights reserved. ! 28: * ! 29: * Audio driver output stream object. ! 30: * ! 31: * HISTORY ! 32: * 07/14/92/mtm Original coding. ! 33: */ ! 34: ! 35: #import <kern/lock.h> ! 36: #import "OutputStream.h" ! 37: #import "AudioChannel.h" ! 38: #import <driverkit/IOAudioPrivate.h> ! 39: #import "audioLog.h" ! 40: #import "audio_types.h" ! 41: #import "audio_mix.h" ! 42: #import "audio_peak.h" ! 43: #import <mach/mach_types.h> ! 44: #import <mach/mach_user_internal.h> ! 45: #import <mach/mach_interface.h> ! 46: #import <mach/vm_param.h> // PAGE_SIZE ! 47: #import <kernserv/kern_server_types.h> ! 48: #import <kernserv/prototypes.h> ! 49: #import <architecture/byte_order.h> ! 50: #import <driverkit/kernelDriver.h> ! 51: ! 52: /* ! 53: * mix buffers contain enough space to support conversions ! 54: * that require up to four times the max dma size. ! 55: */ ! 56: ! 57: /* ! 58: * This size depends unpon current descriptor size. We need a method to do ! 59: * this instead of a #define. ! 60: */ ! 61: ! 62: // With 8K size buffers. ! 63: #define MIX_BUFFER1_SIZE (PAGE_SIZE*8) ! 64: #define MIX_BUFFER2_SIZE (PAGE_SIZE*4) ! 65: ! 66: @implementation OutputStream ! 67: ! 68: /* ! 69: * Overridden from superclass. ! 70: */ ! 71: - initChannel:chan tag:(int)aTag user:(port_t *)user ! 72: owner:(port_t)owner type:(u_int)aType ! 73: { ! 74: int i; ! 75: xfer_record_t *xfer_rec; ! 76: ! 77: if (![super initChannel:chan tag:aTag user:user owner:owner type:aType]) ! 78: return nil; ! 79: leftGain = rightGain = UNITY_GAIN; ! 80: peakHistory = 1; ! 81: queue_init(&xferQueue); ! 82: for (i = 0; i < [chan dmaCount]; i++) { ! 83: xfer_rec = (xfer_record_t *)IOMalloc(sizeof(xfer_record_t)); ! 84: xfer_rec->ddp = 0; ! 85: xfer_rec->size = 0; ! 86: xfer_rec->peak_left = xfer_rec->peak_right = 0; ! 87: xfer_rec->clips = 0; ! 88: queue_enter(&xferQueue, xfer_rec, xfer_record_t *, link); ! 89: } ! 90: mixBuffer1 = (char *)IOMalloc(MIX_BUFFER1_SIZE); ! 91: mixBuffer2 = (char *)IOMalloc(MIX_BUFFER2_SIZE); ! 92: return self; ! 93: } ! 94: ! 95: /* ! 96: * Write data in our task to kernel memory. ! 97: */ ! 98: static BOOL writeToKernel(vm_address_t data, u_int size, vm_address_t *kmem) ! 99: { ! 100: kern_return_t kerr; ! 101: vm_address_t data_page = trunc_page(data); ! 102: u_int offset = data - data_page; ! 103: u_int size_page = round_page(size + offset); ! 104: vm_task_t kernelTask = (vm_task_t)kern_serv_kernel_task_port(); ! 105: ! 106: /* ! 107: * Read-protect the region so vm_write does not do a physical copy. ! 108: */ ! 109: kerr = vm_protect(task_self(), data_page, size_page, FALSE, VM_PROT_READ); ! 110: if (kerr != KERN_SUCCESS) { ! 111: IOLog("Audio: vm_protect returned %d\n", kerr); ! 112: //IOPanic("Audio: vm_protect\n"); ! 113: } ! 114: ! 115: /* ! 116: * Allocate space in the kernel map. ! 117: */ ! 118: kerr = vm_allocate(kernelTask, kmem, size_page, TRUE); ! 119: if (kerr != KERN_SUCCESS) ! 120: return NO; ! 121: ! 122: /* ! 123: * Write data to kernel map. ! 124: */ ! 125: kerr = vm_write(kernelTask, *kmem, data_page, size_page); ! 126: if (kerr != KERN_SUCCESS) { ! 127: IOLog("Audio: vm_write returned %d\n", kerr); ! 128: //IOPanic("Audio: vm_write\n"); ! 129: } ! 130: ! 131: /* ! 132: * Deallocate user data. ! 133: */ ! 134: kerr = vm_deallocate(task_self(), data_page, size_page); ! 135: if (kerr != KERN_SUCCESS) { ! 136: IOLog("Audio: vm_deallocate returned %d\n", kerr); ! 137: //IOPanic("Audio: vm_deallocate\n"); ! 138: } ! 139: /* ! 140: * Return offset of the data in kernel memory. ! 141: */ ! 142: *kmem += offset; ! 143: return YES; ! 144: } ! 145: ! 146: /* ! 147: * Enqueue buffer to region queue. ! 148: */ ! 149: - (BOOL)playBuffer:(void *)data size:(u_int)byteCount ! 150: tag:(int)aTag ! 151: replyTo:(port_t)replyPort ! 152: replyMsgs:(ASMsgRequest)messages ! 153: { ! 154: region_t *region; ! 155: port_t kernReplyPort; ! 156: vm_address_t kmem; ! 157: ! 158: kernReplyPort = IOConvertPort(replyPort, IO_CurrentTask, IO_Kernel); ! 159: if(kernReplyPort == PORT_NULL) ! 160: messages = 0; // No messages if reply port has already gone away! ! 161: /* ! 162: * Truncate count if necessary. ! 163: */ ! 164: if (dataFormat == IOAudioDataFormatLinear16) ! 165: byteCount &= (channelCount == 1 ? ~(2-1) : ~(4-1)); ! 166: ! 167: if (!writeToKernel((vm_address_t)data, byteCount, &kmem)) { ! 168: IOLog("Audio: playback request (%d bytes) too large\n", byteCount); ! 169: return NO; ! 170: } ! 171: ! 172: region = [self newRegion]; ! 173: region->data = region->enq_ptr = kmem; ! 174: region->end = region->data + byteCount; ! 175: region->count = byteCount; ! 176: region->tag = aTag; ! 177: region->reply_port = kernReplyPort; ! 178: region->messages = messages; ! 179: /* ! 180: * Some reply messages are per stream in NXSound interface. ! 181: * FIXME: these only get set if data sent to stream. ! 182: */ ! 183: userReplyMessages = messages; ! 184: userReplyPort = kernReplyPort; ! 185: ! 186: xpr_audio_stream("OS: playbuffer: locking regionQueue\n", 1,2,3,4,5); ! 187: [regionQueueLock lock]; ! 188: queue_enter(®ionQueue, region, region_t *, link); ! 189: [regionQueueLock unlock]; ! 190: xpr_audio_stream("OS: playbuffer: unlocked regionQueue\n", 1,2,3,4,5); ! 191: ! 192: [device _dataPendingForChannel: [self channel]]; ! 193: return YES; ! 194: } ! 195: ! 196: /* ! 197: * Overridden from superclass to allow some conversions. ! 198: */ ! 199: - (BOOL)canConvertRegion:(region_t *)region ! 200: rate:(u_int)srate format:(IOAudioDataFormat)format ! 201: channelCount:(u_int)chans; ! 202: { ! 203: ! 204: if ([super canConvertRegion:region rate:srate ! 205: format:format channelCount:chans]) ! 206: return YES; ! 207: /* ! 208: * FIXME: support other format mixing and scaling. ! 209: */ ! 210: if ((format == IOAudioDataFormatAlaw8) || (format == IOAudioDataFormatAES)) ! 211: return NO; ! 212: /* ! 213: * FIXME: support other rate conversions. ! 214: */ ! 215: if (!((srate == 22050 && samplingRate == 44100) || ! 216: (srate == 44100 && samplingRate == 22050))) ! 217: return NO; ! 218: return YES; ! 219: } ! 220: ! 221: /* ! 222: * Clear to end of buffer so next stream can mix in. ! 223: */ ! 224: - clearForMix:(char *)buf size:(u_int)count format:(IOAudioDataFormat)format ! 225: { ! 226: xpr_audio_stream("OS: clearForMix: %d bytes from 0x%x\n", count, buf, ! 227: 3,4,5); ! 228: if (format == IOAudioDataFormatLinear8) /* && devIsUnary8 */ ! 229: while (count--) ! 230: *buf++ = UNARY8_SILENCE; ! 231: else if (format == IOAudioDataFormatMulaw8) ! 232: while (count--) ! 233: *buf++ = MULAW8_SILENCE; ! 234: else ! 235: bzero(buf, count); ! 236: return self; ! 237: } ! 238: ! 239: /* ! 240: * Add an xfer record to a stream's xfer count queue. ! 241: */ ! 242: static void add_xfer_record(queue_t xferq, dma_desc_t *ddp, u_int count, ! 243: u_int peak_left, u_int peak_right, u_int clips) ! 244: { ! 245: xfer_record_t *xfer_rec; ! 246: ! 247: if (!queue_empty(xferq)) { ! 248: xfer_rec = (xfer_record_t *)queue_first(xferq); ! 249: while (!queue_end(xferq, (queue_entry_t)xfer_rec)) { ! 250: if ((ddp == xfer_rec->ddp) || !xfer_rec->ddp) { ! 251: xfer_rec->ddp = ddp; ! 252: xfer_rec->size = count; ! 253: xfer_rec->peak_left = peak_left; ! 254: xfer_rec->peak_right = peak_right; ! 255: xfer_rec->clips = clips; ! 256: xpr_audio_stream("OS: add_xfer_record: ddp=0x%x size=%d " ! 257: "pl=%d pr=%d clips=%d\n", ddp, count, ! 258: peak_left, peak_right, clips); ! 259: return; ! 260: } ! 261: xfer_rec = (xfer_record_t *)queue_next(&xfer_rec->link); ! 262: } ! 263: } ! 264: } ! 265: ! 266: /* ! 267: * Return stream's xfer count on ddp. ! 268: * Reset count to 0. ! 269: */ ! 270: static u_int xfer_count(queue_t xferq, dma_desc_t *ddp, u_int *peak_left, ! 271: u_int *peak_right, u_int *clips) ! 272: { ! 273: xfer_record_t *xfer_rec; ! 274: u_int count; ! 275: ! 276: if (!queue_empty(xferq)) { ! 277: xfer_rec = (xfer_record_t *)queue_first(xferq); ! 278: while (!queue_end(xferq, (queue_entry_t)xfer_rec)) { ! 279: if (ddp == xfer_rec->ddp) { ! 280: count = xfer_rec->size; ! 281: xfer_rec->size = 0; ! 282: *peak_left = xfer_rec->peak_left; ! 283: *peak_right = xfer_rec->peak_right; ! 284: *clips = xfer_rec->clips; ! 285: xpr_audio_stream("OS: xfer_count: ddp=0x%x count=%d " ! 286: "pl=%d pr=%d clips=%d\n", ddp, count, ! 287: *peak_left, *peak_right, *clips); ! 288: return count; ! 289: } ! 290: xfer_rec = (xfer_record_t *)queue_next(&xfer_rec->link); ! 291: } ! 292: } ! 293: return 0; ! 294: } ! 295: ! 296: #define CONV_NONE 0 ! 297: #define CONV_SWAP (1<<0) ! 298: #define CONV_SCALE (1<<1) ! 299: #define CONV_22_44 (1<<2) ! 300: #define CONV_44_22 (1<<3) ! 301: #define CONV_MONO_STEREO (1<<4) ! 302: #define CONV_STEREO_MONO (1<<5) ! 303: #define CONV_LINEAR8_LINEAR16 (1<<6) ! 304: #define CONV_LINEAR8_MULAW8 (1<<7) ! 305: #define CONV_LINEAR16_LINEAR8 (1<<8) ! 306: #define CONV_LINEAR16_MULAW8 (1<<9) ! 307: #define CONV_MULAW8_LINEAR16 (1<<10) ! 308: #define CONV_MULAW8_LINEAR8 (1<<11) ! 309: ! 310: /* ! 311: * Mix playback data from region into buffer, returning count of ! 312: * bytes mixed. ! 313: */ ! 314: - (u_int)mixRegion:(region_t *)region descriptor:(dma_desc_t *)ddp ! 315: buffer:(vm_address_t)data maxCount:(u_int)max ! 316: virgin:(BOOL)isVirgin rate:(u_int)srate ! 317: format:(IOAudioDataFormat)format ! 318: channelCount:(u_int)chans ! 319: { ! 320: u_int scale_clips = 0, peak_left = 0, peak_right = 0; ! 321: u_int mix_clips = 0; ! 322: u_int in_count, avail, out_count; ! 323: u_int conversions = CONV_NONE; ! 324: boolean_t doMix = TRUE; ! 325: IOAudioDataFormat streamDataFormat = dataFormat; ! 326: /* ! 327: * NOTE: src is read-only - always write into aux1 or aux2. ! 328: * aux1 is MIX_BUFFER1_SIZE, aux2 is MIX_BUFFER2_SIZE. ! 329: */ ! 330: char *src, *aux1 = mixBuffer1, *aux2 = mixBuffer2; ! 331: ! 332: src = (char *)region->enq_ptr; ! 333: in_count = out_count = max; ! 334: avail = region->end - region->enq_ptr; ! 335: if (in_count > avail) ! 336: in_count = out_count = avail; ! 337: ! 338: /* ! 339: * Determine what conversions are required. ! 340: */ ! 341: if (streamDataFormat == IOAudioDataFormatLinear16) ! 342: conversions |= CONV_SWAP; ! 343: ! 344: /* ! 345: * FIXME: this breaks mono pan - need new API. ! 346: */ ! 347: if (leftGain != UNITY_GAIN || rightGain != UNITY_GAIN) ! 348: conversions |= CONV_SCALE; ! 349: if (channelCount == 1 && chans == 2) ! 350: conversions |= CONV_MONO_STEREO; ! 351: else if (channelCount == 2 && chans == 1) ! 352: conversions |= CONV_STEREO_MONO; ! 353: if (samplingRate == 22050 && srate == 44100) ! 354: conversions |= CONV_22_44; ! 355: else if (samplingRate == 44100 && srate == 22050) ! 356: conversions |= CONV_44_22; ! 357: if (streamDataFormat == IOAudioDataFormatLinear8 && ! 358: format == IOAudioDataFormatLinear16) ! 359: conversions |= CONV_LINEAR8_LINEAR16; ! 360: else if (streamDataFormat == IOAudioDataFormatLinear8 && ! 361: format == IOAudioDataFormatMulaw8) ! 362: conversions |= CONV_LINEAR8_MULAW8; ! 363: else if (streamDataFormat == IOAudioDataFormatLinear16 && ! 364: format == IOAudioDataFormatLinear8) ! 365: conversions |= CONV_LINEAR16_LINEAR8; ! 366: else if (streamDataFormat == IOAudioDataFormatLinear16 && ! 367: format == IOAudioDataFormatMulaw8) ! 368: conversions |= CONV_LINEAR16_MULAW8; ! 369: else if (streamDataFormat == IOAudioDataFormatMulaw8 && ! 370: format == IOAudioDataFormatLinear16) ! 371: conversions |= CONV_MULAW8_LINEAR16; ! 372: else if (streamDataFormat == IOAudioDataFormatMulaw8 && ! 373: format == IOAudioDataFormatLinear8) ! 374: conversions |= CONV_MULAW8_LINEAR8; ! 375: ! 376: /* FIXME: can phase variables just keep wrapping around or ! 377: do they need to be set to 0 at some point? */ ! 378: ! 379: /* ! 380: * Perform conversion sequences. ! 381: */ ! 382: switch (conversions) { ! 383: case CONV_NONE: ! 384: break; ! 385: case CONV_SCALE: ! 386: scale_clips = audio_scaleSamples(src, aux1, in_count, streamDataFormat, ! 387: channelCount, (int)leftGain, ! 388: (int)rightGain); ! 389: src = aux1; ! 390: break; ! 391: case CONV_MONO_STEREO: ! 392: in_count /= 2; ! 393: audio_convertMonoToStereo(src, aux1, in_count, streamDataFormat); ! 394: src = aux1; ! 395: break; ! 396: case CONV_STEREO_MONO: ! 397: in_count *= 2; ! 398: if (in_count > avail) ! 399: in_count = avail; ! 400: out_count = in_count / 2; ! 401: audio_convertStereoToMono(src, aux1, in_count, streamDataFormat, ! 402: &channelPhase); ! 403: src = aux1; ! 404: break; ! 405: case CONV_22_44: ! 406: in_count /= 2; ! 407: audio_resample22To44(src, aux1, in_count, streamDataFormat, channelCount ); ! 408: src = aux1; ! 409: break; ! 410: case CONV_44_22: ! 411: in_count *= 2; ! 412: if (in_count > avail) ! 413: in_count = avail; ! 414: out_count = in_count / 2; ! 415: audio_resample44To22(src, aux1, in_count, streamDataFormat, ! 416: &resamplePhase); ! 417: src = aux1; ! 418: break; ! 419: case CONV_MONO_STEREO | CONV_22_44: ! 420: in_count /= 4; ! 421: audio_convertMonoToStereo(src, aux1, in_count, streamDataFormat); ! 422: audio_resample22To44(aux1, aux2, in_count*2, streamDataFormat, channelCount); ! 423: src = aux2; ! 424: break; ! 425: case CONV_STEREO_MONO | CONV_44_22: ! 426: in_count *= 4; ! 427: if (in_count > avail) ! 428: in_count = avail; ! 429: out_count = in_count / 4; ! 430: audio_convertStereoToMono(src, aux1, in_count, streamDataFormat, ! 431: &channelPhase); ! 432: audio_resample44To22(aux1, aux2, in_count/2, streamDataFormat, ! 433: &resamplePhase); ! 434: src = aux2; ! 435: break; ! 436: case CONV_MONO_STEREO | CONV_44_22: ! 437: audio_convertMonoToStereo(src, aux1, in_count, streamDataFormat); ! 438: audio_resample44To22(aux1, aux2, in_count*2, streamDataFormat, ! 439: &resamplePhase); ! 440: src = aux2; ! 441: break; ! 442: case CONV_STEREO_MONO | CONV_22_44: ! 443: audio_convertStereoToMono(src, aux1, in_count, streamDataFormat, ! 444: &channelPhase); ! 445: audio_resample22To44(aux1, aux2, in_count/2, streamDataFormat, channelCount); ! 446: src = aux2; ! 447: break; ! 448: case CONV_MULAW8_LINEAR16: ! 449: in_count /= 2; ! 450: audio_convertMulaw8ToLinear16(src, (short *)aux1, in_count); ! 451: streamDataFormat = IOAudioDataFormatLinear16; ! 452: src = aux1; ! 453: break; ! 454: case CONV_MULAW8_LINEAR8: ! 455: audio_convertMulaw8ToLinear8(src, aux1, in_count); ! 456: streamDataFormat = IOAudioDataFormatLinear8; ! 457: src = aux1; ! 458: break; ! 459: case CONV_LINEAR8_LINEAR16: ! 460: in_count /= 2; ! 461: audio_convertLinear8ToLinear16(src, (short *)aux1, in_count); ! 462: streamDataFormat = IOAudioDataFormatLinear16; ! 463: src = aux1; ! 464: break; ! 465: case CONV_LINEAR8_MULAW8: ! 466: audio_convertLinear8ToMulaw8(src, aux1, in_count); ! 467: streamDataFormat = IOAudioDataFormatMulaw8; ! 468: src = aux1; ! 469: break; ! 470: ! 471: case CONV_SWAP: ! 472: audio_swapSamples((short *)src, (short *)aux1, in_count/2); ! 473: src = aux1; ! 474: break; ! 475: case CONV_SWAP | CONV_SCALE: ! 476: audio_swapSamples((short *)src, (short *)aux1, in_count/2); ! 477: scale_clips = audio_scaleSamples(aux1, aux2, in_count, ! 478: streamDataFormat, ! 479: channelCount, (int)leftGain, ! 480: (int)rightGain); ! 481: src = aux2; ! 482: break; ! 483: case CONV_SWAP | CONV_MONO_STEREO: ! 484: in_count /= 2; ! 485: audio_swapSamples((short *)src, (short *)aux1, in_count/2); ! 486: audio_convertMonoToStereo(aux1, aux2, in_count, streamDataFormat); ! 487: src = aux2; ! 488: break; ! 489: case CONV_SWAP | CONV_STEREO_MONO: ! 490: in_count *= 2; ! 491: if (in_count > avail) ! 492: in_count = avail; ! 493: out_count = in_count / 2; ! 494: /* ! 495: * StereoToMono looks at bits, must swap first. ! 496: */ ! 497: audio_swapSamples((short *)src, (short *)aux1, in_count/2); ! 498: audio_convertStereoToMono(aux1, aux2, in_count, streamDataFormat, ! 499: &channelPhase); ! 500: src = aux2; ! 501: break; ! 502: case CONV_SWAP | CONV_22_44: ! 503: if ( in_count*2 >= max ) ! 504: { ! 505: in_count = max/2; ! 506: out_count = max; ! 507: } ! 508: else ! 509: { ! 510: out_count = avail*2; ! 511: in_count = avail; ! 512: } ! 513: ! 514: // in_count /= 2; ! 515: ! 516: audio_swapSamples((short *)src, (short *)aux1, in_count/2); ! 517: audio_resample22To44(aux1, aux2, in_count, streamDataFormat, channelCount); ! 518: src = aux2; ! 519: break; ! 520: case CONV_SWAP | CONV_44_22: ! 521: in_count *= 2; ! 522: if (in_count > avail) ! 523: in_count = avail; ! 524: out_count = in_count / 2; ! 525: /* ! 526: * Resampling currently doesn't look at bits, so we can swap last. ! 527: */ ! 528: audio_resample44To22(src, aux1, in_count, streamDataFormat, ! 529: &resamplePhase); ! 530: audio_swapSamples((short *)aux1, (short *)aux2, out_count/2); ! 531: src = aux2; ! 532: break; ! 533: case CONV_SWAP | CONV_MONO_STEREO | CONV_22_44: ! 534: in_count /= 4; ! 535: audio_swapSamples((short *)src, (short *)aux1, in_count/2); ! 536: audio_convertMonoToStereo(aux1, aux2, in_count, streamDataFormat); ! 537: audio_resample22To44(aux2, aux1, in_count*2, streamDataFormat, channelCount); ! 538: src = aux1; ! 539: break; ! 540: case CONV_SWAP | CONV_STEREO_MONO | CONV_44_22: ! 541: in_count *= 4; ! 542: if (in_count > avail) ! 543: in_count = avail; ! 544: out_count = in_count / 4; ! 545: audio_swapSamples((short *)src, (short *)aux1, in_count/2); ! 546: audio_convertStereoToMono(aux1, aux2, in_count, streamDataFormat, ! 547: &channelPhase); ! 548: audio_resample44To22(aux2, aux1, in_count/2, streamDataFormat, ! 549: &resamplePhase); ! 550: src = aux1; ! 551: break; ! 552: case CONV_SWAP | CONV_MONO_STEREO | CONV_44_22: ! 553: audio_swapSamples((short *)src, (short *)aux1, in_count/2); ! 554: audio_convertMonoToStereo(aux1, aux2, in_count, streamDataFormat); ! 555: audio_resample44To22(aux2, aux1, in_count*2, streamDataFormat, ! 556: &resamplePhase); ! 557: src = aux1; ! 558: break; ! 559: case CONV_SWAP | CONV_STEREO_MONO | CONV_22_44: ! 560: audio_swapSamples((short *)src, (short *)aux1, in_count/2); ! 561: audio_convertStereoToMono(aux1, aux2, in_count, streamDataFormat, ! 562: &channelPhase); ! 563: audio_resample22To44(aux2, aux1, in_count/2, streamDataFormat, channelCount); ! 564: src = aux1; ! 565: break; ! 566: case CONV_SWAP | CONV_LINEAR16_LINEAR8: ! 567: in_count *= 2; ! 568: if (in_count > avail) ! 569: in_count = avail; ! 570: out_count = in_count / 2; ! 571: audio_swapSamples((short *)src, (short *)aux1, in_count/2); ! 572: audio_convertLinear16ToLinear8((short *)aux1, aux2, in_count/2, ! 573: &formatPhase); ! 574: streamDataFormat = IOAudioDataFormatLinear8; ! 575: src = aux2; ! 576: break; ! 577: case CONV_SWAP | CONV_LINEAR16_MULAW8: ! 578: in_count *= 2; ! 579: if (in_count > avail) ! 580: in_count = avail; ! 581: out_count = in_count / 2; ! 582: audio_swapSamples((short *)src, (short *)aux1, in_count/2); ! 583: audio_convertLinear16ToMulaw8((short *)aux1, aux2, in_count/2, ! 584: &formatPhase); ! 585: streamDataFormat = IOAudioDataFormatMulaw8; ! 586: src = aux2; ! 587: break; ! 588: ! 589: default: ! 590: IOLog("Audio: unsupported mixing conversion 0x%x\n", conversions); ! 591: doMix = FALSE; ! 592: break; ! 593: } ! 594: ! 595: if (doMix) { ! 596: if (peakEnabled) { ! 597: if (streamDataFormat == IOAudioDataFormatLinear16) ! 598: audio_linear16_peak(channelCount, (short *)src, out_count, ! 599: &peak_left, &peak_right); ! 600: else if (streamDataFormat == IOAudioDataFormatLinear8) ! 601: audio_linear8_peak(channelCount, (char *)src, out_count, ! 602: &peak_left, &peak_right); ! 603: else if (streamDataFormat == IOAudioDataFormatMulaw8) ! 604: audio_mulaw8_peak(channelCount, (unsigned char *)src, ! 605: out_count, ! 606: &peak_left, &peak_right); ! 607: } ! 608: ! 609: mix_clips = audio_mix(src, (char *)data, out_count, streamDataFormat, ! 610: isVirgin); ! 611: } ! 612: ! 613: region->enq_ptr += in_count; ! 614: add_xfer_record(&xferQueue, ddp, in_count, ! 615: peak_left, peak_right, ! 616: (scale_clips > mix_clips ? scale_clips : mix_clips)); ! 617: xpr_audio_stream("OS: mixRegion: mixed in %d bytes\n", out_count, 2,3,4,5); ! 618: ! 619: return out_count; ! 620: } ! 621: ! 622: /* ! 623: * Update peak, transfer and clip counts. ! 624: */ ! 625: - completeRegion:(region_t *)region descriptor:(dma_desc_t *)ddp ! 626: size:(u_int)xfer used:(u_int *)used ! 627: { ! 628: u_int peak_left, peak_right, clips; ! 629: ! 630: bytesProcessed += xfer_count(&xferQueue, ddp, &peak_left, &peak_right, ! 631: &clips); ! 632: xpr_audio_stream("OS: completeRegion: play stream nxfer = %d " ! 633: "clips=%d\n", bytesProcessed, clips, 3,4,5); ! 634: [channel incrementClipCount:clips]; ! 635: ! 636: if (peakEnabled) { ! 637: audio_add_peak(peaksLeft, peak_left, ¤tPeak, peakHistory); ! 638: audio_add_peak(peaksRight, peak_right, ¤tPeak, peakHistory); ! 639: xpr_audio_stream("OS: completeRegion: stream peaks %d %d\n", peak_left, ! 640: peak_right, 3,4,5); ! 641: } ! 642: return self; ! 643: } ! 644: ! 645: - (unsigned int)gainLeft ! 646: { ! 647: return leftGain; ! 648: } ! 649: - (unsigned int)gainRight ! 650: { ! 651: return rightGain; ! 652: } ! 653: - (void)setGainLeft:(unsigned int)gain ! 654: { ! 655: leftGain = gain; ! 656: } ! 657: - (void)setGainRight:(unsigned int)gain ! 658: { ! 659: rightGain = gain; ! 660: } ! 661: ! 662: /* ! 663: * Get and set peak parameters. ! 664: */ ! 665: - (BOOL)isDetectingPeaks ! 666: { ! 667: return peakEnabled; ! 668: } ! 669: ! 670: - (void)setDetectPeaks:(BOOL)flag; ! 671: { ! 672: peakEnabled = flag; ! 673: if (peakEnabled && !peaksLeft) { ! 674: peaksLeft = (u_int *)IOMalloc(MAX_PEAK_HISTORY*sizeof(u_int)); ! 675: peaksRight = (u_int *)IOMalloc(MAX_PEAK_HISTORY*sizeof(u_int)); ! 676: audio_clear_peaks(peaksLeft, MAX_PEAK_HISTORY); ! 677: audio_clear_peaks(peaksRight, MAX_PEAK_HISTORY); ! 678: } ! 679: } ! 680: ! 681: /* ! 682: * Get peaks. ! 683: */ ! 684: - getPeakLeft:(u_int *)leftPeak right:(u_int *)rightPeak ! 685: { ! 686: if (peakEnabled) { ! 687: *leftPeak = audio_max_peak(peaksLeft, peakHistory); ! 688: *rightPeak = audio_max_peak(peaksRight, peakHistory); ! 689: } else ! 690: *leftPeak = *rightPeak = 0; ! 691: return self; ! 692: } ! 693: ! 694: /* ! 695: * Free a region. ! 696: */ ! 697: - freeRegion:(region_t *)region ! 698: { ! 699: kern_return_t krtn; ! 700: vm_task_t kernelTask = (vm_task_t)kern_serv_kernel_task_port(); ! 701: ! 702: xpr_audio_stream("OS: freeRegion: dealloc %d bytes at 0x%x from region " ! 703: "0x%x\n", region->count, region->data, region, 4,5); ! 704: krtn = vm_deallocate(kernelTask, region->data, region->count); ! 705: if (krtn != KERN_SUCCESS) ! 706: IOLog("Audio: stream vm_deallocate error %d\n", krtn); ! 707: ! 708: return [super freeRegion:region]; ! 709: } ! 710: ! 711: /* ! 712: * Overriden from superclass. ! 713: */ ! 714: - free ! 715: { ! 716: xfer_record_t *xfer_rec; ! 717: ! 718: if (peaksRight) ! 719: IOFree(peaksRight, MAX_PEAK_HISTORY*sizeof(u_int)); ! 720: if (peaksLeft) ! 721: IOFree(peaksLeft, MAX_PEAK_HISTORY*sizeof(u_int)); ! 722: ! 723: while(!queue_empty(&xferQueue)) { ! 724: queue_remove_first(&xferQueue, xfer_rec, xfer_record_t *, link); ! 725: IOFree(xfer_rec, sizeof(xfer_record_t)); ! 726: } ! 727: if (mixBuffer1) ! 728: IOFree(mixBuffer1, MIX_BUFFER1_SIZE); ! 729: if (mixBuffer2) ! 730: IOFree(mixBuffer2, MIX_BUFFER2_SIZE); ! 731: return [super free]; ! 732: } ! 733: ! 734: @end
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.