Annotation of driverkit/libDriver/Kernel/OutputStream.m, revision 1.1.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.