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

trunk.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"

char *PikaTrunk::status = NULL;

PikaTrunk::PikaTrunk(TResourceHandle hRes, trunknti_t port, int c, int ts) :
Trunk(ts), TimerPort()
{
      TrunkEvent event;
      int bufcount = pikaivr.getAudioBuffers();
//    char buffer[33];

      conf = NULL;
      joined = NULL;
      hDsp = hDsp1 = hPat = 0;
      hTrk = hRes;
      nti = port;
      card = c;

      hTimer = PK_TIMER_Create();
      handler = NULL;

      headers = new TBufferHeader[bufcount];
      bufsize = bufcount * 960 + 960;
      buffers = new unsigned char[bufsize * bufcount];

      PK_TIMER_SetEventHandler(hTimer, (PK_U32)id, (pikacall_t)&PikaTrunk::callback);
      PK_TRUNK_SetEventHandler(hTrk, (PK_U32)id, (pikacall_t)&PikaTrunk::callback);

      if(group->getAnswer())
            PK_TRUNK_CallOfferDetection(hTrk, PK_TRUE);
      else
            PK_TRUNK_CallOfferDetection(hTrk, PK_FALSE);

      PK_TRUNK_DisconnectDetection(hTrk, PK_TRUE);

      flags.trunk = TRUNK_MODE_INACTIVE;
//    getName(buffer);
//    slog(SLOG_DEBUG) << buffer << ": created in group " << group->getName() << endl;

      handler = &PikaTrunk::hangupHandler;
      event.id = TRUNK_ENTER_STATE;
      postEvent(&event);
}

PikaTrunk::~PikaTrunk()
{
      handler = NULL;
      PK_TRUNK_OnHook(hTrk);
      endTimer();
      stopDSP();
      PK_TRUNK_SetEventHandler(hTrk, 0xffff, (pikacall_t)&PikaTrunk::callback);
      PK_TRUNK_ReleaseResource(hTrk);
      PK_TIMER_Delete(hTimer);

      delete[] headers;
      delete[] buffers;
}

bool PikaTrunk::getCIDResource(void)
{
      int rtn;

      if(flags.dsp != DSP_MODE_INACTIVE)
            return false;

      if(nti != TRUNK_LS_NTI)
            return false;

      hDsp = pikaivr.getDSPResource(card, PK_CALLER_ID);
      if(!hDsp)
            return false;

      if(PK_MVIP_HalfDuplexConnect(hTrk, hDsp))
      {
            slog(SLOG_ERROR) << pikaivr.getCardName(card) << id << ": cannot connect cid resource" << endl;
            return false;
      }
      PK_DSP_SetEventHandler(hDsp, (PK_U32)id, (pikacall_t)&PikaTrunk::callback);
      PK_CID_SetBuffer(hDsp, cidbuf, PK_CID_BUFFER_SIZE);
      PK_CID_SetTimeOut(hDsp, group->getCallerid());
      flags.dsp = DSP_MODE_CALLERID;
      return true;
}

bool PikaTrunk::getCPResource(void)
{
      if(flags.dsp == DSP_MODE_TONE || flags.dsp == DSP_MODE_CONF)
            return true;

      stopDSP();
      hDsp = pikaivr.getDSPResource(card, PK_CP_RESOURCES);
      if(!hDsp)
            return false;

      if(PK_MVIP_FullDuplexConnect(hTrk, hDsp))
      {
            slog(SLOG_ERROR) << pikaivr.getCardName(card) << id << ": mvip connect failure" << endl;
            return false;
      }

      hPat = PK_PAT_CreateResource(pikaivr.getCPTable());
      if(!hPat)
      {
            stopDSP();
            return false;
      }
      PK_PAT_SetEventHandler(hPat, id, (pikacall_t)&PikaTrunk::callback);
      PK_PAT_Reset(hPat);
      
      flags.dsp = DSP_MODE_TONE;
      PK_DSP_SetEventHandler(hDsp, id, (pikacall_t)&PikaTrunk::callback);
      PK_VP_EnableToneDetection(hDsp);
      return true;
}

