Skip to content
Snippets Groups Projects
managerimpl.cpp 40 KiB
Newer Older
jpbl's avatar
jpbl committed
/**
 *  Copyright (C) 2004-2005 Savoir-Faire Linux inc.
yanmorin's avatar
 
yanmorin committed
 *  Author: Yan Morin <yan.morin@savoirfairelinux.com>
jpbl's avatar
jpbl committed
 *  Author : Laurielle Lea <laurielle.lea@savoirfairelinux.com>
 *                                                                              
 *  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., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#include <errno.h>
#include <time.h>
yanmorin's avatar
 
yanmorin committed
#include <cstdlib>
#include <iostream>
#include <fstream>
jpbl's avatar
jpbl committed

yanmorin's avatar
 
yanmorin committed
#include <sys/types.h> // mkdir(2)
#include <sys/stat.h>	// mkdir(2)
jpbl's avatar
jpbl committed

yanmorin's avatar
 
yanmorin committed
#include <cc++/socket.h>   // why do I need this here?
#include <ccrtp/channel.h> // why do I need this here?
#include <ccrtp/rtp.h>     // why do I need this here?
yanmorin's avatar
 
yanmorin committed
#include <cc++/file.h>
yanmorin's avatar
 
yanmorin committed

jpbl's avatar
jpbl committed
#include "manager.h"
#include "audio/audiolayer.h"
yanmorin's avatar
 
yanmorin committed
#include "audio/audiocodec.h"
//#include "audio/ringbuffer.h"
yanmorin's avatar
 
yanmorin committed
#include "audio/tonelist.h"

yanmorin's avatar
 
yanmorin committed
#include "sipvoiplink.h"
#include "voIPLink.h"
jpbl's avatar
jpbl committed
#include "call.h"
yanmorin's avatar
 
yanmorin committed

jpbl's avatar
jpbl committed
#include "user_cfg.h"
#include "gui/guiframework.h"

yanmorin's avatar
 
yanmorin committed
#ifdef USE_ZEROCONF
#include "zeroconf/DNSService.h"
yanmorin's avatar
 
yanmorin committed
#include "zeroconf/DNSServiceTXTRecord.h"
yanmorin's avatar
 
yanmorin committed
#endif

yanmorin's avatar
 
yanmorin committed
#define fill_config_str(name, value) \
  (_config.addConfigTreeItem(section, Conf::ConfigTreeItem(std::string(name), std::string(value), type_str)))
#define fill_config_int(name, value) \
  (_config.addConfigTreeItem(section, Conf::ConfigTreeItem(std::string(name), std::string(value), type_int)))

yanmorin's avatar
 
yanmorin committed
#define DFT_VOIP_LINK 0

jpbl's avatar
jpbl committed
ManagerImpl::ManagerImpl (void)
{
jpbl's avatar
jpbl committed
  // Init private variables 
yanmorin's avatar
 
yanmorin committed
  //_error = new Error();
yanmorin's avatar
 
yanmorin committed

yanmorin's avatar
 
yanmorin committed
  _hasZeroconf = false;
yanmorin's avatar
 
yanmorin committed
#ifdef USE_ZEROCONF
yanmorin's avatar
 
yanmorin committed
  _hasZeroconf = true;
yanmorin's avatar
 
yanmorin committed
  _DNSService = new DNSService();
#endif
jpbl's avatar
jpbl committed

yanmorin's avatar
 
yanmorin committed
  // setup
jpbl's avatar
jpbl committed
  _path = ""; 
  _exist = 0;
yanmorin's avatar
 
yanmorin committed
  _setupLoaded = false;
jpbl's avatar
jpbl committed
  _gui = NULL;
yanmorin's avatar
 
yanmorin committed

  // SOUND:
  _codecMap = CodecDescriptorMap().getMap();
jpbl's avatar
jpbl committed
  _audiodriverPA = NULL;
yanmorin's avatar
 
yanmorin committed

  // Initialize after by init() -> initVolume()
  _spkr_volume = 0;
yanmorin's avatar
 
yanmorin committed
  _mic_volume  = 0; 
  _mic_volume_before_mute = 0;
yanmorin's avatar
 
yanmorin committed

yanmorin's avatar
 
yanmorin committed
  // Call
  _currentCallId = 0;
yanmorin's avatar
 
yanmorin committed
  _nbIncomingWaitingCall=0;
yanmorin's avatar
 
yanmorin committed
  _registerState = UNREGISTERED;
yanmorin's avatar
 
yanmorin committed
  _hasTriedToRegister = false;
  // initialize random generator for call id
  srand (time(NULL));
jpbl's avatar
jpbl committed
}

yanmorin's avatar
 
yanmorin committed
// never call if we use only the singleton...
jpbl's avatar
jpbl committed
ManagerImpl::~ManagerImpl (void) 
{
jpbl's avatar
jpbl committed
  terminate();
yanmorin's avatar
 
yanmorin committed

yanmorin's avatar
 
yanmorin committed
#ifdef USE_ZEROCONF
  delete _DNSService; _DNSService = NULL;
#endif

yanmorin's avatar
 
yanmorin committed
  _debug("%s stop correctly.\n", PROGNAME);
yanmorin's avatar
 
yanmorin committed
}
jpbl's avatar
jpbl committed

void 
yanmorin's avatar
 
yanmorin committed
ManagerImpl::init() 
jpbl's avatar
jpbl committed
{
yanmorin's avatar
 
yanmorin committed
  initVolume();

jpbl's avatar
jpbl committed
  if (_exist == 0) {
    _debug("Cannot create config file in your home directory\n");
yanmorin's avatar
 
yanmorin committed
  }

  _debugInit("Load Telephone Tone");
  std::string country = getConfigString(PREFERENCES, ZONE_TONE);
  _telephoneTone = new TelephoneTone(country);
jpbl's avatar
jpbl committed

  try {
yanmorin's avatar
 
yanmorin committed
    initAudioDriver();
jpbl's avatar
jpbl committed
    selectAudioDriver();
  }
yanmorin's avatar
 
yanmorin committed
  catch (const portaudio::PaException &e) {
      getAudioDriver()->setErrorMessage(e.paErrorText());
yanmorin's avatar
 
yanmorin committed
      _debug("Portaudio exception: %s\n", e.paErrorText());
yanmorin's avatar
 
yanmorin committed
  }
  catch (const portaudio::PaCppException &e) {
      getAudioDriver()->setErrorMessage(e.what());
yanmorin's avatar
 
yanmorin committed
      _debug("Portaudio exception: %s\n", e.what());
yanmorin's avatar
 
yanmorin committed
  }
  catch (const std::runtime_error &e) {
      getAudioDriver()->setErrorMessage(e.what());
yanmorin's avatar
 
yanmorin committed
      _debug("Portaudio exception: %s\n", e.what());
yanmorin's avatar
 
yanmorin committed
  }
  catch (...) {
      displayError("An unknown exception occured while selecting audio driver.");
yanmorin's avatar
 
yanmorin committed
      throw;
yanmorin's avatar
 
yanmorin committed
  }
yanmorin's avatar
 
yanmorin committed
  initAudioCodec();
yanmorin's avatar
 
yanmorin committed

yanmorin's avatar
 
yanmorin committed
  _debugInit("Adding new VoIP Link");
yanmorin's avatar
 
yanmorin committed
  // Set a sip voip link by default
yanmorin's avatar
 
yanmorin committed
  _voIPLinkVector.push_back(new SipVoIPLink());
yanmorin's avatar
 
yanmorin committed

yanmorin's avatar
 
yanmorin committed
  // initRegisterVoIP was here, but we doing it after the gui loaded... 
  // the stun detection is long, so it's a better idea to do it after getEvents
yanmorin's avatar
yanmorin committed
  initZeroconf();
jpbl's avatar
jpbl committed
}
jpbl's avatar
jpbl committed

jpbl's avatar
jpbl committed
void ManagerImpl::terminate()
{
yanmorin's avatar
 
yanmorin committed
  saveConfig();
yanmorin's avatar
 
yanmorin committed

yanmorin's avatar
 
yanmorin committed
  _debug("Removing VoIP Links...\n");
yanmorin's avatar
 
yanmorin committed
  for(VoIPLinkVector::iterator pos = _voIPLinkVector.begin();
      pos != _voIPLinkVector.end();
      pos++) {
    delete *pos;
yanmorin's avatar
 
yanmorin committed
    *pos = NULL;
yanmorin's avatar
 
yanmorin committed
  }
yanmorin's avatar
 
yanmorin committed
  _voIPLinkVector.clear();
yanmorin's avatar
 
yanmorin committed

yanmorin's avatar
 
yanmorin committed
  _debug("Removing calls\n");
yanmorin's avatar
 
yanmorin committed
  _mutex.enterMutex();
yanmorin's avatar
 
yanmorin committed
  for(CallVector::iterator pos = _callVector.begin();
      pos != _callVector.end();
      pos++) {
yanmorin's avatar
 
yanmorin committed
    delete *pos;   *pos = NULL;
yanmorin's avatar
 
yanmorin committed
  }
yanmorin's avatar
 
yanmorin committed
  _callVector.clear();
yanmorin's avatar
 
yanmorin committed
  _mutex.leaveMutex();
yanmorin's avatar
 
yanmorin committed

  unloadAudioCodec();

yanmorin's avatar
 
yanmorin committed
  _debug("Unload Audio Driver\n");
yanmorin's avatar
 
yanmorin committed
  delete _audiodriverPA; _audiodriverPA = NULL;
yanmorin's avatar
 
yanmorin committed

  _debug("Unload Telephone Tone\n");
  delete _telephoneTone; _telephoneTone = 0;
jpbl's avatar
jpbl committed
}

void
ManagerImpl::setGui (GuiFramework* gui)
{
	_gui = gui;
}

yanmorin's avatar
 
yanmorin committed
/**
 * Multi Thread with _mutex for callVector
 */
