\documentstyle{article}
%
\parskip=5pt plus 1pt minus 1pt
%
\title{The CARL Audio Switch Daemon}
%
\author{Rusty Wright \\*[3mm]
Computer Audio Research Laboratory \\
University of California San Diego}
%
\begin{document}
%
\pagestyle{headings}
%
\pagenumbering{roman}
%
\maketitle
\clearpage
%
\tableofcontents
\clearpage
%
\pagenumbering{arabic}
%
\section{Introduction}
The audio switch daemon is a program that manages an
audio switch.
When the audio switch daemon starts up it reads a
configuration file and then sets up an ipc socket
and then waits for connections to that socket.
Programs communicate with the daemon by connecting to
it via the ipc socket, send it commands, and recieve
the success/failure status from those commands.
An added bonus from the daemon using an ipc socket is
that it allows the audio
switch to be used in a distributed environment.
Also, since audio switch connections are mediated by a daemon,
the state of all connections is known by the daemon.
%
\section{Configuration File}
When the daemon starts it reads a configuration file.
This file sets the level for various error, debugging,
and informative messages. It also establishes the
symbolic names of the channels for the various input
spaces and output devices. It can also be used to
make static connections.
(Appendix~\ref{syntax-diagram} on page~\pageref{syntax-diagram}
gives a syntax diagram for the configuration file.)
%
\subsection{Configuration Variables}
Configuration variables can be changed with the \mbox{\tt set}
command. The syntax is
\begin{flushleft}
\verb"set ident =" {\em number\/};
\end{flushleft}
or
\begin{flushleft}
\verb"set ident =" \verb'"'{\em string\/}\verb'"';
\end{flushleft}
where \mbox{\em ident\/} is one of the configuration variables and
\mbox{\em number\/} is a non-negative integer and
\mbox{\em string\/} is a quoted string.
\par
Currently there are three configuration variables for logging messages;
\mbox{\tt error\_level}, \mbox{\tt info\_level}, and \mbox{\tt debug\_level}.
These control the logging of error messages, informative messages,
and debugging messages respectively. Inside the daemon are a number of
messages, each of which is in one of the above three classes and each
of which has a level. A log message of a particular level is logged when
bit $i$ that corresponds to that level is set in the configuration variable.
A setting of 0 for a configuration logging message turns off all messages
from that class.\footnote{Currently the messages aren't highly organized;
most messages are either level 1 or 2. What might be considered an
informative message is a matter of taste.} All of these logging messages
are sent to the \mbox{\tt syslog} daemon.
\par
There are other configuration variables that control other behavior of
the daemon. They change and the list grows so the sample configuration
file should be consulted for ones that are used here at CARL. The source
file \mbox{\tt conf.c} has the complete list of configuration variables.
%
\subsection{Symbolic Channel Names}
Channels can be given symbolic names with the commands \mbox{\tt output}
and \mbox{\tt input}. The syntax for these commands is
\begin{flushleft}
\verb"output" {\em ident\/} \verb"is" {\em numlist\/};
\end{flushleft}
or
\begin{flushleft}
\verb"input" {\em ident\/} \verb"is" {\em numlist\/};
\end{flushleft}
where \mbox{\em ident\/} is the symbolic name to be used for those
channels and \mbox{\em numlist\/} is a comma-separated list of
positive integers.
\par
These two commands
also associate a type (input or output) with a symbolic
name. An \mbox{\em output\/}
is one or more channels that are connected
to an output device (digital-to-audio converters, fm stereo,
etc.).
An \mbox{\em input\/} is one or more channels that are connected to
a listening space (auditorium, studio, office, etc.).
%
\subsection{Connect and Disconnect}
Connections are made and broken with the commands \mbox{\tt connect}
and \mbox{\tt disconnect}. When making connections, channels of the
same type cannot be connected together (inputs can't be connected to
inputs and outputs can't be connected to outputs).
The syntax for \mbox{\tt connect}
is
\begin{flushleft}
\verb"connect" {\em channel\/} \verb"to" {\em channel\/};
\end{flushleft}
\par
The \mbox{\tt disconnect} command has two forms. In the first form
both sides of the connection are given. In the second form only
one side of the connection need be given; everything that is
connected to it is disconnected from it.
The syntax for \mbox{\tt disconnect}
is
\begin{flushleft}
\verb"disconnect" {\em channel\/} \verb"from" {\em channel\/};
\end{flushleft}
and
\begin{flushleft}
\verb"disconnect" {\em channel\/};
\end{flushleft}
\par
With both \mbox{\tt connect} and \mbox{\tt disconnect} the \mbox{\em channel\/}
specifier can be a symbolic channel specification as defined with
the \mbox{\tt input} and \mbox{\tt output} commands or it can be a list
of channel numbers separated by commas. In either case the channels
must be preceded with their type (\mbox{\tt input}, or \mbox{\tt output}).
%
\subsubsection{Indexing Symbolic Channel Names}
When using symbolic channel names they can also
be indexed. For example
\begin{verbatim}
connect output dacs[2,3] to input bungalow[0,1];
\end{verbatim}
will connect the last two channels of the dacs to the first
two channels of the bungalow (indices start at 0).
The indices can be any sequence of numbers and are not
required to be consecutive.
%
\section{Resetting the Switch}
The audio switch can be reset with the command
\begin{verbatim}
reset;
\end{verbatim}
This issues a hardware reset to the switch which causes it to
break all connections. The daemon also resets its internal
state about connections and considers all connections to be
broken.
%
\section{Command Syntax}
The syntax of commands sent to the daemon via the ipc socket
is identical to those of the configuration file. Thus
the daemon can be configured by having a program connect
to it and ship it a configuration file. Also,
the configuration of the daemon can be changed by sending
it commands that change any assignments that may have been
in the configuration file.
%
\section{Installation}
In a nutshell, all one needs to do is to compile the daemon,
install it somewhere\footnote{For example in the directory
\mbox{\tt /usr/local/lib}},
add an entry for the daemon's socket in \mbox{\tt /etc/services},
add an entry for the host that the daemon will run on in
\mbox{\tt /etc/hosts}, and
add the necessary lines to \mbox{\tt /etc/rc.local} so that
it gets started at boot time.
\par
At CARL the entry in \mbox{\tt /etc/services} looks like
\begin{verbatim}
# local services
aswdaemon       1234/tcp
\end{verbatim}
\par
Because of the way the \mbox{\tt gethostbyname()} routine works
one can have ``aliases'' in the \mbox{\tt /etc/hosts} file
that represent hosts that provide various services. For
example at CARL our \mbox{\tt /etc/hosts} has
\begin{verbatim}
# CARL local net 128.54.132 -- 10Mb/s Ethernet
128.54.0.0	interlan-network ilbroadcast
128.54.132.1	sdcarl carl loghost mailhost lprhost aswhost
128.54.132.2	sdcarla carla
128.54.132.3	sdfelix felix
128.54.132.4	sdsluggo sluggo
128.54.132.5	sdgumby gumby
\end{verbatim}
The machines \mbox{\em sdcarla\/}, \mbox{\em sdfelix\/}, \mbox{\em sdsluggo\/},
and \mbox{\em sdgumby\/} are SUN
workstations, the machine \mbox{\em sdcarl\/} is a VAX and
acts as a server for most (if not all) of the services
that use a particular device or file. What the above
entry means is that \mbox{\em sdcarl\/} is the host for logging
error messages, is the smart mail host, services all
line printer requests, and services all audio switch
requests.
\par
For this trick to work the software has to be written
appropriately. For example, the audio switch daemon first
tries to get the host entry for the \mbox{\em aswhost\/} and
if that fails gets the host entry for \mbox{\em localhost\/}.
I'm not sure that any of the Berkeley software that came
with 4.2BSD uses this; I learned about it from the SUN
system manager's manual.
\par
The lines to add to \mbox{\tt /etc/rc.local} will look like
\begin{verbatim}
if [ -f /usr/local/lib/asw-daemon ]; then
        (PATH=/carl/lib; asw-daemon) & \
        echo -n ' asw' > /dev/console
fi
\end{verbatim}
There are no lock files to worry about since the daemon
uses a socket; if another daemon is already running the
socket will be in use and subsequent daemons will bomb
when they try to use it.
%
\subsection{Different Audio Switches}
Realizing that not everyone will have the same type of
audio switch that we have, the software has been written
in such a way that different types of audio switches can
be supported. If you are going to be using a different
type of audio switch you will need to
\begin{enumerate}
\item
Write the routines that make connections, break
connections, reset the switch, and an initialization routine
that is called when the daemon starts. The routines that do
this for our audio switch are in the files
\mbox{\tt ss\_conn.c},
\mbox{\tt ss\_disconn.c},
\mbox{\tt ss\_reset.c}, and
\mbox{\tt ss\_init.c}.
You should use these as examples of how to write your own.
If your audio switch doesn't support a reset command you
will still need to write a reset routine, but all it will
need to do is call the routine \mbox{\tt clrconn}.
\item
Edit the file \mbox{\tt switch.c} and add the declarations
for your routines and add entries for them in the
initialization of \mbox{\tt swdev} (look at the file
\mbox{\tt switch.h} for an explanation of each member).
\item
Edit the configuration file and add a line of the form
\begin{flushleft}
\verb"set switch =" \verb'"'{\em type\/}\verb'"';
\end{flushleft}
where \mbox{\em type\/} is the type given in \mbox{\tt swdev}
for your audio switch (it must be quoted).
For example at CARL we use
\begin{verbatim}
set switch = "ss";
\end{verbatim}
If no type is specified then the daemon will use the
first element of the \mbox{\tt swdev} array.
\end{enumerate}
%
\subsection{Multiple Audio Switches}
The software will (might?) also support more than one audio switch.
This requires using different configuration files for
each daemon. When the daemon is started the \mbox{\em --c} flag
should be used and it should be followed by the name of the
configuration file. For example \mbox{\tt /etc/rc.local} could have
\begin{verbatim}
if [ -f /usr/local/lib/asw-daemon ]; then
        (PATH=/carl/lib; asw-daemon -c/usr/local/lib/ss1) & \
        echo -n ' asw1' > /dev/console
        (PATH=/carl/lib; asw-daemon -c/usr/local/lib/ss2) & \
        echo -n ' asw2' > /dev/console
fi
\end{verbatim}
The software also has a hook for using different addresses for
the sockets. By default it looks for \mbox{\tt aswdaemon} in the
\mbox{\tt /etc/services} file; if it doesn't find this it will construct
the name \mbox{\tt aswdaemon-type} where \mbox{\em type\/} was specified with
the \mbox{\tt use} command. Thus \mbox{\tt /etc/services} could have
\begin{verbatim}
# local services
aswdaemon-ss    1234/tcp
aswdaemon-cd    2345/tcp
\end{verbatim}
although setting things up for multiple daemons for the same type
devices isn't entirely straightforward.
\par
{\bf N.B.}: multiple daemons and/or sockets has never been tested.
%
\section{Caveats}
With the current implementation of interprocess communication
there isn't any convenient way to provide security. For example
it would be nice if certain commands that come in through the
socket were restricted so that only a selected set of priviledged
users could invoke them. As it is now anybody could intentionally
or accidently make or break any connections or issue a reset command
or change the symbolic channel names.
\appendix
%
\section{ASW Daemon Configuration File}
\label{syntax-diagram}
The following diagram gives a sort of BNF notation for
the configuration file.
The configuration file is free format.
All lines are terminated by a semicolon.
\par
In the following words in \mbox{\tt typewriter type}
are literals.
An \mbox{\em ident\/}
is any string of alphanumerics or underscore that
starts with an alphabetic.
A \mbox{\em number\/}
is any string of numerics.
\par
Within the configuration file all characters including
and following a sharp sign up to a newline are ignored.
\begin{tabbing}
\hspace*{8ex} \= \hspace*{8ex} \= \hspace*{8ex} \= \hspace*{8ex} \kill
config\_file {\tt ::=} \\
\> file line \\
\> {\tt |} \\
\> error \\
\> {\tt |} \\
\> /* empty */ \\
\\
line {\tt ::=} \\
\> switch\_type \\
\> {\tt |} \\
\> var\_assign \\
\> {\tt |} \\
\> chan\_assign \\
\> {\tt |} \\
\> disconnect \\
\> {\tt |} \\
\> connect \\
\> {\tt |} \\
\> reset \\
\\
switch\_type {\tt ::=} \\
\> {\tt use} ident ; \\
\\
var\_assign {\tt ::=} \\
\> {\tt set} ident {\tt =} number ; \\
\> {\tt |} \\
\> {\tt set} ident {\tt =} string ; \\
\\
chan\_assign {\tt ::=} \\
\> {\tt output} ident {\tt is} numlist ; \\
\> {\tt |} \\
\> {\tt input} ident {\tt is} numlist ; \\
\\
disconnect {\tt ::=} \\
\> {\tt disconnect} channel {\tt from} channel ; \\
\> {\tt |} \\
\> {\tt disconnect} channel ; \\
\\
connect {\tt ::=} \\
\> {\tt connect} channel {\tt to} channel ; \\
\\
reset {\tt ::=} \\
\> {\tt reset} ; \\
\\
channel {\tt ::=} \\
\> type ident \\
\> {\tt |} \\
\> type ident [ numlist ] \\
\> {\tt |} \\
\> type numlist \\
\\
type {\tt ::=} \\
\> {\tt input} \\
\> {\tt |} \\
\> {\tt output} \\
\\
numlist {\tt ::=} \\
\> number \\
\> {\tt |} \\
\> numlist , number \\
\\
number {\tt ::=} \\
\> [0-9][0-9]* \\
\\
ident {\tt ::=} \\
\> [a-zA-Z\_][a-zA-Z\_0-9]* \\
\\
string {\tt ::=} \\
\> {\tt [a-zA-Z\_][a-zA-Z\_0-9]*}        /* must be quoted */ \\
\end{tabbing}
%
\section{Sample Configuration File}
The following is a sample configuration file:
\begin{verbatim}
# debug stuff
config elevel = 10;                            # error messages
config ilevel = 1;                             # info messages
config dlevel = 0;                             # debugging messages
# output devices
output     dacs       is   1, 2, 3, 4;         # d/a converters
output     studio     is   5, 6, 7, 8;
output     muzak      is   9, 10;
# output spaces
input      dacs       is   1, 2;               # a/d converters
input      studio     is   3, 4, 5, 6;
input      main_space is   7, 8, 9, 10;
input      bungalow   is   11, 12, 13, 14;
input      andy       is   15, 16;
input      dgl        is   17, 18;
input      frm        is   19, 20;
input      rusty      is   21, 22;
\end{verbatim}
\end{document}
