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

audio.cc

/*
 * Copyright (c) 1991-1994 Regents of the University of California.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *    This product includes software developed by the Computer Systems
 *    Engineering Group at Lawrence Berkeley Laboratory.
 * 4. Neither the name of the University nor of the Laboratory may be used
 *    to endorse or promote products derived from this software without
 *    specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */
static const char rcsid[] =
    "@(#) $Header: audio.cc,v 1.34 96/05/03 06:26:49 van Exp $ (LBL)";

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#if defined(sgi)
#include <bstring.h>
#endif
#ifdef WIN32
#include <fcntl.h>
#else
#include <unistd.h>
#include <sys/file.h>
#include <fcntl.h>
#endif

#include "audio.h"
#include "filter.h"
#include "mulaw.h"
#include "Tcl.h"


Audio::Audio() :
      lock_fd(-1),
      blksize(FRAMESIZE),
      fd(-1),
      oport(0),
      iport(0),
      oports(1),
      iports(1),
      rmute(0),
      pmute(0),
      loopback(0),
      sampleclk(0),
      rgain(0),
      pgain(0),
      filter(new Filter(this)),
      handler_(0)
{
      for (u_int i = 0; i < sizeof(omode)/sizeof(omode[0]); ++i)
            omode[i] = mode_mikemutesnet;
}

Audio::~Audio()
{
      close(fd);
      delete filter;
}

void Audio::Release()
{
      if (HaveAudio()) {
            unlink();
            (void)close(fd);
            fd = -1;
            notify();
      }
}

void Audio::Obtain()
{
      link(fd, TK_READABLE);
      notify();
}

void Audio::InputPort(int p)
{
      iport = p;
}

void Audio::OutputPort(int p)
{
      oport = p;
}

void Audio::dispatch(int)
{
      while (FrameReady())
            handler_->audio_handle();
}

/*
 * The following are called by user interface routines to get
 * the input/output ports & port types.
 */
int Audio::inputs() const
{
      return (iports);
}

int Audio::input_type(int i) const
{
      return (i < inputs()? i : 0); /*XXX*/
}

int Audio::outputs() const
{
      return (oports);
}

int Audio::output_type(int i) const
{
      return (i < outputs()? i : 0); /*XXX*/
}

int Audio::StrToMode(const char *s) const
{
      if (strcasecmp("MikeMutesNet", s) == 0 ||
          strcasecmp("SpeakerPhone", s) == 0)
            return mode_mikemutesnet;
      else if (strcasecmp("NetMutesMike", s) == 0 ||
               strcasecmp("VTSpeakerPhone", s) == 0)
            return mode_netmutesmike;
      else if (strcasecmp("EchoCancel", s) == 0 || 
             strcasecmp("ec", s) == 0)
            return mode_ec;
      else
            return mode_none;
}

int Audio::StrToIPort(const char *s) const
{
      if (
             strcasecmp("mike", s) == 0 ||
             strcasecmp("microphone", s) == 0 ||
             strcasecmp("mic", s) == 0 ||
             strcasecmp("wave", s) == 0 ||
             strcasecmp("wavein", s) == 0 ||
             strcasecmp("wave in", s) == 0
            )
            return input_mike;
      else if (
             strcasecmp("linein", s) == 0 ||
             strcasecmp("line-in", s) == 0 ||
             strcasecmp("line in", s) == 0 ||
             strcasecmp("line", s) == 0 ||
             strcasecmp("linein1", s) == 0 ||
             strcasecmp("line-in1", s) == 0 ||
             strcasecmp("line-in 1", s) == 0 ||
             strcasecmp("line in 1", s) == 0 
            )
            return input_line;
      else if (
             strcasecmp("linein2", s) == 0 ||
             strcasecmp("line-in2", s) == 0 ||
             strcasecmp("line-in 2", s) == 0 ||
             strcasecmp("line in 2", s) == 0 ||
             strcasecmp("line2", s) == 0 ||
             strcasecmp("aux", s) == 0 ||
             strcasecmp("cd", s) == 0 ||
             strcasecmp("cd audio", s) == 0
            )
            return input_line2;
      else if (
             strcasecmp("linein3", s) == 0 ||
             strcasecmp("line-in3", s) == 0 ||
             strcasecmp("line-in 3", s) == 0 ||
             strcasecmp("line in 3", s) == 0 ||
             strcasecmp("line3", s) == 0 ||
             strcasecmp("synth", s) == 0 ||
             strcasecmp("synthesizer", s) == 0 ||
             strcasecmp("fm", s) == 0 ||
             strcasecmp("wt", s) == 0 ||
             strcasecmp("wavetable", s) == 0
            )
            return input_line3;
      else
            return -1;
}

