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

duplex.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.
//
// As a special exception to the GNU General Public License, permission is
// granted for additional uses of the text contained in its release
// of Bayonne as noted here.
//
// This exception is that permission is hereby granted to link Bayonne 
// with  the Pika MonteCarlo libraries to produce a executable image
// without requiring MonteCarlo itself to be supplied in source form so
// long as each source file so linked contains this exclusion.
//
// This exception does not however invalidate any other reasons why
// the resulting executable file might be covered by the GNU General
// public license or invalidate the licensing requirements of any
// other component or library.
//
// This exception applies only to the code released by OST under the
// name Bayonne.  If you copy code from other releases into a copy of
// Bayonne, as the General Public License permits, the exception does not
// apply to the code that you add in this way.  To avoid misleading
// anyone as to the status of such modified files, you must delete
// this exception notice from them.
//
// If you write modifications of your own to Bayonne, it is your choice
// whether to permit this exception to apply to your modifications.
// If you do not wish that, delete this exception notice, at which
// point the terms of your modification would be covered under the GPL
// as explicitly stated in "COPYING".

#include "driver.h"
#include <sys/ioctl.h>
#include <sys/stat.h>

PikaDuplex::PikaDuplex(PikaTrunk *trunk) :
Service((Trunk *)trunk, keythreads.priAudio()), AudioFile()
{
      reset = false;
      hDsp = trunk->getDevice();
      hOut = trunk->getAltDevice();
      clrAudio();

      control = trunk->getHeaders();
      buffer = trunk->getBuffers();
      buflimit = trunk->getBufferSize();
}

PikaDuplex::~PikaDuplex()
{
      long trim;
      struct stat ino;
      char buffer[12];
      clrAudio();
      Terminate();

      sprintf(buffer, "%ld", getPosition());
      trunk->setSymbol(SYM_PLAYED, buffer);
      sprintf(buffer, "%ld", record.getPosition());
      trunk->setSymbol(SYM_RECORDED, buffer);
      trim = tobytes(getEncoding(), atoi(trunk->getSymbol(SYM_TRIM)));
      Close();
      record.Close();

      stat(data->play.list, &ino);
      truncate(data->play.list, ino.st_size - trim);
      chown(data->play.list, keyserver.getUid(), keyserver.getGid());

      if(reset)
      {
            PK_AUDIO_Reset(hDsp);
            PK_AUDIO_Reset(hOut);
            dspReset();
      }
      else
      {
            PK_AUDIO_Stop(hDsp);
            PK_AUDIO_Stop(hOut);
      }
}

char *PikaDuplex::getContinuation(void)
{
      return getPlayfile();
}

timeout_t PikaDuplex::Stop(void)
{
      clrAudio();
      stopped = true;
      if(reset)
      {
            reset = false;
            PK_AUDIO_Reset(hDsp);
            PK_AUDIO_Reset(hOut);
      }
      return 120 * pikaivr.getAudioBuffers() + keythreads.getResetDelay();
}

