From 3a3b996c0bed7acbc4b9af2890231a05a8e00f25 Mon Sep 17 00:00:00 2001
From: yanmorin <yanmorin>
Date: Thu, 27 Jul 2006 18:06:14 +0000
Subject: [PATCH] Implementing registration and outgoing call

---
 src/iaxvoiplink.cpp | 200 +++++++++++++++++++++++++++++++++++---------
 src/iaxvoiplink.h   |  10 ++-
 src/managerimpl.cpp |   9 +-
 3 files changed, 171 insertions(+), 48 deletions(-)

diff --git a/src/iaxvoiplink.cpp b/src/iaxvoiplink.cpp
index df5d51d513..7bcb0fe602 100644
--- a/src/iaxvoiplink.cpp
+++ b/src/iaxvoiplink.cpp
@@ -26,11 +26,42 @@
 #define IAX_SUCCESS  0
 #define IAX_FAILURE -1
 
+#define RANDOM_IAX_PORT   rand() % 64000 + 1024
+
+// from IAXC : iaxclient.h
+
+/* payload formats : WARNING: must match libiax values!!! */
+/* Data formats for capabilities and frames alike */
+#define IAX__FORMAT_G723_1       (1 << 0)        /* G.723.1 compression */
+#define IAX__FORMAT_GSM          (1 << 1)        /* GSM compression */
+#define IAX__FORMAT_ULAW         (1 << 2)        /* Raw mu-law data (G.711) */
+#define IAX__FORMAT_ALAW         (1 << 3)        /* Raw A-law data (G.711) */
+#define IAX__FORMAT_G726         (1 << 4)        /* ADPCM, 32kbps  */
+#define IAX__FORMAT_ADPCM        (1 << 5)        /* ADPCM IMA */
+#define IAX__FORMAT_SLINEAR      (1 << 6)        /* Raw 16-bit Signed Linear (8000 Hz) PCM */
+#define IAX__FORMAT_LPC10        (1 << 7)        /* LPC10, 180 samples/frame */
+#define IAX__FORMAT_G729A        (1 << 8)        /* G.729a Audio */
+#define IAX__FORMAT_SPEEX        (1 << 9)        /* Speex Audio */
+#define IAX__FORMAT_ILBC         (1 << 10)       /* iLBC Audio */
+
+#define IAX__FORMAT_MAX_AUDIO    (1 << 15)  /* Maximum audio format */
+#define IAX__FORMAT_JPEG         (1 << 16)       /* JPEG Images */
+#define IAX__FORMAT_PNG          (1 << 17)       /* PNG Images */
+#define IAX__FORMAT_H261         (1 << 18)       /* H.261 Video */
+#define IAX__FORMAT_H263         (1 << 19)       /* H.263 Video */
+#define IAX__FORMAT_H263_PLUS    (1 << 20)       /* H.263+ Video */
+#define IAX__FORMAT_MPEG4        (1 << 21)       /* MPEG4 Video */
+#define IAX__FORMAT_H264         (1 << 23)       /* H264 Video */
+#define IAX__FORMAT_THEORA       (1 << 24)       /* Theora Video */
+
 IAXVoIPLink::IAXVoIPLink(const AccountID& accountID)
  : VoIPLink(accountID)
 {
   _evThread = new EventThread(this);
   _regSession = 0;
+
+  // to get random number for RANDOM_PORT
+  srand (time(NULL));
 }
 
 
@@ -48,17 +79,31 @@ IAXVoIPLink::init()
   //_localAddress = "127.0.0.1";
   // port 0 is default
   //  iax_enable_debug(); have to enable debug when compiling iax...
-  int port = iax_init(IAX_DEFAULT_PORTNO);
-  if (port == IAX_FAILURE) {
-    _debug("IAX Failure: Error when initializing\n");
-  } else if ( port == 0 ) {
-    _debug("IAX Warning: already initialize\n");
-  } else {
-    _debug("IAX Info: listening on port %d\n", port);
-    _localPort = port;
-    returnValue = true;
-
-    _evThread->start();
+  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();
+      break;
+    }
+    nbTry--;
+  }
+  if (port == IAX_FAILURE || nbTry==0) {
+    _debug("Fail to initialize iax\n");
   }
   return returnValue;
 }
