# Simple Sound Controller 2

## Object
The  Simple Sound  Controller  Daemon is  a small  Linux  sound application  for
headless phones that offers playback and recording of sounds similar to the alsa
aplay utility  but with superior process  control via a socket  interface. It is
intended to be used  in combination with the alsa use case  manager to provide a
minimalistic audio  stack for  headless phones.  The SSC  daemon comes  with the
following capabilities:

* keep alsa devices open to enable the phone's audio dsp
* play and loop simple sounds from MS WAV or MP3 files
* record audio to a file in the MS WAV format
* controlled with a simple ASCII protocol via TCP and/or unix domain sockets
* informs all connected clients about state changes

This application can be especially useful for platforms where a full blown phone
middleware which comes in example with Android (audioflinger, libmedia) or Gnome
(gstreamer) is not  available or not desirable. In example  Qualcomm's 9x series
supports a Linux enabled build flavor where  most of the voice audio is realized
on a specific DSP which supports all of the required mixing and audio processing
operations. So all what  is actually required on the Linux user  land side is to
setup a bunch of mixer commands for parameterizing the audio dsp, the codec and,
furthermore to keep  alive the audio dsp by opening  associated alsa devices. It
can be also used to play back signal tones like audio prompts, indication tones,
etc. This  software is especially  targeted for such a  use case. It  is written
with  the  aim to  be  easily  extendable and  depends  on  only two  additional
libraries which simplifies porting and maintance.

## Notes on Version 2

Qualcomm has unfortunately discontinued support for the audio foundation library
Alsa used by  default under Linux with  the introduction of Baseline  2.4 of the
Linux Enabled (LE) software release  for the MDM9x28. Officially, Qualcomm never
supported Alsa,  but it worked without  problems until the introduction  of this
baseline. Audio  playback remains  muted with  BL2.4. The  call audio  signal is
present, but the audio calibration files are no longer initialized.

Despite  multiple requests  and extensive  support  from us  in analyzing  these
problems, neither  the Qualcomm support team  nor the development team  could or
wanted to provide a suitable solution to date. Therefore, we had no other choice
than to  adapt the sound controller  software to use proprietary  Qualcomm sound
interfaces.

As  the existing  implementation had  an inconsistent,  difficult to  understand
and  error-prone architecture  due to  multiple  extensions, it  was decided  to
re-implement th sound controller under the current  circumstances. The following
points in particular were taken into account:

* Start, stop and  memory management of  background processes in single threaded
  event loop to avoid race conditions.
* Use of asynchronous I/O for the command & control interface
* Introduction  of an audio abstraction layer,  i.e. use of  callbacks  for  all
  audio functions
* Use of appropriate callbacks for the audio data streams instead of inheritance
  mechanism

By means of a configuration option, it  is possible to choose between the use of
the standard Alsa  interface and the proprietary Qualcomm  solution. The default
configuration is still  Alsa, so that the  software can be compiled  and used on
any modern Linux distribution.

## How to build.
### Build Dependencies