Call *
yanmorin's avatar
 
yanmorin committed
ManagerImpl::pushBackNewCall (CALLID id, enum CallType type)
jpbl's avatar
jpbl committed
{
yanmorin's avatar
 
yanmorin committed
  ost::MutexLock m(_mutex);
yanmorin's avatar
 
yanmorin committed
  Call* call = new Call(id, type, _voIPLinkVector.at(DFT_VOIP_LINK));
  // Set the wanted voip-link (first of the list)
  _callVector.push_back(call);
  return call;
jpbl's avatar
jpbl committed
}

yanmorin's avatar
 
yanmorin committed
/**
 * Multi Thread with _mutex for callVector
 */
jpbl's avatar
jpbl committed
Call*
yanmorin's avatar
 
yanmorin committed
ManagerImpl::getCall (CALLID id)
jpbl's avatar
jpbl committed
{
yanmorin's avatar
 
yanmorin committed
  //_debug("%10d: Getting call\n", id);
yanmorin's avatar
 
yanmorin committed
  Call* call = NULL;
  unsigned int size = _callVector.size();
yanmorin's avatar
 
yanmorin committed
  for (unsigned int i = 0; i < size; i++) {
    call = _callVector.at(i);
    if (call && call->getId() == id) {
      break;
    } else {
      call = NULL;
yanmorin's avatar
 
yanmorin committed
    }
  }
  return call;
jpbl's avatar
jpbl committed
}

yanmorin's avatar
 
yanmorin committed
/**
yanmorin's avatar
 
yanmorin committed
 * Multi Thread with _mutex for callVector
yanmorin's avatar
 
yanmorin committed
 */
jpbl's avatar
jpbl committed
void
yanmorin's avatar
 
