Logo Search packages:      
Sourcecode: nas version File versions  Download package

ausuni.c

/* Unified NAS dda for Sun Sparc architecture

Copyright 1995, 1997, 1998, 2000 Charles Levert

Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:

The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.

Except as contained in this notice, the name of the copyright holder shall
not be used in advertising or otherwise to promote the sale, use or
other dealings in this Software without prior written authorization
from the copyright holder.

 $Id: ausuni.c,v 1.10 2004/06/20 23:27:09 jon Exp $


 HISTORY:

 John Wehle 12/10/2000:
        * ausuni.c: (errno.h): Include.  
                    (devAudioMode): New static variable.  
                    (openDevice): If open for O_RDWR fails
                                then retry open using O_WRONLY.
                    (AuInitPhysicalDevices): Likewise.   
                    (writeOutput): Check devAudioMode and
                                 reopen device if necessary.
                    (readPhysicalInputs): Likewise. 

 


*/

/**
 *
 * Copyright 1993 Network Computing Devices, Inc.
 *
 * Permission to use, copy, modify, distribute, and sell this software and its
 * documentation for any purpose is hereby granted without fee, provided that
 * the above copyright notice appear in all copies and that both that
 * copyright notice and this permission notice appear in supporting
 * documentation, and that the name Network Computing Devices, Inc. not be
 * used in advertising or publicity pertaining to distribution of this
 * software without specific, written prior permission.
 *
 * THIS SOFTWARE IS PROVIDED `AS-IS'.  NETWORK COMPUTING DEVICES, INC.,
 * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING WITHOUT
 * LIMITATION ALL IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
 * PARTICULAR PURPOSE, OR NONINFRINGEMENT.  IN NO EVENT SHALL NETWORK
 * COMPUTING DEVICES, INC., BE LIABLE FOR ANY DAMAGES WHATSOEVER, INCLUDING
 * SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES, INCLUDING LOSS OF USE, DATA,
 * OR PROFITS, EVEN IF ADVISED OF THE POSSIBILITY THEREOF, AND REGARDLESS OF
 * WHETHER IN AN ACTION IN CONTRACT, TORT OR NEGLIGENCE, ARISING OUT OF OR IN
 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 *
 * $NCDId$
 */

#define _AUSUN_C_ 1


#include <stdio.h>                        /* for sprintf */
#include <stdlib.h>                       /* for getenv */
#include <errno.h>
#include "dixstruct.h"                    /* for RESTYPE */
#include "os.h"                           /* for xalloc/xfree and NULL */
#include "nasconf.h"
#include <fcntl.h>
#include <stropts.h>
#include <string.h>                       /* for strcmp */
#ifndef SVR4
#include <sun/audioio.h>
#else                               /* SVR4 */
#include <sys/audioio.h>
#endif                                    /* SVR4 */
#include <audio/audio.h>
#include <audio/Aproto.h>
#include "au.h"

/* These constants are for SS5 and the like (SS4, ultra?) with a
   CS4231.  With SunOS 4.1.x on a SS5, make sure you have at least
   4.1.4 + patch 102387-06.  Solaris 2.5 is reported to work.  Can't
   speak for other CS4231 configurations.  */

#ifndef AUDIO_INTERNAL_CD_IN
#define AUDIO_INTERNAL_CD_IN 0x04
#endif /* not defined AUDIO_INTERNAL_CD_IN */
#ifndef SVR4
#ifndef AUDIO_DEV_CS4231
#define AUDIO_DEV_CS4231 5
#endif /* not defined AUDIO_DEV_CS4231 */
#endif /* not defined SVR4 */

#if defined(SYSV) || defined(SVR4)
#define signal sigset
#else
#define BSD_SIGNALS
#endif

static char name_am79c30[] = "SUNW,am79c30";
static char name_CS4231[]  = "SUNW,CS4231";
static char name_dbri[]    = "SUNW,dbri";
static char name_unknown[] = "unknown audio device";
static char *name_of_physical_device;     /* must point to one of the above */

/* pebl: on some solaris (for example sun rays) have pseudo audio devices as
   there are used for multiply users. The pseudo device is create by 'utadem'
   in /tmp/SUNWut/dev/utaudio/<literal>. It seems that sun uses/encourage to
   use the env AUDIODEV to point to the pseudo devide, so it should be checked
   before trying the default devices. If there is a pseodu device the ctl is
   /tmp/SUNWut/dev/utaudio/<literal>ctl. 
   http://www.sun.com/desktop/products/software/sunforum/sunforumnotes.html*/

static const char *const default_device = "/dev/audio";


extern int errno;

#ifndef SVR4
typedef int     audio_device_t;
#define IS_AMD(_t)            ((_t) == AUDIO_DEV_AMD)
#define IS_CS4231(_t)         ((_t) == AUDIO_DEV_CS4231)
#define IS_DBRI(_t) \
    ((_t) == AUDIO_DEV_SPEAKERBOX || (_t) == AUDIO_DEV_CODEC)
#else                               /* defined SVR4 */
#define IS_AMD(_t)      (!strcmp((_t).name, name_am79c30))
#define IS_CS4231(_t)   (!strcmp((_t).name, name_CS4231))
#define IS_DBRI(_t)     (!strcmp((_t).name, name_dbri))
#endif                                    /* defined SVR4 */

/**********************************************************************/

/* Local compilation options. */
#define ADD_OUTPUTS
#undef DEBUGLOG
#define REVERSE_WRITE
#undef DELAYED_TRIGGER
#define WRITE_EMPTY_ENABLE
#undef SEPARATE_CTLS
#define SYNC_PROCESS_ENABLED

/**********************************************************************/

extern void       AuNativeToULAW8();
extern void       AuULAW8ToNative();
extern void       AuProcessData();
static AuFixedPoint     getPhysicalFeedbackGain();
static AuFixedPoint     getPhysicalInputGain();
static AuUint8          getPhysicalInputMode();

/**********************************************************************/

static AuBool     is_cs4231_or_dbri;
static AuBool     relinquish_device = 0;
static int      devAudio = -1,
                devAudioCtl = -1,
#ifdef SEPARATE_CTLS
                devAudioCtl2 = -1,
#endif
              devAudioMode = O_RDWR,
                bufSize;
