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

play.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"
#include <sys/ioctl.h>
#include <sys/stat.h>

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

PhonedevPlay::PhonedevPlay(PhonedevTrunk *trunk) :
Service((Trunk *)trunk, keythreads.priAudio()), URLAudio()
{
      reset = false;
      id = trunk->id;
      driver = trunk->getDriver();
      dev = trunk->getDevice();
}

PhonedevPlay::~PhonedevPlay()
{
      char buffer[12];
      terminate();
      sprintf(buffer, "%ld", getTransfered());
      trunk->setSymbol(SYM_PLAYED, buffer);
      sprintf(buffer, "%ld", getPosition());
      trunk->setSymbol(SYM_OFFSET, buffer);
      URLAudio::close();
      if(reset)
      {
            ioctl(dev, PHONE_PLAY_STOP); 
            dspReset();
      }
}

char *PhonedevPlay::getContinuation(void)
{
      char *fn;

      if(data->play.mode == PLAY_MODE_TEMP || data->play.mode == PLAY_MODE_ONE)
            return NULL;
retry:
      fn = getPlayfile();
      if(fn && data->play.mode == PLAY_MODE_ANY)
      {
            if(!canAccess(fn))
                  goto retry;
      }
      return fn;
}

void PhonedevPlay::initial(void)
{
      int codec, framing, len, count = 0;
      char buffer[32];
      char *fn;
      struct stat ino;
      struct tm *dt;
      struct tm tbuf;
      char *ann;
      int ctrl;
      
      trunk->getName(buffer);

      if(tts)
            if(!tts->synth(id, data))
                  Service::failure();

#ifdef      POSIX_PHONEDEV
      ctrl = data->play.volume * 10;
      ioctl(dev, PHONE_PLAY_VOLUME, &ctrl);
#else
      ioctl(dev, PHONE_PLAY_VOLUME, data->play.volume * 10);
#endif
retry:
      fn = getPlayfile();
      if(!fn)
      {
            if(data->play.lock)
            {
                  cachelock.unlock();
                  data->play.lock = false;
            }
            if(data->play.mode == PLAY_MODE_ANY)
                  Service::success();
            slog(Slog::levelError) << "no file" << endl;
            Service::failure();
      }
      stat(fn, &ino);
      open(fn);
      if(data->play.lock)
      {
            cachelock.unlock();
            data->play.lock = false;
      }     
      if(!isOpen())
      {
            if(data->play.mode == PLAY_MODE_ANY || data->play.mode == PLAY_MODE_ONE)
                  goto retry;
            slog(Slog::levelError) << fn << ": cannot open" << endl;
            Service::failure();
      }

      if(data->play.mode == PLAY_MODE_TEMP)
            remove(fn);
      if(data->play.offset)
            setPosition(data->play.offset);
      if(data->play.limit)
            setLimit(data->play.limit);
      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, "");
      
      switch(getEncoding())
      {
      case mulawAudio:
            codec = ULAW;
            framing = 20;
            samples = 24000;
            break;
      case alawAudio:
            codec = ALAW;
            samples = 24000;
            len = 80;
      default:
            slog(Slog::levelError) << buffer << ": unsupported codec required" << endl;
            Service::failure();
      }

      reset = true;
#ifdef      POSIX_PHONEDEV
      ctrl = phivr.getAudioBuffers();
      ioctl(dev, PHONE_PLAY_DEPTH, &ctrl);
#else
      ioctl(dev, PHONE_PLAY_DEPTH, phivr.getAudioBuffers());
#endif

      switch(driver)
      {
#ifdef      IXJ_PHONEDEV
      case ixj_driver:
            if(framing == 20)
                  framing = 30;
            break;
#endif
      }

#ifdef      POSIX_PHONEDEV
      for(;;)
      {
            ctrl = framing;
            ioctl(dev, PHONE_FRAME, &ctrl);
            if(framing == ctrl)
                  break;
            if(++count > 4)
                  break;
            Thread::sleep(20);
      }
#else
      while(framing != ioctl(dev, PHONE_FRAME, framing) && count++ < 5)
            Thread::sleep(20);