yanmorin committed
ManagerImpl::deleteCall (CALLID id)
jpbl's avatar
jpbl committed
{
yanmorin's avatar
 
yanmorin committed
  //_debug("%10d: Deleting call\n", id);
yanmorin's avatar
 
yanmorin committed
  CallVector::iterator iter = _callVector.begin();
  while(iter!=_callVector.end()) {
yanmorin's avatar
 
yanmorin committed
    Call *call = *iter;
yanmorin's avatar
 
yanmorin committed
    if (call != NULL && call->getId() == id) {
yanmorin's avatar
 
yanmorin committed
      if (call->getFlagNotAnswered() && call->isIncomingType() && call->getState() != Call::NotExist) {
yanmorin's avatar
 
yanmorin committed
        decWaitingCall();
      }
      delete (*iter); *iter = NULL; 
      call = NULL;
yanmorin's avatar
 
yanmorin committed
      _callVector.erase(iter);
      return;
    }
    iter++;
  }
jpbl's avatar
jpbl committed
}

yanmorin's avatar
 
yanmorin committed
void
ManagerImpl::setCurrentCallId(CALLID id)
{
yanmorin's avatar
 
yanmorin committed
  //_debug("%10d: Setting current callid, old one was: %d\n", id, _currentCallId);
yanmorin's avatar
 
yanmorin committed
  _currentCallId = id;
}

yanmorin's avatar
 
yanmorin committed
void
ManagerImpl::removeCallFromCurrent(CALLID id)
{
  if ( _currentCallId == id ) {
yanmorin's avatar
 
yanmorin committed
    //_debug("%10d: Setting current callid, old one was: %d\n", 0, _currentCallId);
yanmorin's avatar
 
yanmorin committed
    _currentCallId = 0;
  }
}


jpbl's avatar
jpbl committed
///////////////////////////////////////////////////////////////////////////////
// Management of events' IP-phone user
///////////////////////////////////////////////////////////////////////////////
yanmorin's avatar
 
yanmorin committed
/**
 * Main thread
 */
jpbl's avatar
jpbl committed
int 
yanmorin's avatar
 
yanmorin committed
ManagerImpl::outgoingCall (const std::string& to)
yanmorin's avatar
 
yanmorin committed
{
yanmorin's avatar
 
yanmorin committed
  CALLID id = generateNewCallId();
yanmorin's avatar
 
yanmorin committed
  _debug("%10d: Outgoing Call\n", id);
yanmorin's avatar
 
yanmorin committed
  Call *call = pushBackNewCall(id, Outgoing);
yanmorin's avatar
 
yanmorin committed
  ost::MutexLock m(_mutex);
yanmorin's avatar
 
yanmorin committed
  call->setState(Call::Progressing);
yanmorin's avatar
 
yanmorin committed
  call->setCallerIdNumber(to);
yanmorin's avatar
 
yanmorin committed
  if (call->outgoingCall(to) == 0) {
    return id;
  } else {
    return 0;
  }
jpbl's avatar
jpbl committed
}

yanmorin's avatar
 
yanmorin committed
/**
 * User action (main thread)
 * Every Call
 */
jpbl's avatar
jpbl committed
int 
yanmorin's avatar
 
yanmorin committed
ManagerImpl::hangupCall (CALLID id)
jpbl's avatar
jpbl committed
{
yanmorin's avatar
 
yanmorin committed
  _debug("%10d: Hangup Call\n", id);
yanmorin's avatar
 
yanmorin committed
  stopTone();
yanmorin's avatar
 
yanmorin committed
  ost::MutexLock m(_mutex);
  Call* call = getCall(id);
yanmorin's avatar
 
yanmorin committed
  if (call == NULL) {
yanmorin's avatar
 
yanmorin committed
    return -1;
  }
yanmorin's avatar
yanmorin committed
  int result = -1;
  if (call->getState() != Call::Error) { 
    result = call->hangup();
yanmorin's avatar
 
yanmorin committed
  }
yanmorin's avatar
 
yanmorin committed
  deleteCall(id);
yanmorin's avatar
 
yanmorin committed
  // current call id or no line selected
  if (id == _currentCallId || _currentCallId == 0) {
yanmorin's avatar
 
yanmorin committed
    removeCallFromCurrent(id);
yanmorin's avatar
 
yanmorin committed
  }
yanmorin's avatar
 
yanmorin committed
  return result;
jpbl's avatar
jpbl committed
}

yanmorin's avatar
 
yanmorin committed
/**
 * User action (main thread)
 * Every Call
yanmorin's avatar
 
yanmorin committed
 * -1 : call not found
 *  0 : already in this state...
yanmorin's avatar
 
yanmorin committed
 */
jpbl's avatar
jpbl committed
int
yanmorin's avatar
 
yanmorin committed
ManagerImpl::cancelCall (CALLID id)
jpbl's avatar
jpbl committed
{
yanmorin's avatar
 
yanmorin committed
  _debug("%10d: Cancel Call\n", id);
yanmorin's avatar
 
yanmorin committed
  ost::MutexLock m(_mutex);
  Call* call = getCall(id);
  if (call == NULL) { 
    return -1; 
yanmorin's avatar
 
yanmorin committed
  }
yanmorin's avatar
 
yanmorin committed
  int result = call->cancel();
  deleteCall(id);
yanmorin's avatar
 
yanmorin committed
  stopTone();
yanmorin's avatar
 
yanmorin committed
  return result;
jpbl's avatar
jpbl committed
}

yanmorin's avatar
 
yanmorin committed
/**
 * User action (main thread)
 * Incoming Call
 */
jpbl's avatar
jpbl committed
int 
yanmorin's avatar
 
yanmorin committed
ManagerImpl::answerCall (CALLID id)
jpbl's avatar
jpbl committed
{
yanmorin's avatar
 
yanmorin committed
  _debug("%10d: Answer Call\n", id);
yanmorin's avatar
 
yanmorin committed
  ost::MutexLock m(_mutex);
  Call* call = getCall(id);
  if (call == NULL) {
    return -1;
  }
yanmorin's avatar
 
yanmorin committed
  if (call->getFlagNotAnswered()) {
yanmorin's avatar
 
yanmorin committed
    decWaitingCall();
yanmorin's avatar
 
yanmorin committed
    call->setFlagNotAnswered(false);
yanmorin's avatar
 
yanmorin committed
  }
yanmorin's avatar
 
yanmorin committed
  if (call->getState() != Call::OnHold) {
    switchCall(id);
  }
  stopTone(); // before answer, don't stop the audio stream after open it
yanmorin's avatar
 
yanmorin committed
  return call->answer();
jpbl's avatar
jpbl committed
}