bool PikaTrunk::getCFResource(int id)
{
      conf = (PikaConf *)pikaivr.getConference(id);

      if(flags.dsp == DSP_MODE_CONF)
            return true;

      stopDSP();
      if(!conf)
            return false;

      hDsp = conf->getMember(id);
      if(!hDsp)
      {
            conf = NULL;
            return false;
      }
      PK_MVIP_FullDuplexConnect(hTrk, hDsp);
      flags.dsp = DSP_MODE_CONF;
      PK_DSP_SetEventHandler(hDsp, id, (pikacall_t)&PikaTrunk::callback);
      return true;
}

bool PikaTrunk::getDupResource(void)
{
      if(flags.dsp == DSP_MODE_DUPLEX)
            if(hDsp1)
                  return true;

      stopDSP();
      hDsp = pikaivr.getDSPResource(card, PK_VP_RESOURCES);
      hDsp1 = pikaivr.getDSPResource(card, PK_VP_RESOURCES);
      if(!hDsp || !hDsp1)
            return false;

      if(PK_MVIP_HalfDuplexConnect(hTrk, hDsp))
      {
            slog(SLOG_ERROR) << pikaivr.getCardName(card) << id << ": cannot connect record resource" << endl;
            return false;
      }

      if(PK_MVIP_HalfDuplexConnect(hDsp1, hTrk))
      {
            slog(SLOG_ERROR) << pikaivr.getCardName(card) << id << ": cannot connect play resource" << endl;
            return false;
      }
      flags.dsp = DSP_MODE_DUPLEX;
      PK_DSP_SetEventHandler(hDsp, id, (pikacall_t)&PikaTrunk::callback);
      PK_DSP_SetEventHandler(hDsp1, id, (pikacall_t)&PikaTrunk::callback);
      return true;
}

bool PikaTrunk::getVPResource(void)
{
      if(flags.dsp == DSP_MODE_VOICE || flags.dsp == DSP_MODE_CONF)
            return true;

      stopDSP();
      hDsp = pikaivr.getDSPResource(card, PK_VP_RESOURCES);
      if(!hDsp)
            return false;

      if(PK_MVIP_FullDuplexConnect(hTrk, hDsp))
      {
            slog(SLOG_ERROR) << pikaivr.getCardName(card) << id << ": mvip connect failure" << endl;
            return false;
      }

      flags.dsp = DSP_MODE_VOICE;
      PK_DSP_SetEventHandler(hDsp, id, (pikacall_t)&PikaTrunk::callback);
      return true;
}     

void PikaTrunk::setDTMFDetect(bool flag)
{
      if(!flag)
      {
            if(flags.dtmf && hDsp)
                  PK_VP_DisableDTMFDetection(hDsp);
            flags.dtmf = false;
            return;
      }
      
      flags.dtmf = true;
      switch(flags.dsp)
      {
      case DSP_MODE_INACTIVE:
      case DSP_MODE_CALLERID:
            getVPResource();
      case DSP_MODE_VOICE:
      case DSP_MODE_TONE:
      case DSP_MODE_DUPLEX:
            break;
      default:
            flags.dtmf = false;
            return;
      }

      if(flags.dsp != DSP_MODE_VOICE && flags.dsp != DSP_MODE_TONE && flags.dsp != DSP_MODE_DUPLEX)
      {
            flags.dtmf = false;
            return;
      }

      PK_VP_EnableDTMFDetection(hDsp);
}
      
void PikaTrunk::disjoin(void)
{
      TrunkEvent event;

      if(!joined)
            return;

      PK_MVIP_Disconnect(hTrk, joined->hTrk);
      event.id = TRUNK_PART_TRUNKS;
      joined->postEvent(&event);
      joined = NULL;
}
            
void PikaTrunk::stopDSP(void)
{
      if(hDsp && flags.dsp == DSP_MODE_CALLERID)
            PK_CID_Disable(hDsp);

      flags.dsp = DSP_MODE_INACTIVE;
      if(hDsp1)
      {
            PK_DSP_SetEventHandler(hDsp1, 0xffff, (pikacall_t)&PikaTrunk::callback);
            PK_MVIP_Disconnect(hTrk, hDsp1);
            PK_DSP_ReleasePort(hDsp1);
            hDsp1 = 0;
      }
      if(hPat)
      {
            PK_PAT_SetEventHandler(hPat, 0xffff, (pikacall_t)&PikaTrunk::callback);
            PK_VP_DisableToneDetection(hDsp);
            PK_PAT_DeleteResource(hPat);
            hPat = 0;
      }
      if(!hDsp)
            return;
      PK_DSP_SetEventHandler(hDsp, 0xffff, (pikacall_t)&PikaTrunk::callback);
      PK_MVIP_Disconnect(hTrk, hDsp);
      if(conf)
            conf->endMember(hDsp, id);
      else
            PK_DSP_ReleasePort(hDsp);
      conf = NULL;
      hDsp = 0;
}