static volatile AuBool signalEnabled = 0;
#ifdef DELAYED_TRIGGER
static AuBool     delayedTrigger = 0;
#endif
static AuBool     pendingTrigger = AuFalse;
static AuInt32    chunksPerSignal;
static volatile audio_info_t syncAudioInfo;
static audio_info_t audioInfo;
static AuUint8 *auOutputMono,
               *auOutputStereo,
               *auOutputLeft,
               *auOutputRight,
               *auInput,                  /* mono or stereo */
               *emptyOutput;
static volatile AuBool updateSampleRate;
#ifdef SYNC_PROCESS_ENABLED
static volatile AuBool updateSyncAudioInfo;
#endif
static AuUint32 sampleRate,
#ifndef ADD_OUTPUTS
                theAverage,
#endif
               *leftSamples,
               *rightSamples,
               *monoSamples,
               *stereoSamples,
                availInputModes,
                availOutputModes;

extern AuInt32    auMinibufSamples;

char        *VENDOR_STRING;
#define     SUN_VENDOR        "Sun unified dda (running on %s)"
#define     SERVER_CLIENT           0
#define MINIBUF_SAMPLES       800
#define SIGNAL_RATE           10

#define auMinSampleRate       8000
static AuUint32   auMaxSampleRate;

#define auPhysicalOutputChangableMask \
      (AuCompDeviceGainMask | AuCompDeviceOutputModeMask)

#define auPhysicalOutputValueMask \
      (AuCompCommonAllMasks | \
       AuCompDeviceMinSampleRateMask | \
       AuCompDeviceMaxSampleRateMask | \
       AuCompDeviceOutputModeMask | \
       AuCompDeviceGainMask | \
       AuCompDeviceLocationMask | \
       AuCompDeviceChildrenMask)

#define auPhysicalInputValueMask \
      (AuCompCommonAllMasks | \
       AuCompDeviceMinSampleRateMask | \
       AuCompDeviceMaxSampleRateMask | \
       AuCompDeviceLocationMask | \
       AuCompDeviceGainMask)

#define auPhysicalFeedbackValueMask \
      (AuCompCommonAllMasks | \
       AuCompDeviceGainMask)

/**********************************************************************/

/* callback */
static AuStatus
createServerComponents(auServerDeviceListSize, auServerBucketListSize,
                   auServerRadioListSize, auServerMinRate,
                   auServerMaxRate)