yanmorin's avatar
 
yanmorin committed
/**
 * User action (main thread)
 * Every Call
yanmorin's avatar
 
yanmorin committed
 * @return 0 if it fails, -1 if not present
yanmorin's avatar
 
yanmorin committed
 */
jpbl's avatar
jpbl committed
int 
yanmorin's avatar
 
yanmorin committed
ManagerImpl::onHoldCall (CALLID id)
jpbl's avatar
jpbl committed
{
yanmorin's avatar
 
yanmorin committed
  _debug("%10d: On Hold Call\n", id);
yanmorin's avatar
 
yanmorin committed
  ost::MutexLock m(_mutex);
  Call* call = getCall(id);
  if (call == NULL) {
    return -1;
  }
yanmorin's avatar
 
yanmorin committed
  removeCallFromCurrent(id);
yanmorin's avatar
 
yanmorin committed
  if ( call->getState() == Call::OnHold || call->isNotAnswered()) {
yanmorin's avatar
 
yanmorin committed
    return 1;
  }
  return call->onHold();
jpbl's avatar
jpbl committed
}

yanmorin's avatar
 
yanmorin committed
/**
 * User action (main thread)
 * Every Call
 */
jpbl's avatar
jpbl committed
int 
yanmorin's avatar
 
yanmorin committed
ManagerImpl::offHoldCall (CALLID id)
jpbl's avatar
jpbl committed
{
yanmorin's avatar
 
yanmorin committed
  _debug("%10d: Off Hold Call\n", id);
yanmorin's avatar
 
yanmorin committed
  ost::MutexLock m(_mutex);
yanmorin's avatar
 
yanmorin committed
  stopTone();
yanmorin's avatar
 
yanmorin committed
  Call* call = getCall(id);
yanmorin's avatar
 
yanmorin committed
  if (call == 0) {
yanmorin's avatar
 
yanmorin committed
    return -1;
  }
  if (call->getState() == Call::OffHold) {
    return 1;
  }
yanmorin's avatar
 
yanmorin committed
  setCurrentCallId(id);
yanmorin's avatar
 
yanmorin committed
  int returnValue = call->offHold();
yanmorin's avatar
 
yanmorin committed
  // start audio if it's ok
  if (returnValue != -1) {
yanmorin's avatar
 
yanmorin committed
    try {
      getAudioDriver()->startStream();
    } catch(...) {
      _debugException("Off hold could not start audio stream");
    }
yanmorin's avatar
 
yanmorin committed
  }
  return returnValue;
jpbl's avatar
jpbl committed
}

yanmorin's avatar
 
yanmorin committed
/**
 * User action (main thread)
 * Every Call
 */
jpbl's avatar
jpbl committed
int 
yanmorin's avatar
 
yanmorin committed
ManagerImpl::transferCall (CALLID id, const std::string& to)
jpbl's avatar
jpbl committed
{
yanmorin's avatar
 
yanmorin committed
  _debug("%10d: Transfer Call to %s\n", id, to.c_str());
yanmorin's avatar
 
yanmorin committed
  ost::MutexLock m(_mutex);
  Call* call = getCall(id);
yanmorin's avatar
 
yanmorin committed
  if (call == 0) {
yanmorin's avatar
 
yanmorin committed
    return -1;
  }
yanmorin's avatar
 
yanmorin committed
  removeCallFromCurrent(id);
yanmorin's avatar
 
yanmorin committed
  return call->transfer(to);
jpbl's avatar
jpbl committed
}
yanmorin's avatar
 
yanmorin committed

/**
 * User action (main thread)
 * All Call
 */
yanmorin's avatar
 
yanmorin committed
void
ManagerImpl::mute() {
  _mic_volume_before_mute = _mic_volume;
yanmorin's avatar
 
yanmorin committed
  setMicVolume(0);
yanmorin's avatar
 
yanmorin committed
}

yanmorin's avatar
 
yanmorin committed
/**
 * User action (main thread)
 * All Call
 */
yanmorin's avatar
 
yanmorin committed
void
ManagerImpl::unmute() {
yanmorin's avatar
yanmorin committed
  if ( _mic_volume == 0 ) {
    setMicVolume(_mic_volume_before_mute);
  }
jpbl's avatar
jpbl committed
}

yanmorin's avatar
 
yanmorin committed
/**
 * User action (main thread)
 * Call Incoming
 */
jpbl's avatar
jpbl committed
int 
yanmorin's avatar
 
yanmorin committed
ManagerImpl::refuseCall (CALLID id)
jpbl's avatar
jpbl committed
{
yanmorin's avatar
 
yanmorin committed
  _debug("%10d: Refuse Call\n", id);
yanmorin's avatar
 
yanmorin committed
  ost::MutexLock m(_mutex);
  Call *call = getCall(id);
  if (call == NULL) {
    return -1;
yanmorin's avatar
 
yanmorin committed
  }
yanmorin's avatar
 
yanmorin committed

yanmorin's avatar
 
yanmorin committed
  if ( call->getState() != Call::Progressing ) {
yanmorin's avatar
 
yanmorin committed
    return -1;
yanmorin's avatar
 
yanmorin committed
  }
yanmorin's avatar
 
yanmorin committed

yanmorin's avatar
 
yanmorin committed
  int refuse = call->refuse();
  removeCallFromCurrent(id);
yanmorin's avatar
 
yanmorin committed
  deleteCall(id);
yanmorin's avatar
 
yanmorin committed
  stopTone();
yanmorin's avatar
 
yanmorin committed
  return refuse;
jpbl's avatar
jpbl committed
}

yanmorin's avatar
 
