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

record.cpp

// Copyright (C) 2000 Open Source Telecom Corporation.
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.

#include "driver.h"

#ifdef      CCXX_NAMESPACES
using namespace std;
namespace ost {
#endif

VPBRecord::VPBRecord(VPBTrunk *trunk, int h) :
AudioFile(), Service((Trunk *)trunk, keythreads.priAudio())
{
      handle = h;
      reset = false;
      vpbtr = trunk; // DR
}

VPBRecord::~VPBRecord()
{
      char buffer[12];
      struct stat ino;
      int trim;

      // DR - make sure Run() thread has finised before we delete object
      if(reset)
      {
            vpb_record_terminate(handle);
            yield();
      }
      terminate();

      sprintf(buffer, "%ld", getPosition());
      trunk->setSymbol(SYM_OFFSET, buffer);

      if(data->record.minsize)
      {
            if(getPosition() < data->record.minsize)
            {
                  trunk->setSymbol(SYM_RECORDED, "0");
                  remove(data->record.name);
                  AudioFile::close();
                  return;                 
            }
      }

      trim = toBytes(getEncoding(), data->record.trim);
      stat(data->record.name, &ino);
      if(ino.st_size <= trim || data->record.frames)
      {
            trunk->setSymbol(SYM_RECORDED, "0");
            remove(data->record.name);
      }
      else
      {
            sprintf(buffer, "%ld", 
                  getPosition() - data->record.trim);
            trunk->setSymbol(SYM_RECORDED, buffer);
            truncate(data->record.name, ino.st_size - trim);
            chown(data->record.name, keyserver.getUid(), keyserver.getGid());
            if(data->record.save)
                  rename(data->record.name, data->record.save);
      }

      AudioFile::close();

}

void VPBRecord::initial(void)
{
      int codec = VPB_MULAW;
      char buffer[32];
      Audio::Info info;
      const char *ext;
      const char *fmt = data->record.encoding;

      trunk->getName(buffer);
      info.format = raw;
      info.encoding = mulawAudio;
      info.order = 0;
      info.annotation = (char *)data->record.annotation;
      info.rate = 8000;

      ext = strrchr(data->record.name, '/');
      if(!ext)
            ext = data->record.name;
      ext = strrchr(ext, '.');

      if(!ext)
      {
            ext = data->record.extension;
            strcat(data->record.name, ext);
      }

      if(!fmt)
            fmt = "raw";

      if(!stricmp(ext, ".al"))
            info.encoding = alawAudio;
      else if(!stricmp(ext, ".au"))
      {
            info.format = sun;
            info.order = __BIG_ENDIAN;
      }
      else if(!stricmp(ext, ".wav"))
      {
            info.format = riff;
            info.order = __LITTLE_ENDIAN;
      }

      if(!stricmp(fmt, "adpcm") || !stricmp(fmt, "g721"))
            info.encoding = g721ADPCM;
      else if(!stricmp(fmt, "g723"))
            info.encoding = g723_3bit;
      else if(!stricmp(fmt, "pcm"))
            info.encoding = pcm16Mono;

      if(data->record.offset != (unsigned long)-1)
      {
            open(data->record.name);
            setPosition(data->record.offset);
      }
      else if(data->record.append)
            open(data->record.name);
      else
            create(data->record.name, &info);   

      if(!isOpen())
      {
            slog(Slog::levelError) << data->record.name << ": cannot open" << endl;
            Service::failure();
      }
      if(data->record.append)
            setPosition();

      switch(getEncoding())
      {
      case g721ADPCM:
      case okiADPCM:
            codec = VPB_OKIADPCM;
            bufsize = 80;
            samples = 160;
            break;
      case g723_3bit:
            codec = VPB_OKIADPCM24;
            bufsize = 60;
            samples = 160;
            break;
      case mulawAudio:
            codec = VPB_MULAW;
            bufsize = 160;
            samples = 160;
            break;
      case alawAudio:
            codec = VPB_ALAW;
            bufsize = 160;
            samples = 160;
            break;
      case pcm16Mono:
            codec = VPB_LINEAR;
            bufsize = 320;
            samples = 160;
            break;
      default:
            slog(Slog::levelError) << buffer << ": unsupported codec required" << endl;
            Service::failure();
      }

      reset = true;
      vpb_record_buf_start(handle, codec);
}

void VPBRecord::run(void)
{
      char name[33];
      char buffer[bufsize];
      Audio::Error status = Audio::errSuccess;
      unsigned frames = 0;
      float gain;

      if(data->record.gain != 0.0)
      {
            vpb_record_get_gain(handle, &gain);
            gain += data->record.gain;
            if(gain < -12.0)
                  gain = -12.0;

            if(gain > 12.0)
                  gain = 12.0;

            vpb_record_set_gain(handle, gain);
      }
      
      trunk->getName(name);

      if(data->record.info)
            return success();

      setCancel(cancelDeferred);
      while(status == Audio::errSuccess)
      {     
            if(data->record.frames && (int)frames++ >= data->record.frames)
            {
                  frames = 0;
                  setPosition(0);
            }
            if(vpb_record_buf_sync(handle, buffer, bufsize) != VPB_OK)
                  status = errReadIncomplete;
            else
                  status = putSamples(buffer, samples);
            Thread::yield();
      }
      vpb_record_buf_finish(handle);
      reset = false;
      if(status == errWriteFailure)
            slog(Slog::levelError) << name << ": failed record" << endl;
      success();
}

bool VPBTrunk::recordHandler(TrunkEvent *event)
{
      unsigned short mask;

      switch(event->id)
      {
      case TRUNK_EXIT_STATE:
            if(!thread)
                  return true;
            stopServices();
            vpb_record_set_gain(handle, inpgain);
            handler = &VPBTrunk::stepHandler;
            return true;
      case TRUNK_STOP_STATE:
            endTimer();
            stopped = true;
            if(thread)
            {
                  vpb_record_terminate(handle);
                  return true;
            }
            vpb_record_set_gain(handle, inpgain);
            handler = &VPBTrunk::stepHandler;
            return true;
      case TRUNK_DTMF_KEYUP:
            mask = (1 << event->parm.dtmf.digit);
            if(!(mask & data.record.term)) {
                  return false;
            }
            if(thread)
            {
                  stopped = true;
                  trunkSignal(TRUNK_SIGNAL_STEP);
                  vpb_record_terminate(handle);
                  return true;
            }
            return true;
      case TRUNK_SERVICE_SUCCESS:
            if(!stopped)
                  trunkSignal(TRUNK_SIGNAL_STEP);
            exitThread();
            return true;
      case TRUNK_SERVICE_FAILURE:
            if(!stopped)
            {
                  setSymbol(SYM_ERROR, "record-failed");
                  trunkSignal(TRUNK_SIGNAL_ERROR);
            }
            exitThread();
            return true;
      case TRUNK_ENTER_STATE:
            stopped = false;
            enterState("record");
            flags.dsp = DSP_MODE_VOICE;
            status[id] = 'r';
            if(!flags.offhook)
            {
                  flags.offhook = true;
                  vpb_sethook_async(handle, VPB_OFFHOOK);
                  setTimer(getPickupTimer());
                  return true;
            }
      case TRUNK_TIMER_EXPIRED:
            if(thread)  // default timeout handler
                  return false;

            if(data.record.term)
                  setDTMFDetect(true);
            else
                  setDTMFDetect();
            thread = new VPBRecord(this, handle);
            thread->start();
            setTimer(data.record.timeout);
            return true;
      }
      return false;
}

#ifdef      CCXX_NAMESPACES
};
#endif

Generated by  Doxygen 1.6.0   Back to index