@@ -75,42 +120,44 @@ void
 IAXVoIPLink::getEvent() 
 {
   // mutex here
+  _mutexIAX.enterMutex();
+
   iax_event* event = 0;
   IAXCall* call = 0;
   while ( (event = iax_get_event(0)) != 0 ) {
     _debug ("Receive IAX Event: %d\n", event->etype);
     call = iaxFindCallBySession(event->session);
     if (call!=0) {
-	iaxHandleCallEvent(event, call);
+      iaxHandleCallEvent(event, call);
     } else if (event->session != 0 && event->session == _regSession) {
-    	// in iaxclient, there is many session handling, here, only one
-	iaxHandleRegReply(event);
+      // in iaxclient, there is many session handling, here, only one
+      iaxHandleRegReply(event);
     } else {
-    	switch(event->etype) {
-		case IAX_EVENT_REGACK:
-		case IAX_EVENT_REGREJ:
-			_debug("Unknown IAX Registration Event\n");
-		break;
-
-		case IAX_EVENT_REGREQ:
-			_debug("Registration by a peer, don't allow it\n");
-		break;
-		case IAX_EVENT_CONNECT: // new call
-			// New incoming call!	
-		break;
-
-		case IAX_EVENT_TIMEOUT: // timeout for an unknown session
-			
-		break;
-
-		default: 
-			_debug("Unknown event type: %d\n", event->etype);
-	}
+      switch(event->etype) {
+        case IAX_EVENT_REGACK:
+        case IAX_EVENT_REGREJ:
+          _debug("Unknown IAX Registration Event\n");
+        break;
+
+        case IAX_EVENT_REGREQ:
+          _debug("Registration by a peer, don't allow it\n");
+        break;
+        case IAX_EVENT_CONNECT: // new call
+          // New incoming call!	
+        break;
+
+        case IAX_EVENT_TIMEOUT: // timeout for an unknown session
+
+        break;
+
+        default:
+          _debug("Unknown event type: %d\n", event->etype);
+      }
     }
     iax_event_free(event);
   }
   // unlock mutex here
-
+  _mutexIAX.leaveMutex();
   //iaxRefreshRegistrations();
 
   // thread wait 5 millisecond
@@ -130,8 +177,9 @@ IAXVoIPLink::setRegister()
       Manager::instance().displayConfigError("Fill user field for IAX Account");
       return false;
     }
-    // lock
 
+    // lock
+    _mutexIAX.enterMutex();
     _regSession = iax_session_new();
 
     if (!_regSession) {
@@ -147,12 +195,13 @@ IAXVoIPLink::setRegister()
       strcpy(pass, _pass.c_str());
       //iax_register don't use const char*
 
-      _debug("Sending registration to %s with user %s\n", host, user);
-      iax_register(_regSession, host, user, pass, 300);
+      _debug("IAX Sending registration to %s with user %s\n", host, user);
+      int val = iax_register(_regSession, host, user, pass, 300);
+      _debug ("Return value: %d\n", val);
       result = true;
     }
 
-   // unlock
+    _mutexIAX.leaveMutex();
   }
   return result;
 }
@@ -160,9 +209,69 @@ IAXVoIPLink::setRegister()
 bool
 IAXVoIPLink::setUnregister()
 {
+  if (_regSession==0) {
+    // lock here
+    _mutexIAX.enterMutex();
+    iax_destroy(_regSession);
+    _regSession = 0;
+    // unlock here
+    _mutexIAX.leaveMutex();
+    return false;
+  }
   return false;
 }
 