AuUint32    *auServerDeviceListSize,
            *auServerBucketListSize,
            *auServerRadioListSize,
            *auServerMinRate,
            *auServerMaxRate;
{
      AuDeviceID  stereo,
                  mono,
                  left,
                  right;
      ComponentPtr      d,
                  *p;
      AuUint8     num;
      AuUint32    location;
      extern RESTYPE  auComponentType;
      extern ComponentPtr
            *auServerDevices,       /* array of devices */
            auDevices;              /* list of all devices */
      extern AuUint32 auNumServerDevices; /* number of devices */

#ifdef DEBUGLOG
      fprintf(stderr, "createServerComponents()\n");
      fflush(stderr);
#endif

      *auServerMinRate = auMinSampleRate;
      *auServerMaxRate = auMaxSampleRate;

      auNumServerDevices
            = *auServerDeviceListSize
            = *auServerBucketListSize
            = *auServerRadioListSize
            = 0;

      if (is_cs4231_or_dbri) {
            AU_ALLOC_DEVICE(d, 1, 0);
            d->id = left = FakeClientID(SERVER_CLIENT);
            d->changableMask = auPhysicalOutputChangableMask;
            d->valueMask = auPhysicalOutputValueMask;
            d->kind = AuComponentKindPhysicalOutput;
            d->use = AuComponentUseExportMask;
            d->access = AuAccessExportMask | AuAccessListMask;
            d->format = auNativeFormat;
            d->numTracks = 1;
            d->description.type = AuStringLatin1;
            d->description.string = "Left Channel Output";
            d->description.len = strlen(d->description.string);
            d->minSampleRate = auMinSampleRate;
            d->maxSampleRate = auMaxSampleRate;
            d->location = AuDeviceLocationLeftMask;
            d->numChildren = 0;
            d->minibuf = auOutputLeft;
            d->minibufSize = auMinibufSamples * auNativeBytesPerSample *
                  d->numTracks;
            d->physicalDeviceMask = PhysicalOutputLeft;
            leftSamples = &d->minibufSamples;
            AU_ADD_DEVICE(d);

            AU_ALLOC_DEVICE(d, 1, 0);
            d->id = right = FakeClientID(SERVER_CLIENT);
            d->changableMask = auPhysicalOutputChangableMask;
            d->valueMask = auPhysicalOutputValueMask;
            d->kind = AuComponentKindPhysicalOutput;
            d->use = AuComponentUseExportMask;
            d->access = AuAccessExportMask | AuAccessListMask;
            d->format = auNativeFormat;
            d->numTracks = 1;
            d->description.type = AuStringLatin1;
            d->description.string = "Right Channel Output";
            d->description.len = strlen(d->description.string);
            d->minSampleRate = auMinSampleRate;
            d->maxSampleRate = auMaxSampleRate;
            d->location = AuDeviceLocationRightMask;
            d->numChildren = 0;
            d->minibuf = auOutputRight;
            d->minibufSize = auMinibufSamples * auNativeBytesPerSample *
                  d->numTracks;
            d->physicalDeviceMask = PhysicalOutputRight;
            rightSamples = &d->minibufSamples;
            AU_ADD_DEVICE(d);
      }

      if (is_cs4231_or_dbri) {
            num = 2;
            location = AuDeviceLocationLeftMask |
                  AuDeviceLocationRightMask;
      } else {
            num = 0;
            location = AuDeviceLocationCenterMask |
                  AuDeviceLocationInternalMask;
      }
      AU_ALLOC_DEVICE(d, 1, num);
      d->id = mono = FakeClientID(SERVER_CLIENT);
      d->changableMask = auPhysicalOutputChangableMask;
      d->valueMask = auPhysicalOutputValueMask;
      d->kind = AuComponentKindPhysicalOutput;
      d->use = AuComponentUseExportMask;
      d->access = AuAccessExportMask | AuAccessListMask;
      d->format = auNativeFormat;
      d->numTracks = 1;
      d->description.type = AuStringLatin1;
      d->description.string = "Mono Channel Output";
      d->description.len = strlen(d->description.string);
      d->minSampleRate = auMinSampleRate;
      d->maxSampleRate = auMaxSampleRate;
      d->location = location;
      d->numChildren = num;
      if (is_cs4231_or_dbri) {
            d->children = (AuID *) ((AuUint8 *) d +
                              PAD4(sizeof(ComponentRec)));
            d->childSwap = (char *) (d->children + d->numChildren);
            d->children[0] = left;
            d->children[1] = right;
      }
      d->minibuf = auOutputMono;
      d->minibufSize = auMinibufSamples * auNativeBytesPerSample *
            d->numTracks;
      d->physicalDeviceMask = PhysicalOutputMono;
      monoSamples = &d->minibufSamples;
      AU_ADD_DEVICE(d);

      num = is_cs4231_or_dbri ? 2 : 1;
      AU_ALLOC_DEVICE(d, 2, num);
      d->id = stereo = FakeClientID(SERVER_CLIENT);
      d->changableMask = auPhysicalOutputChangableMask;
      d->valueMask = auPhysicalOutputValueMask;
      d->kind = AuComponentKindPhysicalOutput;
      d->use = AuComponentUseExportMask;
      d->access = AuAccessExportMask | AuAccessListMask;
      d->format = auNativeFormat;
      d->numTracks = 2;
      d->description.type = AuStringLatin1;
      d->description.string = "Stereo Channel Output";
      d->description.len = strlen(d->description.string);
      d->minSampleRate = auMinSampleRate;
      d->maxSampleRate = auMaxSampleRate;
      d->location = location;
      d->numChildren = num;
      d->children = (AuID *) ((AuUint8 *) d + PAD4(sizeof(ComponentRec)));
      d->childSwap = (char *) (d->children + num);
      if (is_cs4231_or_dbri) {
            d->children[0] = left;
            d->children[1] = right;
      } else
            d->children[0] = mono;
      d->minibuf = auOutputStereo;
      d->minibufSize = auMinibufSamples * auNativeBytesPerSample *
            d->numTracks;
      d->physicalDeviceMask = PhysicalOutputStereo;
      stereoSamples = &d->minibufSamples;
      AU_ADD_DEVICE(d);

      /* same value; don't recompute */
      /* num = is_cs4231_or_dbri ? 2 : 1; */
      AU_ALLOC_DEVICE(d, num, 0);
      d->id = FakeClientID(SERVER_CLIENT);
      d->changableMask = AuCompDeviceGainMask;
      d->valueMask = auPhysicalFeedbackValueMask;
      d->kind = AuComponentKindPhysicalFeedback;
      d->use = 0;
      d->access = AuAccessListMask;
      d->format = 0;
      d->numTracks = num;
      d->description.type = AuStringLatin1;
      d->description.string = "Feedback";
      d->description.len = strlen(d->description.string);
      d->numChildren = 0;
      d->gain = getPhysicalFeedbackGain();
      d->lineMode = AuDeviceLineModeNone;
      d->physicalDeviceMask = (is_cs4231_or_dbri
                         ? PhysicalFeedbackStereo
                         : PhysicalFeedbackMono);
      d->minibuf = NULL;
      d->minibufSize = 0;
      AU_ADD_DEVICE(d);

      /* same value; don't recompute */
      /* num = is_cs4231_or_dbri ? 2 : 1; */
      AU_ALLOC_DEVICE(d, num, 0);
      d->id = FakeClientID(SERVER_CLIENT);
      if (is_cs4231_or_dbri) {
            d->changableMask = (AuCompDeviceGainMask |
                            AuCompDeviceLineModeMask);
            d->valueMask = (auPhysicalInputValueMask |
                        AuCompDeviceLineModeMask);
      } else {
            d->changableMask = AuCompDeviceGainMask;
            d->valueMask = auPhysicalInputValueMask;
      }
      d->kind = AuComponentKindPhysicalInput;
      d->use = AuComponentUseImportMask;
      d->access = AuAccessImportMask | AuAccessListMask;
      d->format = auNativeFormat;
      d->numTracks = num;
      d->description.type = AuStringLatin1;
      d->description.string = (is_cs4231_or_dbri
                         ? "Stereo Channel Input"
                         : "Mono Channel Input");
      d->description.len = strlen(d->description.string);
      d->minSampleRate = auMinSampleRate;
      d->maxSampleRate = auMaxSampleRate;
      /* External on most machines now */
      d->location = (AuDeviceLocationRightMask | AuDeviceLocationLeftMask |
                   AuDeviceLocationExternalMask);
      d->numChildren = 0;
      d->gain = getPhysicalInputGain();
      d->lineMode = getPhysicalInputMode();
      d->minibuf = auInput;
      d->minibufSize = auMinibufSamples * auNativeBytesPerSample *
            d->numTracks;
      d->physicalDeviceMask = (is_cs4231_or_dbri
                         ? PhysicalInputStereo
                         : PhysicalInputMono);
      AU_ADD_DEVICE(d);

      /* set the array of server devices */
      if (!(auServerDevices =
            (ComponentPtr *) aualloc(sizeof(ComponentPtr) *
                               auNumServerDevices)))
            return AuBadAlloc;

      p = auServerDevices;
      for (d = auDevices; d; d = d->next)
            *p++ = d;

      return AuSuccess;
}

static AuBool
openDevice(wait)
AuBool wait;
{
      audio_info_t info;
        const char *device = NULL;

      /* pebl: Check whether a pseudo device is used, else try the normal ones */
        if ((device = getenv("AUDIODEV")) == NULL)
          device = default_device;


      if (devAudio == -1)
        while ((devAudio = open(device, devAudioMode)) == -1 && wait)
          {
            if (errno == EINVAL && devAudioMode == O_RDWR)
            devAudioMode = O_WRONLY;
            sleep(5);
          }

      if (devAudio != -1) {
            if (is_cs4231_or_dbri) {
                  audioInfo.play.sample_rate
                        = audioInfo.record.sample_rate = sampleRate;
                  aucopy(&audioInfo, &info, sizeof(audio_info_t));
                  ioctl(devAudio, AUDIO_SETINFO, &info);
            }
            
            return AuTrue;
      }

      return AuFalse;
}

static void
closeDevice()
{
      if (devAudio != -1) {
            close(devAudio);
            devAudio = -1;
      }
}

/* cleanup function at server reset */
static void
serverReset()
{
#ifdef DEBUGLOG
      fprintf(stderr, "serverReset()\n");
      fflush(stderr);
#endif

      if (!relinquish_device || openDevice(AuFalse)) {
            signal(SIGPOLL, SIG_IGN);     /* discard pending signals */
            ioctl(devAudio, AUDIO_DRAIN, 0); /* drain everything out */
            if (relinquish_device)
                  closeDevice();
      }
}