int Audio::StrToOPort(const char *s) const
{
      if (
             strcasecmp("speaker", s) == 0 ||
             strcasecmp("wave", s) == 0 ||
             strcasecmp("waveout", s) == 0 ||
             strcasecmp("wave out", s) == 0 
            )
            return output_speaker;
      else if (
             strcasecmp("jack", s) == 0 ||
             strcasecmp("phones", s) == 0 ||
             strcasecmp("headphone", s) == 0 ||
             strcasecmp("headphones", s) == 0
            )
            return output_phones;
      else if (
             strcasecmp("lineout", s) == 0 ||
             strcasecmp("line out", s) == 0 ||
             strcasecmp("line", s) == 0 ||
             strcasecmp("lineout1", s) == 0 ||
             strcasecmp("line out1", s) == 0 ||
             strcasecmp("line1", s) == 0
            )
            return output_line;
      else if (
             strcasecmp("lineout2", s) == 0 ||
             strcasecmp("line out2", s) == 0 ||
             strcasecmp("line out 2", s) == 0 ||
             strcasecmp("line2", s) == 0 ||
             strcasecmp("aux", s) == 0 ||
             strcasecmp("aux out", s) == 0 
            )
            return output_line2;
      else
            return -1;
}

const char* Audio::IPortToStr(int p) const
{
      switch (p) {
      default:
      case input_mike:  return ("mike");
      case input_line:  return ("linein");
      case input_line2: return ("linein2");
      case input_line3: return ("linein3");
      }
}

const char* Audio::OPortToStr(int p) const
{
      switch (p) {
      default:
      case output_speaker:    return ("speaker");
      case output_phones:     return ("jack");
      case output_line: return ("lineout");
      case output_line2:      return ("lineout2");
      }
}

/* XXX this can be coded better */
/*
 * Output the ulaw sample in x and read the mike response back into y.
 * The two signals are guaranteed to coincide in time.  len must be
 * less than the max output buffer available (currently 4K).
 */
int Audio::PlayRec(u_char *x, u_char *y, int len)
{
      int bufsize = (len / blksize) * blksize;
      int rbufsize = bufsize + 4096;
      u_char* tmpbuf = new u_char[rbufsize];
      Flush();
      int cc = write(fd, (char*)x, bufsize);
      if (cc != bufsize) {
            perror("PlayRec write");
            return (bufsize);
      }
      int offset = AdjustTime(0);
      if (offset < 0 || offset + bufsize > rbufsize) {
            fprintf(stderr, "Playrec offset %d\n", offset);
            return (bufsize);
      }
      char* bp = (char*)tmpbuf;
      for (int rem = offset + bufsize; rem > 0; ) {
            if ((cc = read(fd, bp, rem)) <= 0) {
                  perror("PlayRec read");
                  return (bufsize);
            }
            bp += cc;
            rem -= cc;
      }
      memcpy((char*)y, (char*)&tmpbuf[offset], bufsize);
      delete tmpbuf;
      return (bufsize);
}

void Audio::RetrainFilter(int len, int maxtaps)
{
      filter->Train(len, maxtaps);
}

void Audio::RMute()
{
      rmute |= 1;
}

void Audio::RUnmute()
{
      rmute &=~ 1;
}

void Audio::SetRGain(int)
{
}

void Audio::SetPGain(int)
{
}

#if defined(__osf__) || defined(sun) || defined(ultrix)
extern "C" {
int flock(int, int);
}
#endif
#if defined(hpux) || defined(__svr4__) || defined(sco)
#include <fcntl.h>

#define LOCK_SH   1    /* shared lock */
#define LOCK_EX   2    /* exclusive lock */
#define LOCK_NB   4    /* don't block when locking */
#define LOCK_UN   8    /* unlock */

int flock(int fd, int op) {
      struct flock f;
      f.l_whence = 0;
      f.l_start = 0;
      f.l_len = 0;
      if (op == LOCK_UN)
            f.l_type = F_UNLCK;
      else
            f.l_type = F_WRLCK;
      return (fcntl(fd, F_SETLK, &f));
}
#endif

/* XXX should make a NOLOCKING define that configure sets */
#ifdef WIN32
void Audio::openlock()  { printf("Audio:openlock\n"); }
void Audio::unlock()    { printf("Audio:unlock\n"); }
int Audio::lock() { printf("Audio:lock\n"); return (0); }
#else
void Audio::openlock()
{
      char *wrk = new char[sizeof("/tmp/.vat_audio_lock.") + 32];
      sprintf(wrk, "/tmp/.vat_audio_lock.%d", getuid());
      /* open (or create) the lock file */
      lock_fd = open(wrk, O_RDWR|O_CREAT, 0777);
      if (lock_fd < 0) {
            perror(wrk);
            exit(2);
      }
      delete wrk;
}

void Audio::unlock()
{
      if (flock(lock_fd, LOCK_UN))
            perror("vat: sock_audio unlock");
}