void PikaTrunk::endTimer(void)
{
      if(!flags.timer)
            return;
      flags.timer = false;
      TimerPort::endTimer();
      PK_TIMER_Stop(hTimer);
}

void PikaTrunk::setTimer(timeout_t timeout)
{
      endTimer();
      TimerPort::setTimer(timeout);
      PK_TIMER_Start(hTimer, timeout);
      flags.timer = true;
}

void PikaTrunk::incTimer(timeout_t timeout)
{
      if(flags.timer)
            timeout += getTimer();
      setTimer(timeout);
}

void PikaTrunk::getName(char *buffer)
{
      strcpy(buffer, pikaivr.getCardName(card));
      sprintf(buffer + strlen(buffer), "%d", id);
}

void PikaTrunk::Exit(void)
{
      if(!flags.onexit)
            if(redirect("::exit"))
            {
                  flags.onexit = true;
                  return;
            }

      char buffer[33];
      getName(buffer);
      slog(SLOG_DEBUG) << buffer << ": script exiting" << endl;
      handler = &PikaTrunk::hangupHandler;
}

bool PikaTrunk::postEvent(TrunkEvent *event)
{
      bool rtn = true;
      trunkhandler_t prior;
      TBufferHeader *buffer;

      EnterMutex();
      switch(event->id)
      {
      case TRUNK_TIMER_EXPIRED:
            if(!flags.timer)
                  rtn = false;
            break;
      case TRUNK_DTMF_KEYDOWN:
      case TRUNK_DTMF_KEYUP:
            if(flags.offhook)
                  time(&idle);
            if(!flags.dtmf)
                  rtn = false;
            break;
      case TRUNK_AUDIO_IDLE:
      case TRUNK_AUDIO_BUFFER:
            if(flags.dsp != DSP_MODE_VOICE && flags.dsp != DSP_MODE_DUPLEX)
                  rtn = false;
            break;
      case TRUNK_CALLER_ID:
            if(flags.dsp != DSP_MODE_CALLERID)
                  rtn = false;
            break;
      }
      if(!rtn)
      {
            LeaveMutex();
            return false;
      }

      if(!handler)
      {
            slog(SLOG_WARNING) << pikaivr.getCardName(card) << id;
            slog() << ": no handler active; event=" << event->id << endl;
            LeaveMutex();
            return false;
      }

retry:
      debug->DebugEvent(this, event);
      prior = handler;
      rtn = (this->*handler)(event);
      if(rtn)
      {
            if(handler != prior)
            {
                  event->id = TRUNK_ENTER_STATE;
                  goto retry;
            }
            LeaveMutex();
            return rtn;
      }

      rtn = true;
      switch(event->id)
      {
      case TRUNK_AUDIO_BUFFER:
            buffer = (TBufferHeader*)event->parm.data;
            if(buffer->dwFlags == PK_AUDIO_LAST_BUFFER)
            {
                  event->id = TRUNK_AUDIO_IDLE;
                  goto retry;
            }
            if(thread && flags.audio)
            {
                  buffer->dwFlags = 0xffff;     // mark buffer
                  thread->Post();
            }
            break;
      case TRUNK_RINGING_ON:
            ++rings;
            break;
      case TRUNK_ENTER_STATE:
            if(flags.offhook)
                  Trunk::setDTMFDetect();
            else
                  setDTMFDetect(false);
            endTimer();
            break;
      case TRUNK_LINE_WINK:
            if(!flags.offhook)
                  break;
      case TRUNK_STOP_DISCONNECT:
      case TRUNK_CPA_DIALTONE:
            if(flags.onexit)
                  break;
            slog(SLOG_DEBUG) << pikaivr.getCardName(card) << id << ": disconnecting" << endl;
            TrunkSignal(TRUNK_SIGNAL_HANGUP);
            event->id = TRUNK_STOP_STATE;
            goto retry;
            break;
      case TRUNK_TIMER_EXPIRED:
            if(!TrunkSignal(TRUNK_SIGNAL_TIMEOUT))
                  TrunkSignal(TRUNK_SIGNAL_STEP);
            event->id = TRUNK_STOP_STATE;
            goto retry;
            break;
      case TRUNK_DTMF_KEYUP:
            if(digits < 32)
                  dtmf.bin.data[digits++] = digit[event->parm.dtmf.digit];
            dtmf.bin.data[digits] = 0;
            if(TrunkSignal((trunksignal_t)(event->parm.dtmf.digit + TRUNK_SIGNAL_0)))
            {
                  event->id = TRUNK_STOP_STATE;
                  goto retry;
            }
            break;
      case TRUNK_EXIT_SHELL:
            tgi.pid = 0;
            break;
      case TRUNK_STOP_STATE:
            endTimer();
            handler = &PikaTrunk::stepHandler;
            break;
      case TRUNK_EXIT_STATE:
            break;
      case TRUNK_MAKE_BUSY:
            handler = &PikaTrunk::busyHandler;
            break;
      case TRUNK_MAKE_IDLE:
            handler = &PikaTrunk::hangupHandler;
            break;
      default:
            rtn = false;
      }
      if(handler != prior)
      {
            event->id = TRUNK_ENTER_STATE;
            goto retry;
      }
      LeaveMutex();
      return rtn;
}