yanmorin committed
/**
 * User action (main thread)
 */
yanmorin's avatar
 
yanmorin committed
bool
jpbl's avatar
jpbl committed
ManagerImpl::saveConfig (void)
{
yanmorin's avatar
 
yanmorin committed
  _debug("Saving Configuration...\n");
yanmorin's avatar
 
yanmorin committed
  setConfig(AUDIO, VOLUME_SPKR, getSpkrVolume());
  setConfig(AUDIO, VOLUME_MICRO, getMicVolume());

yanmorin's avatar
 
yanmorin committed
  _setupLoaded = _config.saveConfigTree(_path.data());
  return _setupLoaded;
jpbl's avatar
jpbl committed
}

yanmorin's avatar
 
yanmorin committed
/**
 * Main Thread
 */
yanmorin's avatar
 
yanmorin committed
bool
yanmorin's avatar
 
yanmorin committed
ManagerImpl::initRegisterVoIPLink() 
{
yanmorin's avatar
 
yanmorin committed
  int returnValue = true;
yanmorin's avatar
 
yanmorin committed
  _debugInit("Initiate VoIP Link Registration\n");
yanmorin's avatar
 
yanmorin committed
  if (_hasTriedToRegister == false) {
yanmorin's avatar
 
yanmorin committed
    if ( _voIPLinkVector.at(DFT_VOIP_LINK)->init() ) { 
      // we call here, because it's long...
      // If network is available and exosip is start..
yanmorin's avatar
 
yanmorin committed
      if (getConfigInt(SIGNALISATION, AUTO_REGISTER) && _exist == 1) {
        registerVoIPLink();
yanmorin's avatar
 
yanmorin committed
        _hasTriedToRegister = true;
yanmorin's avatar
 
yanmorin committed
      }
yanmorin's avatar
 
yanmorin committed
    } else {
      returnValue = false;
yanmorin's avatar
 
yanmorin committed
    }
  }
yanmorin's avatar
 
yanmorin committed
  return returnValue;
yanmorin's avatar
 
yanmorin committed
}

yanmorin's avatar
 
yanmorin committed

yanmorin's avatar
 
yanmorin committed
/**
 * Initialize action (main thread)
yanmorin's avatar
 
yanmorin committed
 * Note that Registration is only send if STUN is not activated
yanmorin's avatar
 
yanmorin committed
 * @return true if setRegister is call without failure, else return false
yanmorin's avatar
 
yanmorin committed
 */
yanmorin's avatar
 
yanmorin committed
bool
jpbl's avatar
jpbl committed
ManagerImpl::registerVoIPLink (void)
{
yanmorin's avatar
 
yanmorin committed
  _debug("Register VoIP Link\n");
yanmorin's avatar
 
yanmorin committed
  int returnValue = false;
  if (_voIPLinkVector.at(DFT_VOIP_LINK)->setRegister() >= 0) {
    returnValue = true;
    _registerState = REGISTERED;
  } else {
    _registerState = FAILED;
  }
yanmorin's avatar
 
yanmorin committed
  return returnValue;
jpbl's avatar
jpbl committed
}

yanmorin's avatar
 
yanmorin committed
/**
 * Terminate action (main thread)
yanmorin's avatar
 
yanmorin committed
 * @return true if the unregister method is send correctly
yanmorin's avatar
 
yanmorin committed
 */
yanmorin's avatar
 
yanmorin committed
bool 
llea's avatar
llea committed
ManagerImpl::unregisterVoIPLink (void)
{
yanmorin's avatar
 
yanmorin committed
  _debug("Unregister VoIP Link\n");
jpbl's avatar
jpbl committed
	if (_voIPLinkVector.at(DFT_VOIP_LINK)->setUnregister() == 0) {
yanmorin's avatar
 
yanmorin committed
		return true;
llea's avatar
llea committed
	} else {
yanmorin's avatar
 
yanmorin committed
		return false;
llea's avatar
llea committed
	}
}

yanmorin's avatar
 
yanmorin committed
/**
 * User action (main thread)
 */
yanmorin's avatar
 
yanmorin committed
bool 
yanmorin's avatar
 
yanmorin committed
ManagerImpl::sendDtmf (CALLID id, char code)
jpbl's avatar
jpbl committed
{
yanmorin's avatar
 
yanmorin committed
  int sendType = getConfigInt(SIGNALISATION, SEND_DTMF_AS);
yanmorin's avatar
 
yanmorin committed
  int returnValue = false;
yanmorin's avatar
 
yanmorin committed
  switch (sendType) {
yanmorin's avatar
 
yanmorin committed
  case 0: // SIP INFO
yanmorin's avatar
 
yanmorin committed
    playDtmf(code);
yanmorin's avatar
 
yanmorin committed
    _voIPLinkVector.at(DFT_VOIP_LINK)->carryingDTMFdigits(id, code);
    returnValue = true;
    break;

  case 1: // Audio way
    break;
  case 2: // rfc 2833
    break;
  default: // unknown - error config?
    break;
  }
  return returnValue;
jpbl's avatar
jpbl committed
}
yanmorin's avatar
 
yanmorin committed

yanmorin's avatar
 
yanmorin committed
/**
yanmorin's avatar
 
yanmorin committed
 * User action (main thread)
yanmorin's avatar
yanmorin committed
 * Or sip event (dtmf body submit)
yanmorin's avatar
 
yanmorin committed
 */