static void
updateHardware()
{
      /* We don't delay updating anything that can be changed via
         audioCtl, possibly by some other application, anymore.
         Those values aren't cached in static variables either.
         This way, we can control the audio device through the
         server for immediate feedback only operations, which don't
         involve software manipulated audio data, without resorting
         to a non-NAS application. */

      if (updateSampleRate
#ifdef SYNC_PROCESS_ENABLED
          || updateSyncAudioInfo
#endif
            ) {
            audio_info_t info;

            ioctl(devAudioCtl, I_SETSIG, 0);    /* disable signal */

#ifdef SYNC_PROCESS_ENABLED
            if (updateSyncAudioInfo) {
                  ioctl(devAudioCtl, AUDIO_SETINFO, &syncAudioInfo);
                  AUDIO_INITINFO(&syncAudioInfo);
                  updateSyncAudioInfo = AuFalse;
            }

            if (updateSampleRate) {
#endif
                  AUDIO_INITINFO(&info);
                  info.play.sample_rate
                        = info.record.sample_rate
                        = sampleRate;
                  ioctl(devAudio, AUDIO_SETINFO, &info);
                  updateSampleRate = AuFalse;
#ifdef SYNC_PROCESS_ENABLED
            }
#endif

            if (signalEnabled)
                  ioctl(devAudioCtl, I_SETSIG, S_MSG);
      }
}

static void
setAudioCtlInfo()
{
#ifndef SEPARATE_CTLS
#ifdef SYNC_PROCESS_ENABLED
      if (signalEnabled)
            updateSyncAudioInfo = AuTrue;
      else {
#endif
            ioctl(devAudioCtl, I_SETSIG, 0);
            ioctl(devAudioCtl, AUDIO_SETINFO, &syncAudioInfo);
            AUDIO_INITINFO(&syncAudioInfo);
            if (signalEnabled)
                  ioctl(devAudioCtl, I_SETSIG, S_MSG);
#ifdef SYNC_PROCESS_ENABLED
      }
#endif
#else
      ioctl(devAudioCtl2, AUDIO_SETINFO, infoPtr);
#endif
}

/**
  * Gains are mapped thusly:
  *
  *   Software   0 - 49     50 - 100
  *   Hardware   0 - 49     50 - 255
  */
/* g in FixedPoint */
#define gain100togain255(g) (((g) < 0x320000) \
                       ? ((g) >> 16) \
                       : ((0x41999 * ((g) >> 9) - 0x4d77f100) >> 23))
      /* (g - 50) * (205 / 50) + 50 */
#define gain255togain100(g) (((g) < 50) \
                       ? AuFixedPointFromSum((g), 0) \
                       : ((((g) * 0x3e7064) >> 8) + 0x25ce0d))
      /* (g - 50) * (50 / 205) + 50 */


#ifdef SYNC_PROCESS_ENABLED
      /* We assume that AUDIO_INITINFO uses ~0 as a filler. This is
         because clients like aupanel do a get right after a set.  It's
         not a good thing to waste CPU like that, but it should not
         happen that often (usually in response to user action).  */

#define getCtl(info, field) \
      do { \
            while (~syncAudioInfo.field) /*  */ ; \
            ioctl(devAudioCtl, AUDIO_GETINFO, &(info)); \
      } while (0)
#else
#define getCtl(info, field) \
      ioctl(devAudioCtl, AUDIO_GETINFO, &(info))
#endif

/* callback */
static AuFixedPoint
getPhysicalOutputGain()
{
      audio_info_t info;

#ifdef DEBUGLOG
      fprintf(stderr, "getPhysicalOutputGain()\n");
      fflush(stderr);
#endif

      getCtl(info, play.gain);

      return gain255togain100(info.play.gain);
}

/* callback */
static void
setPhysicalOutputGain(gain)
AuFixedPoint gain;
{
#ifdef DEBUGLOG
      fprintf(stderr, "setPhysicalOutputGain(gain=%08d)\n", gain);
      fflush(stderr);
#endif

      syncAudioInfo.play.gain = gain100togain255(gain);
      setAudioCtlInfo();
}

/* callback */
static AuFixedPoint
getPhysicalFeedbackGain()
{
      audio_info_t info;

#ifdef DEBUGLOG
      fprintf(stderr, "getPhysicalFeedbackGain()\n");
      fflush(stderr);
#endif

      getCtl(info, monitor_gain);

      return gain255togain100(info.monitor_gain);
}

/* callback */
static void
setPhysicalFeedbackGain(gain)
AuFixedPoint gain;
{
#ifdef DEBUGLOG
      fprintf(stderr, "setPhysicalFeedbackGain(gain=%08d)\n", gain);
      fflush(stderr);
#endif

      syncAudioInfo.monitor_gain = gain100togain255(gain);
      setAudioCtlInfo();
}

/* callback */
static AuUint8
getPhysicalOutputMode()
{
      AuUint8 mode = 0;
      audio_info_t info;

#ifdef DEBUGLOG
      fprintf(stderr, "getPhysicalOutputMode()\n");
      fflush(stderr);
#endif

      getCtl(info, play.port);

      if (info.play.port & AUDIO_HEADPHONE)
            mode |= AuDeviceOutputModeHeadphone;

      if (info.play.port & AUDIO_SPEAKER)
            mode |= AuDeviceOutputModeSpeaker;

      if (info.play.port & AUDIO_LINE_OUT)
            mode |= AuDeviceOutputModeLineOut;

      return mode;
}

/* callback */
static void
setPhysicalOutputMode(lineMode)
AuUint8 lineMode;
{
#ifdef DEBUGLOG
      fprintf(stderr, "setPhysicalOutputMode(=%d)\n", lineMode);
      fflush(stderr);
#endif

      if (name_of_physical_device == name_am79c30) {
            /* Must implement some kind of a toggle in this case.
               (One and only one behavior.) */

            /* We absolutely must do this before changing
                   syncAudioInfo.  */
            AuUint8 oldLineMode = getPhysicalOutputMode();

            if (lineMode & ~oldLineMode)
                  lineMode &= ~oldLineMode;
      }

#ifdef SYNC_PROCESS_ENABLED
      {
            AuBlock l = AuBlockAudio();
#endif

            /* A final value of zero is allowed for output (play).  */
            /* Any number of bits can be set.  */
            syncAudioInfo.play.port = 0;

            if (lineMode & AuDeviceOutputModeHeadphone)
                  syncAudioInfo.play.port |= AUDIO_HEADPHONE;

            if (lineMode & AuDeviceOutputModeSpeaker)
                  syncAudioInfo.play.port |= AUDIO_SPEAKER;

            if (lineMode & AuDeviceOutputModeLineOut)
                  syncAudioInfo.play.port |= AUDIO_LINE_OUT;

            syncAudioInfo.play.port &= availOutputModes;

#ifdef SYNC_PROCESS_ENABLED
            AuUnBlockAudio(l);
      }
#endif

      setAudioCtlInfo();
}