#endif

      if(count > 4)
      {
            slog(Slog::levelError) << buffer << ": cannot set framing" << endl;
            Service::failure();
      }

#ifdef      POSIX_PHONEDEV
      if(ioctl(dev, PHONE_PLAY_CODEC, &codec))
#else
      if(ioctl(dev, PHONE_PLAY_CODEC, codec))
#endif
      {
            slog(Slog::levelError) << buffer << ": cannot set codec" << endl;
            Service::failure();
      }
      samples = (samples * framing) / 3000;
      bufsize = toBytes(getEncoding(), samples);
}

void PhonedevPlay::run(void)
{
      char name[33];
      char buffer[bufsize];
      Audio::Error status = Audio::errSuccess;
      int len = 0;

      trunk->getName(name);
      if(ioctl(dev, PHONE_PLAY_START))
      {
            slog(Slog::levelError) << name << ": failed channel playback" << endl;
            Service::failure();
      }

      while(status == Audio::errSuccess && !stopped)
      {     
            status = getSamples(buffer, samples);
            if(status == errReadIncomplete && data->play.maxtime)
            {
                  setPosition(0);
                  status = Audio::errSuccess;
                  continue;
            }
            if(status == errReadIncomplete || status == Audio::errSuccess)
                  len = ::write(dev, buffer, bufsize);      
      }
      if(status == errReadFailure)
            slog(Slog::levelError) << name << ": failed playback" << endl;
      ioctl(dev, PHONE_PLAY_STOP);
      reset = false;
      Service::success();
}

bool PhonedevTrunk::playHandler(TrunkEvent *event)
{
      switch(event->id)
      {
      case TRUNK_SERVICE_SUCCESS:
            trunkSignal(TRUNK_SIGNAL_STEP);
            handler = &PhonedevTrunk::stepHandler;
            return true;
      case TRUNK_SERVICE_FAILURE:
            setSymbol(SYM_ERROR, "play-failed");
            trunkSignal(TRUNK_SIGNAL_ERROR);
            handler = &PhonedevTrunk::stepHandler;
            return true;
      case TRUNK_ENTER_STATE:
            enterState("play");
            flags.dsp = DSP_MODE_VOICE;
            status[id] = 'p';
            if(!flags.offhook)
            {
                  setHookState(true);
                  setTimer(250);
                  return true;
            }
      case TRUNK_TIMER_EXPIRED:
            if(thread)
                  return false;

            if(data.play.maxtime)
                  setTimer(data.play.maxtime);

            setDTMFDetect();
            thread = new PhonedevPlay(this);
            thread->start();
            return true;
      }
      return false;
}

bool PhonedevTrunk::playwaitHandler(TrunkEvent *event)
{
      switch(event->id)
      {
        case TRUNK_EXIT_SHELL:
                if(!tgi.pid)
                        return true;
                tgi.pid = 0;
                endTimer();
                if(event->parm.status)
                {
                        trunkSignal(TRUNK_SIGNAL_ERROR);
                        sprintf(buffer, "play-failed-exit-%d",
                                event->parm.status);
                        setSymbol(SYM_ERROR, buffer);
                        handler = &PhonedevTrunk::stepHandler;
                        return true;
                }
                handler = &PhonedevTrunk::playHandler;
                return true;  

        case TRUNK_TIMER_EXPIRED:
                if(tgi.pid)
                {
                        kill(tgi.pid, SIGTERM);
                        tgi.pid = 0;
                }
                sprintf(buffer, "play-failed-timeout");
                setSymbol(SYM_ERROR, buffer);
                trunkSignal(TRUNK_SIGNAL_ERROR);
                handler = &PhonedevTrunk::stepHandler;
                return true;                                                     
                                                                                         
      case TRUNK_ENTER_STATE:
            enterState("playwait");
                endTimer();
                Trunk::setDTMFDetect();
                setTimer(data.play.timeout);
                return true;
        }
        return false;                                                            
}

#ifdef      CCXX_NAMESPACES
};
#endif

Generated by  Doxygen 1.6.0   Back to index