void PikaDuplex::Initial(void)
{
      unsigned codec, speed, rate, len, count = 0;
      char buffer[32];
      char *fn = getPlayfile();
      struct stat ino;
      char *ann;
      struct tm *dt;
      struct tm tbuf;
      audioinfo_t recinfo, playinfo;

      trunk->getName(buffer);

      if(!fn)
      {
            slog(SLOG_ERROR) << buffer << ": no file to play" << endl; 
            Failure();
      }

      stat(fn, &ino);
      Open(fn);   
      if(!isOpen())
      {
            slog(SLOG_ERROR) << buffer << ": " << fn << ": cannot open" << endl;
            Failure();
      }

      dt = localtime_r(&ino.st_ctime, &tbuf);
      sprintf(buffer, "%04d%02d%02d,%02d%02d%02d",
            dt->tm_year + 1900, dt->tm_mon + 1, dt->tm_mday,
            dt->tm_hour, dt->tm_min, dt->tm_sec);
      trunk->setSymbol(SYM_CREATED, buffer);

      ann = getAnnotation();
      if(ann)
            trunk->setSymbol(SYM_ANNOTATION, ann);
      else
            trunk->setSymbol(SYM_ANNOTATION, "");

      rate = getSampleRate();
      switch(getEncoding())
      {
      case MULAW_AUDIO_ENCODING:
            codec = PK_COMPOUND_MU_LAW;
            rate = 8000;
            break;
      case ALAW_AUDIO_ENCODING:
            codec = PK_COMPOUND_A_LAW;
            rate = 8000;
            break;
      case G723_3BIT_ENCODING:
            codec = PK_ADPCM_3_BIT;
            rate = 8000;
            break;
      case G721_ADPCM_ENCODING:
            codec = PK_ADPCM_4_BIT;
            rate = 8000;
            break;
      case PCM8_AUDIO_ENCODING:
            codec = PK_PCM_8_BIT;
            if(!rate)
                  rate = 8000;
            break;
      case PCM16_AUDIO_ENCODING:
            codec = PK_PCM_16_BIT;
            if(!rate)
                  rate = 8000;
            break;
      default:
            slog(SLOG_ERROR) << buffer << ": unsupported codec required" << endl;
            Failure();
      }

      if(!rate)
            rate = (unsigned)samplerate(getEncoding());

      switch(rate)
      {
      case 8000:
      case 8012:
            speed = PK_SAMPLING_RATE_8_KHz;
            break;
      case 6000:
            speed = PK_SAMPLING_RATE_6_KHz;
            break;
      case 4000:
            speed = PK_SAMPLING_RATE_4_KHz;
            break;
      case 11025:
            speed = PK_SAMPLING_RATE_11_KHz;
            break;
      default:
            slog(SLOG_ERROR) << buffer << ": unsupported sample rate " << getSampleRate() << endl;
            Failure();
      }
      getInfo(&playinfo);
      recinfo.format = playinfo.format;
      recinfo.encoding = playinfo.encoding;
      recinfo.order = playinfo.order;
      recinfo.annotation = trunk->getSymbol(SYM_ANNOTATION);
      recinfo.rate = playinfo.rate;
      record.Create(data->play.list, &recinfo);
      if(!record.isOpen())
      {
            slog(SLOG_ERROR) << data->play.list << ": cannot open" << endl;
      }

      PK_AUDIO_SetFormat(hDsp, codec | speed);
      PK_AUDIO_SetFormat(hOut, codec | speed);
      bufsize = PK_AUDIO_BufferSize(hDsp);
      samples = tosamples(getEncoding(), bufsize);
}

audioerror_t PikaDuplex::recAudio(int &frame, int buffers)
{
      audioerror_t status = AUDIO_SUCCESS;
      int len = tosamples(getEncoding(), control[frame].dwBytesRecorded);

      if(len)
            status = record.putSamples(&buffer[frame * bufsize], len);
      else
            status = AUDIO_WRITE_INCOMPLETE;

      if(status == AUDIO_SUCCESS)
      {
            control[frame].lpData = (char *)&buffer[frame * bufsize];
            control[frame].dwBufferLength = bufsize;
            control[frame].dwBytesRecorded = 0;
            control[frame].dwLoops = 0;
            control[frame].lpNext = NULL;
            control[frame].dwFlags = 0;
            PK_AUDIO_InputAddBuffer(hDsp, &control[frame++]);
      }
      if(frame >= buffers)
            frame = 2;
      return status;
}

audioerror_t PikaDuplex::playAudio(int &frame, int buffers)
{
      audioerror_t status;

      status = getSamples(&buffer[frame * bufsize], samples);
        control[frame].lpData = (char *)&buffer[frame * bufsize];
        control[frame].dwBufferLength = bufsize;
        control[frame].dwBytesRecorded = bufsize;
        control[frame].dwLoops = 0;
        control[frame].lpNext = NULL;

      if(status == AUDIO_SUCCESS)
            control[frame].dwFlags = 0;
      else
            control[frame].dwFlags = PK_AUDIO_LAST_BUFFER;
      if(status == AUDIO_SUCCESS || status == AUDIO_READ_INCOMPLETE)
            PK_AUDIO_OutputAddBuffer(hOut, &control[frame++]);
      if(frame >= buffers)
            frame = 0;
      return status;
}