/* callback */
static AuFixedPoint
getPhysicalInputGain()
{
      audio_info_t info;
      unsigned int g;

#ifdef DEBUGLOG
      fprintf(stderr, "getPhysicalInputGain()\n");
      fflush(stderr);
#endif

      getCtl(info, record.gain);
      g = info.record.gain;

      /* This little hack helps get/map/round up/map/set stability.
           Don't ask.  */
      if (is_cs4231_or_dbri && (g >= 50) && (g < 255))
            g -= 5;

      return gain255togain100(g);
}

/* callback */
static AuUint8
getPhysicalInputMode()
{
      AuUint8 mode = 0;
      audio_info_t info;

#ifdef DEBUGLOG
      fprintf(stderr, "getPhysicalInputMode()\n");
      fflush(stderr);
#endif

      getCtl(info, record.port);

      if (info.record.port & AUDIO_MICROPHONE)
            mode |= AuDeviceLineModeHigh;

      if (info.record.port & AUDIO_LINE_IN)
            mode |= AuDeviceLineModeLow;

#ifdef UNCOMMENT_THIS_WHEN_NAS_SUPPORTS_IT
      if (info.record.port & AUDIO_INTERNAL_CD_IN)
            mode |= AuDeviceLineModeInternalCD;
#endif

      return mode;
}

/* callback */
static void
setPhysicalInputGainAndLineMode(gain, lineMode)
AuFixedPoint      gain;
AuUint8           lineMode;
{
      AuUint32    newInputLineMode;

#ifdef DEBUGLOG
      fprintf(stderr,
            "setPhysicalInputGainAndLineMode(gain=%04x.%04x, lineMode=%u)\n",
            gain >> 16, gain & 0xffff, lineMode);
      fflush(stderr);
#endif

      syncAudioInfo.record.gain = gain100togain255(gain);

      /* one and only one bit must be set */
      if (lineMode == AuDeviceLineModeHigh)
            newInputLineMode = AUDIO_MICROPHONE;
      else if (lineMode == AuDeviceLineModeLow)
            newInputLineMode = AUDIO_LINE_IN;
#ifdef UNCOMMENT_THIS_WHEN_NAS_SUPPORTS_IT
      else if (lineMode == AuDeviceLineModeInternalCD)
            newInputLineMode = AUDIO_INTERNAL_CD_IN;
#endif
      else
            newInputLineMode = 0;

#if 0
      /* A value of zero is rejected by some drivers, so don't even try it. */
      /* XXX - Really?  Doesn't matter since zero does not even get here!  */
      if (newInputLineMode &= availInputModes)
#endif
            syncAudioInfo.record.port = newInputLineMode;

      setAudioCtlInfo();
}

/* A zero-length write() triggers a SIGPOLL. */
#define trigger() \
      write(devAudio, emptyOutput, 0)
#define triggerIfPending() \
      do { \
            if (pendingTrigger) { \
                  trigger(); \
                  pendingTrigger = AuFalse; \
            } \
      } while (0)
#ifdef REVERSE_WRITE
#define write0(buf, n) \
      do { triggerIfPending(); write(devAudio, buf, n); } while (0)
#else
#ifndef DELAYED_TRIGGER
#define write0(buf, n) \
      do { write(devAudio, buf, n); triggerIfPending(); } while (0)
#else
#define write0(buf, n) \
      do { write(devAudio, buf, n); delayedTrigger = AuTrue; } while (0)
#endif
#endif

/* Warning:  this function must be called between Au{Block,UnBlock}Audio,
 *   which is already the case in a BSD signal handler.  */
static void
writeEmptyOutput()
{
#ifndef BSD_SIGNALS
      AuBlock         l = AuBlockAudio();
#endif

#ifdef DEBUGLOG
      fprintf(stderr, "writeEmptyOutput(bufSize=%d)\n", bufSize);
      fflush(stderr);
#endif

      write0(emptyOutput, bufSize);

#ifndef BSD_SIGNALS
      AuUnBlockAudio(l);
#endif
}

/* callback */
static void
enableProcessFlow()
{
      AuBlock         l;

#ifdef DEBUGLOG
      fprintf(stderr, "\nenableProcessFlow()\n");
      fflush(stderr);
#endif

      if (relinquish_device)
            openDevice(AuTrue);
      ioctl(devAudio, I_FLUSH, FLUSHRW);  /* flush pending io */
      signalEnabled = AuTrue;
      ioctl(devAudioCtl, I_SETSIG, S_MSG);      /* enable signal */
      updateHardware();
      /* XXX - Shouldn't this be done only one time when audioctl is
           opened? */
      l = AuBlockAudio();
#if defined(REVERSE_WRITE) && defined(WRITE_EMPTY_ENABLE)
      pendingTrigger = AuTrue;
      writeEmptyOutput();
#else
#ifdef WRITE_EMPTY_ENABLE
      write(devAudio, emptyOutput,
            getenv("NAS_EMPTY_SIZE") ? atoi(getenv("NAS_EMPTY_SIZE")) : bufSize);
#endif
      trigger(); /* a SIGPOLL. */
#endif
      AuUnBlockAudio(l);
}

/* callback */
static void
disableProcessFlow()
{
#ifdef DEBUGLOG
      fprintf(stderr, "disableProcessFlow()\n");
      fflush(stderr);
#endif

      signalEnabled = AuFalse;
      ioctl(devAudioCtl, I_SETSIG, 0);    /* disable signal */

#if 0                           /* this seems to cause problems on some
                                   sun kernels/sound drivers */
      ioctl(devAudio, AUDIO_DRAIN, 0);    /* drain everything out */
#endif

      if (relinquish_device)
          closeDevice();
}

/* for CS4231 and dbri */
/* Warning:  this function must be called between Au{Block,UnBlock}Audio,
 *   which is already the case in a BSD signal handler.  */