+Call* 
+IAXVoIPLink::newOutgoingCall(const CallID& id, const std::string& toUrl)
+{
+  IAXCall* call = new IAXCall(id, Call::Outgoing);
+  if (call) {
+    call->setPeerNumber(toUrl);
+    // we have to add the codec before using it in SIPOutgoingInvite...
+    //call->setCodecMap(Manager::instance().getCodecDescriptorMap());
+    if ( iaxOutgoingInvite(call) ) {
+      call->setConnectionState(Call::Progressing);
+      call->setState(Call::Active);
+      addCall(call);
+    } else {
+      delete call; call = 0;
+    }
+  }
+  return call;
+}
+
+bool
+IAXVoIPLink::iaxOutgoingInvite(IAXCall* call) 
+{
+  struct iax_session *newsession;
+  // lock here
+  _mutexIAX.enterMutex();
+  newsession = iax_session_new();
+  if (!newsession) {
+     _debug("IAX Error: Can't make new session for a new call\n");
+     // unlock here
+     _mutexIAX.leaveMutex();
+     return false;
+  }
+  call->setSession(newsession);
+  /* reset activity and ping "timers" */
+  // iaxc_note_activity(callNo);
+  char num[call->getPeerNumber().length()+1];
+  strcpy(num, call->getPeerNumber().c_str());
+
+  char* lang = NULL;
+  int wait = 0;
+  int audio_format_preferred =  IAX__FORMAT_SPEEX;
+  int audio_format_capability = IAX__FORMAT_ULAW | IAX__FORMAT_ALAW | IAX__FORMAT_GSM | IAX__FORMAT_SPEEX;
+
+  iax_call(newsession, num, num, num, lang, wait, audio_format_preferred, audio_format_capability);
+
+  // unlock here
+  _mutexIAX.leaveMutex();
+  return true;
+}
+
+
 IAXCall* 
 IAXVoIPLink::iaxFindCallBySession(struct iax_session* session) 
 {
@@ -196,7 +305,7 @@ IAXVoIPLink::iaxHandleCallEvent(iax_event* event, IAXCall* call)
 
     case IAX_EVENT_ACCEPT:
     break;
-    
+
     case IAX_EVENT_ANSWER:
     break;
     
@@ -233,8 +342,17 @@ IAXVoIPLink::iaxHandleCallEvent(iax_event* event, IAXCall* call)
   }
 }
 
+
+
 void
 IAXVoIPLink::iaxHandleRegReply(iax_event* event) 
 {
-  // use _regSession here, should be equal to event->session;
+  //unregister
+  if (event->etype == IAX_EVENT_REGREJ) {
+    iax_destroy(_regSession);
+    _regSession = 0;
+    Manager::instance().registrationFailed(getAccountID());
+  } else if (event->etype == IAX_EVENT_REGACK) {
+    Manager::instance().registrationSucceed(getAccountID());
+  }
 }
diff --git a/src/iaxvoiplink.h b/src/iaxvoiplink.h
index 92f518d558..ca958f4634 100644
--- a/src/iaxvoiplink.h
+++ b/src/iaxvoiplink.h
@@ -45,7 +45,7 @@ public:
   bool setRegister (void);
   bool setUnregister (void);
 
-  Call* newOutgoingCall(const CallID& id, const std::string& toUrl) {return 0; }
+  Call* newOutgoingCall(const CallID& id, const std::string& toUrl);
   bool answer(const CallID& id) {return false;}
 
   bool hangup(const CallID& id) { return false; }
@@ -83,6 +83,11 @@ private:
    */
   void iaxHandleRegReply(iax_event* event);
 
+  /**
+   * Send an outgoing call invite to iax
+   */
+  bool iaxOutgoingInvite(IAXCall* Call);
+
   EventThread* _evThread;
   /** registration session : 0 if not register */
   struct iax_session* _regSession;
@@ -93,7 +98,8 @@ private:
   std::string _user;
   /** IAX Password */
   std::string _pass;
-  
+
+  ost::Mutex _mutexIAX;
 };
 
 #endif
diff --git a/src/managerimpl.cpp b/src/managerimpl.cpp
index 4449308f8a..e8b8394525 100644
--- a/src/managerimpl.cpp
+++ b/src/managerimpl.cpp
@@ -421,12 +421,11 @@ ManagerImpl::initRegisterVoIPLink()
     if ( iter->second) {
       iter->second->loadConfig();
       if ( iter->second->shouldInitOnStart() ) {
-        iter->second->init();
-        if (iter->second->shouldRegisterOnStart()) {
-          iter->second->registerAccount();
+        if ( iter->second->init() && iter->second->shouldRegisterOnStart()) {
+            iter->second->registerAccount();
         }
-	// init only the first account
-	break;
+        // init only the first account
+        break;
       }
     }
     iter++;
-- 
GitLab