bool
ManagerImpl::playDtmf(char code)
{
yanmorin's avatar
 
yanmorin committed
  stopTone();

yanmorin's avatar
 
yanmorin committed
  // length in milliseconds
  int pulselen = getConfigInt(SIGNALISATION, PULSE_LENGTH);
  if (!pulselen) { return false; }

  // numbers of int = length in milliseconds / 1000 (number of seconds)
  //                = number of seconds * SAMPLING_RATE by SECONDS
  int size = pulselen * (SAMPLING_RATE/1000);

  // this buffer is for mono
  int16* _buf = new int16[size];
yanmorin's avatar
 
yanmorin committed
  bool returnValue = false;

  // Handle dtmf
yanmorin's avatar
 
yanmorin committed
  _key.startTone(code);
yanmorin's avatar
 
yanmorin committed

yanmorin's avatar
 
yanmorin committed
  // copy the sound...
  if ( _key.generateDTMF(_buf, size) ) {
yanmorin's avatar
 
yanmorin committed
    int k;
yanmorin's avatar
 
yanmorin committed

yanmorin's avatar
 
yanmorin committed
    // allocation of more space, for stereo conversion
    int16* buf_ctrl_vol = new int16[size*CHANNELS];
yanmorin's avatar
 
yanmorin committed

yanmorin's avatar
 
yanmorin committed
    // Control volume and format mono->stereo
    for (int j = 0; j < size; j++) {
yanmorin's avatar
 
yanmorin committed
      k = j<<1; // fast multiplication by two
yanmorin's avatar
 
yanmorin committed
      buf_ctrl_vol[k] = buf_ctrl_vol[k+1] = _buf[j];
yanmorin's avatar
 
yanmorin committed
    }
yanmorin's avatar
 
yanmorin committed

yanmorin's avatar
 
yanmorin committed
    AudioLayer *audiolayer = getAudioDriver();
yanmorin's avatar
 
yanmorin committed

yanmorin's avatar
 
yanmorin committed
    // Put buffer to urgentRingBuffer 
yanmorin's avatar
 
yanmorin committed
    // put the size in bytes...
    // so size * CHANNELS * 2 (bytes for the int16)
    int nbInt16InChar = sizeof(int16)/sizeof(char);
yanmorin's avatar
 
yanmorin committed
    audiolayer->putUrgent(buf_ctrl_vol, size * CHANNELS * nbInt16InChar);
yanmorin's avatar
 
yanmorin committed

yanmorin's avatar
 
yanmorin committed
    try {
      // We activate the stream if it's not active yet.
      if (!audiolayer->isStreamActive()) {
        audiolayer->startStream();
      } else {
        audiolayer->sleep(pulselen); // in milliseconds
      }
    } catch(...) {
      _debugException("Portaudio exception when playing a dtmf");
yanmorin's avatar
 
yanmorin committed
    }
yanmorin's avatar
 
yanmorin committed
    delete[] buf_ctrl_vol; buf_ctrl_vol = 0;
yanmorin's avatar
 
yanmorin committed
    returnValue = true;
  }
yanmorin's avatar
 
yanmorin committed
  delete[] _buf; _buf = 0;
yanmorin's avatar
 
yanmorin committed
  return returnValue;
}

jpbl's avatar
jpbl committed
///////////////////////////////////////////////////////////////////////////////
// Management of event peer IP-phone 
yanmorin's avatar
 
yanmorin committed
////////////////////////////////////////////////////////////////////////////////
/**
 * Multi-thread
 */
yanmorin's avatar
 
yanmorin committed
bool
yanmorin's avatar
 
yanmorin committed
ManagerImpl::incomingCallWaiting() {
  ost::MutexLock m(_incomingCallMutex);
  return (_nbIncomingWaitingCall > 0) ? true : false;
}

void
ManagerImpl::incWaitingCall() {
  ost::MutexLock m(_incomingCallMutex);
  _nbIncomingWaitingCall++;
yanmorin's avatar
 
yanmorin committed
  //_debug("incWaitingCall: %d\n", _nbIncomingWaitingCall);
yanmorin's avatar
 
yanmorin committed
}
jpbl's avatar
jpbl committed

yanmorin's avatar
 
yanmorin committed
void
ManagerImpl::decWaitingCall() {
  ost::MutexLock m(_incomingCallMutex);
  _nbIncomingWaitingCall--;
yanmorin's avatar
 
yanmorin committed
  //_debug("decWaitingCall: %d\n", _nbIncomingWaitingCall);
yanmorin's avatar
 
yanmorin committed
}

yanmorin's avatar
 
yanmorin committed

yanmorin's avatar
 
yanmorin committed
/**
 * SipEvent Thread
yanmorin's avatar
 
yanmorin committed
 * Set the call info for incoming call
yanmorin's avatar
 
yanmorin committed
 */
yanmorin's avatar
 
yanmorin committed
void
ManagerImpl::callSetInfo(CALLID id, const std::string& name, const std::string& number)
{
yanmorin's avatar
 
yanmorin committed
  ost::MutexLock m(_mutex);
  Call* call = getCall(id);
yanmorin's avatar
 
yanmorin committed
  if (call != 0) {
yanmorin's avatar
 
yanmorin committed
    call->setCallerIdName(name);
    call->setCallerIdNumber(number);
yanmorin's avatar
 
yanmorin committed
  }
}

/**
 * SipEvent Thread
yanmorin's avatar
 
yanmorin committed
 * ask if it can close the call
yanmorin's avatar
 
yanmorin committed
 */
bool
yanmorin's avatar
 
yanmorin committed
ManagerImpl::callCanBeClosed(CALLID id) {
yanmorin's avatar
 
yanmorin committed
  bool returnValue = false;
  ost::MutexLock m(_mutex);
  Call* call = getCall(id);
  if (call != NULL && call->getState() != Call::Progressing) {
    returnValue = true;
  }
  return returnValue;
}

/**
 * SipEvent Thread
 * ask if it can answer the call
 */
bool
yanmorin's avatar
 
yanmorin committed
ManagerImpl::callCanBeAnswered(CALLID id) {
yanmorin's avatar
 
yanmorin committed
  bool returnValue = false;
  ost::MutexLock m(_mutex);
  Call* call = getCall(id);
yanmorin's avatar
 
yanmorin committed
  if (call != NULL && ( call->getFlagNotAnswered() || 
yanmorin's avatar
 
yanmorin committed
       (call->getState()!=Call::OnHold && call->getState()!=Call::OffHold) )) {
    returnValue = true;
  }
  return returnValue;
}

/**
 * SipEvent Thread
 * ask if it can start the sound thread
 */