static void
writeOutput(p, n)
AuInt16           *p;
unsigned int      n;
{
#ifndef BSD_SIGNALS
      AuBlock         l = AuBlockAudio();
#endif

#ifdef DEBUGLOG
      fprintf(stderr, "writeOutput(n=%d, n*4=%d)\n", n, n<<2);
      fflush(stderr);
#endif

   /*
    * The sbpro can only be opened for reading or for writing, not both.
    */
 
      if (! (devAudioMode == O_RDWR || devAudioMode == O_WRONLY))
        {
          closeDevice ();
          devAudioMode = O_WRONLY;
          openDevice (1);
        }
 

      write0(p, n << 2);

#ifndef BSD_SIGNALS
      AuUnBlockAudio(l);
#endif
}

/* for am79c30 */
/* Warning:  this function must be called between Au{Block,UnBlock}Audio,
 *   which is already the case in a BSD signal handler.  */
static void
writePhysicalOutput(p, n)
AuInt16           *p;
unsigned int      n;
{
#ifndef BSD_SIGNALS
      AuBlock l;
#endif

#ifdef DEBUGLOG
      fprintf(stderr, "writePhysicalOutput(n=%d)\n", n);
      fflush(stderr);
#endif

      AuNativeToULAW8(p, 1, n);
#ifndef BSD_SIGNALS
      l = AuBlockAudio();
#endif

      write0(p, n);

#ifndef BSD_SIGNALS
      AuUnBlockAudio(l);
#endif
}

/* for CS4231 and dbri */
static void
writeStereoOutput()
{
      writeOutput(auOutputStereo, *stereoSamples);
}

/* for am79c30 */
static void
writePhysicalOutputsStereo()
{
      AuInt32     i;
      AuInt16     *s,
            *m;

      s = (AuInt16 *) auOutputStereo;
      m = (AuInt16 *) auOutputMono;

      for (i = 0; i < *stereoSamples; i++, s += 2)
            *m++ = (s[0] + s[1]) >> 1;

      writePhysicalOutput(auOutputMono, *stereoSamples);
}

/* for CS4231 and dbri */
static void
writeMonoOutput()
{
      AuInt16     *m,
            *p;
      int   i;

      m = (AuInt16 *) auOutputMono;
      p = (AuInt16 *) auOutputStereo;

      for (i = 0; i < *monoSamples; i++) {
            *p++ = *m;
            *p++ = *m++;
      }

      writeOutput(auOutputStereo, *monoSamples);
}

/* for am79c30 */
static void
writePhysicalOutputsMono()
{
      writePhysicalOutput(auOutputMono, *monoSamples);
}

/* for CS4231 and dbri */
static void
writeAllOutputs()
{
      AuInt16     *l,
            *r,
            *m,
            *s,
            *p;
      int         i;
      unsigned int      n;
  
      l = (AuInt16 *) auOutputLeft;
      r = (AuInt16 *) auOutputRight;
      m = (AuInt16 *) auOutputMono;
      s = p = (AuInt16 *) auOutputStereo;
      n = aumax(aumax(*monoSamples, *stereoSamples),
              aumax(*leftSamples, *rightSamples));

      /* XXX - This assumes that any non participating flow has null value;
         true? */
      for (i = 0; i < n; i++) {
#ifndef ADD_OUTPUTS
            *p++ = ((*l++ + *m   + *s++) * theAverage) >> 16;
            *p++ = ((*r++ + *m++ + *s++) * theAverage) >> 16;
#else
            *p++ = (*l++ + *m   + *s++);
            *p++ = (*r++ + *m++ + *s++);
#endif
      }
  
      writeOutput(auOutputStereo, n);
}

/* for am79c30 */
static void
writePhysicalOutputsBoth()
{
      AuInt32           i;
      AuInt16           *s,
                  *m;
      AuUint32    n;

      s = (AuInt16 *) auOutputStereo;
      m = (AuInt16 *) auOutputMono;
      n = aumax(*monoSamples, *stereoSamples);

#ifndef ADD_OUTPUTS
      for (i = 0; i < n; i++, s += 2, m++)
            /* XXX - That's not right, conceptually. */
            /* beware: can't put m++ on this line because of
                   unknown order of eval */
            *m = ((s[0] + s[1] + *m) * 0x5555) >> 16;
#else
      for (i = 0; i < n; i++, s += 2)
            *m++ += (s[0] + s[1]) >> 1;
#endif

      writeOutput(auOutputMono, n);
}

/* callback */
static void
readPhysicalInputs()
{
#ifdef DEBUGLOG
  fprintf(stderr, "readPhysicalInputs()\n");
  fflush(stderr);
#endif

 
   /*
    * The sbpro can only be opened for reading or for writing, not both.
    */
  
  if (! (devAudioMode == O_RDWR || devAudioMode == O_RDONLY))
    {
      closeDevice ();
      devAudioMode = O_RDONLY;
      openDevice (1);
    }
  
  read(devAudio, auInput, bufSize);
  
  if (!is_cs4231_or_dbri)
    AuULAW8ToNative(auInput, 1, auMinibufSamples);
}

/* callback */
/* for am79c30 */
static void
setWritePhysicalOutputFunction(flow, funct)
CompiledFlowPtr   flow;
void        (**funct) ();
{
      AuUint32 mask = flow->physicalDeviceMask;

#ifdef DEBUGLOG
      fprintf(stderr, "setWritePhysicalOutputFunction()\n");
      fflush(stderr);
#endif

      if ((mask & (PhysicalOutputMono | PhysicalOutputStereo)) ==
          (PhysicalOutputMono | PhysicalOutputStereo))
            *funct = writePhysicalOutputsBoth;
      else if (mask & PhysicalOutputMono)
            *funct = writePhysicalOutputsMono;
      else if (mask & PhysicalOutputStereo)
            *funct = writePhysicalOutputsStereo;
      else
            *funct = writeEmptyOutput;
}

/* callback */
/* for CS4231 and dbri */
static void
setWriteOutputFunction(flow, funct)
CompiledFlowPtr   flow;
void        (**funct) ();
{
      AuUint32 mask = flow->physicalDeviceMask & AllPhysicalOutputs;

#ifdef DEBUGLOG
      fprintf(stderr, "setWriteOutputFunction()\n");
      fflush(stderr);
#endif

      if (mask)
            if (mask == PhysicalOutputMono)
                  *funct = writeMonoOutput;
            else if (mask == PhysicalOutputStereo)
                  *funct = writeStereoOutput;
            else {
#ifndef ADD_OUTPUTS
                  int both;

                  theAverage = 0x10000;

                  both = (mask & (PhysicalOutputLeft |
                              PhysicalOutputRight)) ? 1 : 0;

                  if (mask & PhysicalOutputMono)
                        both++;

                  if (mask & PhysicalOutputStereo)
                        both++;

                  if (both > 1)
                        theAverage /= both;
#endif

                  *funct = writeAllOutputs;
            } else
                  *funct = writeEmptyOutput;
}