In addition  to the  commonly used  Unix system libraries  and build  tools such
as  libc,  pthreads  and  the  autobuild  suite,  ssc  depends  on  two  utility
libraries,  libcutils  and  libuv.  The   libcutils  library  is  maintained  by
the  same  author.  You  will  need  to  compile  and  install  these  libraries
on  your  system  first.  The  libraries   are  both  provided  under  the  free
and  open   source  licenses   (LGPL  and  MIT).   Refer  to   the  installation
instructions  on  Github for  [libcutils](https://github.com/linneman/libcutils)
and [libuv](https://github.com/libuv/libuv)  for further  explanation how  to do
this.

For the decoding of  mp3 audio, the library libmad needs to  be installed on the
system as well. On debian this can be done via the following command:

    apt-get install libmad0-dev

When libmad is  not present or cannot be found  within the package configuration
stage the mp3 decoding feature will be disabled.

### Download and Compile
Compiling ssc  is done  in the very  same way as  for libcutils  and libintercom
following the guidelines of the free software foundation:

    git clone git://github.com/linneman/ssc.git
    cd ssc

    ./autogen # invokes autoreconf -i for config script generation

    ./configure
    make
    make install # as root

In case  you have  downloaded an  official release as  gzipped tarball  you will
exclusively need the  last three commands since the configure  script is already
delivered with stable releases.

Pay attention to the fact that add  on libraries are per default installed under
the directory  `/usr/local/lib` which is not  in the library path  on many linux
distributions. Thus you  will need to put `/usr/local/lib` to  your library path
e.g. by defining the enviroment variable

    export LD_LIBRARY_PATH=/usr/local/lib.

Alternatively,  you  can  edit  `/etc/ld.so.conf`  which  contains  the  default
directories  searched.  Note  that  you  may  also  need  to  update  the  cache
`/etc/ld.so.cache` by running ldconfig (as root or with sudo).

## Using the Simple Sound Controller Daemon
The application is installed  under the name sscd and can  be simply tested from
the  command  line by  invoking  it  without  arguments.  It is  recommended  to
integrate  it into  the  autostart environment  of your  system.  By default  it
listens to port 5042 and the  UDS file /tmp/ssc.sock for client connections from
the local machine  exclusively. The connection setup can be  altered globally by
editing the configation  file under /etc/ssc.rc or locally by  creating the file
.ssc.rc in your home  directory. When sscd is running you  can simply connect to
it in  example via telnet.  In case  of a successful  connection you will  get a
reply prompt  indicating the application's name.  Enter 'help' to get  a list of
available commands. This is illustrated in the following snippet:

    $ telnet localhost 5042
    Trying 127.0.0.1...
    Connected to localhost.
    Escape character is '^]'.
    Simple Sound Controller 2, enter command or help!
    help
    Simple Sound Controller Daemon 2

    The current implementation reacts to the following commands:
            openidle  : keeps an alsa pcm device open e.g. to activate dsp
            close     : release background process and close pcm device
            play      : start playback background process
            record    : start recording background process
            pause     : pause playback/recording
            resume    : resume playback/recording where it was paused
            listverbs : list currently active process id's (verbs)
            sync-request : pongs back request for sync purposes
            help      : this help test
            quit      : terminate active connection
            terminate : gracefully terminate daemon (for debugging purposes)

    Each command supports various options, use --help for more information.

### Playback Operation
Each command commes with a set of  required options which are annoated by dashes
and separated by blanck characters in the  way as in any other Unix command line
application. Most of  the commands expect an unique  operation identifier (verb)
to be specified which you can freely  choose. The specifier is mapped to an alsa
device and a background process in some case e.g. the playback of an audio file.
In  additioan a  playback operation  needs the  alsa device  hardware specifiere
describing the sound card and the audio  channel to be used for the playback and
a  file to  be played  back. SSC  supports the  Microsoft PCM  WAV and  MP3 file
formats.  Libmad is  used for  the  decoding of  MP3 audio  data. The  following
example command line plays the wav  file 'test.wav' via the alsa hardware device
'plughw:0,0'.

    play --id test -D default -f /tmp/test.wav
    new state=initialized, id=test, device=default, filename=/tmp/test.wav
    new state=preparing, id=test, device=default, filename=/tmp/test.wav
    new state=running, id=test, device=default, filename=/tmp/test.wav
    new state=terminating, id=test, device=default, filename=/tmp/test.wav
    new state=terminated, id=test, device=default, filename=/tmp/test.wav

The device 'default' indicates a virtual alsa device which is typically provided
by the Linux  sound server on modern  Desktop systems. On such  systems the alsa
hardware devices usually can not be  accessed directly because every alsa device
can be  opened only  once which is  already consumed by  the sound  server which
allows the multiplexing of different audio streams.

The  daemon will  send  event messages  about state  changes  of all  background
processes to  all clients. Any other  messages like error messages,  help output
etc. will be send exclusively to the client where the associated request command
was comming from. The command 'listverbs' shows all actively served processes. In
the give example:

    listverbs
    id=test, state=ssc_proc_running, device=default, filename=/tmp/test.wav

the process identifier 'test' is accessing  the alsa device 'default' as long as
its background player task has not been terminated. On constrast to version 1 of
sound controller, tasks are automatically cleaned and removed from the task list
after the associated background process has been terminated.

It is possible to assign a new action to an existing verb identifier like in the
following example:

    play -i tone -D default -f /tmp/test2.wav
    new state=terminating, id=tone, device=default, filename=/tmp/test.wav
    new state=terminated, id=tone, device=default, filename=/tmp/test.wav
    new state=initialized, id=tone, device=default, filename=/tmp/test2.wav
    new state=preparing, id=tone, device=default, filename=/tmp/test2.wav
    new state=running, id=tone, device=default, filename=/tmp/test2.wav
    new state=terminating, id=tone, device=default, filename=/tmp/test2.wav
    new state=terminated, id=tone, device=default, filename=/tmp/test2.wav


Alternatively you can just close an actively served verb identifier:

    close --id test
    new state=terminating, id=test, device=default, filename=/tmp/test.wav
    new state=terminated, id=test, device=default, filename=/tmp/test.wav

or just close all devices by the --all option:

    close --all

Using a dedicated process identifier allows  to take advantage of extended audio
stacks which support mixing such as pulseaudio. If you have pulseaudio installed
on your system, try  the following to run two playback  processes in parallel on
the pulseaudio device 'default':

    play --id test -D default -f /tmp/test.wav -r
    new state=initialized, id=test, device=default, filename=/tmp/test.wav
    new state=preparing, id=test, device=default, filename=/tmp/test.wav
    new state=running, id=test, device=default, filename=/tmp/test.wav
    play --id test2 -D default -f /tmp/test2.wav -r
    new state=initialized, id=test2, device=default, filename=/tmp/test2.wav
    new state=preparing, id=test2, device=default, filename=/tmp/test2.wav
    new state=running, id=test2, device=default, filename=/tmp/test2.wav

Both background processes  will send their audio data to  the same default sound
device which  is served  by pulseaudio.  You shall  hear a  mixure of  the files
test.wav and test2.wav.

### Record Operation
Recording  is done  similarly as  playback but  comes with  a few  more optional
arguments to  specify the sample  rate, the number  of channels and  the maximum
duration of the recorded file as illustrated in the following example:

    record --id test -D default -c 1 -r 16000 -d 20 -f /tmp/test.wav

This records  audio sample from  the virtual  sound device associated  with alsa
device hw:0,0 at a  sample rate of 16kHz using one channel and  a duration of at
maximum 20  seconds. It is  possible to terminate the  recording at any  time by
closing the associated verb. In the given example use the command:

    close --id test

to do so. If not specified otherwise,  the recording process uses by default one
channel, a sample rate of 16 kHz and a duration of 10 seconds. The corresponding
arguments can be ommitted in such case.

### Keep Alsa Devices Open
The command 'openidle' just opens an alsa  device and does nothing else. This is
required in  example for operations  with Qualcomm  SoC ALSA drivers  where such
operations are triggered to keep the audio dsp up and running.

## License
This implementation code stands under the terms of the
[GNU GENERAL PUBLIC LICENSE 2.0](http://www.gnu.org/licenses/old-licenses/gpl-2.0).

July 2023, Otto Linnemann