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