int Audio::lock()
{
      return (flock(lock_fd, (LOCK_EX|LOCK_NB)));
}
#endif

int Audio::command(int argc, const char*const* argv)
{
      Tcl& tcl = Tcl::instance();
      if (argc == 4) {
            if (strcmp(argv[1], "mode") == 0) {
                  int port = StrToOPort(argv[2]);
                  int mode = StrToMode(argv[3]);
                  SetMode(port, mode);
                  return (TCL_OK);
            }
      }
      if (argc == 2) {
            if (strcmp(argv[1], "halfduplex") == 0) {
                  tcl.result(HalfDuplex() ? "1" : "0");
                  return (TCL_OK);
            }
            if (strcmp(argv[1], "obtain") == 0) {
                  Obtain();
                  return (TCL_OK);
            }
            if (strcmp(argv[1], "release") == 0) {
                  Release();
                  return (TCL_OK);
            }
            if (strcmp(argv[1], "have") == 0) {
                  tcl.result(HaveAudio() ? "1" : "0");
                  return (TCL_OK);
            }
      } else if (argc == 3) {
            if (strcmp(argv[1], "test") == 0) {
                  SetLoopback(atoi(argv[2]));
                  return (TCL_OK);
            }
            if (strcmp(argv[1], "input") == 0) {
                  if (strcmp(argv[2], "mute") == 0) {
                        RMute();
                        return (TCL_OK);
                  }
                  if (strcmp(argv[2], "unmute") == 0) {
                        RUnmute();
                        tcl.result(HaveAudio()? "0" : "1");
                        return (TCL_OK);
                  }
                  if (strcmp(argv[2], "current") == 0) {
                        sprintf(tcl.result(), "%d", InputPort());
                        return (TCL_OK);
                  }
                  if (strcmp(argv[2], "names") == 0) {
                        /*
                         * Return a list of the names of the
                         * audio input ports.
                         */
                        char* cp = tcl.result();
                        int n = inputs();
                        for (int i = 0; i < n; ++i) {
                              const char* port = IPortToStr(i);
                              strcpy(cp, port);
                              cp += strlen(port);
                              *cp++ = ' ';
                        }
                        *cp++ = '\0';
                        return (TCL_OK);
                  }
                  if (strcmp(argv[2], "gain") == 0) {
                        sprintf(tcl.result(), "%s %d",
                              IPortToStr(InputPort()), RGain());
                        return (TCL_OK);
                  }
            } else if (strcmp(argv[1], "output") == 0) {
                  if (strcmp(argv[2], "gain") == 0) {
                        sprintf(tcl.result(), "%s %d",
                              OPortToStr(OutputPort()), PGain());
                        return (TCL_OK);
                  }
                  if (strcmp(argv[2], "mute") == 0) {
                        PMute();
                        return (TCL_OK);
                  }
                  if (strcmp(argv[2], "unmute") == 0) {
                        PUnmute();
                        return (TCL_OK);
                  }
                  if (strcmp(argv[2], "current") == 0) {
                        sprintf(tcl.result(), "%d", OutputPort());
                        return (TCL_OK);
                  }
                  if (strcmp(argv[2], "names") == 0) {
                        /*
                         * Return a list of the names of the
                         * audio output ports.
                         */
                        char* cp = tcl.result();
                        int n = outputs();
                        for (int i = 0; i < n; ++i) {
                              const char* port = OPortToStr(i);
                              strcpy(cp, port);
                              cp += strlen(port);
                              *cp++ = ' ';
                        }
                        *cp++ = '\0';
                        return (TCL_OK);
                  }
            }
      } else if (argc == 4) {
            if (strcmp(argv[1], "input") == 0) {
                  if (strcmp(argv[2], "gain") == 0) {
                        SetRGain(atoi(argv[3]));
                        return (TCL_OK);
                  }
                  if (strcmp(argv[2], "set") == 0) {
                        InputPort(StrToIPort(argv[3]));
                        return (TCL_OK);
                  }
                  if (strcmp(argv[2], "name") == 0) {
                        strcpy(tcl.result(),
                               IPortToStr(StrToIPort(argv[3])));
                        return (TCL_OK);
                  }
            }
            if (strcmp(argv[1], "output") == 0) {
                  if (strcmp(argv[2], "gain") == 0) {
                        SetPGain(atoi(argv[3]));
                        return (TCL_OK);
                  } 
                  if (strcmp(argv[2], "set") == 0) {
                        OutputPort(StrToOPort(argv[3]));
                        return (TCL_OK);
                  }
                  if (strcmp(argv[2], "name") == 0) {
                        strcpy(tcl.result(),
                               OPortToStr(StrToOPort(argv[3])));
                        return (TCL_OK);
                  }
            }
      }
      return (TclObject::command(argc, argv));
}

Generated by  Doxygen 1.6.0   Back to index