unsigned long PikaTrunk::getIdleTime(void)
{
      time_t now;

      time(&now);
      if(handler == &PikaTrunk::idleHandler)
            return now - idle;

      return 0;
}

void PikaTrunk::callback(PK_U32 id, PK_U32 pk, PK_U32 p1, PK_U32 p2)
{
      TrunkEvent event;
      Trunk *trunk = pikaivr.getTrunkPort(id);
      char *d;
      char buffer[33];
      unsigned error;

      if(!trunk)
            return;

      memset(&event, 0, sizeof(event));

      switch(pk)
      {
      case PK_EVENT_DSP_WARNING:
            trunk->getName(buffer);
            error = p1 & 0xffff;
            slog(SLOG_WARNING) << buffer << ": dsp failure; reason=" << error << endl;
            return;
      case PK_EVENT_OUTBOX_OVERFLOW:
            trunk->getName(buffer);
            slog(SLOG_ERROR) << buffer << ": underflow error" << endl;
            return;
      case PK_EVENT_INBOX_OVERFLOW:
            trunk->getName(buffer);
            slog(SLOG_ERROR) << buffer << ": overflow error " << endl;
            return;
      case PK_AUDIO_OUTPUT_IDLE:
      case PK_AUDIO_INPUT_IDLE:
            event.id = TRUNK_AUDIO_IDLE;
            break;
      case PK_AUDIO_RETURN_BUFFER:
            event.id = TRUNK_AUDIO_BUFFER;
            event.parm.data = (void *)p1;
            break;
      case PK_EVENT_PULSE_DIGIT:
            event.id = TRUNK_DTMF_KEYDOWN;
            event.parm.dtmf.digit = p1;
            event.parm.dtmf.duration = 100;
            trunk->postEvent(&event);
            event.id = TRUNK_DTMF_KEYUP;
            break;
      case PK_EVENT_DTMF_KEY_DOWN:
            p1 = tolower(p1);
            d = strchr(digit, p1);
            if(!d)
                  return;
            event.id = TRUNK_DTMF_KEYDOWN;
            event.parm.dtmf.digit = (int)(d - digit);
            event.parm.dtmf.duration = p2;
            break;
      case PK_EVENT_DTMF_KEY_UP:
            p1 = tolower(p1);
            d = strchr(digit, p1);
            if(!d)
                  return;
            event.id = TRUNK_DTMF_KEYUP;
            event.parm.dtmf.digit = (int)(d - digit);
            event.parm.dtmf.duration = p2;
            break;
      case PK_EVENT_TGEN_TONE_PLAYED:
      case PK_EVENT_TGEN_INVALID_TONE:
            event.id = TRUNK_TONE_IDLE;
            break;
      case PK_EVENT_CID_READY:
            event.id = TRUNK_DSP_READY;
            event.parm.dsp = DSP_MODE_CALLERID;
            break;
      case PK_EVENT_CID_REPORT:
            if(p1)
                  return;
            event.id = TRUNK_CALLER_ID;   
            event.parm.data = (void *)p2;
            break;
      case PK_EVENT_TRUNK_OFFHOOK:
            event.id = TRUNK_OFF_HOOK;
            event.parm.duration = p1;
            break;
      case PK_EVENT_TRUNK_ONHOOK:
            event.id = TRUNK_ON_HOOK;
            event.parm.duration = p1;
            break;
      case PK_EVENT_TRUNK_RINGING_ON:
            event.id = TRUNK_RINGING_ON;
            event.parm.ring.duration = p1;
            break;
      case PK_EVENT_TRUNK_RINGING_OFF:
            event.id = TRUNK_RINGING_OFF;
            event.parm.ring.duration = p1;
            break;
      case PK_EVENT_TRUNK_DIGIT:
            event.id = TRUNK_RINGING_DID;
            event.parm.ring.digit = p1;
            break;
      case PK_EVENT_ATD_TONE_ON:
            event.id = TRUNK_CPA_DIALTONE;
            break;
      case PK_EVENT_PATTERN_MATCH:
            switch(p1)
            {
            case 0:
                  event.id = TRUNK_CPA_RINGBACK;
                  break;
            case 1:
                  event.id = TRUNK_CPA_BUSYTONE;
                  break;
            case 2:
                  event.id = TRUNK_CPA_FAILURE;
                  break;
            default:
                  return;
            }
            break;
      case PK_EVENT_TRUNK_LC_TERM:
            event.id = TRUNK_LINE_WINK;
            event.parm.duration = p1;
            break;
      case PK_EVENT_TIMER_EXPIRED:
            event.id = TRUNK_TIMER_EXPIRED;
            break;
      default:
            return;
      }
      trunk->postEvent(&event);
}

