1 /* Unified NAS dda for Sun Sparc architecture
2
3 Copyright 1995, 1997, 1998, 2000 Charles Levert
4
5 Permission is hereby granted, free of charge, to any person obtaining
6 a copy of this software and associated documentation files (the
7 "Software"), to deal in the Software without restriction, including
8 without limitation the rights to use, copy, modify, merge, publish,
9 distribute, sublicense, and/or sell copies of the Software, and to
10 permit persons to whom the Software is furnished to do so, subject to
11 the following conditions:
12
13 The above copyright notice and this permission notice shall be included
14 in all copies or substantial portions of the Software.
15
16 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19 IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR
20 OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22 OTHER DEALINGS IN THE SOFTWARE.
23
24 Except as contained in this notice, the name of the copyright holder shall
25 not be used in advertising or otherwise to promote the sale, use or
26 other dealings in this Software without prior written authorization
27 from the copyright holder.
28
29 $Id: ausuni.c 288 2013-08-11 21:28:33Z auerswald $
30
31
32 HISTORY:
33
34 John Wehle 12/10/2000:
35 * ausuni.c: (errno.h): Include.
36 (devAudioMode): New static variable.
37 (openDevice): If open for O_RDWR fails
38 then retry open using O_WRONLY.
39 (AuInitPhysicalDevices): Likewise.
40 (writeOutput): Check devAudioMode and
41 reopen device if necessary.
42 (readPhysicalInputs): Likewise.
43
44
45
46
47 */
48
49 /**
50 *
51 * Copyright 1993 Network Computing Devices, Inc.
52 *
53 * Permission to use, copy, modify, distribute, and sell this software and its
54 * documentation for any purpose is hereby granted without fee, provided that
55 * the above copyright notice appear in all copies and that both that
56 * copyright notice and this permission notice appear in supporting
57 * documentation, and that the name Network Computing Devices, Inc. not be
58 * used in advertising or publicity pertaining to distribution of this
59 * software without specific, written prior permission.
60 *
61 * THIS SOFTWARE IS PROVIDED `AS-IS'. NETWORK COMPUTING DEVICES, INC.,
62 * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING WITHOUT
63 * LIMITATION ALL IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
64 * PARTICULAR PURPOSE, OR NONINFRINGEMENT. IN NO EVENT SHALL NETWORK
65 * COMPUTING DEVICES, INC., BE LIABLE FOR ANY DAMAGES WHATSOEVER, INCLUDING
66 * SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES, INCLUDING LOSS OF USE, DATA,
67 * OR PROFITS, EVEN IF ADVISED OF THE POSSIBILITY THEREOF, AND REGARDLESS OF
68 * WHETHER IN AN ACTION IN CONTRACT, TORT OR NEGLIGENCE, ARISING OUT OF OR IN
69 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
70 *
71 * $NCDId$
72 */
73
74 #define _AUSUN_C_ 1
75
76
77 #include <stdio.h> /* for sprintf */
78 #include <stdlib.h> /* for getenv */
79 #include <errno.h>
80 #include "misc.h"
81 #include "dixstruct.h" /* for RESTYPE */
82 #include "os.h" /* for xalloc/xfree and NULL */
83 #include "nasconf.h"
84 #include <fcntl.h>
85 #include <stropts.h>
86 #include <string.h> /* for strcmp */
87 #ifndef SVR4
88 #include <sun/audioio.h>
89 #else /* SVR4 */
90 #include <sys/audioio.h>
91 #endif /* SVR4 */
92 #include <audio/audio.h>
93 #include <audio/Aproto.h>
94 #include "au.h"
95
96 /* These constants are for SS5 and the like (SS4, ultra?) with a
97 CS4231. With SunOS 4.1.x on a SS5, make sure you have at least
98 4.1.4 + patch 102387-06. Solaris 2.5 is reported to work. Can't
99 speak for other CS4231 configurations. */
100
101 #ifndef AUDIO_INTERNAL_CD_IN
102 #define AUDIO_INTERNAL_CD_IN 0x04
103 #endif /* not defined AUDIO_INTERNAL_CD_IN */
104 #ifndef SVR4
105 #ifndef AUDIO_DEV_CS4231
106 #define AUDIO_DEV_CS4231 5
107 #endif /* not defined AUDIO_DEV_CS4231 */
108 #endif /* not defined SVR4 */
109
110 #if defined(SYSV) || defined(SVR4)
111 #define signal sigset
112 #else
113 #define BSD_SIGNALS
114 #endif
115
116 static char name_am79c30[] = "SUNW,am79c30";
117 static char name_CS4231[] = "SUNW,CS4231";
118 static char name_dbri[] = "SUNW,dbri";
119 static char name_unknown[] = "unknown audio device";
120 static char *name_of_physical_device; /* must point to one of the above */
121
122 /* pebl: on some solaris (for example sun rays) have pseudo audio devices as
123 there are used for multiply users. The pseudo device is create by 'utadem'
124 in /tmp/SUNWut/dev/utaudio/<literal>. It seems that sun uses/encourage to
125 use the env AUDIODEV to point to the pseudo devide, so it should be checked
126 before trying the default devices. If there is a pseodu device the ctl is
127 /tmp/SUNWut/dev/utaudio/<literal>ctl.
128 http://www.sun.com/desktop/products/software/sunforum/sunforumnotes.html*/
129
130 static const char *const default_device = "/dev/audio";
131
132
133 extern int errno;
134
135 #ifndef SVR4
136 typedef int audio_device_t;
137 #define IS_AMD(_t) ((_t) == AUDIO_DEV_AMD)
138 #define IS_CS4231(_t) ((_t) == AUDIO_DEV_CS4231)
139 #define IS_DBRI(_t) \
140 ((_t) == AUDIO_DEV_SPEAKERBOX || (_t) == AUDIO_DEV_CODEC)
141 #else /* defined SVR4 */
142 #define IS_AMD(_t) (!strcmp((_t).name, name_am79c30))
143 #define IS_CS4231(_t) (!strcmp((_t).name, name_CS4231))
144 #define IS_DBRI(_t) (!strcmp((_t).name, name_dbri))
145 #endif /* defined SVR4 */
146
147 /**********************************************************************/
148
149 /* Local compilation options. */
150 #define ADD_OUTPUTS
151 #undef DEBUGLOG
152 #define REVERSE_WRITE
153 #undef DELAYED_TRIGGER
154 #define WRITE_EMPTY_ENABLE
155 #undef SEPARATE_CTLS
156 #define SYNC_PROCESS_ENABLED
157
158 /**********************************************************************/
159
160 extern void AuNativeToULAW8();
161 extern void AuULAW8ToNative();
162 extern void AuProcessData();
163 static AuFixedPoint getPhysicalFeedbackGain();
164 static AuFixedPoint getPhysicalInputGain();
165 static AuUint8 getPhysicalInputMode();
166
167 /**********************************************************************/
168
169 static AuBool is_cs4231_or_dbri;
170 static AuBool relinquish_device = 0;
171 static int devAudio = -1, devAudioCtl = -1,
172 #ifdef SEPARATE_CTLS
173 devAudioCtl2 = -1,
174 #endif
175 devAudioMode = O_RDWR, bufSize;
176 static volatile AuBool signalEnabled = 0;
177 #ifdef DELAYED_TRIGGER
178 static AuBool delayedTrigger = 0;
179 #endif
180 static AuBool pendingTrigger = AuFalse;
181 static AuInt32 chunksPerSignal;
182 static volatile audio_info_t syncAudioInfo;
183 static audio_info_t audioInfo;
184 static AuUint8 *auOutputMono, *auOutputStereo, *auOutputLeft, *auOutputRight, *auInput, /* mono or stereo */
185 *emptyOutput;
186 static volatile AuBool updateSampleRate;
187 #ifdef SYNC_PROCESS_ENABLED
188 static volatile AuBool updateSyncAudioInfo;
189 #endif
190 static AuUint32 sampleRate,
191 #ifndef ADD_OUTPUTS
192 theAverage,
193 #endif
194
195
196 *leftSamples,
197 *rightSamples,
198 *monoSamples, *stereoSamples, availInputModes, availOutputModes;
199
200 extern AuInt32 auMinibufSamples;
201
202 char *VENDOR_STRING;
203 #define SUN_VENDOR "Sun unified dda (running on %s)"
204 #define SERVER_CLIENT 0
205 #define MINIBUF_SAMPLES 800
206 #define SIGNAL_RATE 10
207
208 #define auMinSampleRate 8000
209 static AuUint32 auMaxSampleRate;
210
211 #define auPhysicalOutputChangableMask \
212 (AuCompDeviceGainMask | AuCompDeviceOutputModeMask)
213
214 #define auPhysicalOutputValueMask \
215 (AuCompCommonAllMasks | \
216 AuCompDeviceMinSampleRateMask | \
217 AuCompDeviceMaxSampleRateMask | \
218 AuCompDeviceOutputModeMask | \
219 AuCompDeviceGainMask | \
220 AuCompDeviceLocationMask | \
221 AuCompDeviceChildrenMask)
222
223 #define auPhysicalInputValueMask \
224 (AuCompCommonAllMasks | \
225 AuCompDeviceMinSampleRateMask | \
226 AuCompDeviceMaxSampleRateMask | \
227 AuCompDeviceLocationMask | \
228 AuCompDeviceGainMask)
229
230 #define auPhysicalFeedbackValueMask \
231 (AuCompCommonAllMasks | \
232 AuCompDeviceGainMask)
233
234 /**********************************************************************/
235
236 /* callback */
237 static AuStatus
createServerComponents(auServerDeviceListSize,auServerBucketListSize,auServerRadioListSize,auServerMinRate,auServerMaxRate)238 createServerComponents(auServerDeviceListSize, auServerBucketListSize,
239 auServerRadioListSize, auServerMinRate,
240 auServerMaxRate)
241 AuUint32 *auServerDeviceListSize,
242 *auServerBucketListSize,
243 *auServerRadioListSize, *auServerMinRate, *auServerMaxRate;
244 {
245 AuDeviceID stereo, mono, left, right;
246 ComponentPtr d, *p;
247 AuUint8 num;
248 AuUint32 location;
249 extern RESTYPE auComponentType;
250 extern ComponentPtr *auServerDevices, /* array of devices */
251 auDevices; /* list of all devices */
252 extern AuUint32 auNumServerDevices; /* number of devices */
253
254 #ifdef DEBUGLOG
255 fprintf(stderr, "createServerComponents()\n");
256 fflush(stderr);
257 #endif
258
259 *auServerMinRate = auMinSampleRate;
260 *auServerMaxRate = auMaxSampleRate;
261
262 auNumServerDevices
263 = *auServerDeviceListSize
264 = *auServerBucketListSize = *auServerRadioListSize = 0;
265
266 if (is_cs4231_or_dbri) {
267 AU_ALLOC_DEVICE(d, 1, 0);
268 d->id = left = FakeClientID(SERVER_CLIENT);
269 d->changableMask = auPhysicalOutputChangableMask;
270 d->valueMask = auPhysicalOutputValueMask;
271 d->kind = AuComponentKindPhysicalOutput;
272 d->use = AuComponentUseExportMask;
273 d->access = AuAccessExportMask | AuAccessListMask;
274 d->format = auNativeFormat;
275 d->numTracks = 1;
276 d->description.type = AuStringLatin1;
277 d->description.string = "Left Channel Output";
278 d->description.len = strlen(d->description.string);
279 d->minSampleRate = auMinSampleRate;
280 d->maxSampleRate = auMaxSampleRate;
281 d->location = AuDeviceLocationLeftMask;
282 d->numChildren = 0;
283 d->minibuf = auOutputLeft;
284 d->minibufSize = auMinibufSamples * auNativeBytesPerSample *
285 d->numTracks;
286 d->physicalDeviceMask = PhysicalOutputLeft;
287 leftSamples = &d->minibufSamples;
288 AU_ADD_DEVICE(d);
289
290 AU_ALLOC_DEVICE(d, 1, 0);
291 d->id = right = FakeClientID(SERVER_CLIENT);
292 d->changableMask = auPhysicalOutputChangableMask;
293 d->valueMask = auPhysicalOutputValueMask;
294 d->kind = AuComponentKindPhysicalOutput;
295 d->use = AuComponentUseExportMask;
296 d->access = AuAccessExportMask | AuAccessListMask;
297 d->format = auNativeFormat;
298 d->numTracks = 1;
299 d->description.type = AuStringLatin1;
300 d->description.string = "Right Channel Output";
301 d->description.len = strlen(d->description.string);
302 d->minSampleRate = auMinSampleRate;
303 d->maxSampleRate = auMaxSampleRate;
304 d->location = AuDeviceLocationRightMask;
305 d->numChildren = 0;
306 d->minibuf = auOutputRight;
307 d->minibufSize = auMinibufSamples * auNativeBytesPerSample *
308 d->numTracks;
309 d->physicalDeviceMask = PhysicalOutputRight;
310 rightSamples = &d->minibufSamples;
311 AU_ADD_DEVICE(d);
312 }
313
314 if (is_cs4231_or_dbri) {
315 num = 2;
316 location = AuDeviceLocationLeftMask | AuDeviceLocationRightMask;
317 } else {
318 num = 0;
319 location = AuDeviceLocationCenterMask |
320 AuDeviceLocationInternalMask;
321 }
322 AU_ALLOC_DEVICE(d, 1, num);
323 d->id = mono = FakeClientID(SERVER_CLIENT);
324 d->changableMask = auPhysicalOutputChangableMask;
325 d->valueMask = auPhysicalOutputValueMask;
326 d->kind = AuComponentKindPhysicalOutput;
327 d->use = AuComponentUseExportMask;
328 d->access = AuAccessExportMask | AuAccessListMask;
329 d->format = auNativeFormat;
330 d->numTracks = 1;
331 d->description.type = AuStringLatin1;
332 d->description.string = "Mono Channel Output";
333 d->description.len = strlen(d->description.string);
334 d->minSampleRate = auMinSampleRate;
335 d->maxSampleRate = auMaxSampleRate;
336 d->location = location;
337 d->numChildren = num;
338 if (is_cs4231_or_dbri) {
339 d->children = (AuID *) ((AuUint8 *) d +
340 PAD4(sizeof(ComponentRec)));
341 d->childSwap = (char *) (d->children + d->numChildren);
342 d->children[0] = left;
343 d->children[1] = right;
344 }
345 d->minibuf = auOutputMono;
346 d->minibufSize = auMinibufSamples * auNativeBytesPerSample *
347 d->numTracks;
348 d->physicalDeviceMask = PhysicalOutputMono;
349 monoSamples = &d->minibufSamples;
350 AU_ADD_DEVICE(d);
351
352 num = is_cs4231_or_dbri ? 2 : 1;
353 AU_ALLOC_DEVICE(d, 2, num);
354 d->id = stereo = FakeClientID(SERVER_CLIENT);
355 d->changableMask = auPhysicalOutputChangableMask;
356 d->valueMask = auPhysicalOutputValueMask;
357 d->kind = AuComponentKindPhysicalOutput;
358 d->use = AuComponentUseExportMask;
359 d->access = AuAccessExportMask | AuAccessListMask;
360 d->format = auNativeFormat;
361 d->numTracks = 2;
362 d->description.type = AuStringLatin1;
363 d->description.string = "Stereo Channel Output";
364 d->description.len = strlen(d->description.string);
365 d->minSampleRate = auMinSampleRate;
366 d->maxSampleRate = auMaxSampleRate;
367 d->location = location;
368 d->numChildren = num;
369 d->children = (AuID *) ((AuUint8 *) d + PAD4(sizeof(ComponentRec)));
370 d->childSwap = (char *) (d->children + num);
371 if (is_cs4231_or_dbri) {
372 d->children[0] = left;
373 d->children[1] = right;
374 } else
375 d->children[0] = mono;
376 d->minibuf = auOutputStereo;
377 d->minibufSize = auMinibufSamples * auNativeBytesPerSample *
378 d->numTracks;
379 d->physicalDeviceMask = PhysicalOutputStereo;
380 stereoSamples = &d->minibufSamples;
381 AU_ADD_DEVICE(d);
382
383 /* same value; don't recompute */
384 /* num = is_cs4231_or_dbri ? 2 : 1; */
385 AU_ALLOC_DEVICE(d, num, 0);
386 d->id = FakeClientID(SERVER_CLIENT);
387 d->changableMask = AuCompDeviceGainMask;
388 d->valueMask = auPhysicalFeedbackValueMask;
389 d->kind = AuComponentKindPhysicalFeedback;
390 d->use = 0;
391 d->access = AuAccessListMask;
392 d->format = 0;
393 d->numTracks = num;
394 d->description.type = AuStringLatin1;
395 d->description.string = "Feedback";
396 d->description.len = strlen(d->description.string);
397 d->numChildren = 0;
398 d->gain = getPhysicalFeedbackGain();
399 d->lineMode = AuDeviceLineModeNone;
400 d->physicalDeviceMask = (is_cs4231_or_dbri
401 ? PhysicalFeedbackStereo
402 : PhysicalFeedbackMono);
403 d->minibuf = NULL;
404 d->minibufSize = 0;
405 AU_ADD_DEVICE(d);
406
407 /* same value; don't recompute */
408 /* num = is_cs4231_or_dbri ? 2 : 1; */
409 AU_ALLOC_DEVICE(d, num, 0);
410 d->id = FakeClientID(SERVER_CLIENT);
411 if (is_cs4231_or_dbri) {
412 d->changableMask = (AuCompDeviceGainMask |
413 AuCompDeviceLineModeMask);
414 d->valueMask = (auPhysicalInputValueMask |
415 AuCompDeviceLineModeMask);
416 } else {
417 d->changableMask = AuCompDeviceGainMask;
418 d->valueMask = auPhysicalInputValueMask;
419 }
420 d->kind = AuComponentKindPhysicalInput;
421 d->use = AuComponentUseImportMask;
422 d->access = AuAccessImportMask | AuAccessListMask;
423 d->format = auNativeFormat;
424 d->numTracks = num;
425 d->description.type = AuStringLatin1;
426 d->description.string = (is_cs4231_or_dbri
427 ? "Stereo Channel Input"
428 : "Mono Channel Input");
429 d->description.len = strlen(d->description.string);
430 d->minSampleRate = auMinSampleRate;
431 d->maxSampleRate = auMaxSampleRate;
432 /* External on most machines now */
433 d->location = (AuDeviceLocationRightMask | AuDeviceLocationLeftMask |
434 AuDeviceLocationExternalMask);
435 d->numChildren = 0;
436 d->gain = getPhysicalInputGain();
437 d->lineMode = getPhysicalInputMode();
438 d->minibuf = auInput;
439 d->minibufSize = auMinibufSamples * auNativeBytesPerSample *
440 d->numTracks;
441 d->physicalDeviceMask = (is_cs4231_or_dbri
442 ? PhysicalInputStereo : PhysicalInputMono);
443 AU_ADD_DEVICE(d);
444
445 /* set the array of server devices */
446 if (!(auServerDevices =
447 (ComponentPtr *) aualloc(sizeof(ComponentPtr) *
448 auNumServerDevices)))
449 return AuBadAlloc;
450
451 p = auServerDevices;
452 for (d = auDevices; d; d = d->next)
453 *p++ = d;
454
455 return AuSuccess;
456 }
457
458 static AuBool
openDevice(wait)459 openDevice(wait)
460 AuBool wait;
461 {
462 audio_info_t info;
463 const char *device = NULL;
464
465 /* pebl: Check whether a pseudo device is used, else try the normal ones */
466 if ((device = getenv("AUDIODEV")) == NULL)
467 device = default_device;
468
469
470 if (devAudio == -1)
471 while ((devAudio = open(device, devAudioMode)) == -1 && wait) {
472 if (errno == EINVAL && devAudioMode == O_RDWR)
473 devAudioMode = O_WRONLY;
474 sleep(5);
475 }
476
477 if (devAudio != -1) {
478 if (is_cs4231_or_dbri) {
479 audioInfo.play.sample_rate
480 = audioInfo.record.sample_rate = sampleRate;
481 aucopy(&audioInfo, &info, sizeof(audio_info_t));
482 ioctl(devAudio, AUDIO_SETINFO, &info);
483 }
484
485 return AuTrue;
486 }
487
488 return AuFalse;
489 }
490
491 static void
closeDevice()492 closeDevice()
493 {
494 if (devAudio != -1) {
495 close(devAudio);
496 devAudio = -1;
497 }
498 }
499
500 /* cleanup function at server reset */
501 static void
serverReset()502 serverReset()
503 {
504 #ifdef DEBUGLOG
505 fprintf(stderr, "serverReset()\n");
506 fflush(stderr);
507 #endif
508
509 if (!relinquish_device || openDevice(AuFalse)) {
510 signal(SIGPOLL, SIG_IGN); /* discard pending signals */
511 ioctl(devAudio, AUDIO_DRAIN, 0); /* drain everything out */
512 if (relinquish_device)
513 closeDevice();
514 }
515 }
516
517 static void
updateHardware()518 updateHardware()
519 {
520 /* We don't delay updating anything that can be changed via
521 audioCtl, possibly by some other application, anymore.
522 Those values aren't cached in static variables either.
523 This way, we can control the audio device through the
524 server for immediate feedback only operations, which don't
525 involve software manipulated audio data, without resorting
526 to a non-NAS application. */
527
528 if (updateSampleRate
529 #ifdef SYNC_PROCESS_ENABLED
530 || updateSyncAudioInfo
531 #endif
532 ) {
533 audio_info_t info;
534
535 ioctl(devAudioCtl, I_SETSIG, 0); /* disable signal */
536
537 #ifdef SYNC_PROCESS_ENABLED
538 if (updateSyncAudioInfo) {
539 ioctl(devAudioCtl, AUDIO_SETINFO, &syncAudioInfo);
540 AUDIO_INITINFO(&syncAudioInfo);
541 updateSyncAudioInfo = AuFalse;
542 }
543
544 if (updateSampleRate) {
545 #endif
546 AUDIO_INITINFO(&info);
547 info.play.sample_rate = info.record.sample_rate = sampleRate;
548 ioctl(devAudio, AUDIO_SETINFO, &info);
549 updateSampleRate = AuFalse;
550 #ifdef SYNC_PROCESS_ENABLED
551 }
552 #endif
553
554 if (signalEnabled)
555 ioctl(devAudioCtl, I_SETSIG, S_MSG);
556 }
557 }
558
559 static void
setAudioCtlInfo()560 setAudioCtlInfo()
561 {
562 #ifndef SEPARATE_CTLS
563 #ifdef SYNC_PROCESS_ENABLED
564 if (signalEnabled)
565 updateSyncAudioInfo = AuTrue;
566 else {
567 #endif
568 ioctl(devAudioCtl, I_SETSIG, 0);
569 ioctl(devAudioCtl, AUDIO_SETINFO, &syncAudioInfo);
570 AUDIO_INITINFO(&syncAudioInfo);
571 if (signalEnabled)
572 ioctl(devAudioCtl, I_SETSIG, S_MSG);
573 #ifdef SYNC_PROCESS_ENABLED
574 }
575 #endif
576 #else
577 ioctl(devAudioCtl2, AUDIO_SETINFO, infoPtr);
578 #endif
579 }
580
581 /**
582 * Gains are mapped thusly:
583 *
584 * Software 0 - 49 50 - 100
585 * Hardware 0 - 49 50 - 255
586 */
587 /* g in FixedPoint */
588 #define gain100togain255(g) (((g) < 0x320000) \
589 ? ((g) >> 16) \
590 : ((0x41999 * ((g) >> 9) - 0x4d77f100) >> 23))
591 /* (g - 50) * (205 / 50) + 50 */
592 #define gain255togain100(g) (((g) < 50) \
593 ? AuFixedPointFromSum((g), 0) \
594 : ((((g) * 0x3e7064) >> 8) + 0x25ce0d))
595 /* (g - 50) * (50 / 205) + 50 */
596
597
598 #ifdef SYNC_PROCESS_ENABLED
599 /* We assume that AUDIO_INITINFO uses ~0 as a filler. This is
600 because clients like aupanel do a get right after a set. It's
601 not a good thing to waste CPU like that, but it should not
602 happen that often (usually in response to user action). */
603
604 #define getCtl(info, field) \
605 do { \
606 while (~syncAudioInfo.field) /* */ ; \
607 ioctl(devAudioCtl, AUDIO_GETINFO, &(info)); \
608 } while (0)
609 #else
610 #define getCtl(info, field) \
611 ioctl(devAudioCtl, AUDIO_GETINFO, &(info))
612 #endif
613
614 /* callback */
615 static AuFixedPoint
getPhysicalOutputGain()616 getPhysicalOutputGain()
617 {
618 audio_info_t info;
619
620 #ifdef DEBUGLOG
621 fprintf(stderr, "getPhysicalOutputGain()\n");
622 fflush(stderr);
623 #endif
624
625 getCtl(info, play.gain);
626
627 return gain255togain100(info.play.gain);
628 }
629
630 /* callback */
631 static void
setPhysicalOutputGain(gain)632 setPhysicalOutputGain(gain)
633 AuFixedPoint gain;
634 {
635 #ifdef DEBUGLOG
636 fprintf(stderr, "setPhysicalOutputGain(gain=%08d)\n", gain);
637 fflush(stderr);
638 #endif
639
640 syncAudioInfo.play.gain = gain100togain255(gain);
641 setAudioCtlInfo();
642 }
643
644 /* callback */
645 static AuFixedPoint
getPhysicalFeedbackGain()646 getPhysicalFeedbackGain()
647 {
648 audio_info_t info;
649
650 #ifdef DEBUGLOG
651 fprintf(stderr, "getPhysicalFeedbackGain()\n");
652 fflush(stderr);
653 #endif
654
655 getCtl(info, monitor_gain);
656
657 return gain255togain100(info.monitor_gain);
658 }
659
660 /* callback */
661 static void
setPhysicalFeedbackGain(gain)662 setPhysicalFeedbackGain(gain)
663 AuFixedPoint gain;
664 {
665 #ifdef DEBUGLOG
666 fprintf(stderr, "setPhysicalFeedbackGain(gain=%08d)\n", gain);
667 fflush(stderr);
668 #endif
669
670 syncAudioInfo.monitor_gain = gain100togain255(gain);
671 setAudioCtlInfo();
672 }
673
674 /* callback */
675 static AuUint8
getPhysicalOutputMode()676 getPhysicalOutputMode()
677 {
678 AuUint8 mode = 0;
679 audio_info_t info;
680
681 #ifdef DEBUGLOG
682 fprintf(stderr, "getPhysicalOutputMode()\n");
683 fflush(stderr);
684 #endif
685
686 getCtl(info, play.port);
687
688 if (info.play.port & AUDIO_HEADPHONE)
689 mode |= AuDeviceOutputModeHeadphone;
690
691 if (info.play.port & AUDIO_SPEAKER)
692 mode |= AuDeviceOutputModeSpeaker;
693
694 if (info.play.port & AUDIO_LINE_OUT)
695 mode |= AuDeviceOutputModeLineOut;
696
697 return mode;
698 }
699
700 /* callback */
701 static void
setPhysicalOutputMode(lineMode)702 setPhysicalOutputMode(lineMode)
703 AuUint8 lineMode;
704 {
705 #ifdef DEBUGLOG
706 fprintf(stderr, "setPhysicalOutputMode(=%d)\n", lineMode);
707 fflush(stderr);
708 #endif
709
710 if (name_of_physical_device == name_am79c30) {
711 /* Must implement some kind of a toggle in this case.
712 (One and only one behavior.) */
713
714 /* We absolutely must do this before changing
715 syncAudioInfo. */
716 AuUint8 oldLineMode = getPhysicalOutputMode();
717
718 if (lineMode & ~oldLineMode)
719 lineMode &= ~oldLineMode;
720 }
721 #ifdef SYNC_PROCESS_ENABLED
722 {
723 AuBlock l = AuBlockAudio();
724 #endif
725
726 /* A final value of zero is allowed for output (play). */
727 /* Any number of bits can be set. */
728 syncAudioInfo.play.port = 0;
729
730 if (lineMode & AuDeviceOutputModeHeadphone)
731 syncAudioInfo.play.port |= AUDIO_HEADPHONE;
732
733 if (lineMode & AuDeviceOutputModeSpeaker)
734 syncAudioInfo.play.port |= AUDIO_SPEAKER;
735
736 if (lineMode & AuDeviceOutputModeLineOut)
737 syncAudioInfo.play.port |= AUDIO_LINE_OUT;
738
739 syncAudioInfo.play.port &= availOutputModes;
740
741 #ifdef SYNC_PROCESS_ENABLED
742 AuUnBlockAudio(l);
743 }
744 #endif
745
746 setAudioCtlInfo();
747 }
748
749 /* callback */
750 static AuFixedPoint
getPhysicalInputGain()751 getPhysicalInputGain()
752 {
753 audio_info_t info;
754 unsigned int g;
755
756 #ifdef DEBUGLOG
757 fprintf(stderr, "getPhysicalInputGain()\n");
758 fflush(stderr);
759 #endif
760
761 getCtl(info, record.gain);
762 g = info.record.gain;
763
764 /* This little hack helps get/map/round up/map/set stability.
765 Don't ask. */
766 if (is_cs4231_or_dbri && (g >= 50) && (g < 255))
767 g -= 5;
768
769 return gain255togain100(g);
770 }
771
772 /* callback */
773 static AuUint8
getPhysicalInputMode()774 getPhysicalInputMode()
775 {
776 AuUint8 mode = 0;
777 audio_info_t info;
778
779 #ifdef DEBUGLOG
780 fprintf(stderr, "getPhysicalInputMode()\n");
781 fflush(stderr);
782 #endif
783
784 getCtl(info, record.port);
785
786 if (info.record.port & AUDIO_MICROPHONE)
787 mode |= AuDeviceLineModeHigh;
788
789 if (info.record.port & AUDIO_LINE_IN)
790 mode |= AuDeviceLineModeLow;
791
792 #ifdef UNCOMMENT_THIS_WHEN_NAS_SUPPORTS_IT
793 if (info.record.port & AUDIO_INTERNAL_CD_IN)
794 mode |= AuDeviceLineModeInternalCD;
795 #endif
796
797 return mode;
798 }
799
800 /* callback */
801 static void
setPhysicalInputGainAndLineMode(gain,lineMode)802 setPhysicalInputGainAndLineMode(gain, lineMode)
803 AuFixedPoint gain;
804 AuUint8 lineMode;
805 {
806 AuUint32 newInputLineMode;
807
808 #ifdef DEBUGLOG
809 fprintf(stderr,
810 "setPhysicalInputGainAndLineMode(gain=%04x.%04x, lineMode=%u)\n",
811 gain >> 16, gain & 0xffff, lineMode);
812 fflush(stderr);
813 #endif
814
815 syncAudioInfo.record.gain = gain100togain255(gain);
816
817 /* one and only one bit must be set */
818 if (lineMode == AuDeviceLineModeHigh)
819 newInputLineMode = AUDIO_MICROPHONE;
820 else if (lineMode == AuDeviceLineModeLow)
821 newInputLineMode = AUDIO_LINE_IN;
822 #ifdef UNCOMMENT_THIS_WHEN_NAS_SUPPORTS_IT
823 else if (lineMode == AuDeviceLineModeInternalCD)
824 newInputLineMode = AUDIO_INTERNAL_CD_IN;
825 #endif
826 else
827 newInputLineMode = 0;
828
829 #if 0
830 /* A value of zero is rejected by some drivers, so don't even try it. */
831 /* XXX - Really? Doesn't matter since zero does not even get here! */
832 if (newInputLineMode &= availInputModes)
833 #endif
834 syncAudioInfo.record.port = newInputLineMode;
835
836 setAudioCtlInfo();
837 }
838
839 /* A zero-length write() triggers a SIGPOLL. */
840 #define trigger() \
841 write(devAudio, emptyOutput, 0)
842 #define triggerIfPending() \
843 do { \
844 if (pendingTrigger) { \
845 trigger(); \
846 pendingTrigger = AuFalse; \
847 } \
848 } while (0)
849 #ifdef REVERSE_WRITE
850 #define write0(buf, n) \
851 do { triggerIfPending(); write(devAudio, buf, n); } while (0)
852 #else
853 #ifndef DELAYED_TRIGGER
854 #define write0(buf, n) \
855 do { write(devAudio, buf, n); triggerIfPending(); } while (0)
856 #else
857 #define write0(buf, n) \
858 do { write(devAudio, buf, n); delayedTrigger = AuTrue; } while (0)
859 #endif
860 #endif
861
862 /* Warning: this function must be called between Au{Block,UnBlock}Audio,
863 * which is already the case in a BSD signal handler. */
864 static void
writeEmptyOutput()865 writeEmptyOutput()
866 {
867 #ifndef BSD_SIGNALS
868 AuBlock l = AuBlockAudio();
869 #endif
870
871 #ifdef DEBUGLOG
872 fprintf(stderr, "writeEmptyOutput(bufSize=%d)\n", bufSize);
873 fflush(stderr);
874 #endif
875
876 write0(emptyOutput, bufSize);
877
878 #ifndef BSD_SIGNALS
879 AuUnBlockAudio(l);
880 #endif
881 }
882
883 /* callback */
884 static void
enableProcessFlow()885 enableProcessFlow()
886 {
887 AuBlock l;
888
889 #ifdef DEBUGLOG
890 fprintf(stderr, "\nenableProcessFlow()\n");
891 fflush(stderr);
892 #endif
893
894 if (relinquish_device)
895 openDevice(AuTrue);
896 ioctl(devAudio, I_FLUSH, FLUSHRW); /* flush pending io */
897 signalEnabled = AuTrue;
898 ioctl(devAudioCtl, I_SETSIG, S_MSG); /* enable signal */
899 updateHardware();
900 /* XXX - Shouldn't this be done only one time when audioctl is
901 opened? */
902 l = AuBlockAudio();
903 #if defined(REVERSE_WRITE) && defined(WRITE_EMPTY_ENABLE)
904 pendingTrigger = AuTrue;
905 writeEmptyOutput();
906 #else
907 #ifdef WRITE_EMPTY_ENABLE
908 write(devAudio, emptyOutput,
909 getenv("NAS_EMPTY_SIZE") ? atoi(getenv("NAS_EMPTY_SIZE")) :
910 bufSize);
911 #endif
912 trigger(); /* a SIGPOLL. */
913 #endif
914 AuUnBlockAudio(l);
915 }
916
917 /* callback */
918 static void
disableProcessFlow()919 disableProcessFlow()
920 {
921 #ifdef DEBUGLOG
922 fprintf(stderr, "disableProcessFlow()\n");
923 fflush(stderr);
924 #endif
925
926 signalEnabled = AuFalse;
927 ioctl(devAudioCtl, I_SETSIG, 0); /* disable signal */
928
929 #if 0 /* this seems to cause problems on some
930 sun kernels/sound drivers */
931 ioctl(devAudio, AUDIO_DRAIN, 0); /* drain everything out */
932 #endif
933
934 if (relinquish_device)
935 closeDevice();
936 }
937
938 /* for CS4231 and dbri */
939 /* Warning: this function must be called between Au{Block,UnBlock}Audio,
940 * which is already the case in a BSD signal handler. */
941 static void
writeOutput(p,n)942 writeOutput(p, n)
943 AuInt16 *p;
944 unsigned int n;
945 {
946 #ifndef BSD_SIGNALS
947 AuBlock l = AuBlockAudio();
948 #endif
949
950 #ifdef DEBUGLOG
951 fprintf(stderr, "writeOutput(n=%d, n*4=%d)\n", n, n << 2);
952 fflush(stderr);
953 #endif
954
955 /*
956 * The sbpro can only be opened for reading or for writing, not both.
957 */
958
959 if (!(devAudioMode == O_RDWR || devAudioMode == O_WRONLY)) {
960 closeDevice();
961 devAudioMode = O_WRONLY;
962 openDevice(1);
963 }
964
965
966 write0(p, n << 2);
967
968 #ifndef BSD_SIGNALS
969 AuUnBlockAudio(l);
970 #endif
971 }
972
973 /* for am79c30 */
974 /* Warning: this function must be called between Au{Block,UnBlock}Audio,
975 * which is already the case in a BSD signal handler. */
976 static void
writePhysicalOutput(p,n)977 writePhysicalOutput(p, n)
978 AuInt16 *p;
979 unsigned int n;
980 {
981 #ifndef BSD_SIGNALS
982 AuBlock l;
983 #endif
984
985 #ifdef DEBUGLOG
986 fprintf(stderr, "writePhysicalOutput(n=%d)\n", n);
987 fflush(stderr);
988 #endif
989
990 AuNativeToULAW8(p, 1, n);
991 #ifndef BSD_SIGNALS
992 l = AuBlockAudio();
993 #endif
994
995 write0(p, n);
996
997 #ifndef BSD_SIGNALS
998 AuUnBlockAudio(l);
999 #endif
1000 }
1001
1002 /* for CS4231 and dbri */
1003 static void
writeStereoOutput()1004 writeStereoOutput()
1005 {
1006 writeOutput(auOutputStereo, *stereoSamples);
1007 }
1008
1009 /* for am79c30 */
1010 static void
writePhysicalOutputsStereo()1011 writePhysicalOutputsStereo()
1012 {
1013 AuInt32 i;
1014 AuInt16 *s, *m;
1015
1016 s = (AuInt16 *) auOutputStereo;
1017 m = (AuInt16 *) auOutputMono;
1018
1019 for (i = 0; i < *stereoSamples; i++, s += 2)
1020 *m++ = (s[0] + s[1]) >> 1;
1021
1022 writePhysicalOutput(auOutputMono, *stereoSamples);
1023 }
1024
1025 /* for CS4231 and dbri */
1026 static void
writeMonoOutput()1027 writeMonoOutput()
1028 {
1029 AuInt16 *m, *p;
1030 int i;
1031
1032 m = (AuInt16 *) auOutputMono;
1033 p = (AuInt16 *) auOutputStereo;
1034
1035 for (i = 0; i < *monoSamples; i++) {
1036 *p++ = *m;
1037 *p++ = *m++;
1038 }
1039
1040 writeOutput(auOutputStereo, *monoSamples);
1041 }
1042
1043 /* for am79c30 */
1044 static void
writePhysicalOutputsMono()1045 writePhysicalOutputsMono()
1046 {
1047 writePhysicalOutput(auOutputMono, *monoSamples);
1048 }
1049
1050 /* for CS4231 and dbri */
1051 static void
writeAllOutputs()1052 writeAllOutputs()
1053 {
1054 AuInt16 *l, *r, *m, *s, *p;
1055 int i;
1056 unsigned int n;
1057
1058 l = (AuInt16 *) auOutputLeft;
1059 r = (AuInt16 *) auOutputRight;
1060 m = (AuInt16 *) auOutputMono;
1061 s = p = (AuInt16 *) auOutputStereo;
1062 n = aumax(aumax(*monoSamples, *stereoSamples),
1063 aumax(*leftSamples, *rightSamples));
1064
1065 /* XXX - This assumes that any non participating flow has null value;
1066 true? */
1067 for (i = 0; i < n; i++) {
1068 #ifndef ADD_OUTPUTS
1069 *p++ = ((*l++ + *m + *s++) * theAverage) >> 16;
1070 *p++ = ((*r++ + *m++ + *s++) * theAverage) >> 16;
1071 #else
1072 *p++ = (*l++ + *m + *s++);
1073 *p++ = (*r++ + *m++ + *s++);
1074 #endif
1075 }
1076
1077 writeOutput(auOutputStereo, n);
1078 }
1079
1080 /* for am79c30 */
1081 static void
writePhysicalOutputsBoth()1082 writePhysicalOutputsBoth()
1083 {
1084 AuInt32 i;
1085 AuInt16 *s, *m;
1086 AuUint32 n;
1087
1088 s = (AuInt16 *) auOutputStereo;
1089 m = (AuInt16 *) auOutputMono;
1090 n = aumax(*monoSamples, *stereoSamples);
1091
1092 #ifndef ADD_OUTPUTS
1093 for (i = 0; i < n; i++, s += 2, m++)
1094 /* XXX - That's not right, conceptually. */
1095 /* beware: can't put m++ on this line because of
1096 unknown order of eval */
1097 *m = ((s[0] + s[1] + *m) * 0x5555) >> 16;
1098 #else
1099 for (i = 0; i < n; i++, s += 2)
1100 *m++ += (s[0] + s[1]) >> 1;
1101 #endif
1102
1103 writeOutput(auOutputMono, n);
1104 }
1105
1106 /* callback */
1107 static void
readPhysicalInputs()1108 readPhysicalInputs()
1109 {
1110 #ifdef DEBUGLOG
1111 fprintf(stderr, "readPhysicalInputs()\n");
1112 fflush(stderr);
1113 #endif
1114
1115
1116 /*
1117 * The sbpro can only be opened for reading or for writing, not both.
1118 */
1119
1120 if (!(devAudioMode == O_RDWR || devAudioMode == O_RDONLY)) {
1121 closeDevice();
1122 devAudioMode = O_RDONLY;
1123 openDevice(1);
1124 }
1125
1126 read(devAudio, auInput, bufSize);
1127
1128 if (!is_cs4231_or_dbri)
1129 AuULAW8ToNative(auInput, 1, auMinibufSamples);
1130 }
1131
1132 /* callback */
1133 /* for am79c30 */
1134 static void
setWritePhysicalOutputFunction(flow,funct)1135 setWritePhysicalOutputFunction(flow, funct)
1136 CompiledFlowPtr flow;
1137 void (**funct) ();
1138 {
1139 AuUint32 mask = flow->physicalDeviceMask;
1140
1141 #ifdef DEBUGLOG
1142 fprintf(stderr, "setWritePhysicalOutputFunction()\n");
1143 fflush(stderr);
1144 #endif
1145
1146 if ((mask & (PhysicalOutputMono | PhysicalOutputStereo)) ==
1147 (PhysicalOutputMono | PhysicalOutputStereo))
1148 *funct = writePhysicalOutputsBoth;
1149 else if (mask & PhysicalOutputMono)
1150 *funct = writePhysicalOutputsMono;
1151 else if (mask & PhysicalOutputStereo)
1152 *funct = writePhysicalOutputsStereo;
1153 else
1154 *funct = writeEmptyOutput;
1155 }
1156
1157 /* callback */
1158 /* for CS4231 and dbri */
1159 static void
setWriteOutputFunction(flow,funct)1160 setWriteOutputFunction(flow, funct)
1161 CompiledFlowPtr flow;
1162 void (**funct) ();
1163 {
1164 AuUint32 mask = flow->physicalDeviceMask & AllPhysicalOutputs;
1165
1166 #ifdef DEBUGLOG
1167 fprintf(stderr, "setWriteOutputFunction()\n");
1168 fflush(stderr);
1169 #endif
1170
1171 if (mask)
1172 if (mask == PhysicalOutputMono)
1173 *funct = writeMonoOutput;
1174 else if (mask == PhysicalOutputStereo)
1175 *funct = writeStereoOutput;
1176 else {
1177 #ifndef ADD_OUTPUTS
1178 int both;
1179
1180 theAverage = 0x10000;
1181
1182 both = (mask & (PhysicalOutputLeft |
1183 PhysicalOutputRight)) ? 1 : 0;
1184
1185 if (mask & PhysicalOutputMono)
1186 both++;
1187
1188 if (mask & PhysicalOutputStereo)
1189 both++;
1190
1191 if (both > 1)
1192 theAverage /= both;
1193 #endif
1194
1195 *funct = writeAllOutputs;
1196 } else
1197 *funct = writeEmptyOutput;
1198 }
1199
1200 /* signal handler */
1201 #ifdef DEBUGLOG
1202 #include <sys/time.h>
1203 #endif
1204 static void
processAudioSignal(sig)1205 processAudioSignal(sig)
1206 int sig;
1207 {
1208 int i;
1209 #ifdef DEBUGLOG
1210 static struct timeval tv0;
1211 struct timeval tv1, tv2, tv3;
1212 long ds1, du1, ds2, du2, ds3, du3;
1213
1214 fprintf(stderr, "processAudioSignal...\n");
1215 fflush(stderr);
1216
1217 gettimeofday(&tv1, 0);
1218 #endif /* DEBUGLOG */
1219
1220 updateHardware();
1221
1222 #ifdef DEBUGLOG
1223 gettimeofday(&tv2, 0);
1224 #endif /* DEBUGLOG */
1225
1226 pendingTrigger = AuFalse;
1227 for (i = 0; i < chunksPerSignal - 1; i++)
1228 AuProcessData();
1229
1230 pendingTrigger = AuTrue;
1231 AuProcessData();
1232
1233 #if defined(DELAYED_TRIGGER) && !defined(REVERSE_WRITE)
1234 if (delayedTrigger) {
1235 /* Here's the very reason delaying this is useful.
1236 Don't do it if AuProcessData() called
1237 disableProcessFlow() between the write and now. */
1238 if (signalEnabled)
1239 trigger(); /* a SIGPOLL. */
1240
1241 delayedTrigger = AuFalse;
1242 }
1243 #endif /* DELAYED_TRIGGER && !REVERSE_WRITE */
1244
1245 #ifdef DEBUGLOG
1246 gettimeofday(&tv3, 0);
1247
1248 #define tv_diff(tv_a, tv_b, ds, du) \
1249 do { \
1250 ds = tv_a.tv_sec - tv_b.tv_sec; \
1251 du = tv_a.tv_usec - tv_b.tv_usec; \
1252 if (du < 0) { \
1253 --ds; \
1254 du += 1000000L; \
1255 } \
1256 } while (0)
1257
1258 tv_diff(tv1, tv0, ds1, du1);
1259 tv_diff(tv2, tv1, ds2, du2);
1260 tv_diff(tv3, tv2, ds3, du3);
1261
1262 #undef tv_diff
1263
1264 tv0 = tv1;
1265
1266 fprintf(stderr,
1267 "...processAudioSignal [%ld.%06ld %ld.%06ld %ld.%06ld]\n",
1268 ds1, du1, ds2, du2, ds3, du3);
1269 fflush(stderr);
1270 #endif /* DEBUGLOG */
1271 }
1272
1273 /* callback */
1274 /* for CS4231 and dbri */
1275 static AuUint32
setSampleRate(rate)1276 setSampleRate(rate)
1277 AuUint32 rate;
1278 {
1279 int i;
1280 AuUint32 closestRate;
1281 static AuUint32 rates[] = {
1282 /* 5510, 6620, */
1283 8000, 9600, 11025, 16000, 18900, 22050,
1284 /* 27420, */
1285 32000,
1286 /* 33075, */
1287 37800, 44100, 48000
1288 };
1289
1290 closestRate = 48000;
1291
1292 for (i = 0; i < sizeof(rates) / sizeof(rates[0]); i++)
1293 if ((rates[i] >= rate) && (rates[i] < closestRate))
1294 closestRate = rates[i];
1295
1296 if (closestRate != sampleRate) {
1297 sampleRate = closestRate;
1298 updateSampleRate = AuTrue;
1299 }
1300
1301 chunksPerSignal = sampleRate / SIGNAL_RATE / MINIBUF_SAMPLES;
1302
1303 #ifdef DEBUGLOG
1304 fprintf(stderr, "setSampleRate(rate=%d) --> %d\n", rate, closestRate);
1305 fflush(stderr);
1306 #endif
1307
1308 return closestRate;
1309 }
1310
1311 #define PhysicalOneTrackBufferSize \
1312 PAD4(auMinibufSamples * auNativeBytesPerSample * 1)
1313 #define PhysicalTwoTrackBufferSize \
1314 PAD4(auMinibufSamples * auNativeBytesPerSample * 2)
1315
1316 AuBool
AuInitPhysicalDevices()1317 AuInitPhysicalDevices()
1318 {
1319 int open_for_business;
1320 static AuUint8 *physicalBuffers;
1321 AuUint32 physicalBuffersSize;
1322 audio_info_t info;
1323 extern AuUint32 auPhysicalOutputBuffersSize;
1324 extern AuUint8 *auPhysicalOutputBuffers;
1325 char *nas_device_policy;
1326
1327 #ifdef DEBUGLOG
1328 fprintf(stderr, "AuInitPhysicalDevices()\n");
1329 fflush(stderr);
1330 #endif
1331
1332 if (VENDOR_STRING) {
1333 aufree(VENDOR_STRING);
1334 VENDOR_STRING = (char *) 0;
1335 }
1336
1337 if (NasConfig.DoDeviceRelease) {
1338 relinquish_device = AuTrue;
1339 if (NasConfig.DoDebug)
1340 osLogMsg("Init: will close device when finished with stream.\n");
1341 } else {
1342 relinquish_device = AuFalse;
1343 if (NasConfig.DoDebug)
1344 osLogMsg("Init: will open device exclusively.\n");
1345 }
1346
1347 if (devAudio == -1) {
1348 audio_device_t type;
1349 const char *device = NULL;
1350 char *devicectl = NULL;
1351
1352 /* pebl: Check whether a pseudo device is used, else try the normal one */
1353 if ((device = getenv("AUDIODEV")) == NULL)
1354 device = default_device;
1355
1356 #ifdef DEBUGLOG
1357 fprintf(stderr, "Trying device %s\n", device);
1358 fflush(stderr);
1359 #endif
1360
1361 devAudio = open(device, devAudioMode);
1362 if (devAudio == -1 && errno == EINVAL && devAudioMode == O_RDWR) {
1363 devAudioMode = O_WRONLY;
1364 devAudio = open(device, devAudioMode);
1365 }
1366
1367
1368 /* pebl: We cannot just concat "ctl" on variable device, so
1369 make a copy and concat "ctl". (free it again) */
1370 if (!(devicectl = (char *) aualloc(strlen(device) +
1371 strlen("ctl") + 1)))
1372 return AuFalse;
1373 sprintf(devicectl, "%sctl", device);
1374
1375 open_for_business = (devAudio != -1 &&
1376 #ifdef SEPARATE_CTLS
1377 (devAudioCtl2 = open(devicectl, O_RDWR)) != -1
1378 &&
1379 #endif
1380 (devAudioCtl =
1381 open(devicectl, O_RDWR)) != -1);
1382
1383 aufree(devicectl);
1384
1385 if (open_for_business) {
1386 #ifndef AUDIO_GETDEV
1387 name_of_physical_device = name_unknown;
1388 #else /* defined AUDIO_GETDEV */
1389 if ((open_for_business =
1390 (ioctl(devAudio, AUDIO_GETDEV, &type) != -1))) {
1391 if (IS_AMD(type))
1392 name_of_physical_device = name_am79c30;
1393 else if (IS_CS4231(type))
1394 name_of_physical_device = name_CS4231;
1395 else if (IS_DBRI(type))
1396 name_of_physical_device = name_dbri;
1397 else
1398 name_of_physical_device = name_unknown;
1399 }
1400 #endif /* defined AUDIO_GETDEV */
1401 }
1402
1403 if (!open_for_business) {
1404 if (devAudio != -1)
1405 close(devAudio);
1406 if (devAudioCtl != -1)
1407 close(devAudioCtl);
1408 #ifdef SEPARATE_CTLS
1409 if (devAudioCtl2 != -1)
1410 close(devAudioCtl2);
1411 #endif
1412 devAudio = devAudioCtl = -1;
1413 name_of_physical_device = 0;
1414 return AuFalse;
1415 }
1416 }
1417
1418 if (!(VENDOR_STRING = (char *) aualloc(strlen(SUN_VENDOR) +
1419 strlen(name_of_physical_device)
1420 - 1)))
1421 return AuFalse;
1422
1423 sprintf(VENDOR_STRING, SUN_VENDOR, name_of_physical_device);
1424
1425 if (physicalBuffers) {
1426 aufree(physicalBuffers);
1427 physicalBuffers = 0;
1428 }
1429
1430 if (emptyOutput) {
1431 aufree(emptyOutput);
1432 emptyOutput = 0;
1433 }
1434
1435 is_cs4231_or_dbri =
1436 (name_of_physical_device == name_CS4231 ||
1437 name_of_physical_device == name_dbri);
1438
1439 auMaxSampleRate = is_cs4231_or_dbri ? 48000 : 8000;
1440
1441 auMinibufSamples = MINIBUF_SAMPLES;
1442
1443 /* the output buffers need to be twice as large for output
1444 range checking */
1445 physicalBuffersSize = (PhysicalOneTrackBufferSize * 2 + /* mono output */
1446 PhysicalTwoTrackBufferSize * 2); /* stereo output */
1447
1448 if (is_cs4231_or_dbri) {
1449 physicalBuffersSize += (PhysicalTwoTrackBufferSize + /* stereo input */
1450 PhysicalOneTrackBufferSize * 2 + /* left output */
1451 PhysicalOneTrackBufferSize * 2); /* right output */
1452 bufSize = MINIBUF_SAMPLES * 2 * 2; /* stereo, 16 bits */
1453 } else {
1454 physicalBuffersSize += PhysicalTwoTrackBufferSize; /* mono input */
1455 bufSize = MINIBUF_SAMPLES; /* mono, 8 bits */
1456 }
1457
1458 if (!(emptyOutput = (AuUint8 *) aualloc(bufSize)))
1459 return AuFalse;
1460
1461 auset(emptyOutput, is_cs4231_or_dbri ? 0 : 0xff, bufSize);
1462
1463 if (!(physicalBuffers = (AuUint8 *) aualloc(physicalBuffersSize)))
1464 return AuFalse;
1465
1466 auInput = physicalBuffers;
1467
1468 if (is_cs4231_or_dbri) {
1469 auOutputMono = auInput + PhysicalTwoTrackBufferSize;
1470 auOutputLeft = auOutputMono + 2 * PhysicalOneTrackBufferSize;
1471 auOutputRight = auOutputLeft + 2 * PhysicalOneTrackBufferSize;
1472 auOutputStereo = auOutputRight + 2 * PhysicalOneTrackBufferSize;
1473
1474 auPhysicalOutputBuffersSize =
1475 physicalBuffersSize - PhysicalTwoTrackBufferSize;
1476 } else {
1477 auOutputMono = auInput + PhysicalOneTrackBufferSize;
1478 auOutputStereo = auOutputMono + 2 * PhysicalOneTrackBufferSize;
1479
1480 auPhysicalOutputBuffersSize =
1481 physicalBuffersSize - PhysicalTwoTrackBufferSize;
1482 }
1483
1484 auPhysicalOutputBuffers = auOutputMono;
1485
1486 signal(SIGPOLL, processAudioSignal);
1487
1488 AuRegisterCallback(AuCreateServerComponentsCB, createServerComponents);
1489 AuRegisterCallback(AuSetPhysicalOutputGainCB, setPhysicalOutputGain);
1490 AuRegisterCallback(AuGetPhysicalOutputGainCB, getPhysicalOutputGain);
1491 AuRegisterCallback(AuGetPhysicalOutputModeCB, getPhysicalOutputMode);
1492 AuRegisterCallback(AuSetPhysicalOutputModeCB, setPhysicalOutputMode);
1493 AuRegisterCallback(AuGetPhysicalFeedbackGainCB,
1494 getPhysicalFeedbackGain);
1495 AuRegisterCallback(AuSetPhysicalFeedbackGainCB,
1496 setPhysicalFeedbackGain);
1497 AuRegisterCallback(AuSetPhysicalInputGainAndLineModeCB,
1498 setPhysicalInputGainAndLineMode);
1499 AuRegisterCallback(AuGetPhysicalInputGainCB, getPhysicalInputGain);
1500 AuRegisterCallback(AuGetPhysicalInputModeCB, getPhysicalInputMode);
1501 AuRegisterCallback(AuEnableProcessFlowCB, enableProcessFlow);
1502 AuRegisterCallback(AuDisableProcessFlowCB, disableProcessFlow);
1503 AuRegisterCallback(AuReadPhysicalInputsCB, readPhysicalInputs);
1504
1505 if (is_cs4231_or_dbri) {
1506 AuRegisterCallback(AuSetWritePhysicalOutputFunctionCB,
1507 setWriteOutputFunction);
1508 AuRegisterCallback(AuSetSampleRateCB, setSampleRate);
1509 } else {
1510 AuRegisterCallback(AuSetWritePhysicalOutputFunctionCB,
1511 setWritePhysicalOutputFunction);
1512 }
1513
1514 ioctl(devAudioCtl, AUDIO_GETINFO, &info);
1515 availInputModes = info.record.avail_ports;
1516 availOutputModes = info.play.avail_ports;
1517 sampleRate = info.play.sample_rate; /* XXX */
1518 chunksPerSignal = sampleRate / SIGNAL_RATE / MINIBUF_SAMPLES;
1519
1520 AUDIO_INITINFO(&audioInfo);
1521 /* We only need to setup fields that differ from the open()
1522 defaults. */
1523 if (is_cs4231_or_dbri) {
1524 audioInfo.play.encoding
1525 = audioInfo.record.encoding = AUDIO_ENCODING_LINEAR;
1526 audioInfo.play.precision = audioInfo.record.precision = 16;
1527 audioInfo.play.channels = audioInfo.record.channels = 2;
1528
1529 aucopy(&audioInfo, &info, sizeof(audio_info_t));
1530 ioctl(devAudio, AUDIO_SETINFO, &info);
1531 }
1532
1533 AUDIO_INITINFO(&syncAudioInfo);
1534
1535 /* bogus resource so we can have a cleanup function at server reset */
1536 AddResource(FakeClientID(SERVER_CLIENT),
1537 CreateNewResourceType(serverReset), 0);
1538
1539 if (relinquish_device)
1540 closeDevice();
1541
1542 return AuTrue;
1543 }
1544