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