bool PikaTrunk::scrDetect(void)
{
      data.dialxfer.timeout = atoi(getValue("16")) * 1000;
      TrunkStep(TRUNK_STEP_DETECT);
      return false;
}

bool PikaTrunk::scrJoin(void)
{
      Trunk *trunk = pikaivr.getTrunkPort(atoi(getValue("-1")));

      if(!trunk)
      {
            Error("join-no-port");
            return true;
      }

      data.join.trunk = trunk;
      data.join.wakeup = atoi(getValue("0")) * 1000;
      TrunkStep(TRUNK_STEP_JOIN);
      return false;
}

bool PikaTrunk::scrWait(void)
{
      data.join.trunk = NULL;
      data.join.wakeup = atoi(getValue("0")) * 1000;
      TrunkStep(TRUNK_STEP_JOIN);
      return false;
}

bool PikaTrunk::scrLeave(void)
{
      stopDSP();
      Advance();
      return true;
}

bool PikaTrunk::scrConf(void)
{
      stopDSP();
      if(!getCFResource(atoi(getValue("-1"))))
      {
            Error("conf-unavailable");
            return true;
      }
      Advance();
      return true;
}

bool PikaTrunk::scrDuplex(void)
{
      strstream str(data.play.list, sizeof(data.play.list) - 1);
      char *cp;
      char buffer[32];

      if(pikaivr.getAudioBuffers() < 4)
      {
            getName(buffer);
            slog(SLOG_ERROR) << buffer << "insufficient buffers; fix [pika]" << endl;
            Error("duplex-insufficient-buffering");
            return true;
      }

      cp = getValue(NULL);
      if(!cp)
      {
            Error("duplex-no-file-to-record");
            return true;
      }

      str << cp;

      while(NULL != (cp = getValue(NULL)))
            str << "," << cp;

      str << ends;

      data.play.list[sizeof(data.play.list) - 1] = 0;
      data.play.name = data.play.list;
      data.play.volume = atoi(getSymbol(SYM_VOLUME));
      while(*data.play.name && *data.play.name != ',')
            ++data.play.name;
      if(*data.play.name != ',')
      {
            Error("duplex-no-file-to-play");
            return true;
      }
      *(data.play.name++) = 0;
      data.play.limit = data.play.offset = 0;
      TrunkStep(TRUNK_STEP_DUPLEX);
      return false;
}


Generated by  Doxygen 1.6.0   Back to index