bool
ManagerImpl::callIsOnHold(CALLID id) {
  bool returnValue = false;
  ost::MutexLock m(_mutex);
  Call* call = getCall(id);
  if (call != NULL && (call->getState()==Call::OnHold)) {
yanmorin's avatar
 
yanmorin committed
    returnValue = true;
  }
  return returnValue;
}

yanmorin's avatar
 
yanmorin committed
/**
 * SipEvent Thread
 */
jpbl's avatar
jpbl committed
int 
yanmorin's avatar
 
yanmorin committed
ManagerImpl::incomingCall (CALLID id, const std::string& name, const std::string& number)
jpbl's avatar
jpbl committed
{
yanmorin's avatar
 
yanmorin committed
  _debug("%10d: Incoming call\n", id);
yanmorin's avatar
 
yanmorin committed
  ost::MutexLock m(_mutex);
  Call* call = getCall(id);
  if (call == NULL) {
    return -1;
  }
  call->setType(Incoming);
  call->setState(Call::Progressing);
yanmorin's avatar
 
yanmorin committed

yanmorin's avatar
 
yanmorin committed
  if ( _currentCallId == 0 ) {
    call->setFlagNotAnswered(false);
    ringtone();
yanmorin's avatar
 
yanmorin committed
    switchCall(id);
yanmorin's avatar
 
yanmorin committed
  } else {
    incWaitingCall();
  }
yanmorin's avatar
 
yanmorin committed

  // TODO: Account not yet implemented
  std::string accountId = "acc1";
yanmorin's avatar
 
yanmorin committed
  std::string from = name;     call->setCallerIdName(name);
  call->setCallerIdNumber(number);
  if ( !number.empty() ) {
yanmorin's avatar
 
yanmorin committed
    from.append(" <");
    from.append(number);
    from.append(">");
  }
  return _gui->incomingCall(id, accountId, from);
jpbl's avatar
jpbl committed
}

yanmorin's avatar
 
yanmorin committed
/**
 * SipEvent Thread
 * for outgoing message, send by SipEvent
 */
void 
ManagerImpl::incomingMessage(const std::string& message) {
  if (_gui) {
    _gui->incomingMessage(message);
  }
}

yanmorin's avatar
 
yanmorin committed
/**
 * SipEvent Thread
 * for outgoing call, send by SipEvent
 */
jpbl's avatar
jpbl committed
void 
yanmorin's avatar
 
yanmorin committed
ManagerImpl::peerAnsweredCall (CALLID id)
jpbl's avatar
jpbl committed
{
yanmorin's avatar
 
yanmorin committed
  _debug("%10d: Peer Answered Call\n", id);
yanmorin's avatar
 
yanmorin committed
  ost::MutexLock m(_mutex);
yanmorin's avatar
 
yanmorin committed
  Call* call = getCall(id);
yanmorin's avatar
 
yanmorin committed
  if (call != 0) {
yanmorin's avatar
 
yanmorin committed
    call->setFlagNotAnswered(false);
yanmorin's avatar
 
yanmorin committed
    call->setState(Call::Answered);
yanmorin's avatar
 
yanmorin committed

yanmorin's avatar
 
yanmorin committed
    stopTone();
    // switch current call
    switchCall(id);
    if (_gui) _gui->peerAnsweredCall(id);
  }
jpbl's avatar
jpbl committed
}

yanmorin's avatar
 
yanmorin committed
/**
 * SipEvent Thread
 * for outgoing call, send by SipEvent
 */
yanmorin's avatar
 
yanmorin committed
int
yanmorin's avatar
 
yanmorin committed
ManagerImpl::peerRingingCall (CALLID id)
jpbl's avatar
jpbl committed
{
yanmorin's avatar
 
yanmorin committed
  _debug("%10d: Peer Ringing Call\n", id);
yanmorin's avatar
 
yanmorin committed
  ost::MutexLock m(_mutex);
yanmorin's avatar
 
yanmorin committed
  Call* call = getCall(id);
yanmorin's avatar
 
yanmorin committed
  if (call != 0) {
    call->setState(Call::Ringing);
jpbl's avatar
jpbl committed

yanmorin's avatar
 
yanmorin committed
    // ring
    ringback();
    if (_gui) _gui->peerRingingCall(id);
  }
yanmorin's avatar
 
yanmorin committed
  return 1;
jpbl's avatar
jpbl committed
}

yanmorin's avatar
 
yanmorin committed
/**
 * SipEvent Thread
 * for outgoing call, send by SipEvent
 */
jpbl's avatar
jpbl committed
int 
yanmorin's avatar
 
yanmorin committed
ManagerImpl::peerHungupCall (CALLID id)
jpbl's avatar
jpbl committed
{
yanmorin's avatar
 
yanmorin committed
  _debug("%10d: Peer Hungup Call\n", id);
yanmorin's avatar
 
yanmorin committed
  ost::MutexLock m(_mutex);
yanmorin's avatar
 
yanmorin committed
  Call* call = getCall(id);
yanmorin's avatar
 
yanmorin committed
  if ( call == NULL ) {
    return -1;
yanmorin's avatar
 
yanmorin committed
  }
yanmorin's avatar
 
yanmorin committed
  if ( _currentCallId == id ) {
    stopTone();
  }
jpbl's avatar
jpbl committed

yanmorin's avatar
 
yanmorin committed
  if (_gui) _gui->peerHungupCall(id);
yanmorin's avatar
 
yanmorin committed
  deleteCall(id);
yanmorin's avatar
 
yanmorin committed
  call->setState(Call::Hungup);

yanmorin's avatar
 
yanmorin committed
  removeCallFromCurrent(id);
yanmorin's avatar
 
yanmorin committed
  return 1;
jpbl's avatar
jpbl committed
}

yanmorin's avatar
 
yanmorin committed
/**
 * Multi Thread
 */
