Annotation of driverkit/libDriver/Kernel/OutputStream.m, revision 1.1

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(&regionQueue, 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, &currentPeak, peakHistory);
        !           638:         audio_add_peak(peaksRight, peak_right, &currentPeak, 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

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.