1 /* $Id: auvoxware.c 288 2013-08-11 21:28:33Z auerswald $ */
2 
3 /*
4    SCCS: @(#) auvoxware.c 11.4 95/04/14
5 */
6 /*-------------------------------------------------------------------------
7 
8 Copyright (C) 1995 The Santa Cruz Operation, Inc.
9 All Rights Reserved.
10 
11 Permission to use, copy, modify and distribute this software
12 for any purpose is hereby granted without fee, provided that the
13 above copyright notice and this notice appear in all copies
14 and that both the copyright notice and this notice appear in
15 supporting documentation.  SCO makes no representations about
16 the suitability of this software for any purpose.  It is provided
17 "AS IS" without express or implied warranty.
18 
19 SCO DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
20 INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
21 IN NO EVENT SHALL SCO BE LIABLE FOR ANY SPECIAL, INDIRECT,
22 PUNITIVE, CONSEQUENTIAL OR INCIDENTAL DAMAGES OR ANY DAMAGES
23 WHATSOEVER RESULTING FROM LOSS OF USE, LOSS OF DATA OR LOSS OF
24 PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
25 TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
26 PERFORMANCE OF THIS SOFTWARE.
27 
28 -------------------------------------------------------------------------*/
29 /*
30    AUVoxConfig additions (sysseh@devetir.qld.gov.au)
31    96-01-15
32         Put the following  keywords in -
33                 minrate         -       Minimum sampling rate
34                 maxrate         -       Maximum sampling rate
35                 fragsize        -       The fragment size
36                 minfrags        -       Minimum number of frags in queue
37                 maxfrags        -       Maximum fragments in queue
38                 wordsize        -       8 or 16 bit samples
39                 device          -       What device file to use
40                 numchans        -       Mono (1) or stereo (2)
41                 debug           -       Output messages during operation
42                 verbose         -       Be chatty about config
43                 inputsection    -       Next lot of specs are for input
44                 outputsection   -       Next specs are for output
45                 end             -       End an input or output section
46 */
47 /*
48    SCO Modification History:
49    S005, 24-Apr-95, shawnm@sco.com
50         base # of driver buffer fragments on data rate
51    S004, 12-Apr-95, shawnm@sco.com
52         finish integration of ausco.c, fix setitimer calls
53    S003, 28-Mar-95, shawnm@sco.com, sysseh@devetir.qld.gov.au
54         incorporate patch for stereo/mono mixing from Stephen Hocking
55    S002, 21-Mar-95, shawnm@sco.com
56         incorporate signal handling and audio block/unblock from ausco.c
57    S001, 21-Mar-95, shawnm@sco.com, sysseh@devetir.qld.gov.au
58         SYSSEH incorporate parts of patch from Stephen Hocking
59 */
60 /*
61  * Copyright 1993 Network Computing Devices, Inc. Copyright (C) Siemens
62  * Nixdorf Informationssysteme AG 1993
63  *
64  * Permission to use, copy, modify, distribute, and sell this software and its
65  * documentation for any purpose is hereby granted without fee, provided that
66  * the above copyright notice appear in all copies and that both that
67  * copyright notice and this permission notice appear in supporting
68  * documentation, and that the name Network Computing Devices, Inc.  or
69  * Siemens Nixdorf Informationssysteme AG not be used in advertising or
70  * publicity pertaining to distribution of this software without specific,
71  * written prior permission.
72  *
73  * THIS SOFTWARE IS PROVIDED `AS-IS'.  NETWORK COMPUTING DEVICES, INC. AND
74  * SIEMENS NIXDORF INFORMATIONSSYSTEME AG DISCLAIMS ALL WARRANTIES WITH
75  * REGARD TO THIS SOFTWARE, INCLUDING WITHOUT LIMITATION ALL IMPLIED
76  * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR
77  * NONINFRINGEMENT.  IN NO EVENT SHALL NETWORK COMPUTING DEVICES, INC. NOR
78  * SIEMENS NIXDORF INFORMATIONSSYSTEME AG BE LIABLE FOR ANY DAMAGES
79  * WHATSOEVER, INCLUDING SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES,
80  * INCLUDING LOSS OF USE, DATA, OR PROFITS, EVEN IF ADVISED OF THE
81  * POSSIBILITY THEREOF, AND REGARDLESS OF WHETHER IN AN ACTION IN CONTRACT,
82  * TORT OR NEGLIGENCE, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
83  * PERFORMANCE OF THIS SOFTWARE.
84  *
85  * $NCDId: @(#)auvoxware.c,v 1.10 1996/04/24 17:04:19 greg Exp $
86  *
87  * Copyright (C) Siemens Nixdorf Informationssysteme AG 1993 All rights reserved
88  */
89 
90 /*
91  * Originally from the merge of auvoxware by Amancio Hasty (hasty@netcom.com)
92  * & auvoxsvr4 by Stephen Hocking (sysseh@devetir.qld.gov.au).
93  * 16bit fixes and Linux patches supplied by Christian
94  * Schlichtherle (s_schli@ira.uka.de).
95  *
96  * BUGS:
97  * - When the soundcard can do only 8 bit recording, "aurecord" records
98  *   twice as long as it should. Is this our fault?
99  *
100  * TODO:
101  * - Adapt the buffer sizes to the current sampling rate,
102  *   so that we can record/play high quality audio samples without
103  *   swallows/pauses.
104  *   Note that setting the buffer size to a fixed maximum will not work,
105  *   because it causes playing at slow sample rate to pause. :-(
106  *   I already tried to do this, but it seems that the rest of the server
107  *   code doesn't recognize the changed buffer sizes. Any help in doing
108  *   this is welcome!
109  *   [chris]
110  * - Support a second input channel for stereo sampling,
111  *   so that microphone sampling is done on the mono channel
112  *   while line sampling is done on the stereo channel.
113  *   [chris]
114  *
115  * CHANGELOG:
116  * - 94/7/2:
117  *   Completely rewrote this file. Features:
118  *   + Makes use of two sound cards if available.
119  *     So you can concurrently record and play samples.
120  *   + Tested to work with all combinations of 8/16 bit, mono/stereo
121  *     sound card sampling modes.
122  *   + Uses a stereo input channel if hardware supports this.
123  *   + Can play stereo samples on mono sound cards (but who cares?).
124  *   + Always uses the highest possible audio quality, i.e. 8/16 bit and
125  *     mono/stereo parameters are fixed while only the sampling rate is
126  *     variable. This reduces swallows and pauses to the (currently)
127  *     unavoidable minimum while consuming a little bit more cpu time.
128  *   + Format conversion stuff is pushed back to the rest of the server code.
129  *     Only mono/stereo conversion is done here.
130  *   + Debugging output uses indentation.
131  *   [chris]
132  */
133 
134 #include <stdio.h>
135 #include <stdlib.h>
136 #if !defined(SVR4) && !defined(__FreeBSD__)
137 #include <getopt.h>
138 #endif
139 #include <sys/types.h>
140 #include <errno.h>
141 #ifndef _POSIX_SOURCE
142 # include <sys/ioctl.h>
143 #endif
144 
145 #if defined(__CYGWIN__)
146 # ifndef O_SYNC
147 #  define O_SYNC          _FSYNC
148 # endif
149 extern int errno;
150 #endif
151 
152 
153 #include "nasconf.h"
154 #include "config.h"
155 #include "aulog.h"
156 
157 #if defined(DEBUGDSPOUT) || defined(DEBUGDSPIN)
158 int dspin, dspout;
159 #endif
160 
161 #  define IDENTMSG (debug_msg_indentation += 2)
162 #  define UNIDENTMSG (debug_msg_indentation -= 2)
163 
164 static int debug_msg_indentation = 0;
165 
166 #include <errno.h>
167 #include "misc.h"
168 #include "dixstruct.h"          /* for RESTYPE */
169 #include "os.h"                 /* for xalloc/xfree and NULL */
170 #include <fcntl.h>
171 #include <sys/time.h>
172 #include <sys/param.h>
173 #include <assert.h>
174 
175 #if defined(__DragonFly__)
176 #  include <sys/soundcard.h>
177 #  ifndef O_SYNC
178 #     define O_SYNC O_FSYNC
179 #  endif
180 #elif defined(__FreeBSD__)
181 # if __FreeBSD_version >= 500001
182 #  include <sys/soundcard.h>
183 # else
184 #  include <machine/soundcard.h>
185 # endif
186 /* PC Speaker functions seems to be unused here
187 # include <machine/pcaudioio.h>
188 */
189 #else
190 # ifdef __NetBSD__
191 #  include <sys/ioctl.h>
192 #  include <soundcard.h>
193 # else
194 #  include <sys/soundcard.h>
195 # endif
196 #endif
197 
198 #include <audio/audio.h>
199 #include <audio/Aproto.h>
200 #include "au.h"
201 
202 static AuBool processFlowEnabled;
203 static void disableProcessFlow(void);
204 static void closeDevice(void);
205 
206 #define SERVER_CLIENT           0
207 
208 #define MAX_MINIBUF_SAMPLES     1024    /* Must be a power of 2 */
209 
210 #define PhysicalOneTrackBufferSize \
211     PAD4(auMinibufSamples * auNativeBytesPerSample * 1)
212 #define PhysicalTwoTrackBufferSize \
213     PAD4(auMinibufSamples * auNativeBytesPerSample * 2)
214 
215 /* VOXware sound driver mixer control variables */
216 
217 #define useMixerNone 0
218 #define useMixerIGain 1
219 #define useMixerRecLev 2
220 #define useMixerLineMic 3
221 
222 static AuBool relinquish_device = 0;
223 static AuBool leave_mixer = 0;
224 static AuBool share_in_out = 0;
225 static AuBool share_mixer = 0;
226 
227 static int recControlMode = 0;  /* how to control recording level */
228 static int outmixerfd = -1;     /* The output device mixer device */
229 static int inmixerfd = -1;      /* The input device mixer device */
230 static int devmask = 0;         /* Bitmask for supported mixer devices */
231 static int recmask = 0;         /* Supported recording sources */
232 
233 int VOXMixerInit   = FALSE;     /* overridden by nasd.conf */
234 int VOXReInitMixer = FALSE;     /* overridden by nasd.conf */
235 
236 /* end of VOXware driver mixer control variables */
237 
238 SndStat *confStat;
239 
240 SndStat sndStatIn = {
241     -1,                         /* fd */
242     16,                         /* wordSize */
243     1,                          /* isStereo */
244     0,                          /* curSampleRate */
245     4000,                       /* minSampleRate */
246     44100,                      /* maxSampleRate */
247     256,                        /* fragSize */
248     3,                          /* minFrags */
249     32,                         /* maxFrags */
250     "/dev/dsp1",                /* device */
251     "/dev/mixer1",              /* mixer */
252     O_RDONLY,                   /* howToOpen */
253     1,                          /* autoOpen */
254     0,                          /* forceRate */
255     0,                          /* isPCSpeaker */
256     50,                         /* default gain */
257     100                         /* gain reduction factor */
258 };
259 
260 SndStat sndStatOut = {
261 
262     -1,                         /* fd */
263     16,                         /* wordSize */
264     1,                          /* isStereo */
265     0,                          /* curSampleRate */
266     4000,                       /* minSampleRate */
267     44100,                      /* maxSampleRate */
268     256,                        /* fragSize */
269     3,                          /* minFrags */
270     32,                         /* maxFrags */
271     "/dev/dsp",                 /* device */
272     "/dev/mixer",               /* mixer */
273     O_WRONLY,                   /* howToOpen */
274     1,                          /* autoOpen */
275     0,                          /* forceRate */
276     0,                          /* isPCSpeaker */
277     50,                         /* default gain */
278     100                         /* gain reduction factor */
279 };
280 
281 #define auDefaultInputGain      AuFixedPointFromSum(sndStatIn.gain, 0)
282 #define auDefaultOutputGain     AuFixedPointFromSum(sndStatOut.gain, 0)
283 
284 static AuUint8 *auOutputMono, *auOutputStereo, *auInput;
285 
286 static ComponentPtr monoInputDevice,
287         stereoInputDevice, monoOutputDevice, stereoOutputDevice;
288 
289 extern AuInt32 auMinibufSamples;
290 
291 
292 #define auPhysicalOutputChangableMask AuCompDeviceGainMask
293 
294 #define auPhysicalOutputValueMask \
295   (AuCompCommonAllMasks \
296    | AuCompDeviceMinSampleRateMask \
297    | AuCompDeviceMaxSampleRateMask \
298    | AuCompDeviceGainMask \
299    | AuCompDeviceLocationMask \
300    | AuCompDeviceChildrenMask)
301 
302 #define auPhysicalInputChangableMask \
303   (AuCompDeviceGainMask | AuCompDeviceLineModeMask)
304 
305 #define auPhysicalInputValueMask \
306   (AuCompCommonAllMasks \
307    | AuCompDeviceMinSampleRateMask \
308    | AuCompDeviceMaxSampleRateMask \
309    | AuCompDeviceLocationMask \
310    | AuCompDeviceGainMask \
311    | AuCompDeviceChildrenMask)
312 
313 static void setPhysicalOutputGain(AuFixedPoint gain);
314 static void setPhysicalInputGainAndLineMode(AuFixedPoint gain,
315                                             AuUint8 lineMode);
316 
317 
318 /* internal funtions for enabling/disabling intervalProc using sigaction
319    semantics */
320 
321 static void intervalProc(int sig);
322 
323 /* use this in disableIntervalProc() instead of SIG_IGN for testing */
324 #if 0
325 static void ignoreProc(int sig)
326 {
327   osLogMsg("SIGNAL IGNORE: ENTRY\n");
328   return;
329 }
330 #endif
331 
enableIntervalProc(void)332 static void enableIntervalProc(void)
333 {
334     struct sigaction action;
335 
336     action.sa_handler = (void (*)(int))intervalProc;
337     action.sa_flags = 0;
338     sigemptyset(&action.sa_mask);
339     sigaddset(&action.sa_mask, SIGALRM);
340 
341     if (sigaction(SIGALRM, &action, NULL) == -1)
342         {
343           osLogMsg("enableIntervalProc: sigaction failed: %s\n",
344                    strerror(errno));
345         }
346 
347     return;
348 }
349 
disableIntervalProc(void)350 static void disableIntervalProc(void)
351 {
352     struct sigaction action;
353 
354     action.sa_handler = (void (*)(int))SIG_IGN;
355     action.sa_flags = 0;
356 
357     if (sigaction(SIGALRM, &action, NULL) == -1)
358         {
359           osLogMsg("disableIntervalProc: sigaction failed: %s\n",
360                    strerror(errno));
361         }
362 
363     return;
364 }
365 
366 static AuBool audioBlocked = AuFalse;
367 
_AuBlockAudio(void)368 AuBlock _AuBlockAudio(void)
369 {
370     sigset_t set;
371 
372     audioBlocked = AuTrue;
373     sigemptyset(&set);
374     sigaddset(&set, SIGALRM);
375     sigprocmask(SIG_BLOCK, &set, NULL);
376     return 0;
377 }
378 
_AuUnBlockAudio(AuBlock _x)379 void _AuUnBlockAudio(AuBlock _x)
380 {
381     sigset_t set;
382 
383     audioBlocked = AuFalse;
384     sigemptyset(&set);
385     sigaddset(&set, SIGALRM);
386     sigprocmask(SIG_UNBLOCK, &set, NULL);
387     return;
388 }
389 
390 
391 /* ### SCO ### */
392 #ifdef sco
393 
394 AuBlock
AuBlockAudio(void)395 AuBlockAudio(void)
396 {
397     audioBlocked = AuTrue;
398     return 0;
399 }
400 
401 void
AuUnBlockAudio(AuBlock id)402 AuUnBlockAudio(AuBlock id)
403 {
404     audioBlocked = AuFalse;
405 }
406 
407 #endif /* sco */
408 
409 static int
readMixerOutputGain(void)410 readMixerOutputGain(void)
411 {
412     int pcm_level = 0;
413 
414     if (outmixerfd != -1) {
415         if (ioctl(outmixerfd, MIXER_READ(SOUND_MIXER_PCM), &pcm_level) == -1) {
416             osLogMsg("readMixerOutputGain: "
417                      "%s: ioctl(%d, MIXER_READ(SOUND_MIXER_PCM)) failed: %s\n",
418                      sndStatOut.mixer, outmixerfd, strerror(errno));
419             return sndStatOut.gain;
420         }
421     } else {
422         return sndStatOut.gain;
423     }
424 
425     pcm_level = ((pcm_level & 0xFF) + (pcm_level >> 8)) / 2;
426     if (sndStatOut.gainScale) {
427         pcm_level *= 100;
428         pcm_level /= sndStatOut.gainScale;
429     }
430     return pcm_level;
431 }
432 
433 static int
readMixerInputMode(void)434 readMixerInputMode(void)
435 {
436     int input_mode = 0;
437 
438     if (inmixerfd != -1) {
439         if (ioctl(inmixerfd,MIXER_READ(SOUND_MIXER_RECSRC),&input_mode) == -1) {
440             osLogMsg("readMixerInputMode: "
441                      "%s: ioctl(%d, MIXER_READ(SOUND_MIXER_RECSRC)) failed: "
442                      "%s\n", sndStatIn.mixer, inmixerfd, strerror(errno));
443             return 1<<SOUND_MIXER_LINE;
444         }
445         if (!(input_mode & (SOUND_MASK_MIC | SOUND_MIXER_LINE))) {
446             return 1<<SOUND_MIXER_LINE;
447         }
448     } else {
449         return 1<<SOUND_MIXER_LINE;
450     }
451 
452     return input_mode;
453 }
454 
455 static int
readMixerInputGain(void)456 readMixerInputGain(void)
457 {
458     int in_level = 0;
459     int recsrc = 0;
460 
461     recsrc = readMixerInputMode();
462 
463     if (inmixerfd != -1) {
464         switch (recControlMode) {
465         case useMixerIGain:
466             if (ioctl(inmixerfd,MIXER_READ(SOUND_MIXER_IGAIN),&in_level) == -1){
467                 osLogMsg("readMixerInputGain: %s: "
468                          "ioctl(MIXER_READ(SOUND_MIXER_IGAIN)) failed: %s\n",
469                          sndStatIn.mixer, strerror(errno));
470                 return sndStatIn.gain;
471             }
472             break;
473 
474         case useMixerRecLev:
475             if (ioctl(inmixerfd,MIXER_READ(SOUND_MIXER_RECLEV),&in_level)==-1) {
476                 osLogMsg("readMixerInputGain: "
477                          "%s: ioctl(%d, MIXER_READ(SOUND_MIXER_RECLEV)) failed:"
478                          " %s\n", sndStatIn.mixer, inmixerfd, strerror(errno));
479                 return sndStatIn.gain;
480             }
481             break;
482 
483         case useMixerLineMic:
484             if (recsrc & SOUND_MASK_LINE) {
485                 if (ioctl(inmixerfd, MIXER_READ(SOUND_MIXER_LINE), &in_level)
486                     == -1) {
487                     osLogMsg("readMixerInputGain: "
488                              "%s: ioctl(%d, MIXER_READ(SOUND_MIXER_LINE)) "
489                              "failed: %s\n",
490                              sndStatIn.mixer, inmixerfd, strerror(errno));
491                     return sndStatIn.gain;
492                 }
493             } else if (recsrc & SOUND_MASK_MIC) {
494                 if (ioctl(inmixerfd, MIXER_READ(SOUND_MIXER_MIC), &in_level)
495                     == -1) {
496                     osLogMsg("readMixerInputGain: "
497                              "%s: ioctl(%d, MIXER_READ(SOUND_MIXER_MIC)) "
498                              "failed: %s\n",
499                              sndStatIn.mixer, inmixerfd, strerror(errno));
500                     return sndStatIn.gain;
501                 }
502             } else {
503                 return sndStatIn.gain;
504             }
505             break;
506 
507         case useMixerNone:
508             return sndStatIn.gain;
509             break;
510 
511         default:
512             osLogMsg("readMixerInputGain: "
513                      "unknown value %d of recControlMode\n", recControlMode);
514             return sndStatIn.gain;
515         }
516     } else {
517         return sndStatIn.gain;
518     }
519 
520     in_level = ((in_level & 0xFF) + (in_level >> 8)) / 2;
521     if (sndStatIn.gainScale) {
522         in_level *= 100;
523         in_level /= sndStatIn.gainScale;
524     }
525     return in_level;
526 }
527 
528 static AuInt8
mixerInputModeToNAS(int input_mode)529 mixerInputModeToNAS(int input_mode)
530 {
531     if (input_mode & SOUND_MASK_MIC)
532         return AuDeviceInputModeMicrophone;
533 
534     if (input_mode & SOUND_MASK_LINE)
535         return AuDeviceInputModeLineIn;
536 
537     if (NasConfig.DoDebug)
538         osLogMsg("mixerInputModeToNAS: input mode %d is neither LINE (%d) "
539                  "nor MIC (%d)\n", input_mode, SOUND_MASK_LINE, SOUND_MASK_MIC);
540 
541     return AuDeviceInputModeLineIn;
542 }
543 
544 static void
setMixerDefaults(void)545 setMixerDefaults(void)
546 {
547     setPhysicalOutputGain(auDefaultOutputGain);
548     setPhysicalInputGainAndLineMode(auDefaultInputGain, AuDeviceLineModeLow);
549 }
550 
551 static int
createServerComponents(AuUint32 * auServerDeviceListSize,AuUint32 * auServerBucketListSize,AuUint32 * auServerRadioListSize,AuUint32 * auServerMinRate,AuUint32 * auServerMaxRate)552 createServerComponents(AuUint32 * auServerDeviceListSize,
553                        AuUint32 * auServerBucketListSize,
554                        AuUint32 * auServerRadioListSize,
555                        AuUint32 * auServerMinRate,
556                        AuUint32 * auServerMaxRate)
557 {
558     ComponentPtr d, *p;
559     AuUint8 formatIn, formatOut;
560     AuUint32 bytesPerSampleIn, bytesPerSampleOut;
561     static AuBool initialized = AuFalse;
562     extern RESTYPE auComponentType;
563     extern ComponentPtr *auServerDevices,       /* array of devices */
564         auDevices;              /* list of all devices */
565     extern AuUint32 auNumServerDevices; /* number of devices */
566 
567 
568     if (NasConfig.DoDebug) {
569         osLogMsg("createServerComponents(...);\n");
570         IDENTMSG;
571     }
572 
573     *auServerMinRate = aumax(sndStatIn.minSampleRate,
574                              sndStatOut.minSampleRate);
575     *auServerMaxRate = aumax(sndStatIn.maxSampleRate,
576                              sndStatOut.maxSampleRate);
577 
578     auNumServerDevices = *auServerDeviceListSize
579             = *auServerBucketListSize = *auServerRadioListSize = 0;
580 
581     formatIn = (sndStatIn.wordSize == 16) ? AuFormatLinearSigned16LSB
582             : AuFormatLinearUnsigned8;
583     formatOut = (sndStatOut.wordSize == 16) ? AuFormatLinearSigned16LSB
584             : AuFormatLinearUnsigned8;
585 
586     bytesPerSampleIn = sndStatIn.wordSize / 8;
587     bytesPerSampleOut = sndStatOut.wordSize / 8;
588 
589     AU_ALLOC_DEVICE(d, 1, 0);
590     d->id = FakeClientID(SERVER_CLIENT);
591     d->changableMask = auPhysicalOutputChangableMask;
592     d->valueMask = auPhysicalOutputValueMask;
593     d->kind = AuComponentKindPhysicalOutput;
594     d->use = AuComponentUseExportMask;
595     d->access = AuAccessExportMask | AuAccessListMask;
596     d->format = formatOut;
597     d->numTracks = 1;
598     d->description.type = AuStringLatin1;
599     d->description.string = "Mono Channel Output";
600     d->description.len = strlen(d->description.string);
601     d->minSampleRate = sndStatOut.minSampleRate;
602     d->maxSampleRate = sndStatOut.maxSampleRate;
603     d->location =
604             AuDeviceLocationCenterMask | AuDeviceLocationInternalMask;
605     d->numChildren = 0;
606     d->minibuf = auOutputMono;
607     d->minibufSize = d->numTracks * bytesPerSampleOut * auMinibufSamples;
608     d->physicalDeviceMask = PhysicalOutputMono;
609     AU_ADD_DEVICE(d);
610 
611     monoOutputDevice = d;
612 
613     AU_ALLOC_DEVICE(d, 2, 1);
614     d->id = FakeClientID(SERVER_CLIENT);
615     d->changableMask = auPhysicalOutputChangableMask;
616     d->valueMask = auPhysicalOutputValueMask;
617     d->kind = AuComponentKindPhysicalOutput;
618     d->use = AuComponentUseExportMask;
619     d->access = AuAccessExportMask | AuAccessListMask;
620     d->format = formatOut;
621     d->numTracks = 2;
622     d->description.type = AuStringLatin1;
623     d->description.string = "Stereo Channel Output";
624     d->description.len = strlen(d->description.string);
625     d->minSampleRate = sndStatOut.minSampleRate;
626     d->maxSampleRate = sndStatOut.maxSampleRate;
627     d->location =
628             AuDeviceLocationCenterMask | AuDeviceLocationInternalMask;
629     d->numChildren = 1;
630     d->children = (AuID *) ((AuUint8 *) d + PAD4(sizeof(ComponentRec)));
631     d->childSwap = (char *) (d->children + d->numChildren);
632     d->children[0] = monoOutputDevice->id;
633     d->minibuf = auOutputStereo;
634     d->minibufSize = d->numTracks * bytesPerSampleOut * auMinibufSamples;
635     d->physicalDeviceMask = PhysicalOutputStereo;
636     AU_ADD_DEVICE(d);
637 
638     stereoOutputDevice = d;
639 
640     AU_ALLOC_DEVICE(d, (sndStatIn.isStereo + 1), 0);
641     d->id = FakeClientID(SERVER_CLIENT);
642     d->changableMask = auPhysicalInputChangableMask;
643     d->valueMask = auPhysicalInputValueMask;
644     d->kind = AuComponentKindPhysicalInput;
645     d->use = AuComponentUseImportMask;
646     d->access = AuAccessImportMask | AuAccessListMask;
647     d->format = formatIn;
648     d->numTracks = sndStatIn.isStereo + 1;
649     d->description.type = AuStringLatin1;
650     d->description.string = (sndStatIn.isStereo) ? "Stereo Channel Input"
651             : "Mono Channel Input";
652     d->description.len = strlen(d->description.string);
653     d->minSampleRate = sndStatOut.minSampleRate;
654     d->maxSampleRate = sndStatOut.maxSampleRate;
655     d->location = AuDeviceLocationRightMask | AuDeviceLocationLeftMask
656             | AuDeviceLocationExternalMask;
657     d->numChildren = 0;
658     d->minibuf = auInput;
659     d->minibufSize = d->numTracks * bytesPerSampleIn * auMinibufSamples;
660     d->physicalDeviceMask = (sndStatIn.isStereo) ? PhysicalInputStereo
661             : PhysicalInputMono;
662     AU_ADD_DEVICE(d);
663 
664     monoInputDevice = d;        /* Should have two input devices - FIXME */
665     stereoInputDevice = d;
666 
667     /* set the array of server devices */
668     if (!(auServerDevices = (ComponentPtr *) aualloc(sizeof(ComponentPtr)
669                                                      *
670                                                      auNumServerDevices)))
671     {
672         UNIDENTMSG;
673         return AuBadAlloc;
674     }
675 
676     p = auServerDevices;
677     d = auDevices;
678 
679     while (d) {
680         *p++ = d;
681         d = d->next;
682     }
683 
684     if (!initialized) {
685         initialized = AuTrue;
686         if (!leave_mixer) {
687             setMixerDefaults();
688         }
689 
690         /* JET - close the device if requested... only needs to happen
691            here during first time init as diasableProcessFlow will handle
692            it from here on out. */
693 
694         if (relinquish_device)
695             closeDevice();
696 
697     }
698 
699     UNIDENTMSG;
700 
701     return AuSuccess;
702 }
703 
704 static AuInt32
setTimer(AuInt32 rate)705 setTimer(AuInt32 rate)
706 {
707     AuInt32 timer_ms;
708     AuInt32 foo;
709     struct itimerval ntval, otval;
710 
711     if (NasConfig.DoDebug > 5) {
712         osLogMsg("setTimer(rate = %d);\n", rate);
713         IDENTMSG;
714     }
715 
716     /* change timer according to new sample rate */
717     if (rate == 0) {            /* Disable timer case */
718         ntval.it_value.tv_sec = ntval.it_value.tv_usec = 0;
719         ntval.it_interval.tv_sec = ntval.it_interval.tv_usec = 0;
720         timer_ms = 0x7fff;
721     } else {
722         timer_ms = (auMinibufSamples * 500) / rate;
723         ntval.it_interval.tv_sec = 0;
724         ntval.it_interval.tv_usec = timer_ms * 1000;
725         ntval.it_value.tv_sec = 0;
726         ntval.it_value.tv_usec = timer_ms * 10;
727     }
728     foo = setitimer(ITIMER_REAL, &ntval, &otval);
729 
730     UNIDENTMSG;
731 
732     return timer_ms;
733 }
734 
735 
736 #ifdef sco
737 static void
oneMoreTick(void)738 oneMoreTick(void)
739 {
740     struct itimerval ntval, otval;
741     int foo;
742 
743     ntval.it_interval.tv_sec = 0;
744     ntval.it_interval.tv_usec = 0;
745     ntval.it_value.tv_sec = 0;
746     ntval.it_value.tv_usec = 10;
747     foo = setitimer(ITIMER_REAL, &ntval, &otval);
748 }
749 #endif /* sco */
750 
751 
752 static void
setFragmentSize(SndStat * sndStatPtr)753 setFragmentSize(SndStat * sndStatPtr)
754 {
755     int fragarg, i, j;
756     int datarate, numfrags;
757 
758     datarate = sndStatPtr->curSampleRate;
759     if (sndStatPtr->isStereo)
760         datarate *= 2;
761     if (sndStatPtr->wordSize == 16)
762         datarate *= 2;
763     datarate /= 2;              /* half second */
764     numfrags = datarate / MAX_MINIBUF_SAMPLES;
765     if (numfrags < sndStatPtr->minFrags)
766         numfrags = sndStatPtr->minFrags;
767     else if (numfrags > sndStatPtr->maxFrags)
768         numfrags = sndStatPtr->maxFrags;
769 
770     j = MAX_MINIBUF_SAMPLES;
771     for (i = 0; j; i++)         /* figure out what power of 2 MAX_MINIBUF_SAMPLES is */
772         j = j >> 1;
773     fragarg = (numfrags << 16) | i;     /* numfrags of size MAX_MINIBUF_SAMPLES */
774     ioctl(sndStatPtr->fd, SNDCTL_DSP_SETFRAGMENT, &fragarg);
775 }
776 
777 
778 static AuUint32
setSampleRate(AuUint32 rate)779 setSampleRate(AuUint32 rate)
780 {
781     AuBlock l;
782 
783     setTimer(0);                /* JET - turn off the timer here so the
784                                    following code has a chance to clean
785                                    things up. A race can result
786                                    otherwise.  */
787     if (NasConfig.DoDebug) {
788         osLogMsg("setSampleRate(rate = %d);\n", rate);
789         IDENTMSG;
790     }
791 
792     l = AuBlockAudio();
793 
794     if (sndStatOut.curSampleRate != rate) {
795         sndStatOut.curSampleRate = rate;
796 
797 #if defined(SNDCTL_DSP_SETFRAGMENT)
798         setFragmentSize(&sndStatOut);
799 #endif
800         ioctl(sndStatOut.fd, SNDCTL_DSP_SYNC, NULL);
801         ioctl(sndStatOut.fd, SNDCTL_DSP_SPEED,
802               &(sndStatOut.curSampleRate));
803         if (sndStatOut.forceRate)
804             sndStatOut.curSampleRate = rate;
805         if (NasConfig.DoDebug)
806             osLogMsg("setSampleRate(): set output sample rate to %d\n",
807                      sndStatOut.curSampleRate);
808     }
809 
810     if ((sndStatIn.fd == sndStatOut.fd) && (sndStatIn.fd != -1)) {
811         sndStatIn = sndStatOut;
812         if (NasConfig.DoDebug)
813             osLogMsg("setSampleRate(): setting sndStatIn = sndStatOut\n");
814     }
815     else if (sndStatIn.curSampleRate != rate) {
816         sndStatIn.curSampleRate = rate;
817 
818 #if defined(SNDCTL_DSP_SETFRAGMENT)
819         setFragmentSize(&sndStatIn);
820 #endif
821         ioctl(sndStatIn.fd, SNDCTL_DSP_SYNC, NULL);
822         ioctl(sndStatIn.fd, SNDCTL_DSP_SPEED, &(sndStatIn.curSampleRate));
823         if (sndStatIn.forceRate)
824             sndStatIn.curSampleRate = rate;
825         if (NasConfig.DoDebug)
826             osLogMsg("setSampleRate(): set input sample rate to %d\n",
827                      sndStatIn.curSampleRate);
828     }
829 #if defined(AUDIO_DRAIN)
830     if (sndStatOut.isPCSpeaker)
831         ioctl(sndStatOut.fd, AUDIO_DRAIN, 0);
832 #endif
833 
834     AuUnBlockAudio(l);
835 
836     setTimer(rate);
837 
838     UNIDENTMSG;
839 
840     return sndStatOut.curSampleRate;
841 }
842 
843 static void setupSoundcard(SndStat * sndStatPtr);
844 
845 static AuBool
openDevice(AuBool wait)846 openDevice(AuBool wait)
847 {
848     unsigned int extramode = 0;
849     int retries;
850     int curSampleRate;
851 
852     setTimer(0);                /* no timers here */
853 #if defined(__CYGWIN__)         /* we want the file to be created if necc under
854                                    windows */
855     extramode = O_CREAT;
856 #endif
857 
858     if (NasConfig.DoDebug) {
859         osLogMsg("openDevice\n");
860     }
861 
862     curSampleRate = sndStatOut.curSampleRate;
863     if (NasConfig.DoDebug) {
864         osLogMsg("openDevice: current sample rate = %d\n", curSampleRate);
865         if (sndStatOut.curSampleRate != sndStatIn.curSampleRate)
866             osLogMsg("openDevice: sndStatOut.curSampleRate !="
867                      " sndStatIn.curSampleRate\n");
868     }
869 
870     if (NasConfig.DoDebug) {
871         osLogMsg("openDevice OUT %s mode %d\n",
872                  sndStatOut.device, sndStatOut.howToOpen);
873     }
874 
875 
876     if (sndStatOut.device[0] != '\0') {
877         if (sndStatOut.fd == -1) {
878             while ((sndStatOut.fd = open(sndStatOut.device,
879                                          sndStatOut.
880 #if defined(__FreeBSD__)
881                                          howToOpen | extramode,
882 #else
883                                          howToOpen | O_SYNC | extramode,
884 #endif
885                                          0666)) == -1 && wait) {
886                 osLogMsg("openDevice: waiting on output device\n");
887                 sleep(1);
888             }
889             setupSoundcard(&sndStatOut);
890         } else {
891             if (NasConfig.DoDebug) {
892                 osLogMsg("openDevice: output device already open\n");
893             }
894         }
895     } else {
896         if (NasConfig.DoDebug) {
897             osLogMsg("openDevice: no output device specified\n");
898         }
899     }
900 
901 #if  !defined(__CYGWIN__)
902     if (sndStatIn.device[0] != '\0') {
903         if (sndStatIn.fd == -1 && !share_in_out) {
904             if (NasConfig.DoDebug)
905                 osLogMsg("openDevice IN %s mode %d\n", sndStatIn.device,
906                          sndStatIn.howToOpen);
907 
908             retries = 0;
909             while ((sndStatIn.fd = open(sndStatIn.device,
910                                         sndStatIn.howToOpen | extramode,
911                                         0666)) == -1 && wait) {
912                 osLogMsg("openDevice: waiting on input device, retry %d\n",
913                          retries);
914                 sleep(1);
915                 retries++;
916 
917                 if (retries >= 5) {
918                     osLogMsg("openDevice: maximum retries exceeded, "
919                              "giving up\n");
920                     sndStatIn.fd = -1;
921                     break;
922                 }
923             }
924             if (sndStatIn.fd != -1 && sndStatOut.fd != sndStatIn.fd)
925                 setupSoundcard(&sndStatIn);
926         } else {
927             sndStatIn.fd = sndStatOut.fd;
928             if (NasConfig.DoDebug) {
929                 osLogMsg("openDevice: input device already open\n");
930             }
931         }
932     } else {
933         if (NasConfig.DoDebug) {
934             osLogMsg("openDevice: no input device specified\n");
935         }
936     }
937 
938     if (outmixerfd == -1) {
939         if (sndStatOut.mixer[0] == '\0') {
940             osLogMsg("openDevice: no output mixer device specified\n");
941         } else {
942             while ((outmixerfd = open(sndStatOut.mixer, O_RDWR | extramode,
943                                    0666)) == -1 && wait) {
944                 if ((errno == EAGAIN) || (errno == EBUSY)) {
945                     osLogMsg("openDevice: waiting on mixer device %s\n",
946                              sndStatOut.mixer);
947                     sleep(1);
948                 } else {
949                     osLogMsg("openDevice: could not open output mixer device"
950                              " %s: %s\n", sndStatOut.mixer, strerror(errno));
951                     break;
952                 }
953             }
954             if (outmixerfd != -1)
955                 osLogMsg("openDevice: opened mixer %s\n", sndStatOut.mixer);
956         }
957     } else {
958         if (NasConfig.DoDebug) {
959             osLogMsg("openDevice: output mixer device already open\n");
960         }
961     }
962 
963     if ((inmixerfd == -1) && !share_mixer) {
964         if (sndStatIn.mixer[0] == '\0') {
965             osLogMsg("openDevice: no input mixer device specified\n");
966         } else {
967             while ((inmixerfd = open(sndStatIn.mixer, O_RDWR | extramode,
968                                    0666)) == -1 && wait) {
969                 if ((errno == EAGAIN) || (errno == EBUSY)) {
970                     osLogMsg("openDevice: waiting on mixer device %s\n",
971                              sndStatIn.mixer);
972                     sleep(1);
973                 } else {
974                     osLogMsg("openDevice: could not open input mixer device"
975                              " %s: %s\n", sndStatIn.mixer, strerror(errno));
976                     break;
977                 }
978             }
979             if (inmixerfd != -1)
980                 osLogMsg("openDevice: opened mixer %s\n", sndStatIn.mixer);
981         }
982     } else {
983         if (share_mixer) {
984             inmixerfd = outmixerfd;
985         }
986         if (NasConfig.DoDebug) {
987             osLogMsg("openDevice: input mixer device already open\n");
988         }
989     }
990 #endif
991 
992     ioctl(sndStatOut.fd, SNDCTL_DSP_SYNC, NULL);
993 
994     {
995         int rate;
996 #ifndef sco
997         rate = sndStatOut.curSampleRate;
998         ioctl(sndStatOut.fd, SNDCTL_DSP_SPEED, &sndStatOut.curSampleRate);
999         if (sndStatOut.forceRate)
1000             sndStatOut.curSampleRate = rate;
1001 #endif /* sco */
1002 
1003         if (sndStatOut.fd != sndStatIn.fd) {
1004             ioctl(sndStatIn.fd, SNDCTL_DSP_SYNC, NULL);
1005 #ifndef sco
1006             rate = sndStatIn.curSampleRate;
1007             ioctl(sndStatIn.fd, SNDCTL_DSP_SPEED,
1008                   &sndStatIn.curSampleRate);
1009             if (sndStatIn.forceRate)
1010                 sndStatIn.curSampleRate = rate;
1011 #endif /* sco */
1012         }
1013     }
1014 
1015     setSampleRate(curSampleRate);
1016 
1017     return AuTrue;
1018 }
1019 
1020 static void
closeDevice(void)1021 closeDevice(void)
1022 {
1023     if (NasConfig.DoDebug) {
1024         osLogMsg("closeDevice: out\n");
1025     }
1026     if (sndStatOut.fd == -1) {
1027         if (NasConfig.DoDebug) {
1028             osLogMsg("closeDevice: output device already closed\n");
1029         }
1030     } else {
1031         if (NasConfig.DoDebug)
1032             osLogMsg("closeDevice OUT %s mode %d\n", sndStatOut.device,
1033                      sndStatOut.howToOpen);
1034 
1035         while (close(sndStatOut.fd)) {
1036             osLogMsg("closeDevice: waiting on output device\n");
1037             sleep(1);
1038         }
1039     }
1040 
1041     if (!share_in_out) {
1042         if (NasConfig.DoDebug) {
1043             osLogMsg("closeDevice: in\n");
1044         }
1045         if (sndStatIn.fd == -1) {
1046             if (NasConfig.DoDebug) {
1047                 osLogMsg("closeDevice: input device already closed\n");
1048             }
1049         } else {
1050             if (NasConfig.DoDebug)
1051                 osLogMsg("closeDevice IN %s mode %d\n",
1052                          sndStatIn.device, sndStatIn.howToOpen);
1053 
1054             while (close(sndStatIn.fd)) {
1055                 osLogMsg("closeDevice: waiting on input device\n");
1056                 sleep(1);
1057             }
1058         }
1059     }
1060 
1061     if (NasConfig.DoDebug) {
1062         osLogMsg("closeDevice: mixer\n");
1063     }
1064 
1065     if (NasConfig.DoKeepMixer) {
1066         if (NasConfig.DoDebug) {
1067             osLogMsg("closeDevice: leaving mixer device(s) open\n");
1068         }
1069     } else {
1070         if (-1 == outmixerfd) {
1071             if (NasConfig.DoDebug) {
1072                 osLogMsg("closeDevice: output mixer device already closed\n");
1073             }
1074         } else {
1075             while (close(outmixerfd)) {
1076                 osLogMsg("closeDevice: waiting on output mixer device\n");
1077                 sleep(1);
1078             }
1079             if (NasConfig.DoDebug) {
1080                 osLogMsg("closeDevice: closed output mixer device\n");
1081             }
1082             outmixerfd = -1;
1083         }
1084         if (-1 == inmixerfd) {
1085             if (NasConfig.DoDebug) {
1086                 osLogMsg("closeDevice: input mixer device already closed\n");
1087             }
1088         } else {
1089             while (!share_mixer && close(inmixerfd)) {
1090                 osLogMsg("closeDevice: waiting on input mixer device\n");
1091                 sleep(1);
1092             }
1093             if (NasConfig.DoDebug) {
1094                 osLogMsg("closeDevice: closed input mixer device\n");
1095             }
1096             inmixerfd = -1;
1097         }
1098     }
1099 
1100     sndStatIn.fd = -1;
1101     sndStatOut.fd = -1;
1102 }
1103 
1104 
1105 static void
serverReset(void)1106 serverReset(void)
1107 {
1108     if (NasConfig.DoDebug) {
1109         osLogMsg("serverReset();\n");
1110         IDENTMSG;
1111     }
1112 
1113     setTimer(0);
1114     disableIntervalProc();
1115 
1116 #if defined(AUDIO_DRAIN)
1117     if (sndStatOut.isPCSpeaker)
1118         ioctl(sndStatOut.fd, AUDIO_DRAIN, 0);
1119     else {
1120 #endif
1121 
1122         ioctl(sndStatIn.fd, SNDCTL_DSP_SYNC, NULL);
1123         if (sndStatOut.fd != sndStatIn.fd)
1124             ioctl(sndStatOut.fd, SNDCTL_DSP_SYNC, NULL);
1125 
1126 #if defined(AUDIO_DRAIN)
1127     }
1128 #endif
1129 
1130     if (relinquish_device)
1131         closeDevice();
1132 
1133     if (NasConfig.DoDebug > 2) {
1134         osLogMsg(" done.\n");
1135     }
1136 
1137     if (NasConfig.DoDebug) {
1138         UNIDENTMSG;
1139     }
1140 }
1141 
1142 static void
intervalProc(int sig)1143 intervalProc(int sig)
1144 {
1145     extern void AuProcessData();
1146 
1147 #if !defined(sco)
1148     setTimer(0);                /* turn off the timer here so that
1149                                    a potential race is avoided */
1150 
1151     if (processFlowEnabled)
1152         AuProcessData();
1153 
1154     setTimer(sndStatOut.curSampleRate);
1155 #else
1156     if (!audioBlocked && processFlowEnabled)
1157         AuProcessData();
1158 #endif /* sco */
1159 }
1160 
1161 /**
1162   * Gains are mapped thusly:
1163   *
1164   *   Software   s      0 - 100
1165   *   Hardware   h      0 - 100
1166 **/
1167 
1168 static void
setPhysicalOutputGain(AuFixedPoint gain)1169 setPhysicalOutputGain(AuFixedPoint gain)
1170 {
1171     AuInt32 g = AuFixedPointIntegralAddend(gain);
1172     AuInt32 gusvolume;
1173 
1174     if (g > 100)
1175         g = 100;
1176     if (g < 0)
1177         g = 0;
1178 
1179     if (sndStatOut.gainScale) {
1180         g *= sndStatOut.gainScale;
1181         g /= 100;
1182     }
1183 
1184     gusvolume = g | (g << 8);
1185     if (outmixerfd != -1)
1186         if (ioctl(outmixerfd, MIXER_WRITE(SOUND_MIXER_PCM), &gusvolume) == -1)
1187             osLogMsg("setPhysicalOutputGain: "
1188                      "%s: ioctl(MIXER_WRITE(SOUND_MIXER_PCM)) failed: %s\n",
1189                      sndStatOut.mixer, strerror(errno));
1190 }
1191 
1192 static AuFixedPoint
getPhysicalOutputGain(void)1193 getPhysicalOutputGain(void)
1194 {
1195     return AuFixedPointFromSum(readMixerOutputGain(), 0);
1196 }
1197 
1198 static void
setPhysicalInputGainAndLineMode(AuFixedPoint gain,AuUint8 lineMode)1199 setPhysicalInputGainAndLineMode(AuFixedPoint gain, AuUint8 lineMode)
1200 {
1201     AuInt16 g = AuFixedPointIntegralAddend(gain);
1202     AuInt16 inputAttenuation;
1203     AuInt16 zero = 0;
1204     int recsrc;
1205 
1206     if (g < 100)
1207         inputAttenuation = g;
1208     else
1209         inputAttenuation = 100;
1210 
1211     if (sndStatIn.gainScale) {
1212         inputAttenuation *= sndStatIn.gainScale;
1213         inputAttenuation /= 100;
1214     }
1215 
1216     if (lineMode == AuDeviceLineModeHigh) {
1217         recsrc = SOUND_MASK_MIC & recmask;
1218     } else if (lineMode == AuDeviceLineModeLow) {
1219         recsrc = SOUND_MASK_LINE & recmask;
1220     } else {
1221         osLogMsg("setPhysicalInputGainAndLineMode: illegal lineMode %d\n",
1222                  lineMode);
1223         recsrc = readMixerInputMode();
1224     }
1225 
1226     inputAttenuation = inputAttenuation << 8 | inputAttenuation;
1227 
1228     if (inmixerfd != -1) {
1229         switch (recControlMode) {
1230         case useMixerNone:
1231             break;
1232 
1233         case useMixerIGain:
1234             if (ioctl
1235                 (inmixerfd, MIXER_WRITE(SOUND_MIXER_IGAIN),
1236                  &inputAttenuation) == -1)
1237                 osLogMsg("setPhysicalInputGainAndLineMode: "
1238                          "%s: ioctl(MIXER_WRITE(SOUND_MIXER_IGAIN)) failed: "
1239                          "%s\n", sndStatIn.mixer, strerror(errno));
1240             break;
1241 
1242         case useMixerRecLev:
1243             if (ioctl
1244                 (inmixerfd, MIXER_WRITE(SOUND_MIXER_RECLEV),
1245                  &inputAttenuation) == -1)
1246                 osLogMsg("setPhysicalInputGainAndLineMode: "
1247                          "%s: ioctl(MIXER_WRITE(SOUND_MIXER_RECLEV)) failed: "
1248                          "%s\n", sndStatIn.mixer, strerror(errno));
1249             break;
1250 
1251         case useMixerLineMic:
1252             if (lineMode == AuDeviceLineModeHigh) {
1253                 if (ioctl(inmixerfd, MIXER_WRITE(SOUND_MIXER_LINE), &zero) ==
1254                     -1)
1255                     osLogMsg("setPhysicalInputGainAndLineMode: "
1256                              "%s: ioctl(MIXER_WRITE(SOUND_MIXER_LINE)) failed: "
1257                              "%s\n", sndStatIn.mixer, strerror(errno));
1258                 if (ioctl
1259                     (inmixerfd, MIXER_WRITE(SOUND_MIXER_MIC),
1260                      &inputAttenuation) == -1)
1261                     osLogMsg("setPhysicalInputGainAndLineMode: "
1262                              "%s: ioctl(MIXER_WRITE(SOUND_MIXER_MIC)) failed: "
1263                              "%s\n", sndStatIn.mixer, strerror(errno));
1264             } else if (lineMode == AuDeviceLineModeLow) {
1265                 if (ioctl
1266                     (inmixerfd, MIXER_WRITE(SOUND_MIXER_LINE),
1267                      &inputAttenuation) == -1)
1268                     osLogMsg("setPhysicalInputGainAndLineMode: "
1269                              "%s: ioctl(MIXER_WRITE(SOUND_MIXER_LINE)) failed: "
1270                              "%s\n", sndStatIn.mixer, strerror(errno));
1271                 if (ioctl(inmixerfd, MIXER_WRITE(SOUND_MIXER_MIC), &zero) ==
1272                     -1)
1273                     osLogMsg("setPhysicalInputGainAndLineMode: "
1274                              "%s: ioctl(MIXER_WRITE(SOUND_MIXER_MIC)) failed: "
1275                              "%s\n", sndStatIn.mixer, strerror(errno));
1276             }
1277             break;
1278 
1279         default:
1280             osLogMsg("setPhysicalInputGainAndLineMode: "
1281                      "unknown value %d of recControlMode\n", recControlMode);
1282             break;
1283         }
1284 
1285         if (ioctl(inmixerfd, MIXER_WRITE(SOUND_MIXER_RECSRC), &recsrc) == -1)
1286             osLogMsg("setPhysicalInputGainAndLineMode: "
1287                      "%s: ioctl(MIXER_WRITE(SOUND_MIXER_RECSRC)) failed: %s\n",
1288                      sndStatIn.mixer, strerror(errno));
1289     }
1290 }
1291 
1292 static AuFixedPoint
getPhysicalInputGain(void)1293 getPhysicalInputGain(void)
1294 {
1295     return AuFixedPointFromSum(readMixerInputGain(), 0);
1296 }
1297 
1298 static AuInt8
getPhysicalInputLineMode(void)1299 getPhysicalInputLineMode(void)
1300 {
1301     return mixerInputModeToNAS(readMixerInputMode());
1302 }
1303 
1304 static void
enableProcessFlow(void)1305 enableProcessFlow(void)
1306 {
1307 
1308     if (NasConfig.DoDebug) {
1309         osLogMsg("enableProcessFlow();\n");
1310     }
1311 
1312     if (relinquish_device) {
1313         openDevice(AuTrue);
1314         if (VOXReInitMixer && VOXMixerInit) {
1315             setMixerDefaults();
1316         }
1317     }
1318 
1319 #if defined(sco)
1320     if (!processFlowEnabled) {
1321         processFlowEnabled = AuTrue;
1322         setTimer(sndStatOut.curSampleRate);
1323     }
1324 #else  /* sco */
1325     processFlowEnabled = AuTrue;
1326 #endif /* sco */
1327 
1328 }
1329 
1330 static void
disableProcessFlow(void)1331 disableProcessFlow(void)
1332 {
1333 #ifndef sco
1334     int rate;
1335 
1336     processFlowEnabled = AuFalse;
1337 #endif /* sco */
1338 
1339     if (NasConfig.DoDebug) {
1340         osLogMsg("disableProcessFlow() - starting\n");
1341     }
1342 
1343 #ifdef sco
1344     if (processFlowEnabled) {
1345 #endif /* sco */
1346 
1347         ioctl(sndStatOut.fd, SNDCTL_DSP_SYNC, NULL);
1348 #ifndef sco
1349         rate = sndStatOut.curSampleRate;
1350         ioctl(sndStatOut.fd, SNDCTL_DSP_SPEED, &sndStatOut.curSampleRate);
1351         if (sndStatOut.forceRate)
1352             sndStatOut.curSampleRate = rate;
1353 #endif /* sco */
1354 
1355         if (sndStatOut.fd != sndStatIn.fd) {
1356             ioctl(sndStatIn.fd, SNDCTL_DSP_SYNC, NULL);
1357 #ifndef sco
1358             rate = sndStatOut.curSampleRate;
1359             ioctl(sndStatIn.fd, SNDCTL_DSP_SPEED,
1360                   &sndStatIn.curSampleRate);
1361             if (sndStatIn.forceRate)
1362                 sndStatIn.curSampleRate = rate;
1363 #endif /* sco */
1364         }
1365 #ifdef sco
1366         oneMoreTick();
1367 #endif
1368 
1369 #ifdef sco
1370         processFlowEnabled = AuFalse;
1371 #endif
1372 
1373         if (relinquish_device)
1374             closeDevice();
1375 
1376         if (NasConfig.DoDebug) {
1377             osLogMsg("disableProcessFlow() - done;\n");
1378         }
1379 #ifdef sco
1380     }
1381 #endif /* sco */
1382 }
1383 
1384 
1385 #if defined(__GNUC__) && !defined(linux) && !defined(__GNU__) && !defined(__GLIBC__) && !defined(USL) && !defined(__CYGWIN__)
1386 inline
1387 #endif
1388         static void
monoToStereoLinearSigned16LSB(AuUint32 numSamples)1389 monoToStereoLinearSigned16LSB(AuUint32 numSamples)
1390 {
1391     AuInt16 *s = (AuInt16 *) monoOutputDevice->minibuf;
1392     AuInt16 *d = (AuInt16 *) stereoOutputDevice->minibuf;
1393 
1394     while (numSamples--) {
1395         *d++ = *s;
1396         *d++ = *s++;
1397     }
1398 }
1399 
1400 #if defined(__GNUC__) && !defined(linux) && !defined(__GNU__) && !defined(__GLIBC__) && !defined(USL) && !defined(__CYGWIN__)
1401 inline
1402 #endif
1403         static void
monoToStereoLinearUnsigned8(AuUint32 numSamples)1404 monoToStereoLinearUnsigned8(AuUint32 numSamples)
1405 {
1406     AuUint8 *s = (AuUint8 *) monoOutputDevice->minibuf;
1407     AuUint8 *d = (AuUint8 *) stereoOutputDevice->minibuf;
1408 
1409     while (numSamples--) {
1410         *d++ = *s;
1411         *d++ = *s++;
1412     }
1413 }
1414 
1415 static void
writePhysicalOutputsMono(void)1416 writePhysicalOutputsMono(void)
1417 {
1418     AuBlock l;
1419     void *buf;
1420     int bufSize;
1421 
1422     if (sndStatOut.isStereo) {
1423         switch (monoOutputDevice->format) {
1424         case AuFormatLinearSigned16LSB:
1425             monoToStereoLinearSigned16LSB(monoOutputDevice->
1426                                           minibufSamples);
1427             break;
1428 
1429         case AuFormatLinearUnsigned8:
1430             monoToStereoLinearUnsigned8(monoOutputDevice->minibufSamples);
1431             break;
1432 
1433         default:
1434             /* check createServerComponents(...)! */
1435             assert(0);
1436         }
1437 
1438         buf = stereoOutputDevice->minibuf;
1439         bufSize = stereoOutputDevice->bytesPerSample
1440                 * monoOutputDevice->minibufSamples;
1441     } else {
1442         buf = monoOutputDevice->minibuf;
1443         bufSize = monoOutputDevice->bytesPerSample
1444                 * monoOutputDevice->minibufSamples;
1445     }
1446 
1447     l = AuBlockAudio();
1448     write(sndStatOut.fd, buf, bufSize);
1449 
1450 #ifdef DEBUGDSPOUT
1451     {
1452         char tempbuf[80];
1453 
1454         snprintf(tempbuf, sizeof tempbuf, "\nwriteMono buf: %d size: %d\n",
1455                  buf, bufSize);
1456         write(dspout, tempbuf, strlen(tempbuf));
1457         write(dspout, buf, bufSize);
1458     }
1459 #endif /* DEBUGDSPOUT */
1460 
1461     AuUnBlockAudio(l);
1462 }
1463 
1464 #if defined(__GNUC__) && !defined(linux) && !defined(__GNU__) && !defined(__GLIBC__) && !defined(USL) && !defined(__CYGWIN__)
1465 inline
1466 #endif
1467         static void
stereoToMonoLinearSigned16LSB(AuUint32 numSamples)1468 stereoToMonoLinearSigned16LSB(AuUint32 numSamples)
1469 {
1470     AuInt16 *s = (AuInt16 *) stereoOutputDevice->minibuf;
1471     AuInt16 *d = (AuInt16 *) monoOutputDevice->minibuf;
1472 
1473     while (numSamples--) {
1474         *d++ = (s[0] + s[1]) / 2;
1475         s += 2;
1476     }
1477 }
1478 
1479 #if defined(__GNUC__) && !defined(linux) && !defined(__GNU__) && !defined(__GLIBC__) && !defined(USL) && !defined(__CYGWIN__)
1480 inline
1481 #endif
1482         static void
stereoToMonoLinearUnsigned8(AuUint32 numSamples)1483 stereoToMonoLinearUnsigned8(AuUint32 numSamples)
1484 {
1485     AuUint8 *s = (AuUint8 *) stereoOutputDevice->minibuf;
1486     AuUint8 *d = (AuUint8 *) monoOutputDevice->minibuf;
1487 
1488     while (numSamples--) {
1489         *d++ = (s[0] + s[1]) / 2;
1490         s += 2;
1491     }
1492 }
1493 
1494 static void
writePhysicalOutputsStereo(void)1495 writePhysicalOutputsStereo(void)
1496 {
1497     AuBlock l;
1498     void *buf;
1499     int bufSize;
1500 
1501     if (sndStatOut.isStereo) {
1502         buf = stereoOutputDevice->minibuf;
1503         bufSize = stereoOutputDevice->bytesPerSample
1504                 * stereoOutputDevice->minibufSamples;
1505     } else {
1506         switch (stereoOutputDevice->format) {
1507         case AuFormatLinearSigned16LSB:
1508             stereoToMonoLinearSigned16LSB(stereoOutputDevice->
1509                                           minibufSamples);
1510             break;
1511 
1512         case AuFormatLinearUnsigned8:
1513             stereoToMonoLinearUnsigned8(stereoOutputDevice->
1514                                         minibufSamples);
1515             break;
1516 
1517         default:
1518             /* check createServerComponents(...)! */
1519             assert(0);
1520         }
1521 
1522         buf = monoOutputDevice->minibuf;
1523         bufSize = monoOutputDevice->bytesPerSample
1524                 * stereoOutputDevice->minibufSamples;
1525     }
1526 
1527     l = AuBlockAudio();
1528     write(sndStatOut.fd, buf, bufSize);
1529 
1530 #ifdef DEBUGDSPOUT
1531     {
1532         char tempbuf[80];
1533 
1534         snprintf(tempbuf, sizeof tempbuf, "\nwriteStereo buf: %d size: %d\n",
1535                  buf, bufSize);
1536         write(dspout, tempbuf, strlen(tempbuf));
1537         write(dspout, buf, bufSize);
1538     }
1539 #endif /* DEBUGDSPOUT */
1540 
1541     AuUnBlockAudio(l);
1542 }
1543 
1544 static void
writePhysicalOutputsBoth(void)1545 writePhysicalOutputsBoth(void)
1546 {
1547     AuInt16 *m = (AuInt16 *) monoOutputDevice->minibuf;
1548     AuInt16 *p, *s;
1549     AuUint8 *m8 = (AuUint8 *) monoOutputDevice->minibuf;
1550     AuUint8 *p8, *s8;
1551     AuUint32 max = aumax(monoOutputDevice->minibufSamples,
1552                          stereoOutputDevice->minibufSamples);
1553     AuUint32 i;
1554 
1555     switch (stereoOutputDevice->format) {
1556     case AuFormatLinearSigned16LSB:
1557         p = s = (AuInt16 *) stereoOutputDevice->minibuf;
1558 
1559         for (i = 0; i < max; i++) {
1560             *p++ = (*m + *s++) / 2;
1561             *p++ = (*m++ + *s++) / 2;
1562         }
1563         break;
1564 
1565     case AuFormatLinearUnsigned8:
1566         p8 = s8 = (AuUint8 *) stereoOutputDevice->minibuf;
1567 
1568         for (i = 0; i < max; i++) {
1569             *p8++ = (*m8 + *s8++) / 2;
1570             *p8++ = (*m8++ + *s8++) / 2;
1571         }
1572         break;
1573 
1574     default:
1575         assert(0);
1576     }
1577 
1578     stereoOutputDevice->minibufSamples = max;
1579 
1580     writePhysicalOutputsStereo();
1581 }
1582 
1583 static void
readPhysicalInputs(void)1584 readPhysicalInputs(void)
1585 {
1586     AuBlock l;
1587 
1588     /* Should make use of two input devices - FIXME */
1589 
1590     l = AuBlockAudio();
1591     read(sndStatIn.fd, stereoInputDevice->minibuf,
1592          stereoInputDevice->bytesPerSample * auMinibufSamples);
1593 
1594 #ifdef DEBUGDSPIN
1595     {
1596         char tempbuf[80];
1597         snprintf(tempbuf, sizeof tempbuf, "\nreadInputs buf: %d size: %d\n",
1598                 stereoInputDevice->minibuf,
1599                 stereoInputDevice->bytesPerSample * auMinibufSamples);
1600         write(dspin, tempbuf, strlen(tempbuf));
1601         write(dspin, stereoInputDevice->minibuf,
1602               stereoInputDevice->bytesPerSample * auMinibufSamples);
1603     }
1604 #endif /* DEBUGDSPIN */
1605 
1606     AuUnBlockAudio(l);
1607 }
1608 
1609 static void
noop(void)1610 noop(void)
1611 {
1612 }
1613 
1614 static void
setWritePhysicalOutputFunction(CompiledFlowPtr flow,void (** funct)(void))1615 setWritePhysicalOutputFunction(CompiledFlowPtr flow, void (**funct) (void))
1616 {
1617     AuUint32 mask = flow->physicalDeviceMask;
1618 
1619     if ((mask & (PhysicalOutputMono | PhysicalOutputStereo)) ==
1620         (PhysicalOutputMono | PhysicalOutputStereo))
1621         *funct = writePhysicalOutputsBoth;
1622     else if (mask & PhysicalOutputMono)
1623         *funct = writePhysicalOutputsMono;
1624     else if (mask & PhysicalOutputStereo)
1625         *funct = writePhysicalOutputsStereo;
1626     else
1627         *funct = noop;
1628 }
1629 
1630 /*
1631  * Setup soundcard at maximum audio quality.
1632  */
1633 
1634 #if defined(__FreeBSD__)
1635 #define NO_16_BIT_SAMPLING
1636 #endif
1637 
1638 static void
setupSoundcard(SndStat * sndStatPtr)1639 setupSoundcard(SndStat * sndStatPtr)
1640 {
1641 
1642     if (NasConfig.DoDebug) {
1643         osLogMsg("setupSoundcard(...);\n");
1644         IDENTMSG;
1645     }
1646 
1647     if (NasConfig.DoDebug)
1648         if (sndStatPtr == &sndStatOut) {
1649             osLogMsg("++ Setting up Output device (%s)\n",
1650                      sndStatPtr->device);
1651         } else {
1652             osLogMsg("++ Setting up Input device (%s)\n",
1653                      sndStatPtr->device);
1654         }
1655 
1656 
1657     if (sndStatPtr->isPCSpeaker) {
1658         if (NasConfig.DoDebug)
1659             osLogMsg("+++ Device is a PC speaker\n");
1660         sndStatPtr->curSampleRate = sndStatPtr->maxSampleRate
1661                 = sndStatPtr->minSampleRate = 8000;
1662         sndStatPtr->isStereo = 0;
1663         sndStatPtr->wordSize = 8;
1664     } else {
1665         if (NasConfig.DoDebug)
1666             osLogMsg("+++ requesting wordsize of %d, ",
1667                      sndStatPtr->wordSize);
1668         if (ioctl
1669             (sndStatPtr->fd, SNDCTL_DSP_SAMPLESIZE, &sndStatPtr->wordSize)
1670             || sndStatPtr->wordSize != 16) {
1671             sndStatPtr->wordSize = 8;
1672             ioctl(sndStatPtr->fd, SNDCTL_DSP_SAMPLESIZE,
1673                   &sndStatPtr->wordSize);
1674         }
1675         if (NasConfig.DoDebug)
1676             osLogMsg("got %d\n", sndStatPtr->wordSize);
1677 
1678         if (NasConfig.DoDebug)
1679             osLogMsg("+++ requesting %d channel(s), ",
1680                      sndStatPtr->isStereo + 1);
1681         if (ioctl(sndStatPtr->fd, SNDCTL_DSP_STEREO, &sndStatPtr->isStereo)
1682             == -1 || !sndStatPtr->isStereo) {
1683             sndStatPtr->isStereo = 0;
1684             ioctl(sndStatPtr->fd, SNDCTL_DSP_STEREO,
1685                   &sndStatPtr->isStereo);
1686         }
1687         if (NasConfig.DoDebug)
1688             osLogMsg("got %d channel(s)\n", sndStatPtr->isStereo + 1);
1689 
1690         if (NasConfig.DoDebug)
1691             osLogMsg("+++ Requesting minimum sample rate of %d, ",
1692                      sndStatPtr->minSampleRate);
1693         ioctl(sndStatPtr->fd, SNDCTL_DSP_SPEED,
1694               &sndStatPtr->minSampleRate);
1695         if (NasConfig.DoDebug)
1696             osLogMsg("got %d\n", sndStatPtr->minSampleRate);
1697 
1698         if (NasConfig.DoDebug)
1699             osLogMsg("+++ Requesting maximum sample rate of %d, ",
1700                      sndStatPtr->maxSampleRate);
1701         ioctl(sndStatPtr->fd, SNDCTL_DSP_SPEED,
1702               &sndStatPtr->maxSampleRate);
1703         if (NasConfig.DoDebug)
1704             osLogMsg("got %d\n", sndStatPtr->maxSampleRate);
1705 
1706         sndStatPtr->curSampleRate = sndStatPtr->maxSampleRate;
1707 
1708     }
1709 
1710 #if defined(SNDCTL_DSP_SETFRAGMENT)
1711     setFragmentSize(sndStatPtr);
1712 #endif
1713 
1714     UNIDENTMSG;
1715 }
1716 
1717 
1718 #ifdef sco
1719 static AuBool
scoInterrupts(void)1720 scoInterrupts(void)
1721 {
1722     struct sigaction act;
1723 
1724     act.sa_handler = intervalProc;
1725     act.sa_flags = 0;
1726     sigemptyset(&act.sa_mask);
1727     sigaddset(&act.sa_mask, SIGALRM);
1728     if (sigaction(SIGALRM, &act, (struct sigaction *) NULL) == -1) {
1729         ErrorF("sigaction SIGALRM");
1730         return FALSE;
1731     }
1732 
1733     return TRUE;
1734 }
1735 #endif /* sco */
1736 
1737 static AuBool
initMixer(void)1738 initMixer(void)
1739 {
1740     unsigned int extramode = 0;
1741 
1742 #if defined(__CYGWIN__)         /* we want the file to be created if necc under
1743                                    windows */
1744     extramode = O_CREAT;
1745 #endif
1746 
1747     /* open output mixer device */
1748     if (sndStatOut.mixer[0] != '\0') {
1749         if ((outmixerfd=open(sndStatOut.mixer, O_RDWR|extramode, 0666)) == -1) {
1750             UNIDENTMSG;
1751             osLogMsg("initMixer: could not open output mixer device %s: %s\n",
1752                      sndStatOut.mixer, strerror(errno));
1753             return AuFalse;
1754         }
1755         if (NasConfig.DoDebug)
1756             osLogMsg("initMixer: opened output mixer device %s\n",
1757                      sndStatOut.mixer, outmixerfd);
1758     } else {
1759         if (NasConfig.DoDebug)
1760             osLogMsg("initMixer: no output mixer device specified\n");
1761     }
1762 
1763     /* open input mixer device */
1764     if (sndStatIn.mixer[0] != '\0') {
1765         if (strcmp(sndStatIn.mixer, sndStatOut.mixer) != 0) {
1766             if ((inmixerfd = open(sndStatIn.mixer, O_RDWR | extramode,
1767                                 0666)) == -1) {
1768                 UNIDENTMSG;
1769                 osLogMsg("initMixer: could not open input mixer device %s: %s\n"
1770                          , sndStatIn.mixer, strerror(errno));
1771                 if (outmixerfd != -1) {
1772                     osLogMsg("initMixer: using output mixer %s for input\n",
1773                              sndStatOut.mixer);
1774                     share_mixer = AuTrue;
1775                     inmixerfd = outmixerfd;
1776                     sndStatIn.mixer = sndStatOut.mixer;
1777                 } else {
1778                     return AuFalse;
1779                 }
1780             }
1781         } else {
1782             share_mixer = AuTrue;
1783             inmixerfd = outmixerfd;
1784             sndStatIn.mixer = sndStatOut.mixer;
1785             if (NasConfig.DoDebug)
1786                 osLogMsg("initMixer: using the same mixer device for"
1787                          " in- and output\n");
1788         }
1789         if (NasConfig.DoDebug)
1790             osLogMsg("initMixer: opened input mixer device %s\n",
1791                      sndStatIn.mixer, inmixerfd);
1792     } else {
1793         if (NasConfig.DoDebug)
1794             osLogMsg("initMixer: no input mixer device specified\n");
1795         return AuTrue;
1796     }
1797 
1798     /* get recording devices of input mixer */
1799     if (ioctl(inmixerfd, SOUND_MIXER_READ_DEVMASK, &devmask) == -1) {
1800         osLogMsg("initMixer: %s: ioctl(SOUND_MIXER_READ_DEVMASK) failed: %s\n",
1801                  sndStatIn.mixer, strerror(errno));
1802         osLogMsg("initMixer: closing input mixer device\n");
1803         close(inmixerfd);
1804         inmixerfd = -1;
1805     } else {
1806         if (devmask & (1 << SOUND_MIXER_IGAIN)) {
1807             recControlMode = useMixerIGain;
1808         } else if (devmask & (1 << SOUND_MIXER_RECLEV)) {
1809             recControlMode = useMixerRecLev;
1810         } else if ((devmask & (1 << SOUND_MIXER_LINE)) ||
1811                    (devmask & (1 << SOUND_MIXER_MIC))) {
1812             recControlMode = useMixerLineMic;
1813         } else {
1814             recControlMode = useMixerNone;
1815             osLogMsg("initMixer: %s: can't control recording level\n",
1816                      sndStatIn.mixer);
1817         }
1818 
1819         if (NasConfig.DoDebug)
1820             osLogMsg("initMixer: %s: using recording level control method %d\n",
1821                      sndStatIn.mixer, recControlMode);
1822 
1823         if (ioctl(inmixerfd, SOUND_MIXER_READ_RECMASK, &recmask) == -1) {
1824             osLogMsg("initMixer: %s: ioctl(SOUND_MIXER_READ_RECMASK) failed: "
1825                      "%s\n", sndStatIn.mixer, strerror(errno));
1826             return AuFalse;
1827         }
1828     }
1829     return AuTrue;
1830 }
1831 
1832 AuBool
AuInitPhysicalDevices(void)1833 AuInitPhysicalDevices(void)
1834 {
1835     static AuBool AL_initialized = AuFalse;
1836     static AuUint8 *physicalBuffers;
1837     AuUint32 physicalBuffersSize;
1838     extern AuUint8 *auPhysicalOutputBuffers;
1839     extern AuUint32 auPhysicalOutputBuffersSize;
1840     extern void AuProcessData();
1841     unsigned int extramode = 0; /* for extra open modes (cygwin) */
1842 #if defined(AUDIO_GETINFO)
1843     audio_info_t spkrinf;
1844 #endif
1845 
1846 #if defined(__CYGWIN__)
1847     extramode = O_CREAT;
1848 #endif
1849 
1850     if (NasConfig.DoDebug) {
1851         osLogMsg("AuInitPhysicalDevices();\n");
1852         IDENTMSG;
1853     }
1854 
1855     if (NasConfig.DoDeviceRelease) {
1856         relinquish_device = AuTrue;
1857         if (NasConfig.DoDebug)
1858             osLogMsg("Init: will close device when finished with stream.\n");
1859     } else {
1860         relinquish_device = AuFalse;
1861         if (NasConfig.DoDebug)
1862             osLogMsg("Init: will open device exclusivly.\n");
1863     }
1864 
1865     if (NasConfig.DoKeepMixer) {
1866         if (NasConfig.DoDebug) {
1867             osLogMsg("Init: will keep mixer device open.\n");
1868         }
1869     } else {
1870         if (NasConfig.DoDebug) {
1871             osLogMsg("Init: will close mixer device when closing audio device.\n");
1872         }
1873     }
1874 
1875     if (VOXMixerInit) {
1876         leave_mixer = AuFalse;
1877         if (NasConfig.DoDebug)
1878             osLogMsg("Init: will initialize mixer device options.\n");
1879     } else {
1880         leave_mixer = AuTrue;
1881         if (NasConfig.DoDebug)
1882             osLogMsg("Init: Leaving the mixer device options alone at startup.\n");
1883     }
1884 
1885     /*
1886      * create the input and output ports
1887      */
1888     if (!AL_initialized) {
1889         int fd;
1890 
1891         AL_initialized = AuTrue;
1892 
1893         if (sndStatOut.autoOpen) {
1894             if (sndStatOut.device[0] != '\0') {
1895                 if (NasConfig.DoDebug)
1896                     osLogMsg("Init: openDevice OUT %s mode %d\n",
1897                              sndStatOut.device, sndStatOut.howToOpen);
1898 
1899                 if ((fd = open(sndStatOut.device,
1900 #if defined(__FreeBSD__)
1901                                sndStatOut.howToOpen | extramode,
1902 #else
1903                                sndStatOut.howToOpen | O_SYNC | extramode,
1904 #endif
1905                                0)) == -1) {
1906                     UNIDENTMSG;
1907                     osLogMsg("Init: Output open(%s) failed: %s\n",
1908                              sndStatOut.device, strerror(errno));
1909                     return AuFalse;
1910                 }
1911                 sndStatOut.fd = fd;
1912 #if defined(AUDIO_GETINFO)
1913                 if (sndStatOut.isPCSpeaker) {
1914                     ioctl(fd, AUDIO_GETINFO, &spkrinf);
1915                     spkrinf.play.encoding = AUDIO_ENCODING_RAW;
1916                     ioctl(fd, AUDIO_SETINFO, &spkrinf);
1917                 }
1918 #endif
1919             } else {
1920                 if (NasConfig.DoDebug)
1921                     osLogMsg("Init: no output device specified\n");
1922             }
1923         }
1924 #ifdef DEBUGDSPOUT
1925         dspout = open("/tmp/dspout", O_WRONLY | O_CREAT, 00666);
1926 #endif
1927 #ifdef DEBUGDSPIN
1928         dspin = open("/tmp/dspin", O_WRONLY | O_CREAT, 00666);
1929 #endif
1930 
1931 
1932         if (sndStatIn.autoOpen) {
1933 
1934             if (sndStatIn.device[0] != '\0') {
1935                 if (NasConfig.DoDebug)
1936                     osLogMsg("Init: openDevice(1) IN %s mode %d\n",
1937                              sndStatIn.device, sndStatIn.howToOpen);
1938 
1939                 if ((fd =
1940                      open(sndStatIn.device, sndStatIn.howToOpen | extramode,
1941                           0)) != -1)
1942                     sndStatIn.fd = fd;
1943                 else {
1944                     sndStatIn.fd = sndStatOut.fd;
1945                     share_in_out = AuTrue;
1946                     osLogMsg("Init: Input open(%s) failed: %s, using output device\n", sndStatIn.device, strerror(errno));
1947                 }
1948             } else {
1949                 if (NasConfig.DoDebug)
1950                     osLogMsg("Init: no input device specified\n");
1951             }
1952         }
1953 
1954         if (sndStatOut.fd != -1)
1955             setupSoundcard(&sndStatOut);
1956         if ((sndStatIn.fd != -1) && (sndStatOut.fd != sndStatIn.fd))
1957             setupSoundcard(&sndStatIn);
1958 
1959         if (!sndStatOut.isPCSpeaker) {
1960             if (initMixer() == AuFalse) {
1961                 osLogMsg("Init: initMixer failed\n");
1962                 if (outmixerfd != -1) {
1963                     osLogMsg("Init: closing output mixer device\n");
1964                     close(outmixerfd);
1965                     outmixerfd = -1;
1966                 }
1967                 if (inmixerfd != -1) {
1968                     osLogMsg("Init: closing input mixer device\n");
1969                     close(inmixerfd);
1970                     inmixerfd = -1;
1971                 }
1972             } else {
1973                 if (NasConfig.DoDebug)
1974                     osLogMsg("Init: initMixer was successful\n");
1975             }
1976         }
1977     }
1978 
1979     if (physicalBuffers)
1980         aufree(physicalBuffers);
1981 
1982     auMinibufSamples = MAX_MINIBUF_SAMPLES;
1983 
1984     /* the output buffers need to be twice as large for output range checking */
1985     physicalBuffersSize = PhysicalTwoTrackBufferSize +  /* mono/stereo input */
1986             PhysicalOneTrackBufferSize * 2 +    /* mono output */
1987             PhysicalTwoTrackBufferSize * 2;     /* stereo output */
1988 
1989     if (!(physicalBuffers = (AuUint8 *) aualloc(physicalBuffersSize))) {
1990         UNIDENTMSG;
1991         return AuFalse;
1992     }
1993 
1994     auInput = physicalBuffers;
1995     auOutputMono = auInput + PhysicalTwoTrackBufferSize;
1996     auOutputStereo = auOutputMono + 2 * PhysicalOneTrackBufferSize;
1997 
1998     auPhysicalOutputBuffers = auOutputMono;
1999     auPhysicalOutputBuffersSize = physicalBuffersSize -
2000             PhysicalTwoTrackBufferSize;
2001 
2002     /*
2003      * Call AuProcessData() in signal handler often enough to drain the
2004      * input devices and keep the output devices full at the current
2005      * sample rate.
2006      */
2007 
2008     processFlowEnabled = AuFalse;
2009 
2010 #ifdef sco
2011     if (!scoInterrupts()) {
2012         return AuFalse;
2013     }
2014 #else
2015 
2016     enableIntervalProc();
2017 
2018 #endif /* sco */
2019 
2020     setTimer(0);
2021 
2022     AuRegisterCallback(AuCreateServerComponentsCB, createServerComponents);
2023     AuRegisterCallback(AuSetPhysicalOutputGainCB, setPhysicalOutputGain);
2024     AuRegisterCallback(AuGetPhysicalOutputGainCB, getPhysicalOutputGain);
2025     AuRegisterCallback(AuSetPhysicalInputGainAndLineModeCB,
2026                        setPhysicalInputGainAndLineMode);
2027     AuRegisterCallback(AuGetPhysicalInputGainCB, getPhysicalInputGain);
2028     AuRegisterCallback(AuGetPhysicalInputModeCB, getPhysicalInputLineMode);
2029     AuRegisterCallback(AuEnableProcessFlowCB, enableProcessFlow);
2030     AuRegisterCallback(AuDisableProcessFlowCB, disableProcessFlow);
2031     AuRegisterCallback(AuReadPhysicalInputsCB, readPhysicalInputs);
2032     AuRegisterCallback(AuSetWritePhysicalOutputFunctionCB,
2033                        setWritePhysicalOutputFunction);
2034 
2035     AuRegisterCallback(AuSetSampleRateCB, setSampleRate);
2036 
2037     /* bogus resource so we can have a cleanup function at server reset */
2038     AddResource(FakeClientID(SERVER_CLIENT),
2039                 CreateNewResourceType(serverReset), 0);
2040 
2041     UNIDENTMSG;
2042 
2043     return AuTrue;
2044 }
2045