void PikaDuplex::Run(void)
{
      int maxbuffers = pikaivr.getAudioBuffers();
      int playbuffers = 2;
      int playframe = 0;
      int recframe = 2;
      int recbuffers = maxbuffers - playbuffers;
      int len = 0;
      audioerror_t status = AUDIO_SUCCESS;
      char name[33];
      int delay;

      reset = true;
      trunk->getName(name);

      if(playbuffers > maxbuffers)
            playbuffers = maxbuffers;
      
      // start

      while(recframe < maxbuffers)
      {
            control[recframe].lpData = (char *)&buffer[recframe * bufsize];
            control[recframe].dwBufferLength = bufsize;
            control[recframe].dwBytesRecorded = 0;
            control[recframe].dwLoops = 0;
            control[recframe].lpNext = NULL;
            control[recframe].dwFlags = 0;
            PK_AUDIO_InputAddBuffer(hDsp, &control[recframe]);
            ++recframe;
      }

      while(!stopped && playframe < playbuffers)
      {     
            status = getSamples(&buffer[playframe * bufsize], samples);
            control[playframe].lpData = (char *)&buffer[playframe * bufsize];
            control[playframe].dwBufferLength = bufsize;
            control[playframe].dwBytesRecorded = bufsize;
            control[playframe].dwLoops = 0;
            control[playframe].lpNext = NULL;
            if(status != AUDIO_READ_INCOMPLETE && status != AUDIO_SUCCESS)
                  break;
            if(status == AUDIO_READ_INCOMPLETE)
                  control[playframe].dwFlags = PK_AUDIO_LAST_BUFFER;
            else
                  control[playframe].dwFlags = 0;
            PK_AUDIO_OutputAddBuffer(hOut, &control[playframe++]);            
      }
      
      delay = playframe;
      if(playframe > 0 || recframe > 2)
            setAudio();

      if(playframe > 0)
            PK_AUDIO_OutputStart(hOut);
      
      if(recframe > 2)
            PK_AUDIO_InputStart(hDsp);

      recframe = 2;
      playframe = 0;
      while(status == AUDIO_SUCCESS && !stopped)
      {
            Wait();
            if(control[playframe].dwFlags == 0xffff)
                  status = playAudio(playframe, playbuffers);
            else if(control[recframe].dwFlags == 0xffff)
                  status = recAudio(recframe, maxbuffers);
      }

      reset = false;
      clrAudio();
      if(status == AUDIO_READ_FAILURE)
      {
            slog(SLOG_ERROR) << name << ": failed playback" << endl;
            Failure();
      }
      Sleep(delay * 120l + 120);
      Success();
}

bool PikaTrunk::duplexHandler(TrunkEvent *event)
{
      switch(event->id)
      {
      case TRUNK_STOP_STATE:
            stopServices();
            flags.reset = false;
            endTimer();
            handler = &PikaTrunk::stepHandler;
            return true;
      case TRUNK_AUDIO_IDLE:
            if(!thread)
            {
                  setTimer(32);
                  return true;
            }
            return true;
      case TRUNK_SERVICE_SUCCESS:
//          stopServices();
            flags.reset = false;
            TrunkSignal(TRUNK_SIGNAL_STEP);
            handler = &PikaTrunk::exitHandler;
            return true;
      case TRUNK_SERVICE_FAILURE:
//          stopServices();
            flags.reset = false;
            setSymbol(SYM_ERROR, "play-failed");
            TrunkSignal(TRUNK_SIGNAL_ERROR);
            handler = &PikaTrunk::exitHandler;
            return true;
      case TRUNK_ENTER_STATE:
            debug->DebugState(this, "duplex");
            status[id] = 'p';
            if(!flags.offhook)
            {
                  PK_TRUNK_OffHook(hTrk);
                  flags.offhook = true;
                  setTimer(group->getPickup());
            }
            else
                  setTimer(125);
            return true;
      case TRUNK_OFF_HOOK:
            if(thread)
                  return true;
      case TRUNK_TIMER_EXPIRED:
            endTimer();
            if(!getDupResource())
            {
                  setSymbol(SYM_ERROR, "dsp-unavailable");
                  TrunkSignal(TRUNK_SIGNAL_ERROR);
                  handler = &PikaTrunk::stepHandler;
                  return true;
            }
            Trunk::setDTMFDetect();
            thread = new PikaDuplex(this);
            thread->Start();
            return true;
      }
      return false;
}


Generated by  Doxygen 1.6.0   Back to index