void
ManagerImpl::callBusy(CALLID id) {
  _debug("%10d: Call is busy\n", id);
  playATone(Tone::TONE_BUSY);
  ost::MutexLock m(_mutex);
  Call* call = getCall(id);
  if (call != 0) {
    call->setState(Call::Busy);
  }
  deleteCall(id);
  call->setState(Call::Hungup);

  removeCallFromCurrent(id);
}

/**
 * Multi Thread
 */
void
ManagerImpl::callFailure(CALLID id) {
  _debug("%10d: Call failed\n", id);
  playATone(Tone::TONE_BUSY);
  _mutex.enterMutex();
  Call* call = getCall(id);
  if (call != 0) {
    call->setState(Call::Error);
  }
  _mutex.leaveMutex();
  if (_gui) {
    _gui->callFailure(id);
  }
  deleteCall(id);
  call->setState(Call::Hungup);

  removeCallFromCurrent(id);
}

yanmorin's avatar
 
yanmorin committed
/**
 * SipEvent Thread
 * for outgoing call, send by SipEvent
 */
jpbl's avatar
jpbl committed
void 
yanmorin's avatar
 
yanmorin committed
ManagerImpl::displayTextMessage (CALLID id, const std::string& message)
jpbl's avatar
jpbl committed
{
jpbl's avatar
jpbl committed
  if(_gui) {
    _gui->displayTextMessage(id, message);
  }
jpbl's avatar
jpbl committed
}

yanmorin's avatar
 
yanmorin committed
/**
 * SipEvent Thread
 * for outgoing call, send by SipEvent
 */
jpbl's avatar
jpbl committed
void 
yanmorin's avatar
 
yanmorin committed
ManagerImpl::displayErrorText (CALLID id, const std::string& message)
jpbl's avatar
jpbl committed
{
jpbl's avatar
jpbl committed
  if(_gui) {
    _gui->displayErrorText(id, message);
yanmorin's avatar
yanmorin committed
  } else {
    std::cerr << message << std::endl;
jpbl's avatar
jpbl committed
  }
jpbl's avatar
jpbl committed
}

yanmorin's avatar
 
yanmorin committed
/**
 * SipEvent Thread
 * for outgoing call, send by SipEvent
 */
jpbl's avatar
jpbl committed
void 
yanmorin's avatar
 
yanmorin committed
ManagerImpl::displayError (const std::string& voIPError)
jpbl's avatar
jpbl committed
{
jpbl's avatar
jpbl committed
  if(_gui) {
yanmorin's avatar
 
yanmorin committed
    _gui->displayError(voIPError);
jpbl's avatar
jpbl committed
  }
jpbl's avatar
jpbl committed
}

yanmorin's avatar
 
yanmorin committed
/**
 * SipEvent Thread
 * for outgoing call, send by SipEvent
 */
jpbl's avatar
jpbl committed
void 
yanmorin's avatar
 
yanmorin committed
ManagerImpl::displayStatus (const std::string& status)
jpbl's avatar
jpbl committed
{
jpbl's avatar
jpbl committed
  if(_gui) {
    _gui->displayStatus(status);
  }
jpbl's avatar
jpbl committed
}

yanmorin's avatar
 
yanmorin committed
/**
 * SipEvent Thread
 * for outgoing call, send by SipEvent
 */
void 
ManagerImpl::displayConfigError (const std::string& message)
{
  if(_gui) {
    _gui->displayConfigError(message);
  }
}

yanmorin's avatar
 
yanmorin committed
/**
 * SipEvent Thread
 * for outgoing call, send by SipEvent
 */
yanmorin's avatar
 
yanmorin committed
ManagerImpl::startVoiceMessageNotification (const std::string& nb_msg)
yanmorin's avatar
 
yanmorin committed
  if (_gui) _gui->sendVoiceNbMessage(nb_msg);
yanmorin's avatar
 
yanmorin committed
/**
 * SipEvent Thread
 * for outgoing call, send by SipEvent
 */
void
ManagerImpl::stopVoiceMessageNotification (void)
{
yanmorin's avatar
 
yanmorin committed
  if (_gui) _gui->sendVoiceNbMessage(std::string("0"));
yanmorin's avatar
 
yanmorin committed
/**
 * SipEvent Thread
 */
void 
ManagerImpl::registrationSucceed()
{
  if (_gui) _gui->sendRegistrationState(true);
}

/**
 * SipEvent Thread
 */
void 
ManagerImpl::registrationFailed()
{
  if (_gui) _gui->sendRegistrationState(false);
}

yanmorin's avatar
 
yanmorin committed
/**
 * Multi Thread
 */
yanmorin's avatar
 
yanmorin committed
bool 
yanmorin's avatar
 
yanmorin committed
ManagerImpl::playATone(Tone::TONEID toneId) {
yanmorin's avatar
 
yanmorin committed
  _toneMutex.enterMutex();
yanmorin's avatar
 
yanmorin committed
  _telephoneTone->setCurrentTone(toneId);
yanmorin's avatar
 
yanmorin committed
  _toneMutex.leaveMutex();
yanmorin's avatar
 
yanmorin committed

yanmorin's avatar
 
yanmorin committed
  try {
    getAudioDriver()->startStream();
  } catch(...) {
    _debugException("Off hold could not start audio stream");
  }
yanmorin's avatar
 
yanmorin committed
  return true;
yanmorin's avatar
 
yanmorin committed
}

yanmorin's avatar
 
yanmorin committed
/**
 * Multi Thread
 */
yanmorin's avatar
 
yanmorin committed
void 
ManagerImpl::stopTone() {
yanmorin's avatar
 
yanmorin committed
  try {
    getAudioDriver()->stopStream();
  } catch(...) {
    _debugException("Stop tone and stop stream");
  }
yanmorin's avatar
 
yanmorin committed

yanmorin's avatar
 
yanmorin committed
  _toneMutex.enterMutex();
  _telephoneTone->setCurrentTone(Tone::TONE_NULL);
yanmorin's avatar
 
yanmorin committed
  _toneMutex.leaveMutex();

yanmorin's avatar
 
yanmorin committed
  // for ringing tone..