|
|
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.