Skip to content
Snippets Groups Projects
Select Git revision
  • d05d90a82be6d5161e748944f076cf4799f8695c
  • master default protected
  • release/202005
  • release/202001
  • release/201912
  • release/201911
  • release/releaseWindowsTestOne
  • release/windowsReleaseTest
  • release/releaseTest
  • release/releaseWindowsTest
  • release/201910
  • release/qt/201910
  • release/windows-test/201910
  • release/201908
  • release/201906
  • release/201905
  • release/201904
  • release/201903
  • release/201902
  • release/201901
  • release/201812
  • 4.0.0
  • 2.2.0
  • 2.1.0
  • 2.0.1
  • 2.0.0
  • 1.4.1
  • 1.4.0
  • 1.3.0
  • 1.2.0
  • 1.1.0
31 results

iaxvoiplink.cpp

Blame
  • user avatar
    Emmanuel Milou authored
    382883bb
    History
    Code owners
    Assign users and groups as approvers for specific file changes. Learn more.
    iaxvoiplink.cpp 21.53 KiB
    /*
     *  Copyright (C) 2006-2007 Savoir-Faire Linux inc.
     *  Author: Alexandre Bourget <alexandre.bourget@savoirfairelinux.com>
     *  Author: Yan Morin <yan.morin@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 3 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 "iaxvoiplink.h"
    #include "global.h" // for _debug
    #include "iaxcall.h"
    #include "eventthread.h"
    
    #include "manager.h"
    #include "audio/audiolayer.h"
    
    //#include <iax/iax-client.h>
    #include <math.h>
    #include <dlfcn.h>
    
    #define IAX_BLOCKING    1
    #define IAX_NONBLOCKING 0
    
    #define IAX_SUCCESS  0
    #define IAX_FAILURE -1
    
    #define RANDOM_IAX_PORT   rand() % 64000 + 1024
    
    #define MUSIC_ONHOLD true
    
    #define CHK_VALID_CALL   if (call == NULL) { _debug("IAX: Call doesn't exists\n"); \
      return false; }
    
      IAXVoIPLink::IAXVoIPLink(const AccountID& accountID)
    : VoIPLink(accountID)
    {
      _evThread = new EventThread(this);
      _regSession = NULL;
      _nextRefreshStamp = 0;
    
      // to get random number for RANDOM_PORT
      srand (time(NULL));
    
      audiolayer = NULL;
    
      converter = new SamplerateConverter();
    
      int nbSamplesMax = (int) ( converter->getFrequence() * converter->getFramesize() / 1000 );
    
      micData = new SFLDataFormat[nbSamplesMax];
      micDataConverted = new SFLDataFormat[nbSamplesMax];
      micDataEncoded = new unsigned char[nbSamplesMax];
    
      spkrDataConverted = new SFLDataFormat[nbSamplesMax];
      spkrDataDecoded = new SFLDataFormat[nbSamplesMax];
    }
    
    
    IAXVoIPLink::~IAXVoIPLink()
    {
      delete _evThread; _evThread = NULL;
      _regSession = NULL; // shall not delete it
      terminate();
    
      audiolayer = NULL;
    
      delete [] micData;  micData = NULL;
      delete [] micDataConverted;  micDataConverted = NULL;
      delete [] micDataEncoded;  micDataEncoded = NULL;
    
      delete [] spkrDataDecoded; spkrDataDecoded = NULL;
      delete [] spkrDataConverted; spkrDataConverted = NULL;
    }
    
      bool
    IAXVoIPLink::init()
    {
      // If it was done, don't do it again, until we call terminate()
      if (_initDone)
        return false;
    
      bool returnValue = false;
      //_localAddress = "127.0.0.1";
      // port 0 is default
      //  iax_enable_debug(); have to enable debug when compiling iax...
      int port = IAX_DEFAULT_PORTNO;
      int last_port = 0;
      int nbTry = 3;
    
      while (port != IAX_FAILURE && nbTry) {
        last_port = port;
        port = iax_init(port);
        if ( port < 0 ) {
          _debug("IAX Warning: already initialize on port %d\n", last_port);
          port = RANDOM_IAX_PORT;
        } else if (port == IAX_FAILURE) {
          _debug("IAX Fail to start on port %d", last_port);
          port = RANDOM_IAX_PORT;
        } else {
          _debug("IAX Info: listening on port %d\n", last_port);
          _localPort = last_port;
          returnValue = true;
          _evThread->start();
    
          audiolayer = Manager::instance().getAudioDriver();
          break;
        }
        nbTry--;
    
        _initDone = true;
      }
      if (port == IAX_FAILURE || nbTry==0) {
        _debug("Fail to initialize iax\n");
    
        _initDone = false;
      }
    
      return returnValue;
    }
    
      void
    IAXVoIPLink::terminate()
    {
      // If it was done, don't do it again, until we call init()
      if (!_initDone)
        return;
    
      // iaxc_shutdown();  
    
      // Hangup all calls
      terminateIAXCall();
    
      _initDone = false;
    }
    
      void
    IAXVoIPLink::terminateIAXCall()
    {
      std::string reason = "Dumped Call";
      ost::MutexLock m(_callMapMutex);
      CallMap::iterator iter = _callMap.begin();
      IAXCall *call;
      while( iter != _callMap.end() ) {
        call = dynamic_cast<IAXCall*>(iter->second);
        if (call) {
          _mutexIAX.enterMutex();
          iax_hangup(call->getSession(), (char*)reason.c_str());
          _mutexIAX.leaveMutex();
          call->setSession(NULL);
          delete call; call = NULL;
        }
        iter++;
      }
      _callMap.clear();
    }
    
      void
    IAXVoIPLink::getEvent() 
    {
      IAXCall* call = NULL;
    
      // lock iax_ stuff..
      _mutexIAX.enterMutex();
      iax_event* event = NULL;
      while ( (event = iax_get_event(IAX_NONBLOCKING)) != NULL ) {
        // If we received an 'ACK', libiax2 tells apps to ignore them.
        if (event->etype == IAX_EVENT_NULL) {
          continue;
        }
    
        //_debug ("Receive IAX Event: %d (0x%x)\n", event->etype, event->etype);
    
        call = iaxFindCallBySession(event->session);
    
        if (call) {
          // We know that call, deal with it
          iaxHandleCallEvent(event, call);
          //_audiocodec = Manager::instance().getCodecDescriptorMap().getCodec( call -> getAudioCodec() ); 
        }
        else if (event->session && event->session == _regSession) {
          // This is a registration session, deal with it
          iaxHandleRegReply(event);
        }
        else {
          // We've got an event before it's associated with any call
          iaxHandlePrecallEvent(event);
        }
    
        iax_event_free(event);
      }
      _mutexIAX.leaveMutex();
    
      // Do the doodle-moodle to send audio from the microphone to the IAX channel.
      sendAudioFromMic();
    
      // Refresh registration.
      if (_nextRefreshStamp && _nextRefreshStamp - 2 < time(NULL)) {
        sendRegister();
      }
    
      // thread wait 3 millisecond
      _evThread->sleep(3);
    }
    
      void
    IAXVoIPLink::sendAudioFromMic(void)
    {
      IAXCall* currentCall = getIAXCall(Manager::instance().getCurrentCallId());
    
      if (!currentCall) {
        // Let's mind our own business.
        return;
      }
    
      if( currentCall -> getAudioCodec() < 0 )
        return;
    
    
      // Just make sure the currentCall is in state to receive audio right now.
      //_debug("Here we get: connectionState: %d   state: %d \n",
      // currentCall->getConnectionState(),
      // currentCall->getState());
    
      if (currentCall->getConnectionState() != Call::Connected ||
          currentCall->getState() != Call::Active) {
        return;
      }
    
      AudioCodec* ac = currentCall -> getCodecMap().getCodec( currentCall -> getAudioCodec() );
      if (!ac) {
        // Audio codec still not determined.
        if (audiolayer) {
          // To keep latency low..
          //audiolayer->flushMic();
        }
        return;
      }
    
      // Send sound here
      if (audiolayer) {
    
        // we have to get 20ms of data from the mic *20/1000 = /50
        // rate/50 shall be lower than IAX__20S_48KHZ_MAX
        int maxBytesToGet = audiolayer->getSampleRate()* audiolayer->getFrameSize() / 1000 * sizeof(SFLDataFormat);
    
        // available bytes inside ringbuffer
        int availBytesFromMic = audiolayer->canGetMic();
    
        if (availBytesFromMic < maxBytesToGet) {
          // We need packets full!
          return;
        }
    
        // take the lowest
        int bytesAvail = (availBytesFromMic < maxBytesToGet) ? availBytesFromMic : maxBytesToGet;
        //_debug("available = %d, maxBytesToGet = %d\n", availBytesFromMic, maxBytesToGet);
    
        // Get bytes from micRingBuffer to data_from_mic
        int nbSample = audiolayer->getMic( micData, bytesAvail ) / sizeof(SFLDataFormat);
    
        // resample
        nbSample = converter->downsampleData( micData , micDataConverted , (int)ac ->getClockRate() ,  (int)audiolayer->getSampleRate() , nbSample );
    
        // for the mono: range = 0 to IAX_FRAME2SEND * sizeof(int16)
        int compSize = ac->codecEncode( micDataEncoded, micDataConverted , nbSample*sizeof(int16));
    
        // Send it out!
        _mutexIAX.enterMutex();
        // Make sure the session and the call still exists.
        if (currentCall->getSession()) {
          if ( iax_send_voice(currentCall->getSession(), currentCall->getFormat(), micDataEncoded, compSize, nbSample) == -1) {
    	_debug("IAX: Error sending voice data.\n");
          }
        }
        _mutexIAX.leaveMutex();
      }
    }
    
    
      IAXCall* 
    IAXVoIPLink::getIAXCall(const CallID& id) 
    {
      Call* call = getCall(id);
      if (call) {
        return dynamic_cast<IAXCall*>(call);
      }
      return NULL;
    }
    
    
    
      bool
    IAXVoIPLink::sendRegister() 
    {
      bool result = false;
      if (_host.empty()) {
        return false;
      }
      if (_user.empty()) {
        return false;
      }
    
      // lock
      _mutexIAX.enterMutex();
    
      // Always use a brand new session
      if (_regSession) {
        iax_destroy(_regSession);
      }
    
      _regSession = iax_session_new();
    
      if (!_regSession) {
        _debug("Error when generating new session for register");
      } else {
        // refresh
        // last reg
        char host[_host.length()+1]; 
        strcpy(host, _host.c_str());
        char user[_user.length()+1];
        strcpy(user, _user.c_str());
        char pass[_pass.length()+1]; 
        strcpy(pass, _pass.c_str());
        // iax_register doesn't use const char*
    
        _debug("IAX Sending registration to %s with user %s\n", host, user);
        int val = iax_register(_regSession, host, user, pass, 120);
        _debug ("Return value: %d\n", val);
        // set the time-out to 15 seconds, after that, resend a registration request.
        // until we unregister.
        _nextRefreshStamp = time(NULL) + 10;
        result = true;
    
        setRegistrationState(Trying);
      }
    
      // unlock
      _mutexIAX.leaveMutex();
    
      return result;
    }
    
    
    
    
      bool
    IAXVoIPLink::sendUnregister()
    {
      _mutexIAX.enterMutex();
      if (_regSession) {
        /** @todo Should send a REGREL in sendUnregister()... */
    
        //iax_send_regrel(); doesn't exist yet :)
        iax_destroy(_regSession);
    
        _regSession = NULL;
      }
      _mutexIAX.leaveMutex();
    
      _nextRefreshStamp = 0;
    
      _debug("IAX2 send unregister\n");
      setRegistrationState(Unregistered);
    
      return false;
    }
    
      Call* 
    IAXVoIPLink::newOutgoingCall(const CallID& id, const std::string& toUrl)
    {
      IAXCall* call = new IAXCall(id, Call::Outgoing);
      call->setCodecMap(Manager::instance().getCodecDescriptorMap());
    
    
      if (call) {
        call->setPeerNumber(toUrl);
    
        if ( iaxOutgoingInvite(call) ) {
          call->setConnectionState(Call::Progressing);
          call->setState(Call::Active);
          addCall(call);
        } else {
          delete call; call = NULL;
        }
      }
      return call;
    }
    
    
      bool 
    IAXVoIPLink::answer(const CallID& id)
    {
      IAXCall* call = getIAXCall(id);
      call->setCodecMap(Manager::instance().getCodecDescriptorMap());
    
      CHK_VALID_CALL;
    
      _mutexIAX.enterMutex();
      iax_answer(call->getSession());
      _mutexIAX.leaveMutex();
    
      call->setState(Call::Active);
      call->setConnectionState(Call::Connected);
      // Start audio
      audiolayer->startStream();
      //audiolayer->flushMic();
    
      return true;
    }
    
      bool 
    IAXVoIPLink::hangup(const CallID& id)
    {
      IAXCall* call = getIAXCall(id);
      std::string reason = "Dumped Call";
      CHK_VALID_CALL;
    
      _mutexIAX.enterMutex();
      iax_hangup(call->getSession(), (char*) reason.c_str());
      _mutexIAX.leaveMutex();
      call->setSession(NULL);
      if (Manager::instance().isCurrentCall(id)) {
        // stop audio
      }
      removeCall(id);
      return true;	
    }
    
      bool 
    IAXVoIPLink::onhold(const CallID& id) 
    {
      IAXCall* call = getIAXCall(id);
    
      CHK_VALID_CALL;
    
      //if (call->getState() == Call::Hold) { _debug("Call is already on hold\n"); return false; }
    
      _mutexIAX.enterMutex();
      iax_quelch_moh(call->getSession() , MUSIC_ONHOLD);
      _mutexIAX.leaveMutex();
    
      call->setState(Call::Hold);
      return true;
    }
    
      bool 
    IAXVoIPLink::offhold(const CallID& id)
    {
      IAXCall* call = getIAXCall(id);
    
      CHK_VALID_CALL;
    
      //if (call->getState() == Call::Active) { _debug("Call is already active\n"); return false; }
      _mutexIAX.enterMutex();
      iax_unquelch(call->getSession());
      _mutexIAX.leaveMutex();
      audiolayer->startStream();
      call->setState(Call::Active);
      return true;
    }
    
      bool 
    IAXVoIPLink::transfer(const CallID& id, const std::string& to)
    {
      IAXCall* call = getIAXCall(id);
    
      CHK_VALID_CALL;
    
      char callto[to.length()+1];
      strcpy(callto, to.c_str());
    
      _mutexIAX.enterMutex();
      iax_transfer(call->getSession(), callto); 
      _mutexIAX.leaveMutex();
    
      // should we remove it?
      // removeCall(id);
    }
    
      bool 
    IAXVoIPLink::refuse(const CallID& id)
    {
      IAXCall* call = getIAXCall(id);
      std::string reason = "Call rejected manually.";
    
      CHK_VALID_CALL;
    
      _mutexIAX.enterMutex();
      iax_reject(call->getSession(), (char*) reason.c_str());
      _mutexIAX.leaveMutex();
      removeCall(id);
    }
    
      bool
    IAXVoIPLink::carryingDTMFdigits(const CallID& id, char code)
    {
      IAXCall* call = getIAXCall(id);
    
      CHK_VALID_CALL;
    
      _mutexIAX.enterMutex();
      iax_send_dtmf(call->getSession(), code);
      _mutexIAX.leaveMutex();
    }
    
    
    
      bool
    IAXVoIPLink::iaxOutgoingInvite(IAXCall* call) 
    {
      struct iax_session *newsession;
      ost::MutexLock m(_mutexIAX);
    
      newsession = iax_session_new();
      if (!newsession) {
        _debug("IAX Error: Can't make new session for a new call\n");
        return false;
      }
      call->setSession(newsession);
      /* reset activity and ping "timers" */
      // iaxc_note_activity(callNo);
    
      std::string strNum = _user + ":" + _pass + "@" + _host + "/" + call->getPeerNumber();  
    
      char user[_user.length()+1];
      strcpy(user, _user.c_str());
    
      char num[strNum.length()+1];
      strcpy(num, strNum.c_str());
    
      char* lang = NULL;
      int wait = 0;
      /** @todo Make preference dynamic, and configurable */
      int audio_format_preferred =  call->getFirstMatchingFormat(call->getSupportedFormat());
      int audio_format_capability = call->getSupportedFormat();
    
      _debug("IAX New call: %s\n", num);
      iax_call(newsession, user, user, num, lang, wait, audio_format_preferred, audio_format_capability);
    
      return true;
    }
    
    
      IAXCall* 
    IAXVoIPLink::iaxFindCallBySession(struct iax_session* session) 
    {
      // access to callMap shoud use that
      // the code below is like findSIPCallWithCid() 
      ost::MutexLock m(_callMapMutex);	
      IAXCall* call = NULL;
      CallMap::iterator iter = _callMap.begin();
      while(iter != _callMap.end()) {
        call = dynamic_cast<IAXCall*>(iter->second);
        if (call && call->getSession() == session) {
          return call;
        }
        iter++;
      }
      return NULL; // not found
    }
    
      void
    IAXVoIPLink::iaxHandleCallEvent(iax_event* event, IAXCall* call) 
    {
      // call should not be 0
      // note activity?
      //
      CallID id = call->getCallId();
      int16* output = 0; // for audio output
    
      switch(event->etype) {
        case IAX_EVENT_HANGUP:
          Manager::instance().peerHungupCall(id); 
          if (Manager::instance().isCurrentCall(id)) {
    	audiolayer->stopStream();
    	// stop audio
          }
          removeCall(id);
          break;
    
        case IAX_EVENT_REJECT:
          //Manager::instance().peerHungupCall(id); 
          if (Manager::instance().isCurrentCall(id)) {
    	// stop audio
    	audiolayer->stopStream();
          }
          call->setConnectionState(Call::Connected);
          call->setState(Call::Error);
          Manager::instance().callFailure(id);
          removeCall(id);
          break;
    
        case IAX_EVENT_ACCEPT:
          // Call accepted over there by the computer, not the user yet.
          if (event->ies.format) {
    	call->setFormat(event->ies.format);
          }
          break;
    
        case IAX_EVENT_ANSWER:
          if (call->getConnectionState() != Call::Connected){
    	call->setConnectionState(Call::Connected);
    	call->setState(Call::Active);
    
    	if (event->ies.format) {
    	  // Should not get here, should have been set in EVENT_ACCEPT
    	  call->setFormat(event->ies.format);
    	}
    
    	Manager::instance().peerAnsweredCall(id);
    	//audiolayer->flushMic();
    	//audiolayer->startStream();
    	// start audio here?
          } else {
    	// deja connecté ?
          }
          break;
    
        case IAX_EVENT_BUSY:
          call->setConnectionState(Call::Connected);
          call->setState(Call::Busy);
          Manager::instance().callBusy(id);
          removeCall(id);
          break;
    
        case IAX_EVENT_VOICE:
          //_debug("Should have a decent value!!!!!! = %i\n" , call -> getAudioCodec());
          //if( !audiolayer -> isCaptureActive())
    	//audiolayer->startStream();
          iaxHandleVoiceEvent(event, call);
          break;
    
        case IAX_EVENT_TEXT:
          break;
    
        case IAX_EVENT_RINGA:
          call->setConnectionState(Call::Ringing);
          Manager::instance().peerRingingCall(call->getCallId());
          break;
    
        case IAX_IE_MSGCOUNT:	
          break;
        case IAX_EVENT_PONG:
          break;
    
        case IAX_EVENT_URL:
          break;
    
          //    case IAX_EVENT_CNG: ??
          //    break;
    
        case IAX_EVENT_TIMEOUT:
          break;
    
        case IAX_EVENT_TRANSFER:
          break;
    
        default:
          _debug("Unknown event type (in call event): %d\n", event->etype);
    
      }
    }
    
    
    /* Handle audio event, VOICE packet received */
      void
    IAXVoIPLink::iaxHandleVoiceEvent(iax_event* event, IAXCall* call)
    { 
      // If we receive datalen == 0, some things of the jitter buffer in libiax2/iax.c
      // were triggered
      if (!event->datalen) {
        // Skip this empty packet.
        //_debug("IAX: Skipping empty jitter-buffer interpolated packet\n");
        return;
      }
    
      if (audiolayer) {
        // On-the-fly codec changing (normally, when we receive a full packet)
        // as per http://tools.ietf.org/id/draft-guy-iax-03.txt
        // - subclass holds the voiceformat property.
        if (event->subclass && event->subclass != call->getFormat()) {
          call->setFormat(event->subclass);
        }
        //_debug("Receive: len=%d, format=%d, _receiveDataDecoded=%p\n", event->datalen, call->getFormat(), _receiveDataDecoded);
        AudioCodec* ac = call->getCodecMap().getCodec( call -> getAudioCodec() );
    
        unsigned char* data = (unsigned char*)event->data;
        unsigned int size   = event->datalen;
    
        // Decode data with relevant codec
        int max = (int)( ac->getClockRate() * audiolayer->getFrameSize() / 1000 );
    
        if (size > max) {
          _debug("The size %d is bigger than expected %d. Packet cropped. Ouch!\n", size, max);
          size = max;
        }
    
        int expandedSize = ac->codecDecode( spkrDataDecoded , data , size );
        int nbInt16      = expandedSize/sizeof(int16);
    
        if (nbInt16 > max) {
          _debug("We have decoded an IAX VOICE packet larger than expected: %s VS %s. Cropping.\n", nbInt16, max);
          nbInt16 = max;
        }
    
        int nbSample = nbInt16;
        // resample
        nbInt16 = converter->upsampleData( spkrDataDecoded , spkrDataConverted , ac->getClockRate() , audiolayer->getSampleRate() , nbSample);
    
        audiolayer->playSamples( spkrDataConverted , nbInt16 * sizeof(SFLDataFormat), true);
    
      } else {
        _debug("IAX: incoming audio, but no sound card open");
      }
    
    }
    
    /**
     * Handle the registration process
     */
      void
    IAXVoIPLink::iaxHandleRegReply(iax_event* event) 
    {
      if (event->etype == IAX_EVENT_REGREJ) {
        /* Authentication failed! */
        _mutexIAX.enterMutex();
        iax_destroy(_regSession);
        _mutexIAX.leaveMutex();
        _regSession = NULL;
        setRegistrationState(ErrorAuth);
      }
      else if (event->etype == IAX_EVENT_REGACK) {
        /* Authentication succeeded */
        _mutexIAX.enterMutex();
        iax_destroy(_regSession);
        _mutexIAX.leaveMutex();
        _regSession = NULL;
    
        // I mean, save the timestamp, so that we re-register again in the REFRESH time.
        // Defaults to 60, as per draft-guy-iax-03.
        _nextRefreshStamp = time(NULL) + (event->ies.refresh ? event->ies.refresh : 60);
        setRegistrationState(Registered);
      }
    }
    
      void
    IAXVoIPLink::iaxHandlePrecallEvent(iax_event* event)
    {
      IAXCall* call = NULL;
      CallID   id;
      std::string reason = "Error ringing user.";
    
      switch(event->etype) {
        case IAX_EVENT_REGACK:
        case IAX_EVENT_REGREJ:
          _debug("IAX Registration Event in a pre-call setup\n");
          break;
    
        case IAX_EVENT_REGREQ:
          // Received when someone wants to register to us!?!
          // Asterisk receives and answers to that, not us, we're a phone.
          _debug("Registration by a peer, don't allow it\n");
          break;
    
        case IAX_EVENT_CONNECT:
          // We've got an incoming call! Yikes!
          _debug("> IAX_EVENT_CONNECT (receive)\n");
    
          id = Manager::instance().getNewCallID();
    
    
          call = new IAXCall(id, Call::Incoming);
    
          if (!call) {
    	_debug("! IAX Failure: unable to create an incoming call");
    	return;
          }
    
          // Setup the new IAXCall
          // Associate the call to the session.
          call->setSession(event->session);
    
          // setCallAudioLocal(call);
          call->setCodecMap(Manager::instance().getCodecDescriptorMap());
          call->setConnectionState(Call::Progressing);
    
    
          if (event->ies.calling_number)
    	call->setPeerNumber(std::string(event->ies.calling_number));
          if (event->ies.calling_name)
    	call->setPeerName(std::string(event->ies.calling_name));
    
          if (Manager::instance().incomingCall(call, getAccountID())) {
    	/** @todo Faudra considérer éventuellement le champ CODEC PREFS pour
    	 * l'établissement du codec de transmission */
    
    	// Remote lists its capabilities
    	int format = call->getFirstMatchingFormat(event->ies.capability);
    	// Remote asks for preferred codec voiceformat
    	int pref_format = call->getFirstMatchingFormat(event->ies.format);
    
    	// Priority to remote's suggestion. In case it's a forwarding, no transcoding
    	// will be needed from the server, thus less latency.
    	if (pref_format)
    	  format = pref_format;
    
    	iax_accept(event->session, format);
    	iax_ring_announce(event->session);
    
    	addCall(call);
          } else {
    	// reject call, unable to add it
    	iax_reject(event->session, (char*)reason.c_str());
    
    	delete call; call = NULL;
          }
    
          break;
    
        case IAX_EVENT_HANGUP:
          // Remote peer hung up
          call = iaxFindCallBySession(event->session);
          id = call->getCallId();
    
          Manager::instance().peerHungupCall(id);
          removeCall(id);
          break;
    
        case IAX_EVENT_TIMEOUT: // timeout for an unknown session
    
          break;
    
        case IAX_IE_MSGCOUNT:	
          //_debug("messssssssssssssssssssssssssssssssssssssssssssssssages\n");
          break;
    
        default:
          _debug("Unknown event type (in precall): %d\n", event->etype);
      }
    
    }
    
      int 
    IAXVoIPLink::iaxCodecMapToFormat(IAXCall* call)
    {
      CodecOrder map = call->getCodecMap().getActiveCodecs();
      printf("taytciatcia = %i\n", map.size());
      return 0;
    }