/* signal handler */
#ifdef DEBUGLOG
#include <sys/time.h>
#endif
static void
processAudioSignal(sig)
int sig;
{
      int i;
#ifdef DEBUGLOG
      static struct timeval tv0;
      struct timeval tv1, tv2, tv3;
      long ds1, du1, ds2, du2, ds3, du3;

      fprintf(stderr, "processAudioSignal...\n");
      fflush(stderr);

      gettimeofday(&tv1, 0);
#endif /* DEBUGLOG */

      updateHardware();

#ifdef DEBUGLOG
      gettimeofday(&tv2, 0);
#endif /* DEBUGLOG */

      pendingTrigger = AuFalse;
      for (i = 0; i < chunksPerSignal - 1; i++)
            AuProcessData();

      pendingTrigger = AuTrue;
      AuProcessData();

#if defined(DELAYED_TRIGGER) && !defined(REVERSE_WRITE)
      if (delayedTrigger) {
            /* Here's the very reason delaying this is useful.
               Don't do it if AuProcessData() called
               disableProcessFlow() between the write and now. */
            if (signalEnabled)
                  trigger();  /* a SIGPOLL. */

            delayedTrigger = AuFalse;
      }
#endif /* DELAYED_TRIGGER && !REVERSE_WRITE*/

#ifdef DEBUGLOG
      gettimeofday(&tv3, 0);

#define tv_diff(tv_a, tv_b, ds, du) \
      do { \
            ds = tv_a.tv_sec - tv_b.tv_sec; \
            du = tv_a.tv_usec - tv_b.tv_usec; \
            if (du < 0) { \
                  --ds; \
                  du += 1000000L; \
            } \
      } while (0)

      tv_diff(tv1, tv0, ds1, du1);
      tv_diff(tv2, tv1, ds2, du2);
      tv_diff(tv3, tv2, ds3, du3);

#undef tv_diff

      tv0=tv1;

      fprintf(stderr,
            "...processAudioSignal [%ld.%06ld %ld.%06ld %ld.%06ld]\n",
            ds1, du1, ds2, du2, ds3, du3);
      fflush(stderr);
#endif /* DEBUGLOG */
}

/* callback */
/* for CS4231 and dbri */
static AuUint32
setSampleRate(rate)
AuUint32 rate;
{
      int             i;
      AuUint32        closestRate;
      static AuUint32 rates[] = {
            /* 5510, 6620, */
            8000, 9600, 11025, 16000, 18900, 22050,
            /* 27420, */
            32000,
            /* 33075, */
            37800, 44100, 48000
      };

      closestRate = 48000;

      for (i = 0; i < sizeof(rates) / sizeof(rates[0]); i++)
            if ((rates[i] >= rate) && (rates[i] < closestRate))
                  closestRate = rates[i];

      if (closestRate != sampleRate) {
            sampleRate = closestRate;
            updateSampleRate = AuTrue;
      }

      chunksPerSignal = sampleRate / SIGNAL_RATE / MINIBUF_SAMPLES;

#ifdef DEBUGLOG
      fprintf(stderr, "setSampleRate(rate=%d) --> %d\n", rate, closestRate);
      fflush(stderr);
#endif

      return closestRate;
}

#define     PhysicalOneTrackBufferSize \
      PAD4(auMinibufSamples * auNativeBytesPerSample * 1)
#define     PhysicalTwoTrackBufferSize \
      PAD4(auMinibufSamples * auNativeBytesPerSample * 2)

AuBool
AuInitPhysicalDevices()
{
      int         open_for_business;
      static AuUint8    *physicalBuffers;
      AuUint32    physicalBuffersSize;
      audio_info_t      info;
      extern AuUint32   auPhysicalOutputBuffersSize;
      extern AuUint8    *auPhysicalOutputBuffers;
      char        *nas_device_policy;

#ifdef DEBUGLOG
      fprintf(stderr, "AuInitPhysicalDevices()\n");
      fflush(stderr);
#endif

      if (VENDOR_STRING) {
            aufree(VENDOR_STRING);
            VENDOR_STRING = (char *) 0;
      }

      if (NasConfig.DoDeviceRelease) {
            relinquish_device = AuTrue;
            if (NasConfig.DoDebug)
                  osLogMsg("Init: will close device when finished with stream.\n");
      } else {
            relinquish_device = AuFalse;
            if (NasConfig.DoDebug)
                  osLogMsg("Init: will open device exclusively.\n");
      }

      if (devAudio == -1) {
            audio_device_t  type;
            const char *device = NULL;
            char *devicectl = NULL;

            /* pebl: Check whether a pseudo device is used, else try the normal one */
            if ((device = getenv("AUDIODEV")) == NULL)
              device = default_device;

#ifdef DEBUGLOG
            fprintf(stderr,"Trying device %s\n",device);
            fflush(stderr);
#endif

            devAudio = open(device, devAudioMode);
            if (devAudio == -1 && errno == EINVAL && 
                devAudioMode == O_RDWR)
              {
                devAudioMode = O_WRONLY;
                devAudio = open(device, devAudioMode);
              }
 

            /* pebl: We cannot just concat "ctl" on variable device, so
                   make a copy and concat "ctl".  (free it again) */
            if (!(devicectl = (char *) aualloc(strlen(device) +
                                       strlen("ctl"))))
              return AuFalse;
            sprintf(devicectl,"%sctl",device);

            open_for_business =
                  (devAudio != -1 &&
#ifdef SEPARATE_CTLS
                   (devAudioCtl2 = open(devicectl, O_RDWR)) != -1 &&
#endif
                   (devAudioCtl  = open(devicectl, O_RDWR)) != -1);

            aufree(devicectl);

            if (open_for_business) {
#ifndef AUDIO_GETDEV
                  name_of_physical_device = name_unknown;
#else  /* defined AUDIO_GETDEV */
                  if ((open_for_business =
                       (ioctl(devAudio, AUDIO_GETDEV, &type) != -1))) {
                        if (IS_AMD(type))
                              name_of_physical_device = name_am79c30;
                        else if (IS_CS4231(type))
                              name_of_physical_device = name_CS4231;
                        else if (IS_DBRI(type))
                              name_of_physical_device = name_dbri;
                        else
                              name_of_physical_device = name_unknown;
                  }
#endif /* defined AUDIO_GETDEV */
            }

            if (!open_for_business) {
                  if (devAudio != -1)
                        close(devAudio);
                  if (devAudioCtl != -1)
                        close(devAudioCtl);
#ifdef SEPARATE_CTLS
                  if (devAudioCtl2 != -1)
                        close(devAudioCtl2);
#endif
                  devAudio = devAudioCtl = -1;
                  name_of_physical_device = 0;
                  return AuFalse;
            }
      }

      if (!(VENDOR_STRING = (char *) aualloc(strlen(SUN_VENDOR) +
                                     strlen(name_of_physical_device)
                                     - 1)))
            return AuFalse;

      sprintf(VENDOR_STRING, SUN_VENDOR, name_of_physical_device);

      if (physicalBuffers) {
            aufree(physicalBuffers);
            physicalBuffers = 0;
      }

      if (emptyOutput) {
            aufree(emptyOutput);
            emptyOutput = 0;
      }

      is_cs4231_or_dbri =
            (name_of_physical_device == name_CS4231 ||
             name_of_physical_device == name_dbri);

      auMaxSampleRate = is_cs4231_or_dbri ? 48000 : 8000;

      auMinibufSamples = MINIBUF_SAMPLES;

      /* the output buffers need to be twice as large for output
           range checking */
      physicalBuffersSize =
            (PhysicalOneTrackBufferSize * 2 +   /* mono output */
             PhysicalTwoTrackBufferSize * 2);   /* stereo output */

      if (is_cs4231_or_dbri) {
            physicalBuffersSize +=
                  (PhysicalTwoTrackBufferSize + /* stereo input */
                   PhysicalOneTrackBufferSize * 2 + /* left output */
                   PhysicalOneTrackBufferSize * 2); /* right output */
            bufSize = MINIBUF_SAMPLES * 2 * 2;  /* stereo, 16 bits */
      } else {
            physicalBuffersSize +=
                  PhysicalTwoTrackBufferSize;   /* mono input */
            bufSize = MINIBUF_SAMPLES;          /* mono, 8 bits */
      }

      if (!(emptyOutput = (AuUint8 *) aualloc(bufSize)))
            return AuFalse;

      auset(emptyOutput,
            is_cs4231_or_dbri ? 0 : 0xff,
            bufSize);

      if (!(physicalBuffers = (AuUint8 *) aualloc(physicalBuffersSize)))
            return AuFalse;

      auInput = physicalBuffers;

      if (is_cs4231_or_dbri) {
            auOutputMono = auInput + PhysicalTwoTrackBufferSize;
            auOutputLeft = auOutputMono + 2 * PhysicalOneTrackBufferSize;
            auOutputRight = auOutputLeft + 2 * PhysicalOneTrackBufferSize;
            auOutputStereo = auOutputRight + 2 * PhysicalOneTrackBufferSize;

            auPhysicalOutputBuffersSize =
                  physicalBuffersSize - PhysicalTwoTrackBufferSize;
      } else {
            auOutputMono = auInput + PhysicalOneTrackBufferSize;
            auOutputStereo = auOutputMono + 2 * PhysicalOneTrackBufferSize;

            auPhysicalOutputBuffersSize =
                  physicalBuffersSize - PhysicalTwoTrackBufferSize;
      }

      auPhysicalOutputBuffers = auOutputMono;

      signal(SIGPOLL, processAudioSignal);

      AuRegisterCallback(AuCreateServerComponentsCB, createServerComponents);
      AuRegisterCallback(AuSetPhysicalOutputGainCB, setPhysicalOutputGain);
      AuRegisterCallback(AuGetPhysicalOutputGainCB, getPhysicalOutputGain);
      AuRegisterCallback(AuGetPhysicalOutputModeCB, getPhysicalOutputMode);
      AuRegisterCallback(AuSetPhysicalOutputModeCB, setPhysicalOutputMode);
      AuRegisterCallback(AuGetPhysicalFeedbackGainCB,
                     getPhysicalFeedbackGain);
      AuRegisterCallback(AuSetPhysicalFeedbackGainCB,
                     setPhysicalFeedbackGain);
      AuRegisterCallback(AuSetPhysicalInputGainAndLineModeCB,
                     setPhysicalInputGainAndLineMode);
      AuRegisterCallback(AuGetPhysicalInputGainCB, getPhysicalInputGain);
      AuRegisterCallback(AuGetPhysicalInputModeCB, getPhysicalInputMode);
      AuRegisterCallback(AuEnableProcessFlowCB, enableProcessFlow);
      AuRegisterCallback(AuDisableProcessFlowCB, disableProcessFlow);
      AuRegisterCallback(AuReadPhysicalInputsCB, readPhysicalInputs);

      if (is_cs4231_or_dbri) {
            AuRegisterCallback(AuSetWritePhysicalOutputFunctionCB,
                           setWriteOutputFunction);
            AuRegisterCallback(AuSetSampleRateCB, setSampleRate);
      } else {
            AuRegisterCallback(AuSetWritePhysicalOutputFunctionCB,
                           setWritePhysicalOutputFunction);
      }

      ioctl(devAudioCtl, AUDIO_GETINFO, &info);
      availInputModes = info.record.avail_ports;
      availOutputModes = info.play.avail_ports;
      sampleRate = info.play.sample_rate; /* XXX */
      chunksPerSignal = sampleRate / SIGNAL_RATE / MINIBUF_SAMPLES;

      AUDIO_INITINFO(&audioInfo);
      /* We only need to setup fields that differ from the open()
           defaults.  */
      if (is_cs4231_or_dbri) {
            audioInfo.play.encoding
                  = audioInfo.record.encoding = AUDIO_ENCODING_LINEAR;
            audioInfo.play.precision
                  = audioInfo.record.precision = 16;
            audioInfo.play.channels
                  = audioInfo.record.channels = 2;

            aucopy(&audioInfo, &info, sizeof(audio_info_t));
            ioctl(devAudio, AUDIO_SETINFO, &info);
      }

      AUDIO_INITINFO(&syncAudioInfo);

      /* bogus resource so we can have a cleanup function at server reset */
      AddResource(FakeClientID(SERVER_CLIENT),
                CreateNewResourceType(serverReset), 0);

      if (relinquish_device)
            closeDevice();

      return AuTrue;
}

Generated by  Doxygen 1.6.0   Back to index