diff --git a/sflphone-gtk/src/configurationmanager-glue.h b/sflphone-gtk/src/configurationmanager-glue.h
index ba2d46b61d762461b715f06ee93ec4d07afd6ede..1f3810ccc8a47fdc5c9ef8fb363a27dd39823a32 100644
--- a/sflphone-gtk/src/configurationmanager-glue.h
+++ b/sflphone-gtk/src/configurationmanager-glue.h
@@ -1,7 +1,6 @@
 /* Generated by dbus-binding-tool; do not edit! */
 
-#include <glib/gtypes.h>
-#include <glib/gerror.h>
+#include <glib.h>
 #include <dbus/dbus-glib.h>
 
 G_BEGIN_DECLS
@@ -2001,6 +2000,156 @@ org_sflphone_SFLphone_ConfigurationManager_get_sip_port_async (DBusGProxy *proxy
   stuff->userdata = userdata;
   return dbus_g_proxy_begin_call (proxy, "getSipPort", org_sflphone_SFLphone_ConfigurationManager_get_sip_port_async_callback, stuff, g_free, G_TYPE_INVALID);
 }
+static
+#ifdef G_HAVE_INLINE
+inline
+#endif
+gboolean
+org_sflphone_SFLphone_ConfigurationManager_set_stun_server (DBusGProxy *proxy, const char * IN_server, GError **error)
+
+{
+  return dbus_g_proxy_call (proxy, "setStunServer", error, G_TYPE_STRING, IN_server, G_TYPE_INVALID, G_TYPE_INVALID);
+}
+
+typedef void (*org_sflphone_SFLphone_ConfigurationManager_set_stun_server_reply) (DBusGProxy *proxy, GError *error, gpointer userdata);
+
+static void
+org_sflphone_SFLphone_ConfigurationManager_set_stun_server_async_callback (DBusGProxy *proxy, DBusGProxyCall *call, void *user_data)
+{
+  DBusGAsyncData *data = (DBusGAsyncData*) user_data;
+  GError *error = NULL;
+  dbus_g_proxy_end_call (proxy, call, &error, G_TYPE_INVALID);
+  (*(org_sflphone_SFLphone_ConfigurationManager_set_stun_server_reply)data->cb) (proxy, error, data->userdata);
+  return;
+}
+
+static
+#ifdef G_HAVE_INLINE
+inline
+#endif
+DBusGProxyCall*
+org_sflphone_SFLphone_ConfigurationManager_set_stun_server_async (DBusGProxy *proxy, const char * IN_server, org_sflphone_SFLphone_ConfigurationManager_set_stun_server_reply callback, gpointer userdata)
+
+{
+  DBusGAsyncData *stuff;
+  stuff = g_new (DBusGAsyncData, 1);
+  stuff->cb = G_CALLBACK (callback);
+  stuff->userdata = userdata;
+  return dbus_g_proxy_begin_call (proxy, "setStunServer", org_sflphone_SFLphone_ConfigurationManager_set_stun_server_async_callback, stuff, g_free, G_TYPE_STRING, IN_server, G_TYPE_INVALID);
+}
+static
+#ifdef G_HAVE_INLINE
+inline
+#endif
+gboolean
+org_sflphone_SFLphone_ConfigurationManager_get_stun_server (DBusGProxy *proxy, char ** OUT_server, GError **error)
+
+{
+  return dbus_g_proxy_call (proxy, "getStunServer", error, G_TYPE_INVALID, G_TYPE_STRING, OUT_server, G_TYPE_INVALID);
+}
+
+typedef void (*org_sflphone_SFLphone_ConfigurationManager_get_stun_server_reply) (DBusGProxy *proxy, char * OUT_server, GError *error, gpointer userdata);
+
+static void
+org_sflphone_SFLphone_ConfigurationManager_get_stun_server_async_callback (DBusGProxy *proxy, DBusGProxyCall *call, void *user_data)
+{
+  DBusGAsyncData *data = (DBusGAsyncData*) user_data;
+  GError *error = NULL;
+  char * OUT_server;
+  dbus_g_proxy_end_call (proxy, call, &error, G_TYPE_STRING, &OUT_server, G_TYPE_INVALID);
+  (*(org_sflphone_SFLphone_ConfigurationManager_get_stun_server_reply)data->cb) (proxy, OUT_server, error, data->userdata);
+  return;
+}
+
+static
+#ifdef G_HAVE_INLINE
+inline
+#endif
+DBusGProxyCall*
+org_sflphone_SFLphone_ConfigurationManager_get_stun_server_async (DBusGProxy *proxy, org_sflphone_SFLphone_ConfigurationManager_get_stun_server_reply callback, gpointer userdata)
+
+{
+  DBusGAsyncData *stuff;
+  stuff = g_new (DBusGAsyncData, 1);
+  stuff->cb = G_CALLBACK (callback);
+  stuff->userdata = userdata;
+  return dbus_g_proxy_begin_call (proxy, "getStunServer", org_sflphone_SFLphone_ConfigurationManager_get_stun_server_async_callback, stuff, g_free, G_TYPE_INVALID);
+}
+static
+#ifdef G_HAVE_INLINE
+inline
+#endif
+gboolean
+org_sflphone_SFLphone_ConfigurationManager_enable_stun (DBusGProxy *proxy, GError **error)
+
+{
+  return dbus_g_proxy_call (proxy, "enableStun", error, G_TYPE_INVALID, G_TYPE_INVALID);
+}
+
+typedef void (*org_sflphone_SFLphone_ConfigurationManager_enable_stun_reply) (DBusGProxy *proxy, GError *error, gpointer userdata);
+
+static void
+org_sflphone_SFLphone_ConfigurationManager_enable_stun_async_callback (DBusGProxy *proxy, DBusGProxyCall *call, void *user_data)
+{
+  DBusGAsyncData *data = (DBusGAsyncData*) user_data;
+  GError *error = NULL;
+  dbus_g_proxy_end_call (proxy, call, &error, G_TYPE_INVALID);
+  (*(org_sflphone_SFLphone_ConfigurationManager_enable_stun_reply)data->cb) (proxy, error, data->userdata);
+  return;
+}
+
+static
+#ifdef G_HAVE_INLINE
+inline
+#endif
+DBusGProxyCall*
+org_sflphone_SFLphone_ConfigurationManager_enable_stun_async (DBusGProxy *proxy, org_sflphone_SFLphone_ConfigurationManager_enable_stun_reply callback, gpointer userdata)
+
+{
+  DBusGAsyncData *stuff;
+  stuff = g_new (DBusGAsyncData, 1);
+  stuff->cb = G_CALLBACK (callback);
+  stuff->userdata = userdata;
+  return dbus_g_proxy_begin_call (proxy, "enableStun", org_sflphone_SFLphone_ConfigurationManager_enable_stun_async_callback, stuff, g_free, G_TYPE_INVALID);
+}
+static
+#ifdef G_HAVE_INLINE
+inline
+#endif
+gboolean
+org_sflphone_SFLphone_ConfigurationManager_is_stun_enabled (DBusGProxy *proxy, gint* OUT_state, GError **error)
+
+{
+  return dbus_g_proxy_call (proxy, "isStunEnabled", error, G_TYPE_INVALID, G_TYPE_INT, OUT_state, G_TYPE_INVALID);
+}
+
+typedef void (*org_sflphone_SFLphone_ConfigurationManager_is_stun_enabled_reply) (DBusGProxy *proxy, gint OUT_state, GError *error, gpointer userdata);
+
+static void
+org_sflphone_SFLphone_ConfigurationManager_is_stun_enabled_async_callback (DBusGProxy *proxy, DBusGProxyCall *call, void *user_data)
+{
+  DBusGAsyncData *data = (DBusGAsyncData*) user_data;
+  GError *error = NULL;
+  gint OUT_state;
+  dbus_g_proxy_end_call (proxy, call, &error, G_TYPE_INT, &OUT_state, G_TYPE_INVALID);
+  (*(org_sflphone_SFLphone_ConfigurationManager_is_stun_enabled_reply)data->cb) (proxy, OUT_state, error, data->userdata);
+  return;
+}
+
+static
+#ifdef G_HAVE_INLINE
+inline
+#endif
+DBusGProxyCall*
+org_sflphone_SFLphone_ConfigurationManager_is_stun_enabled_async (DBusGProxy *proxy, org_sflphone_SFLphone_ConfigurationManager_is_stun_enabled_reply callback, gpointer userdata)
+
+{
+  DBusGAsyncData *stuff;
+  stuff = g_new (DBusGAsyncData, 1);
+  stuff->cb = G_CALLBACK (callback);
+  stuff->userdata = userdata;
+  return dbus_g_proxy_begin_call (proxy, "isStunEnabled", org_sflphone_SFLphone_ConfigurationManager_is_stun_enabled_async_callback, stuff, g_free, G_TYPE_INVALID);
+}
 #endif /* defined DBUS_GLIB_CLIENT_WRAPPERS_org_sflphone_SFLphone_ConfigurationManager */
 
 G_END_DECLS
diff --git a/sflphone-gtk/src/configwindow.c b/sflphone-gtk/src/configwindow.c
index be137c73cf4bc7c7e1f9257351c5e5c3eacc656e..a15290e3bfa511942377ca14416d7bd5397fe148 100644
--- a/sflphone-gtk/src/configwindow.c
+++ b/sflphone-gtk/src/configwindow.c
@@ -109,7 +109,7 @@ config_window_fill_account_list()
  * Delete an account
  */
     static void
-delete_account(GtkWidget *widget, gpointer data UNUSED)
+delete_account(GtkWidget *widget UNUSED, gpointer data UNUSED)
 {
     if(selectedAccount)
     {
@@ -449,24 +449,15 @@ create_accounts_tab()
 void stun_state( void )
 {
     
-    guint i, size;
-    gchar * stun_enabled = "FALSE";
-    account_t * account;
+    guint stun_enabled = 0;
 
     gboolean stunActive = (gboolean)gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON( stunEnable ));
     gtk_widget_set_sensitive( GTK_WIDGET( stunServer ) , stunActive );
+
     // Check if we actually change the state
-    size = account_list_get_size();
-    for(i=0; i<size; i++)
-    {
-        account = account_list_get_nth(i);
-        if( strcmp(g_hash_table_lookup(account->properties, ACCOUNT_TYPE), "SIP" ) == 0 )
-        {
-            stun_enabled = g_hash_table_lookup(account->properties, ACCOUNT_SIP_STUN_ENABLED);
-            break;
-        }
-    }
-    if( (stunActive && strcmp(stun_enabled, "FALSE")==0) || (!stunActive && strcmp(stun_enabled, "TRUE")==0) )
+    stun_enabled = dbus_stun_is_enabled();
+    
+    if( (stunActive && stun_enabled ==0 ) || (!stunActive && stun_enabled ==1))
     {
         gtk_widget_set_sensitive( GTK_WIDGET( applyButton ) , TRUE );
     }
@@ -477,24 +468,8 @@ void stun_state( void )
 
 void update_registration( void )
 {
-    guint nb_accounts, i;
-    account_t *current;
-
-    nb_accounts = account_list_get_size();
-
-    for(i=0; i<nb_accounts;i++){
-        
-        current = account_list_get_nth(i);
-        // If SIP account, then set the new value
-        if( strcmp(g_hash_table_lookup(current->properties, ACCOUNT_TYPE), "SIP" ) == 0 )
-        {
-            g_hash_table_replace(current->properties, g_strdup(ACCOUNT_SIP_STUN_SERVER), 
-                                    g_strdup((gchar *)gtk_entry_get_text(GTK_ENTRY(stunServer))));
-            g_hash_table_replace(current->properties, g_strdup(ACCOUNT_SIP_STUN_ENABLED), 
-                                    g_strdup(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(stunEnable)) ? "TRUE": "FALSE"));
-            dbus_set_account_details(current);
-        }
-    }
+    dbus_set_stun_server((gchar *)gtk_entry_get_text(GTK_ENTRY(stunServer)));
+    dbus_enable_stun();
 
     gtk_widget_set_sensitive(GTK_WIDGET( applyButton ) , FALSE );
 }
@@ -505,23 +480,11 @@ GtkWidget* create_stun_tab()
     gchar * stun_server= "stun.fwdnet.net:3478";
     gchar * stun_enabled = "FALSE";
     GtkWidget * label;
-    account_t * account;
-    guint i, size;
 
-    // All SIP accounts are supposed to have the same STUN configuration
-    // So let's take the first SIP account we find
-    size = account_list_get_size();
-    for(i=0; i<size; i++)
-    {
-        account = account_list_get_nth(i);
-        if( strcmp(g_hash_table_lookup(account->properties, ACCOUNT_TYPE), "SIP" ) == 0 )
-        {
-            stun_enabled = g_hash_table_lookup(account->properties, ACCOUNT_SIP_STUN_ENABLED);
-            stun_server = g_hash_table_lookup(account->properties, ACCOUNT_SIP_STUN_SERVER);
-            break;
-        }
-    }
-    
+    /* Retrieve the STUN configuration */
+    stun_enabled = (dbus_stun_is_enabled()==1)?"TRUE":"FALSE";
+    stun_server = dbus_get_stun_server();
+
     tableNat = gtk_table_new ( 3, 2  , FALSE/* homogeneous */);
 
     // NAT detection code section
diff --git a/sflphone-gtk/src/dbus.c b/sflphone-gtk/src/dbus.c
index 7ed21b2118a4241b4dffd5ef73e120a12848ffe4..aa2edb87b9cb287bc1924d1fc5f0ba3a901321b4 100644
--- a/sflphone-gtk/src/dbus.c
+++ b/sflphone-gtk/src/dbus.c
@@ -39,6 +39,7 @@ DBusGConnection * connection;
 DBusGProxy * callManagerProxy;
 DBusGProxy * configurationManagerProxy;
 DBusGProxy * instanceProxy;
+DBusGProxy * nameOwnerProxy;
 
 static void  
 incoming_call_cb (DBusGProxy *proxy UNUSED,
@@ -172,18 +173,32 @@ error_alert(DBusGProxy *proxy UNUSED,
   sflphone_throw_exception( errCode );
 }
 
+
+static void nameOwnerChanged(DBusGProxy *proxy, char *name, char *old_owner, char *new_owner, gpointer data )
+{
+
+    g_print("******************************************************************\n");
+    g_print("Owner name of the service %s changed from %s to %s\n", name, old_owner, new_owner);
+    g_print("******************************************************************\n");
+
+    if (strcmp(name, "org.sflphone.SFLphone")!=0)   return;
+
+}
+
 gboolean 
 dbus_connect ()
 {
 
   GError *error = NULL;
   connection = NULL;
+  instanceProxy = NULL;
+  nameOwnerProxy = NULL;
   
   g_type_init ();
 
   connection = dbus_g_bus_get (DBUS_BUS_SESSION, &error);
   
-  if (connection == NULL)
+  if (error)
   {
     g_printerr ("Failed to open connection to bus: %s\n",
                 error->message);
@@ -191,13 +206,32 @@ dbus_connect ()
     return FALSE;
   }
 
+    
+    nameOwnerProxy = dbus_g_proxy_new_for_name( connection,
+                                                    DBUS_SERVICE_DBUS,
+                                                    DBUS_PATH_DBUS,
+                                                    DBUS_INTERFACE_DBUS);
+
+    if( nameOwnerProxy==NULL)
+    {
+        g_printerr ("Failed to get proxy to NameOwner\n");
+        return FALSE;
+    }
+
+    dbus_g_proxy_add_signal( nameOwnerProxy, "NameOwnerChanged",
+                G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INVALID);
+    dbus_g_proxy_connect_signal (nameOwnerProxy, "NameOwnerChanged",
+                G_CALLBACK (nameOwnerChanged), NULL, NULL);
+
+
   /* Create a proxy object for the "bus driver" (name "org.freedesktop.DBus") */
   
   instanceProxy = dbus_g_proxy_new_for_name (connection,
                                      "org.sflphone.SFLphone",
                                      "/org/sflphone/SFLphone/Instance",
                                      "org.sflphone.SFLphone.Instance");
-  if (!instanceProxy) 
+                                     
+  if (instanceProxy==NULL) 
   {
     g_printerr ("Failed to get proxy to Instance\n");
     return FALSE;
@@ -210,7 +244,8 @@ dbus_connect ()
                                      "org.sflphone.SFLphone",
                                      "/org/sflphone/SFLphone/CallManager",
                                      "org.sflphone.SFLphone.CallManager");
-  if (!callManagerProxy) 
+
+  if (callManagerProxy==NULL) 
   {
     g_printerr ("Failed to get proxy to CallManagers\n");
     return FALSE;
@@ -256,6 +291,7 @@ dbus_connect ()
                                   "org.sflphone.SFLphone",
                                   "/org/sflphone/SFLphone/ConfigurationManager",
                                   "org.sflphone.SFLphone.ConfigurationManager");
+
   if (!configurationManagerProxy) 
   {
     g_printerr ("Failed to get proxy to ConfigurationManager\n");
@@ -1505,3 +1541,58 @@ dbus_get_sip_port( void )
         return (guint)portNum;
 }
 
+gchar* dbus_get_stun_server (void)
+{
+        GError* error = NULL;
+        gchar* server;
+        org_sflphone_SFLphone_ConfigurationManager_get_stun_server(
+                        configurationManagerProxy,
+                        &server,
+                        &error);
+        if(error)
+        {
+                g_error_free(error);
+        }
+        return server;
+}
+
+void dbus_set_stun_server( gchar* server)
+{
+        GError* error = NULL;
+        org_sflphone_SFLphone_ConfigurationManager_set_stun_server(
+                        configurationManagerProxy,
+                        server,
+                        &error);
+        if(error)
+        {
+                g_error_free(error);
+        }
+}
+
+guint dbus_stun_is_enabled (void)
+{
+    GError* error = NULL;
+    guint stun;
+    org_sflphone_SFLphone_ConfigurationManager_is_stun_enabled(
+                        configurationManagerProxy,
+                        &stun,
+                        &error);
+        if(error)
+        {
+                g_error_free(error);
+        }
+        return stun;
+}
+
+void dbus_enable_stun (void)
+{
+    
+    GError* error = NULL;
+    org_sflphone_SFLphone_ConfigurationManager_enable_stun(
+                        configurationManagerProxy,
+                        &error);
+        if(error)
+        {
+                g_error_free(error);
+        }
+}
diff --git a/sflphone-gtk/src/dbus.h b/sflphone-gtk/src/dbus.h
index 4989443f06897300ebcd52e6cea87c6721cbcc58..f621cd04b10d75cf9bd98792b34bfa8d368f9432 100644
--- a/sflphone-gtk/src/dbus.h
+++ b/sflphone-gtk/src/dbus.h
@@ -429,4 +429,10 @@ void dbus_set_sip_port(const guint portNum);
 
 guint dbus_get_sip_port();
 
+gchar* dbus_get_stun_server (void);
+void dbus_set_stun_server( gchar* server);
+
+guint dbus_stun_is_enabled (void);
+void dbus_enable_stun (void);
+
 #endif
diff --git a/src/Makefile.am b/src/Makefile.am
index 5be031174cdf639b7967fbb297021f6256af06e5..311be41e02e478b31e549bd5a1a2e9c29cc6b65f 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -39,8 +39,7 @@ sflphoned_SOURCES = \
 		call.cpp \
 		account.cpp \
 		sipcall.cpp \
-		$(IAXSOURCES) \
-		useragent.cpp
+		$(IAXSOURCES) 
 
 sflphoned_CXXFLAGS = \
 		-DPREFIX=\"$(prefix)\" -DPROGSHAREDIR=\"${datadir}/sflphone\" \
@@ -62,6 +61,8 @@ sflphoned_LDADD = \
 		@PULSEAUDIO_LIBS@ \
 		@SAMPLERATE_LIBS@ 
 
+#sflphoned_LDFLAGS=-pg
+
 noinst_LTLIBRARIES = libsflphone.la
 
 noinst_HEADERS = \
@@ -78,8 +79,7 @@ noinst_HEADERS = \
 		accountcreator.h \
         sipvoiplink.h \
 		call.h \
-		sipcall.h \
-		useragent.h
+		sipcall.h 
 		
 libsflphone_la_LIBADD = \
 	$(src)/libs/stund/libstun.la \
diff --git a/src/account.cpp b/src/account.cpp
index 5bc6ba36ebb8325da825c8e93d3e1fdfa30dc1a7..b50fc71fc49d5648d875ac8bc4cb99758b82a9d3 100644
--- a/src/account.cpp
+++ b/src/account.cpp
@@ -22,9 +22,10 @@
 #include "account.h"
 #include "manager.h"
 
-Account::Account(const AccountID& accountID) : 
-    _accountID(accountID), _link(NULL), _enabled(false)
+Account::Account(const AccountID& accountID, std::string type) : 
+    _accountID(accountID), _link(NULL), _enabled(false), _type(type)
 {
+    setRegistrationState(Unregistered);
 }
 
 Account::~Account()
@@ -46,3 +47,9 @@ void Account::loadConfig()
 #endif
 }
 
+void Account::setRegistrationState( RegistrationState state ) { 
+    _registrationState = state; 
+
+    // Notify the client
+    Manager::instance().connectionStatusNotification( );
+}
diff --git a/src/account.h b/src/account.h
index 571f7220315facc986953b1c7a9cc9a2cb2f7b89..faf33dc162725e39c3dd4ad23985c0bb207b83c3 100644
--- a/src/account.h
+++ b/src/account.h
@@ -38,6 +38,19 @@ class VoIPLink;
 
 typedef std::string AccountID;
 
+/** Contains all the state an Voip can be in */
+typedef enum RegistrationState {
+        Unregistered, 
+        Trying, 
+        Registered, 
+        Error, 
+        ErrorAuth , 
+        ErrorNetwork , 
+        ErrorHost, 
+        ErrorExistStun, 
+        ErrorConfStun
+} RegistrationState;
+
 #define AccountNULL ""
 
 // Common account parameters
@@ -59,7 +72,7 @@ class Account{
 
     public:
 
-        Account(const AccountID& accountID);
+        Account(const AccountID& accountID, std::string type);
 
         /**
          * Virtual destructor
@@ -106,10 +119,28 @@ class Account{
          * Get the registration state of the specified link
          * @return RegistrationState	The registration state of underlying VoIPLink
          */
-        VoIPLink::RegistrationState getRegistrationState() { return _link->getRegistrationState(); }
+        inline RegistrationState getRegistrationState() { return _registrationState; }
 
-    private:
+        void setRegistrationState( RegistrationState state );
+
+        /* inline functions */
+        /* They should be treated like macro definitions by the C++ compiler */
+        inline std::string getUsername( void ) { return _username; }
+        inline void setUsername( std::string username) { _username = username; }
+
+        inline std::string getHostname( void ) { return _hostname; }
+        inline void setHostname( std::string hostname) { _hostname = hostname; }
+
+        inline std::string getPassword( void ) { return _password; }
+        inline void setPassword( std::string password ) { _password = password; }
+
+        inline std::string getAlias( void ) { return _alias; }
+        inline void setAlias( std::string alias ) { _alias = alias; }
 
+        inline std::string getType( void ) { return _type; }
+        inline void setType( std::string type ) { _type = type; }
+
+    private:
         // copy constructor
         Account(const Account& rh);
 
@@ -122,6 +153,32 @@ class Account{
          */
         AccountID _accountID;
 
+        /**
+         * Account login information: username
+         */
+        std::string _username;
+
+        /**
+         * Account login information: hostname
+         */
+        std::string _hostname;
+
+        /**
+         * Account login information: password
+         */
+        std::string _password;
+
+        /**
+         * Account login information: Alias
+         */
+        std::string _alias;
+
+        /*
+         * The account type
+         * IAX2 or SIP
+         */
+        std::string _type;
+
         /**
          * Voice over IP Link contains a listener thread and calls
          */
@@ -134,6 +191,11 @@ class Account{
          */
         bool _enabled;
 
+        /*
+         * The registration state of the account
+         */
+        RegistrationState _registrationState;
+
 };
 
 #endif
diff --git a/src/audio/Makefile.am b/src/audio/Makefile.am
index 19cf33ee8124858805aa0f2bd72f73a7c1ec69e8..73659fe66c2bec7b756b3db7049ca65d14f8ef4c 100644
--- a/src/audio/Makefile.am
+++ b/src/audio/Makefile.am
@@ -30,6 +30,7 @@ libaudio_la_SOURCES = \
 		dtmf.cpp \
 		tone.cpp \
 		alsalayer.cpp \
+		audiolayer.cpp \
 		pulselayer.cpp \
 		audiodevice.cpp \
 		dtmfgenerator.cpp \
diff --git a/src/audio/alsalayer.cpp b/src/audio/alsalayer.cpp
index acd933c9d071b4d82e1a02c7206f07ab069a279d..5409c855963e18002f45ebb8ab787a98afef0f83 100644
--- a/src/audio/alsalayer.cpp
+++ b/src/audio/alsalayer.cpp
@@ -1,5 +1,5 @@
 /*
- *  Copyright (C) 2008 Savoir-Faire Linux inc.
+ *  Copyright (C) 2008 2009 Savoir-Faire Linux inc.
  *  Author: Emmanuel Milou <emmanuel.milou@savoirfairelinux.com>
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -19,13 +19,7 @@
 
 #include "alsalayer.h"
 
-void* ringtoneThreadEntry( void *ptr);
-
-static pthread_t ringtone_thread;
-bool ringtone_thread_is_running;
-
-pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER;
-pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
+int framesPerBufferAlsa = 2048;
 
 // Constructor
     AlsaLayer::AlsaLayer( ManagerImpl* manager ) 
@@ -34,70 +28,63 @@ pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
     , _CaptureHandle(NULL)
     , _periodSize()
     , _audioPlugin()
-    , _inChannel()
-    , _outChannel()
-    , _defaultVolume(100)
-      , IDSoundCards() 
+    , IDSoundCards() 
+    , _is_prepared_playback (false)
+    , _is_running_playback (false)
+    , _is_open_playback (false)
+    , _is_prepared_capture (false)
+    , _is_running_capture (false)
+    , _is_open_capture (false)
+    , _trigger_request (false)
+ 
 {
     _debug(" Constructor of AlsaLayer called\n");
-
-    // The flag to stop the ringtone thread loop
-    ringtone_thread_is_running = false;
+    /* Instanciate the audio thread */
+    _audioThread = new AudioThread (this);
 }
 
 // Destructor
 AlsaLayer::~AlsaLayer (void) 
 { 
-    _debugAlsa("Close ALSA streams\n");
-    closeCaptureStream();
-    closePlaybackStream();
-    deviceClosed = true;
-
-    ringtone_thread_is_running = false;
-    pthread_join(ringtone_thread, NULL);
+    _debug("Destructor of AlsaLayer called\n");
+    closeLayer();
 }
 
     void
 AlsaLayer::closeLayer()
 {
     _debugAlsa("Close ALSA streams\n");
+    
+    if (_audioThread)
+    {
+        _debug("Try to stop audio thread\n");
+        delete _audioThread; _audioThread=NULL;
+    }
+
     closeCaptureStream();
     closePlaybackStream();
-    deviceClosed = true;
-    
-    ringtone_thread_is_running = false;
 }
 
     bool 
 AlsaLayer::openDevice (int indexIn, int indexOut, int sampleRate, int frameSize, int stream , std::string plugin) 
 {
-
-    // We don't accept that the audio plugin is changed during a conversation
-    if( _talk ){
-        _debug("can't switch audio plugin when talking\n. Please hang up and try again...\n");
-        return false;
-    }
-        
-    if(deviceClosed == false)
+    /* Close the devices before open it */  
+    if (stream == SFL_PCM_BOTH && is_capture_open() == true && is_playback_open() == true)
     {
-        if( stream == SFL_PCM_CAPTURE )
-            closeCaptureStream();
-        else if( stream == SFL_PCM_PLAYBACK)
-            closePlaybackStream();
-        else
-        {
-            closeCaptureStream();
-            closePlaybackStream();
-        }
+        closeCaptureStream();
+        closePlaybackStream();
     }
+    else if ((stream == SFL_PCM_CAPTURE || stream == SFL_PCM_BOTH) && is_capture_open() == true)
+        closeCaptureStream ();
+    else if ((stream == SFL_PCM_PLAYBACK || stream == SFL_PCM_BOTH) && is_playback_open () == true)
+        closePlaybackStream ();
+
 
     _indexIn = indexIn;
     _indexOut = indexOut;
     _sampleRate = sampleRate;
     _frameSize = frameSize;	
     _audioPlugin = plugin;
-    _inChannel = 1;
-    _outChannel = 1;
 
     _debugAlsa(" Setting AlsaLayer: device     in=%2d, out=%2d\n", _indexIn, _indexOut);
     _debugAlsa("                   : alsa plugin=%s\n", _audioPlugin.c_str());
@@ -105,17 +92,7 @@ AlsaLayer::openDevice (int indexIn, int indexOut, int sampleRate, int frameSize,
     _debugAlsa("                   : sample rate=%5d, format=%s\n", _sampleRate, SFLDataFormatString);
 
     ost::MutexLock lock( _mutex );
-
     
-    /*void **hint;
-    int r = snd_device_name_hint(-1, "pcm", &hint);
-
-    while( *hint ){
-        printf("%s\n", snd_device_name_get_hint(*hint, "DESC"));
-        ++hint;
-    }*/
-
-
     std::string pcmp = buildDeviceTopo( plugin , indexOut , 0);
     std::string pcmc = buildDeviceTopo( PCM_PLUGHW , indexIn , 0);
 
@@ -125,142 +102,40 @@ AlsaLayer::openDevice (int indexIn, int indexOut, int sampleRate, int frameSize,
     void
 AlsaLayer::startStream(void) 
 {
-    if( _CaptureHandle && _PlaybackHandle )
-    {
-        _talk = true ;
-        _debugAlsa(" Start stream\n");
-        int err;
-        //ost::MutexLock lock( _mutex );
-        snd_pcm_prepare( _CaptureHandle );
-        snd_pcm_start( _CaptureHandle ) ;
-
-        snd_pcm_prepare( _PlaybackHandle );
-        if( (err = snd_pcm_start( _PlaybackHandle)) < 0 )  _debugAlsa(" Cannot start (%s)\n", snd_strerror(err));
-    }
+    _debug ("Start ALSA streams\n");
+    prepareCaptureStream ();
+    startCaptureStream ();
+    startPlaybackStream ();
 } 
 
     void
 AlsaLayer::stopStream(void) 
 {
-    if( _CaptureHandle && _PlaybackHandle )
-    {
-        //ost::MutexLock lock( _mutex );
-        _debugAlsa(" Stop Stream\n ");
-        _talk = false;
-        snd_pcm_drop( _CaptureHandle );
-        snd_pcm_prepare( _CaptureHandle );
-        snd_pcm_drop( _PlaybackHandle );
-        snd_pcm_prepare( _PlaybackHandle );
-        _urgentBuffer.flush();
-    }
-}
-
-
-void* ringtoneThreadEntry( void *ptr )
-{ 
-    while( ringtone_thread_is_running )
-    {
-        ( ( AlsaLayer *) ptr) -> playTones();
-        //sleep(0.1);
-    }
-    /*
-    pthread_mutex_lock(&mut);
-    while( ((AlsaLayer*)ptr)->_manager->getTelephoneTone() == NULL )
-    {
-        pthread_cond_wait(&cond, &mut);
-    }
-    ( AlsaLayer *) ptr -> playTones();
-    pthread_mutex_unlock(&mut);*/
-    return 0;
-}
-
-
-    void 
-AlsaLayer::fillHWBuffer( void)
-{
+    _debug ("Stop ALSA streams\n");
+    stopCaptureStream ();
+    //stopPlaybackStream ();
 
-  unsigned char* data;
-  int pcmreturn, l1, l2;
-  short s1, s2;
-  int periodSize = 128 ;
-  int frames = periodSize >> 2 ;
-  _debug("frames  = %d\n", frames);
-
-  data = (unsigned char*)malloc(periodSize);
-  for(l1 = 0; l1 < 100; l1++) {
-    for(l2 = 0; l2 < frames; l2++) {
-      s1 = 0;
-      s2 = 0;
-      data[4*l2] = (unsigned char)s1;
-      data[4*l2+1] = s1 >> 8;
-      data[4*l2+2] = (unsigned char)s2;
-      data[4*l2+3] = s2 >> 8;
-    }
-    while ((pcmreturn = snd_pcm_writei(_PlaybackHandle, data, frames)) < 0) {
-      snd_pcm_prepare(_PlaybackHandle);
-      //_debugAlsa("< Buffer Underrun >\n");
-    }
-  }
+    /* Flush the ring buffers */
+    flushUrgent();
+    flushMain();
 }
 
-    bool
-AlsaLayer::isStreamActive (void) 
-{
-    ost::MutexLock lock( _mutex );
-    return (isPlaybackActive() && isCaptureActive());
-}
-
-    int 
-AlsaLayer::playSamples(void* buffer, int toCopy, bool isTalking)
-{
-    //ost::MutexLock lock( _mutex );
-    if( isTalking )
-        _talk = true;
-    if ( _PlaybackHandle ){ 
-        write( adjustVolume( buffer , toCopy , SFL_PCM_PLAYBACK ) , toCopy );
-    }
-    return 0;
-}
-
-    int
-AlsaLayer::putUrgent(void* buffer, int toCopy)
-{
-    int nbBytes = 0;
-
-    if ( _PlaybackHandle ){ 
-        //fillHWBuffer();
-        int a = _urgentBuffer.AvailForPut();
-        if( a >= toCopy ){
-            nbBytes = _urgentBuffer.Put( buffer , toCopy , _defaultVolume );
-        } else {
-            nbBytes = _urgentBuffer.Put( buffer , a , _defaultVolume ) ;
-        }
-    }
-
-    return nbBytes;
-}
-
-void AlsaLayer::trigger_thread(void)
-{
-        _debug("Wake up the ringtone thread\n");
-        pthread_cond_broadcast(&cond);
-}
-
-
     int
 AlsaLayer::canGetMic()
 {
     int avail;
-    if ( _CaptureHandle ) {
-        avail = snd_pcm_avail_update( _CaptureHandle );
-        //printf("%d\n", avail ); 
-        if(avail > 0)
-            return avail;
-        else 
-            return 0;  
+    
+    if (! _CaptureHandle )
+        return 0;
+
+    avail = snd_pcm_avail_update( _CaptureHandle );
+    
+    if( avail == -EPIPE ){
+        stop_capture ();
+        return 0;
     }
     else
-        return 0;
+        return ((avail < 0)? 0:avail);
 }
 
     int 
@@ -275,75 +150,77 @@ AlsaLayer::getMic(void *buffer, int toCopy)
     return res ;
 }
 
-
-    bool
-AlsaLayer::isStreamStopped (void) 
-{
-    ost::MutexLock lock( _mutex );
-    return !(isStreamActive());
-}
-
-
-void AlsaLayer::reducePulseAppsVolume( void ){}
-void AlsaLayer::restorePulseAppsVolume( void ){}
-
 //////////////////////////////////////////////////////////////////////////////////////////////
 /////////////////   ALSA PRIVATE FUNCTIONS   ////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////////////////////////////
+    
+void AlsaLayer::stopCaptureStream (void)
+{
+    if(_CaptureHandle){
+        snd_pcm_drop (_CaptureHandle);
+        stop_capture ();
+    }
+}
 
+void AlsaLayer::closeCaptureStream (void)
+{
+    if( is_capture_prepared() == true && is_capture_running() == true ) 
+        stopCaptureStream ();
+    if (is_capture_open())
+        snd_pcm_close (_CaptureHandle);
 
+    close_capture ();
+}
 
-    void
-AlsaLayer::playTones( void )
+void AlsaLayer::startCaptureStream (void)
 {
-    int frames;
-    int maxBytes;
+    if(_CaptureHandle){
+        snd_pcm_start (_CaptureHandle);
+        start_capture();
+    }
+}
 
-    pthread_mutex_lock(&mut);
-    while(!_manager-> getTelephoneTone() && !_manager->getTelephoneFile())
-    {
-        _debug("Make the ringtone thread wait\n");
-        pthread_cond_wait(&cond, &mut);
-    }
-
-    //frames = _periodSize  ; 
-    frames = 940  ; 
-    maxBytes = frames * sizeof(SFLDataFormat)  ;
-    SFLDataFormat* out = (SFLDataFormat*)malloc(maxBytes * sizeof(SFLDataFormat));
-    if( _talk ) {}
-    else {
-        AudioLoop *tone = _manager -> getTelephoneTone();
-        if( tone != 0 ){
-            tone -> getNext( out , frames , _manager->getSpkrVolume() );
-            write( out , maxBytes );
-        } 
-        else if( ( tone=_manager->getTelephoneFile() ) != 0 ){
-            tone ->getNext( out , frames , _manager->getSpkrVolume() );
-            write( out , maxBytes );
-        }
+void AlsaLayer::prepareCaptureStream (void)
+{
+    if (is_capture_open() ) {
+        if(snd_pcm_prepare (_CaptureHandle) < 0)    _debug("Error preparing the device\n");
+        prepare_capture ();
     }
-    // free the temporary data buffer 
-    free( out ); out = 0;
-    pthread_mutex_unlock(&mut);
 }
 
+void AlsaLayer::stopPlaybackStream (void)
+{
+    if( _PlaybackHandle){
+        snd_pcm_drop (_PlaybackHandle);
+        stop_playback ();
+    }
+}
 
-bool
-AlsaLayer::isPlaybackActive(void) {
-    ost::MutexLock guard( _mutex );
-    if( _PlaybackHandle )
-        return (snd_pcm_state(_PlaybackHandle) == SND_PCM_STATE_RUNNING ? true : false); 
-    else
-        return false;
+
+void AlsaLayer::closePlaybackStream (void)
+{
+    if( is_playback_prepared() == true && is_playback_running() == true ) 
+        stopPlaybackStream ();
+    if (is_playback_open()) 
+        snd_pcm_close (_PlaybackHandle);
+
+    close_playback ();
 }
 
-bool
-AlsaLayer::isCaptureActive(void) {
-    ost::MutexLock guard( _mutex );
-    if( _CaptureHandle )
-        return (snd_pcm_state( _CaptureHandle) == SND_PCM_STATE_RUNNING ? true : false); 
-    else
-        return false;
+void AlsaLayer::startPlaybackStream (void)
+{
+    if( _PlaybackHandle){
+        snd_pcm_start (_PlaybackHandle);
+        start_playback();
+    }
+}
+
+void AlsaLayer::preparePlaybackStream (void)
+{
+    if(is_playback_open()){
+        if( snd_pcm_prepare (_PlaybackHandle) < 0)  _debug("Error preparing the device\n");
+        prepare_playback ();
+    }
 }
 
 bool AlsaLayer::alsa_set_params( snd_pcm_t *pcm_handle, int type, int rate ){
@@ -444,23 +321,8 @@ bool AlsaLayer::alsa_set_params( snd_pcm_t *pcm_handle, int type, int rate ){
         return false;
     }
 
-    if( type == 1 ){
-        /*if( (err = snd_async_add_pcm_handler( &_AsyncHandler, pcm_handle , AlsaCallBack, this ) < 0)){
-            _debugAlsa(" Unable to install the async callback handler (%s)\n", snd_strerror(err));
-            return false;
-        }*/
-        
-        // So the loop could start when the ringtone thread entry function is reached
-        ringtone_thread_is_running = true;
-        if( pthread_create(&ringtone_thread, NULL, ringtoneThreadEntry, this) != 0 )
-        {
-            _debug("Unable to start the ringtone posix thread\n");
-            return false;
-        }
-    }
 
     snd_pcm_sw_params_free( swparams );
-    deviceClosed = false;
 
     return true;
 }
@@ -477,13 +339,17 @@ AlsaLayer::open_device(std::string pcm_p, std::string pcm_c, int flag)
         if((err = snd_pcm_open(&_PlaybackHandle, pcm_p.c_str(),  SND_PCM_STREAM_PLAYBACK, 0 )) < 0){
             _debugAlsa("Error while opening playback device %s\n",  pcm_p.c_str());
             setErrorMessage( ALSA_PLAYBACK_DEVICE );
+            close_playback ();
             return false;
         }
         if(!alsa_set_params( _PlaybackHandle, 1, getSampleRate() )){
             _debug("playback failed\n");
             snd_pcm_close( _PlaybackHandle );
+            close_playback ();
             return false;
         }
+
+        open_playback ();
     }
 
     if(flag == SFL_PCM_BOTH || flag == SFL_PCM_CAPTURE)
@@ -491,20 +357,23 @@ AlsaLayer::open_device(std::string pcm_p, std::string pcm_c, int flag)
         if( (err = snd_pcm_open(&_CaptureHandle,  pcm_c.c_str(),  SND_PCM_STREAM_CAPTURE, 0)) < 0){
             _debugAlsa("Error while opening capture device %s\n",  pcm_c.c_str());
             setErrorMessage( ALSA_CAPTURE_DEVICE );
+            close_capture ();
             return false;
         }
         if(!alsa_set_params( _CaptureHandle, 0, 8000 /*getSampleRate()*/ )){
             _debug("capture failed\n");
             snd_pcm_close( _CaptureHandle );
+            close_capture ();
             return false;
         }
-        if( (err = snd_pcm_start( _CaptureHandle ))<0) {
-          _debugAlsa( "snd_pcm_start failed\n");
-        }
+
+        open_capture ();
+        
+        startCaptureStream ();
     }
 
-    //TODO something, really!
-    _talk = false;
+    /* Start the secondary audio thread for callbacks */
+    _audioThread->start();
 
     return true;
 }
@@ -513,33 +382,34 @@ AlsaLayer::open_device(std::string pcm_p, std::string pcm_c, int flag)
     int
 AlsaLayer::write(void* buffer, int length)
 {
-    //if(snd_pcm_state( _PlaybackHandle ) == SND_PCM_STATE_XRUN)
-    //handle_xrun_playback();  
-    //_debugAlsa("avail = %d - toWrite = %d\n" , snd_pcm_avail_update( _PlaybackHandle ) , length / 2);
 
-    snd_pcm_uframes_t frames = snd_pcm_bytes_to_frames( _PlaybackHandle, length);
-    int err = snd_pcm_writei( _PlaybackHandle , buffer , frames );
-    switch(err) {
-        case -EAGAIN: 
-            _debugAlsa("EAGAIN (%s)\n", snd_strerror( err ));
-            snd_pcm_resume( _PlaybackHandle );
-            break;
-        case -EPIPE: 
-            _debugAlsa(" UNDERRUN (%s)\n", snd_strerror(err));
-            handle_xrun_playback();
-            snd_pcm_writei( _PlaybackHandle , buffer , frames );
-            break;
-        case -ESTRPIPE:
-            _debugAlsa(" ESTRPIPE(%s)\n", snd_strerror(err));
-            snd_pcm_resume( _PlaybackHandle );
-            break;
-        case -EBADFD:
-            _debugAlsa(" (%s)\n", snd_strerror( err ));
-            break;
+
+    if (_trigger_request == true)
+    {
+        _trigger_request = false;
+        startPlaybackStream ();
     }
 
-    if( ( err >=0 ) && ( err < (int)frames ) )
-        _debugAlsa("Short write : %d out of %d\n", err , (int)frames);
+    snd_pcm_uframes_t frames = snd_pcm_bytes_to_frames( _PlaybackHandle, length);
+    int err;
+    if ((err=snd_pcm_writei( _PlaybackHandle , buffer , frames ))<0) 
+    {
+        switch(err) {
+            case -EPIPE: 
+            case -ESTRPIPE: 
+            case -EIO: 
+                //_debugAlsa(" XRUN playback ignored (%s)\n", snd_strerror(err));
+                handle_xrun_playback();
+                if (snd_pcm_writei( _PlaybackHandle , buffer , frames )<0)
+                    _debugAlsa ("XRUN handling failed\n");
+                _trigger_request = true;
+                break;
+            default:
+                //_debugAlsa ("Write error unknown - dropping frames **********************************: %s\n", snd_strerror(err));
+                stopPlaybackStream ();
+                break;
+        }
+    }
 
     return ( err > 0 )? err : 0 ;
 }
@@ -547,29 +417,32 @@ AlsaLayer::write(void* buffer, int length)
     int
 AlsaLayer::read( void* buffer, int toCopy)
 {
-    if(deviceClosed || _CaptureHandle == NULL)
-        return 0;
+    ost::MutexLock lock( _mutex );
+    
+    int samples;
 
-    int err;
     if(snd_pcm_state( _CaptureHandle ) == SND_PCM_STATE_XRUN)
     {
-        snd_pcm_prepare( _CaptureHandle );
-        snd_pcm_start( _CaptureHandle );
+        _debug("xrun caught before start\n");
+        prepareCaptureStream ();
+        startCaptureStream ();
     }
+    
     snd_pcm_uframes_t frames = snd_pcm_bytes_to_frames( _CaptureHandle, toCopy );
-    if(( err = snd_pcm_readi( _CaptureHandle, buffer, frames)) < 0 ) {
-        switch(err){
-            case EPERM:
-                _debugAlsa(" Capture EPERM (%s)\n", snd_strerror(err));
-                snd_pcm_prepare( _CaptureHandle);
-                snd_pcm_start( _CaptureHandle );
-                break;
-            case -EAGAIN:
-                _debugAlsa(" Capture EAGAIN (%s)\n", snd_strerror(err));
-                break;
+    if(( samples = snd_pcm_readi( _CaptureHandle, buffer, frames)) < 0 ) {
+        switch (samples)
+        {
             case -EPIPE:
-                _debugAlsa(" Capture EPIPE (%s)\n", snd_strerror(err));
+            case -ESTRPIPE:
+            case -EIO:
+                _debugAlsa(" XRUN capture ignored (%s)\n", snd_strerror(samples));
                 handle_xrun_capture();
+                samples = snd_pcm_readi( _CaptureHandle, buffer, frames);
+                if (samples<0)  samples=0;
+                break;
+            default:
+                //_debugAlsa ("Error when capturing data ***********************************************: %s\n", snd_strerror(samples));
+                stopCaptureStream();
                 break;
         }
         return 0;
@@ -577,14 +450,6 @@ AlsaLayer::read( void* buffer, int toCopy)
 
     return toCopy;
 
-}
-
-    int
-AlsaLayer::putInCache( char code UNUSED, 
-        void *buffer UNUSED, 
-        int toCopy UNUSED )
-{
-    return 1;
 }
 
     void
@@ -596,9 +461,9 @@ AlsaLayer::handle_xrun_capture( void )
     int res = snd_pcm_status( _CaptureHandle, status );
     if( res <= 0){
         if(snd_pcm_status_get_state(status) == SND_PCM_STATE_XRUN ){
-            snd_pcm_drop( _CaptureHandle );
-            snd_pcm_prepare( _CaptureHandle );
-            snd_pcm_start( _CaptureHandle ); 
+            stopCaptureStream ();
+            prepareCaptureStream ();
+            startCaptureStream ();
         }
     }
     else
@@ -618,9 +483,9 @@ AlsaLayer::handle_xrun_playback( void )
         state = snd_pcm_status_get_state( status );
         if( state  == SND_PCM_STATE_XRUN )
         {
-            snd_pcm_drop( _PlaybackHandle );
-            snd_pcm_prepare( _PlaybackHandle );
-            //snd_pcm_start( _PlaybackHandle ); 
+            stopPlaybackStream ();
+            preparePlaybackStream ();
+            _trigger_request = true;
         }
     }
 }
@@ -695,25 +560,7 @@ AlsaLayer::getSoundCardsInfo( int stream )
     return cards_id;
 }
 
-    void
-AlsaLayer::closeCaptureStream( void)
-{
-    if(_CaptureHandle){
-        snd_pcm_drop( _CaptureHandle );
-        snd_pcm_close( _CaptureHandle );
-        _CaptureHandle = 0;
-    }
-}
 
-    void
-AlsaLayer::closePlaybackStream( void)
-{
-    if(_PlaybackHandle){
-        snd_pcm_drop( _PlaybackHandle );
-        snd_pcm_close( _PlaybackHandle );
-        _PlaybackHandle = 0;
-    }
-}
 
     bool
 AlsaLayer::soundCardIndexExist( int card , int stream )
@@ -749,8 +596,68 @@ AlsaLayer::soundCardGetIndex( std::string description )
     return 0;
 }
 
-    void*
-AlsaLayer::adjustVolume( void* buffer , int len, int stream )
+void AlsaLayer::audioCallback (void)
+{
+
+    int toGet, toPut, urgentAvail, normalAvail, micAvailPut, maxBytes; 
+    unsigned short spkrVolume, micVolume;
+    AudioLoop *tone;
+
+    SFLDataFormat *out;
+
+    spkrVolume = _manager->getSpkrVolume();
+    micVolume  = _manager->getMicVolume();
+
+    // AvailForGet tell the number of chars inside the buffer
+    // framePerBuffer are the number of data for one channel (left)
+    urgentAvail = _urgentRingBuffer.AvailForGet();
+    if (urgentAvail > 0) {
+        // Urgent data (dtmf, incoming call signal) come first.     
+        toGet = (urgentAvail < (int)(framesPerBufferAlsa * sizeof(SFLDataFormat))) ? urgentAvail : framesPerBufferAlsa * sizeof(SFLDataFormat);
+        out =  (SFLDataFormat*)malloc(toGet * sizeof(SFLDataFormat) );
+        _urgentRingBuffer.Get(out, toGet, spkrVolume);
+        /* Play the sound */
+        write( out , toGet );
+        free(out); out=0;
+        // Consume the regular one as well (same amount of bytes)
+        _voiceRingBuffer.Discard(toGet);
+    } else {
+        tone = _manager->getTelephoneTone();
+        toGet = 940  ; 
+        maxBytes = toGet * sizeof(SFLDataFormat)  ;
+        if ( tone != 0) {
+            out = (SFLDataFormat*)malloc(maxBytes * sizeof(SFLDataFormat));
+            tone->getNext(out, toGet, spkrVolume);
+            write (out , maxBytes);
+        } else if ( (tone=_manager->getTelephoneFile()) != 0 ) {
+            out =  (SFLDataFormat*)malloc(maxBytes * sizeof(SFLDataFormat) );
+            tone->getNext(out, toGet, spkrVolume);
+            write (out , maxBytes);
+        } else {
+            // If nothing urgent, play the regular sound samples
+            normalAvail = _voiceRingBuffer.AvailForGet();
+            toGet = (normalAvail < (int)(framesPerBufferAlsa * sizeof(SFLDataFormat))) ? normalAvail : framesPerBufferAlsa * sizeof(SFLDataFormat);
+            out =  (SFLDataFormat*)malloc(framesPerBufferAlsa * sizeof(SFLDataFormat));
+
+            if (toGet) {
+                _voiceRingBuffer.Get(out, toGet, spkrVolume);
+                write (out, toGet);
+            } else {
+                bzero(out, framesPerBufferAlsa * sizeof(SFLDataFormat));
+            }
+        }
+        free(out); out=0;
+    }
+    
+    // Additionally handle the mic's audio stream 
+    //micAvailPut = _micRingBuffer.AvailForPut();
+    //toPut = (micAvailPut <= (int)(framesPerBufferAlsa * sizeof(SFLDataFormat))) ? micAvailPut : framesPerBufferAlsa * sizeof(SFLDataFormat);
+    //_debug("AL: Nb sample: %d char, [0]=%f [1]=%f [2]=%f\n", toPut, in[0], in[1], in[2]);
+    //_micRingBuffer.Put(in, toPut, micVolume);
+}
+
+
+void* AlsaLayer::adjustVolume( void* buffer , int len, int stream )
 {
     int vol, i, size;
     SFLDataFormat *src = NULL;
@@ -768,4 +675,3 @@ AlsaLayer::adjustVolume( void* buffer , int len, int stream )
     }
     return src ; 
 }
-
diff --git a/src/audio/alsalayer.h b/src/audio/alsalayer.h
index c9dfa016d2cf8d61d68df15d815d7cc8f13eb088..875e0cc14124b19963b50e7fbc947e9ba3e7ad65 100644
--- a/src/audio/alsalayer.h
+++ b/src/audio/alsalayer.h
@@ -21,8 +21,8 @@
 #define _ALSA_LAYER_H
 
 #include "audiolayer.h"
-
-#include <pthread.h>
+#include "eventthread.h"
+#include <alsa/asoundlib.h>
 
 class RingBuffer;
 class ManagerImpl;
@@ -48,8 +48,6 @@ class AlsaLayer : public AudioLayer {
      */
     ~AlsaLayer(void);
 
-    void trigger_thread(void);
-
     void closeLayer( void );
 
     /**
@@ -81,52 +79,6 @@ class AlsaLayer : public AudioLayer {
      */
     void stopStream(void);
     
-    /**
-     * Check if the playback is running
-     * @return true if the state of the playback handle equals SND_PCM_STATE_RUNNING
-     *	       false otherwise
-     */
-    bool isPlaybackActive( void );
-
-    /**
-     * Check if the capture is running
-     * @return true if the state of the capture handle equals SND_PCM_STATE_RUNNING
-     *	       false otherwise
-     */
-    bool isCaptureActive( void );
-
-    /**
-     * Check if both capture and playback are running
-     * @return true if capture and playback are running
-     *	       false otherwise
-     */
-    bool isStreamActive(void);
-
-    /**
-     * Check if both capture and playback are stopped
-     * @return true if capture and playback are stopped
-     *	       false otherwise
-     */
-    bool isStreamStopped(void);
-
-    /**
-     * Send samples to the audio device. 
-     * @param buffer The buffer containing the data to be played ( voice and DTMF )
-     * @param toCopy The number of samples, in bytes
-     * @param isTalking	If whether or not the conversation is running
-     * @return int The number of bytes played
-     */
-    int playSamples(void* buffer, int toCopy, bool isTalking);
-
-    /**
-     * Send a chunk of data to the hardware buffer to start the playback
-     * Copy data in the urgent buffer. 
-     * @param buffer The buffer containing the data to be played ( ringtones )
-     * @param toCopy The size of the buffer
-     * @return int  The number of bytes copied in the urgent buffer
-     */
-    int putUrgent(void* buffer, int toCopy);
-
     /**
      * Query the capture device for number of bytes available in the hardware ring buffer
      * @return int The number of bytes available
@@ -185,34 +137,9 @@ class AlsaLayer : public AudioLayer {
      */
     std::string getAudioPlugin( void ) { return _audioPlugin; }
 
-    /**
-     * UNUSED in ALSA layer
-     */
-    int putInCache( char code, void *buffer, int toCopy );
-
-
-    /**
-     * UNUSED in ALSA layer
-     */
-    void reducePulseAppsVolume( void );
-
-    /**
-     * UNUSED in ALSA layer
-     */
-    void restorePulseAppsVolume( void ); 
-
-    /**
-     * UNUSED in ALSA layer
-     */
-    void setPlaybackVolume( UNUSED int volume ){}
-    void setCaptureVolume( UNUSED int volume ){}
-
-    /**
-     * Callback used for asynchronous playback.
-     * Write tones buffer to the alsa internal ring buffer.
-     */
-    void playTones( void );
+    void audioCallback (void);
 
+    bool isCaptureActive (void) { return is_capture_running (); }
 
   private:
   
@@ -222,29 +149,44 @@ class AlsaLayer : public AudioLayer {
     // Assignment Operator
     AlsaLayer& operator=( const AlsaLayer& rh);
 
+    bool _is_prepared_playback;
+    bool _is_prepared_capture;
+    bool _is_running_capture;
+    bool _is_running_playback;
+    bool _is_open_playback;
+    bool _is_open_capture;
+    bool _trigger_request;
+    
+    bool is_playback_prepared (void) { return _is_prepared_playback; }
+    bool is_capture_prepared (void) { return _is_prepared_capture; }
+    void prepare_playback (void) { _is_prepared_playback = true; }
+    void prepare_capture (void) { _is_prepared_capture = true; }
+    bool is_capture_running (void) { return _is_running_capture; }
+    bool is_playback_running (void) { return _is_running_playback; }
+    void start_playback (void) { _is_running_playback = true; }
+    void stop_playback (void) { _is_running_playback = false; _is_prepared_playback = false; }
+    void start_capture (void) { _is_running_capture = true; }
+    void stop_capture (void) { _is_running_capture = false; _is_prepared_capture = false; }
+    void close_playback (void) { _is_open_playback = false; }
+    void close_capture (void) { _is_open_capture = false; }
+    void open_playback (void) { _is_open_playback = true; }
+    void open_capture (void) { _is_open_capture = true; }
+    bool is_capture_open (void) { return _is_open_capture; }
+    bool is_playback_open (void) { return _is_open_playback; }
+    
     /**
      * Drop the pending frames and close the capture device
      * ALSA Library API
      */
     void closeCaptureStream( void );
+    void stopCaptureStream( void );
+    void startCaptureStream( void );
+    void prepareCaptureStream( void );
 
-    /**
-     * Drop the pending frames and close the playback device
-     * ALSA Library API
-     */
     void closePlaybackStream( void );
-
-    /**
-     * Fill the alsa internal ring buffer with chunks of data
-     */
-    void fillHWBuffer( void) ;
-
-    /**
-     * Callback used for asynchronous playback.
-     * Called when a certain amount of data is written ot the device
-     * @param pcm_callback  The callback pointer
-     */
-    //static void AlsaCallBack( snd_async_handler_t* pcm_callback);
+    void stopPlaybackStream( void );
+    void startPlaybackStream( void );
+    void preparePlaybackStream( void );
 
     /**
      * Open the specified device.
@@ -280,6 +222,8 @@ class AlsaLayer : public AudioLayer {
      */
     int read( void* buffer, int toCopy);
     
+    
+
     /**
      * Recover from XRUN state for capture
      * ALSA Library API
@@ -292,7 +236,9 @@ class AlsaLayer : public AudioLayer {
      */
     void handle_xrun_playback( void );
     
-    /**
+    void* adjustVolume( void* buffer , int len, int stream );
+    
+/**
      * Handles to manipulate playback stream
      * ALSA Library API
      */
@@ -309,38 +255,16 @@ class AlsaLayer : public AudioLayer {
      */
     snd_pcm_uframes_t _periodSize;
 
-    /**
-     * Volume is controlled by the application. Data buffer are modified here to adjust to the right volume selected by the user on the main interface
-     * @param buffer  The buffer to adjust
-     * @param len The number of bytes
-     * @param stream  The stream mode ( PLAYBACK - CAPTURE )
-     */
-    void * adjustVolume( void * , int , int);
-
     /**
      * name of the alsa audio plugin used
      */
     std::string _audioPlugin;
 
-    /**
-     * Input channel (mic) should be 1 mono
-     */
-    unsigned int _inChannel; 
-
-    /**
-     * Output channel (stereo) should be 1 mono
-     */
-    unsigned int _outChannel; 
-
-    /**
-     * Default volume for incoming RTP and Urgent sounds.
-     */
-    unsigned short _defaultVolume; // 100
-
-
     /** Vector to manage all soundcard index - description association of the system */
     std::vector<HwIDPair> IDSoundCards;
 
+    AudioThread *_audioThread;
+
 };
 
 #endif // _ALSA_LAYER_H_
diff --git a/src/audio/audiolayer.cpp b/src/audio/audiolayer.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..3eea4392c737b51c3f954b438ca3dac7b57a30b9
--- /dev/null
+++ b/src/audio/audiolayer.cpp
@@ -0,0 +1,69 @@
+/*
+ *  Copyright (C) 2009 Savoir-Faire Linux inc.
+ *  Author: Emmanuel Milou <emmanuel.milou@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 "audiolayer.h"
+
+void AudioLayer::flushMain (void)
+{
+    ost::MutexLock guard(_mutex);
+    _voiceRingBuffer.flush();
+}
+
+void AudioLayer::flushUrgent (void)
+{
+    ost::MutexLock guard(_mutex);
+    _urgentRingBuffer.flush();
+}
+
+void AudioLayer::flushMic (void)
+{
+    ost::MutexLock guard(_mutex);
+    _micRingBuffer.flush();
+}
+
+int AudioLayer::putUrgent(void* buffer, int toCopy)
+{
+    int a;
+
+    ost::MutexLock guard(_mutex);
+    a = _urgentRingBuffer.AvailForPut();
+    if ( a >= toCopy ) {
+        return _urgentRingBuffer.Put(buffer, toCopy, _defaultVolume);
+    } else {
+        return _urgentRingBuffer.Put(buffer, a, _defaultVolume);
+    }
+    return 0;
+}
+
+int AudioLayer::putMain (void *buffer, int toCopy)
+{
+    int a;
+
+    ost::MutexLock guard(_mutex);
+    a = _voiceRingBuffer.AvailForPut();
+    if ( a >= toCopy ) {
+        return _voiceRingBuffer.Put(buffer, toCopy, _defaultVolume);
+    } else {
+        _debug("Chopping sound, Ouch! RingBuffer full ?\n");
+        return _voiceRingBuffer.Put(buffer, a, _defaultVolume);
+    }
+    return 0;
+}
+
+
diff --git a/src/audio/audiolayer.h b/src/audio/audiolayer.h
index 658ac3825deaad2d14fec6c31e547d60648d4ed3..679738b68c7fc15242eff85fd5e52c6068687f2f 100644
--- a/src/audio/audiolayer.h
+++ b/src/audio/audiolayer.h
@@ -22,24 +22,16 @@
 #ifndef _AUDIO_LAYER_H
 #define _AUDIO_LAYER_H
 
-#include "../global.h"
-#include "../manager.h"
+#include "global.h"
 #include "audiodevice.h"
 #include "ringbuffer.h"
+#include "manager.h"
 
 #include <cc++/thread.h> // for ost::Mutex
-#include <vector>
 
-#include <alsa/asoundlib.h>
-#include <pulse/pulseaudio.h>
-
-#include <iostream>
-#include <istream>
-#include <sstream>
 
 #define FRAME_PER_BUFFER	160
 
-
 /**
  * @file  audiolayer.h
  * @brief Main sound class. Manages the data transfers between the application and the hardware. 
@@ -47,282 +39,225 @@
 
 class AudioLayer {
 
-  private:
-	
-    //copy constructor
-    AudioLayer(const AudioLayer& rh);
-
-    // assignment operator
-    AudioLayer& operator=(const AudioLayer& rh);
-
-  public:
-    /**
-     * Constructor
-     * @param manager An instance of managerimpl
-     */
-    AudioLayer( ManagerImpl* manager , int type )
-	: _layerType( type )
-        , _manager(manager)
-	, _urgentBuffer( SIZEBUF )
-        , _talk ( false )
-        , deviceClosed ( true )
-        , _indexIn ( 0 )
-        , _indexOut ( 0 )
-        , _sampleRate ( 0 )
-        , _frameSize ( 0 )
-        , _inChannel( 1 )
-        , _outChannel ( 1 )
-        , _errorMessage ( 0 )
-        , _mutex ()
+    private:
+
+        //copy constructor
+        AudioLayer(const AudioLayer& rh);
+
+        // assignment operator
+        AudioLayer& operator=(const AudioLayer& rh);
+
+    public:
+        /**
+         * Constructor
+         * @param manager An instance of managerimpl
+         */
+        AudioLayer( ManagerImpl* manager , int type )
+            : _layerType( type )
+              , _manager(manager)
+              , _voiceRingBuffer( SIZEBUF )
+              , _urgentRingBuffer( SIZEBUF)
+              , _micRingBuffer( SIZEBUF )
+              , _defaultVolume(100)
+              , _indexIn ( 0 )
+              , _indexOut ( 0 )
+              , _sampleRate ( 0 )
+              , _frameSize ( 0 )
+              , _inChannel( 1 )
+              , _outChannel ( 1 )
+              , _errorMessage ( 0 )
+              , _mutex ()
     {
 
     }
 
-    
-    /**
-     * Destructor
-     */
-    ~AudioLayer(void){}
-
-    virtual void closeLayer( void ) = 0;
-
-    virtual void trigger_thread(void)=0;
-
-    /**
-     * Check if no devices are opened, otherwise close them.
-     * Then open the specified devices by calling the private functions open_device
-     * @param indexIn	The number of the card choosen for capture
-     * @param indexOut	The number of the card choosen for playback
-     * @param sampleRate  The sample rate 
-     * @param frameSize	  The frame size
-     * @param stream	  To indicate which kind of stream you want to open
-     *			  SFL_PCM_CAPTURE
-     *			  SFL_PCM_PLAYBACK
-     *			  SFL_PCM_BOTH
-     * @param plugin	  The alsa plugin ( dmix , default , front , surround , ...)
-     */
-    virtual bool openDevice(int indexIn, int indexOut, int sampleRate, int frameSize, int stream , std::string plugin) = 0;
-
-    /**
-     * Start the capture stream and prepare the playback stream. 
-     * The playback starts accordingly to its threshold
-     * ALSA Library API
-     */
-    virtual void startStream(void) = 0;
-
-    /**
-     * Stop the playback and capture streams. 
-     * Drops the pending frames and put the capture and playback handles to PREPARED state
-     * ALSA Library API
-     */
-    virtual void stopStream(void) = 0;
-    
-
-    /**
-     * Check if the capture is running
-     * @return true if the state of the capture handle equals SND_PCM_STATE_RUNNING
-     *	       false otherwise
-     */
-    virtual bool isCaptureActive( void ) = 0;
-
-    /**
-     * Send samples to the audio device. 
-     * @param buffer The buffer containing the data to be played ( voice and DTMF )
-     * @param toCopy The number of samples, in bytes
-     * @param isTalking	If whether or not the conversation is running
-     * @return int The number of bytes played
-     */
-    virtual int playSamples(void* buffer, int toCopy, bool isTalking) = 0;
-
-    /**
-     * Send a chunk of data to the hardware buffer to start the playback
-     * Copy data in the urgent buffer. 
-     * @param buffer The buffer containing the data to be played ( ringtones )
-     * @param toCopy The size of the buffer
-     * @return int  The number of bytes copied in the urgent buffer
-     */
-    virtual int putUrgent(void* buffer, int toCopy) = 0; 
-
-    virtual int putInCache(char code, void* buffer, int toCopy) = 0;
-
-    /**
-     * Query the capture device for number of bytes available in the hardware ring buffer
-     * @return int The number of bytes available
-     */
-    virtual int canGetMic() = 0;
-
-    /**
-     * Get data from the capture device
-     * @param buffer The buffer for data
-     * @param toCopy The number of bytes to get
-     * @return int The number of bytes acquired ( 0 if an error occured)
-     */
-    virtual int getMic(void * buffer, int toCopy) = 0;
-    
-    /**
-     * Scan the sound card available on the system
-     * @param stream To indicate whether we are looking for capture devices or playback devices
-     *		   SFL_PCM_CAPTURE
-     *		   SFL_PCM_PLAYBACK
-     *		   SFL_PCM_BOTH
-     * @return std::vector<std::string> The vector containing the string description of the card
-     */
-    virtual std::vector<std::string> getSoundCardsInfo( int stream ) = 0;
-
-    /**
-     * Check if the given index corresponds to an existing sound card and supports the specified streaming mode
-     * @param card   An index
-     * @param stream  The stream mode
-     *		  SFL_PCM_CAPTURE
-     *		  SFL_PCM_PLAYBACK
-     *		  SFL_PCM_BOTH
-     * @return bool True if it exists and supports the mode
-     *		    false otherwise
-     */
-    virtual bool soundCardIndexExist( int card , int stream ) = 0;
-    
-    /**
-     * An index is associated with its string description
-     * @param description The string description
-     * @return	int	  Its index
-     */
-    virtual int soundCardGetIndex( std::string description ) = 0;
-
-    /**
-     * Get the current audio plugin.
-     * @return std::string  The name of the audio plugin
-     */
-    virtual std::string getAudioPlugin( void ) = 0; 
-
-    virtual void reducePulseAppsVolume( void ) = 0;
-    virtual void restorePulseAppsVolume( void ) = 0;
-
-    virtual void setPlaybackVolume( int volume ) = 0;
-    virtual void setCaptureVolume( int volume ) = 0;
-  
-    /**
-     * Write accessor to the error state
-     * @param error The error code
-     *		    Could be: ALSA_PLAYBACK_DEVICE
-     *			      ALSA_CAPTURE_DEVICE
-     */  
-    void setErrorMessage(const int& error) { _errorMessage = error; }
-    
-    /**
-     * Read accessor to the error state
-     * @return int  The error code
-     */
-    int getErrorMessage() { return _errorMessage; }
-
-    /**
-     * Get the index of the audio card for capture
-     * @return int The index of the card used for capture
-     *			0 for the first available card on the system, 1 ...
-     */
-    int getIndexIn() { return _indexIn; }
-
-    /**
-     * Get the index of the audio card for playback
-     * @return int The index of the card used for playback
-     *			0 for the first available card on the system, 1 ...
-     */
-    int getIndexOut() { return _indexOut; }
-
-    /**
-     * Get the sample rate of the audio layer
-     * @return unsigned int The sample rate
-     *			    default: 44100 HZ
-     */
-    unsigned int getSampleRate() { return _sampleRate; }
-
-    /**
-     * Get the frame size of the audio layer
-     * @return unsigned int The frame size
-     *			    default: 20 ms
-     */
-    unsigned int getFrameSize() { return _frameSize; }
-
-    /**
-     * Get the current state. Conversation or not
-     * @return bool true if playSamples has been called  
-     *		    false otherwise
-     */
-    bool getCurrentState( void ) { return _talk; }
-
-    int getLayerType( void ) { return _layerType; }
-
-  protected:
-
-    int _layerType;
-
-    /**
-     * Drop the pending frames and close the capture device
-     */
-    virtual void closeCaptureStream( void ) = 0;
-
-    /**
-     * Drop the pending frames and close the playback device
-     */
-    virtual void closePlaybackStream( void ) = 0;
-
-    /** Augment coupling, reduce indirect access */
-    ManagerImpl* _manager; 
-
-    /**
-     * Urgent ring buffer used for ringtones
-     */
-    RingBuffer _urgentBuffer;
-
-    /**
-     * Determine if both endpoints hang up.
-     *	true if conversation is running
-     *	false otherwise
-     */
-    bool _talk;
-    
-    /**
-     * Enable to determine if the devices are opened or not
-     *		  true if the devices are closed
-     *		  false otherwise
-     */
-    bool deviceClosed;
-
-    /**
-     * Number of audio cards on which capture stream has been opened 
-     */
-    int _indexIn;
-
-    /**
-     * Number of audio cards on which playback stream has been opened 
-     */
-    int _indexOut;
-
-    /**
-     * Sample Rate SFLphone should send sound data to the sound card 
-     * The value can be set in the user config file- now: 44100HZ
-     */
-    unsigned int _sampleRate;
-
-    /**
-     * Length of the sound frame we capture or read in ms
-     * The value can be set in the user config file - now: 20ms
-     */	 		
-    unsigned int _frameSize;
-
-    /**
-     * Input channel (mic) should be 1 mono
-     */
-    unsigned int _inChannel; 
-
-    /**
-     * Output channel (stereo) should be 1 mono
-     */
-    unsigned int _outChannel; 
-
-   /** Contains the current error code */
-    int _errorMessage;
-
-    ost::Mutex _mutex;
+        /**
+         * Destructor
+         */
+        virtual ~AudioLayer(void) {} 
+
+        virtual void closeLayer( void ) = 0;
+
+        /**
+         * Check if no devices are opened, otherwise close them.
+         * Then open the specified devices by calling the private functions open_device
+         * @param indexIn	The number of the card choosen for capture
+         * @param indexOut	The number of the card choosen for playback
+         * @param sampleRate  The sample rate 
+         * @param frameSize	  The frame size
+         * @param stream	  To indicate which kind of stream you want to open
+         *			  SFL_PCM_CAPTURE
+         *			  SFL_PCM_PLAYBACK
+         *			  SFL_PCM_BOTH
+         * @param plugin	  The alsa plugin ( dmix , default , front , surround , ...)
+         */
+        virtual bool openDevice(int indexIn, int indexOut, int sampleRate, int frameSize, int stream , std::string plugin) = 0;
+
+        /**
+         * Start the capture stream and prepare the playback stream. 
+         * The playback starts accordingly to its threshold
+         * ALSA Library API
+         */
+        virtual void startStream(void) = 0;
+
+        /**
+         * Stop the playback and capture streams. 
+         * Drops the pending frames and put the capture and playback handles to PREPARED state
+         * ALSA Library API
+         */
+        virtual void stopStream(void) = 0;
+
+        /**
+         * Query the capture device for number of bytes available in the hardware ring buffer
+         * @return int The number of bytes available
+         */
+        virtual int canGetMic() = 0;
+
+        /**
+         * Get data from the capture device
+         * @param buffer The buffer for data
+         * @param toCopy The number of bytes to get
+         * @return int The number of bytes acquired ( 0 if an error occured)
+         */
+        virtual int getMic(void * buffer, int toCopy) = 0;
+
+        /**
+         * Send a chunk of data to the hardware buffer to start the playback
+         * Copy data in the urgent buffer. 
+         * @param buffer The buffer containing the data to be played ( ringtones )
+         * @param toCopy The size of the buffer
+         * @return int  The number of bytes copied in the urgent buffer
+         */
+        int putUrgent(void* buffer, int toCopy);
+
+        /**
+         * Put voice data in the main sound buffer
+         * @param buffer    The buffer containing the voice data ()
+         * @param toCopy    The size of the buffer
+         * @return int      The number of bytes copied
+         */
+        int putMain(void* buffer, int toCopy);
+
+        void flushMain (void);
+
+        void flushUrgent (void);
+
+        /**
+         * Flush the mic ringbuffer
+         */
+        void flushMic();
+
+        virtual bool isCaptureActive (void) = 0;
+
+        /**
+         * Write accessor to the error state
+         * @param error The error code
+         *		    Could be: ALSA_PLAYBACK_DEVICE
+         *			      ALSA_CAPTURE_DEVICE
+         */  
+        void setErrorMessage(const int& error) { _errorMessage = error; }
+
+        /**
+         * Read accessor to the error state
+         * @return int  The error code
+         */
+        int getErrorMessage() { return _errorMessage; }
+
+        /**
+         * Get the index of the audio card for capture
+         * @return int The index of the card used for capture
+         *			0 for the first available card on the system, 1 ...
+         */
+        int getIndexIn() { return _indexIn; }
+
+        /**
+         * Get the index of the audio card for playback
+         * @return int The index of the card used for playback
+         *			0 for the first available card on the system, 1 ...
+         */
+        int getIndexOut() { return _indexOut; }
+
+        /**
+         * Get the sample rate of the audio layer
+         * @return unsigned int The sample rate
+         *			    default: 44100 HZ
+         */
+        unsigned int getSampleRate() { return _sampleRate; }
+
+        /**
+         * Get the frame size of the audio layer
+         * @return unsigned int The frame size
+         *			    default: 20 ms
+         */
+        unsigned int getFrameSize() { return _frameSize; }
+
+        int getLayerType( void ) { return _layerType; }
+
+        /**
+         * Default volume for incoming RTP and Urgent sounds.
+         */
+        unsigned short _defaultVolume; // 100
+
+    protected:
+
+        int _layerType;
+
+        /**
+         * Drop the pending frames and close the capture device
+         */
+        virtual void closeCaptureStream( void ) = 0;
+
+        /**
+         * Drop the pending frames and close the playback device
+         */
+        virtual void closePlaybackStream( void ) = 0;
+
+        /** Augment coupling, reduce indirect access */
+        ManagerImpl* _manager; 
+
+        /**
+         * Urgent ring buffer used for ringtones
+         */
+        RingBuffer _urgentRingBuffer;
+        RingBuffer _voiceRingBuffer;
+        RingBuffer _micRingBuffer;
+
+        /**
+         * Number of audio cards on which capture stream has been opened 
+         */
+        int _indexIn;
+
+        /**
+         * Number of audio cards on which playback stream has been opened 
+         */
+        int _indexOut;
+
+        /**
+         * Sample Rate SFLphone should send sound data to the sound card 
+         * The value can be set in the user config file- now: 44100HZ
+         */
+        unsigned int _sampleRate;
+
+        /**
+         * Length of the sound frame we capture or read in ms
+         * The value can be set in the user config file - now: 20ms
+         */	 		
+        unsigned int _frameSize;
+
+        /**
+         * Input channel (mic) should be 1 mono
+         */
+        unsigned int _inChannel; 
+
+        /**
+         * Output channel (stereo) should be 1 mono
+         */
+        unsigned int _outChannel; 
+
+        /** Contains the current error code */
+        int _errorMessage;
+
+        ost::Mutex _mutex;
 };
 
 #endif // _AUDIO_LAYER_H_
diff --git a/src/audio/audiortp.cpp b/src/audio/audiortp.cpp
index c2f3ec87673b1d73b58029c8215bd0cfc3a24b43..ed25feec437a4373e2dc787453a348e3e9bb510a 100644
--- a/src/audio/audiortp.cpp
+++ b/src/audio/audiortp.cpp
@@ -52,21 +52,22 @@ AudioRtp::~AudioRtp (void) {
 
 int 
 AudioRtp::createNewSession (SIPCall *ca) {
-  ost::MutexLock m(_threadMutex);
-
-  // something should stop the thread before...
-  if ( _RTXThread != 0 ) { 
-    _debug("! ARTP Failure: Thread already exists..., stopping it\n");
-    delete _RTXThread; _RTXThread = 0;
-    //return -1; 
-  }
+    ost::MutexLock m(_threadMutex);
+
+    // something should stop the thread before...
+    if ( _RTXThread != 0 ) { 
+        _debug("**********************************************************\n");
+        _debug("! ARTP Failure: Thread already exists..., stopping it\n");
+        _debug("**********************************************************\n");
+        delete _RTXThread; _RTXThread = 0;
+    }
 
   // Start RTP Send/Receive threads
   _symmetric = Manager::instance().getConfigInt(SIGNALISATION,SYMMETRIC) ? true : false;
   _RTXThread = new AudioRtpRTX (ca, _symmetric);
   try {
     if (_RTXThread->start() != 0) {
-      _debug("! ARTP Failure: unable to start RTX Thread\n");
+     _debug("! ARTP Failure: unable to start RTX Thread\n");
       return -1;
     }
   } catch(...) {
@@ -88,8 +89,8 @@ AudioRtp::closeRtpSession () {
     _debugException("! ARTP Exception: when stopping audiortp\n");
     throw;
   }
-  AudioLayer* audiolayer = Manager::instance().getAudioDriver();
-  audiolayer->stopStream();
+  //AudioLayer* audiolayer = Manager::instance().getAudioDriver();
+  //audiolayer->stopStream();
 }
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -99,7 +100,7 @@ AudioRtpRTX::AudioRtpRTX (SIPCall *sipcall, bool sym) : time(new ost::Time()), _
 		               _sym(sym), micData(NULL), micDataConverted(NULL), micDataEncoded(NULL), spkrDataDecoded(NULL), spkrDataConverted(NULL), 
 		               converter(NULL), _layerSampleRate(),_codecSampleRate(), _layerFrameSize(), _audiocodec(NULL)
 {
-  setCancel(cancelDeferred);
+  setCancel(cancelDefault);
   // AudioRtpRTX should be close if we change sample rate
   // TODO: Change bind address according to user settings.
   // TODO: this should be the local ip not the external (router) IP
@@ -261,7 +262,7 @@ AudioRtpRTX::sendSessionFromMic(int timestamp)
     int nb_sample_up = nbSample;
     int nbSamplesMax = _layerFrameSize * _audiocodec->getClockRate() / 1000;
 
-    //_debug("resample data\n");
+    //_debug("resample data = %i\n", nb_sample_up);
     nbSample = reSampleData(_audiocodec->getClockRate(), nb_sample_up, DOWN_SAMPLING);	
 
     if ( nbSample < nbSamplesMax - 10 ) { // if only 10 is missing, it's ok
@@ -339,8 +340,10 @@ AudioRtpRTX::receiveSessionForSpkr (int& countTime)
 #else
 #endif
       
-      audiolayer->playSamples( spkrDataConverted, nbSample * sizeof(SFLDataFormat), true);
+    //audiolayer->playSamples( spkrDataConverted, nbSample * sizeof(SFLDataFormat), true);
+    audiolayer->putMain (spkrDataConverted, nbSample * sizeof(SFLDataFormat));
       
+
       // Notify (with a beep) an incoming call when there is already a call 
       countTime += time->getSecond();
       if (Manager::instance().incomingCallWaiting() > 0) {
diff --git a/src/audio/pulselayer.cpp b/src/audio/pulselayer.cpp
index 98a6cd6aa54fcf9e3a25a0ae50eb1e263a9f53c5..45fb6edbae5810fec4c1b66935583532857327cf 100644
--- a/src/audio/pulselayer.cpp
+++ b/src/audio/pulselayer.cpp
@@ -32,14 +32,10 @@ static  void audioCallback ( pa_stream* s, size_t bytes, void* userdata )
   
     PulseLayer::PulseLayer(ManagerImpl* manager)
   : AudioLayer( manager , PULSEAUDIO ) 
-  , _mainSndRingBuffer( SIZEBUF )
-  , _urgentRingBuffer( SIZEBUF)
-  , _micRingBuffer( SIZEBUF )
   , context(NULL)
   , m(NULL)
   , playback()
   , record()
-  , cache()   
 {
   PulseLayer::streamState = 0;
   _debug("Pulse audio constructor: Create context\n");
@@ -48,24 +44,31 @@ static  void audioCallback ( pa_stream* s, size_t bytes, void* userdata )
 // Destructor
 PulseLayer::~PulseLayer (void) 
 { 
-  _debug(" Destroy pulselayer\n");
-  delete playback;
-  delete record;
-  pa_context_disconnect(context);
-  pa_context_unref( context );
+    //closeLayer();
+  
+    /* Delete the pointer streams */
+    delete playback;
+    delete record;
+  
+    pa_context_disconnect( context );  
+    pa_context_unref( context );
+
+    sleep(2);
 }
 
   void
 PulseLayer::closeLayer( void )
 { 
+  _debug(" Destroy pulselayer\n");
+  
   playback->disconnect(); 
   record->disconnect();
  
   while(PulseLayer::streamState != 2)
     ;
   PulseLayer::streamState = 0; 
-  pa_context_disconnect( context );  
-  pa_context_unref( context );
+
+  //TODO  Remove this ugly hack
   sleep(2);
 }
 
@@ -89,7 +92,7 @@ PulseLayer::connectPulseAudioServer( void )
   }
 
   pa_threaded_mainloop_unlock( m );
-  serverinfo();
+  //serverinfo();
   //muteAudioApps(99);
   _debug("Context creation done\n");
 }
@@ -139,7 +142,6 @@ PulseLayer::createStreams( pa_context* c )
   record = new AudioStream(c, CAPTURE_STREAM, CAPTURE_STREAM_NAME , _manager->getMicVolume());
   pa_stream_set_read_callback( record->pulseStream() , audioCallback, this);
   //pa_stream_set_underflow_callback( record->pulseStream() , underflow , this);
-  //cache = new AudioStream(c, UPLOAD_STREAM, "Cache samples", _manager->getSpkrVolume());
 
   pa_threaded_mainloop_signal(m , 0);
 }
@@ -179,37 +181,6 @@ PulseLayer::closePlaybackStream( void )
 {
 }
 
-  int 
-PulseLayer::playSamples(void* buffer, int toCopy, bool isTalking UNUSED)
-{
-  int a = _mainSndRingBuffer.AvailForPut();
-  if ( a >= toCopy ) {
-    return _mainSndRingBuffer.Put(buffer, toCopy, 100);
-  } else {
-    _debug("Chopping sound, Ouch! RingBuffer full ?\n");
-    return _mainSndRingBuffer.Put(buffer, a, 100);
-  }
-  return 0;
-}
-
-  void
-PulseLayer::flushMain()
-{
-  _mainSndRingBuffer.flush();
-}
-
-  int
-PulseLayer::putUrgent(void* buffer, int toCopy)
-{
-  int a = _urgentRingBuffer.AvailForPut();
-  if ( a >= toCopy ) {
-    return _urgentRingBuffer.Put(buffer, toCopy, 100 );
-  } else {
-    return _urgentRingBuffer.Put(buffer, a, 100 );
-  }
-  return 0;
-}
-
   int
 PulseLayer::canGetMic()
 {
@@ -229,12 +200,6 @@ PulseLayer::getMic(void *buffer, int toCopy)
     return 0;
 }
 
-  void
-PulseLayer::flushMic()
-{
-  _micRingBuffer.flush();
-}
-
   void 
 PulseLayer::startStream (void) 
 {
@@ -252,6 +217,8 @@ PulseLayer::stopStream (void)
   pa_stream_flush( playback->pulseStream(), NULL, NULL );
   pa_stream_flush( record->pulseStream(), NULL, NULL );
   flushMic();
+  flushMain();
+  flushUrgent();
 }
 
 
@@ -304,13 +271,13 @@ void PulseLayer::writeToSpeaker( void )
 
   if (urgentAvail > 0) {
     // Urgent data (dtmf, incoming call signal) come first.		
-    //_debug("Play urgent!: %i\n" , urgentAvail);
+    //_debug("Play urgent!: %i\e" , urgentAvail);
     toGet = (urgentAvail < (int)(framesPerBuffer * sizeof(SFLDataFormat))) ? urgentAvail : framesPerBuffer * sizeof(SFLDataFormat);
     out =  (SFLDataFormat*)pa_xmalloc(toGet * sizeof(SFLDataFormat) );
     _urgentRingBuffer.Get(out, toGet, 100);
     pa_stream_write( playback->pulseStream() , out , toGet  , pa_xfree, 0 , PA_SEEK_RELATIVE);
     // Consume the regular one as well (same amount of bytes)
-    _mainSndRingBuffer.Discard(toGet);
+    _voiceRingBuffer.Discard(toGet);
   }
   else
   {
@@ -330,11 +297,11 @@ void PulseLayer::writeToSpeaker( void )
     } 
     else {
       out =  (SFLDataFormat*)pa_xmalloc(framesPerBuffer * sizeof(SFLDataFormat));
-      normalAvail = _mainSndRingBuffer.AvailForGet();
+      normalAvail = _voiceRingBuffer.AvailForGet();
       toGet = (normalAvail < (int)(framesPerBuffer * sizeof(SFLDataFormat))) ? normalAvail : framesPerBuffer * sizeof(SFLDataFormat);
       if (toGet) {
-	    _mainSndRingBuffer.Get(out, toGet, 100);
-	    _mainSndRingBuffer.Discard(toGet);
+	    _voiceRingBuffer.Get(out, toGet, 100);
+	    _voiceRingBuffer.Discard(toGet);
       } 
       else {
 	    bzero(out, framesPerBuffer * sizeof(SFLDataFormat));
@@ -364,15 +331,6 @@ void PulseLayer::readFromMic( void )
   }
 }
 
-  int
-PulseLayer::putInCache( char code UNUSED, void *buffer UNUSED, int toCopy UNUSED )
-{
-  _debug("Put the DTMF in cache\n");
-  //pa_stream_write( cache->pulseStream() , buffer , toCopy  , pa_xfree, 0 , PA_SEEK_RELATIVE);
-  //pa_stream_finish_upload( cache->pulseStream() );
-  return 1;
-}
-
 static void retrieve_server_info(pa_context *c UNUSED, const pa_server_info *i, void *userdata UNUSED)
 {
   _debug("Server Info: Process owner : %s\n" , i->user_name);  
diff --git a/src/audio/pulselayer.h b/src/audio/pulselayer.h
index dc22bfaedd968324b232946770ff06b7d08b5428..bdb34085b62e9abea85f27f4517b4f76b701e780 100644
--- a/src/audio/pulselayer.h
+++ b/src/audio/pulselayer.h
@@ -23,6 +23,8 @@
 #include "audiolayer.h"
 #include "audiostream.h"
 
+#include <pulse/pulseaudio.h>
+
 #define PLAYBACK_STREAM_NAME	    "SFLphone out"
 #define CAPTURE_STREAM_NAME	    "SFLphone in"
 
@@ -36,8 +38,6 @@ class PulseLayer : public AudioLayer {
 
     void closeLayer( void );
 
-    void trigger_thread(void){}
-
     /**
      * Check if no devices are opened, otherwise close them.
      * Then open the specified devices by calling the private functions open_device
@@ -57,28 +57,6 @@ class PulseLayer : public AudioLayer {
 
     void stopStream(void);
 
-    /**
-     * UNUSED in pulseaudio layer
-     */
-    bool isCaptureActive( void ) { return true; }
-
-    /**
-     * UNUSED in pulseaudio layer
-     */
-    bool isStreamActive (void); 
-
-    /**
-     * Flush the main ringbuffer, reserved for the voice
-     */
-    void flushMain();
-    
-    int putUrgent(void* buffer, int toCopy);
-
-    /**
-     * UNUSED in pulseaudio layer
-     */
-    int putInCache( char code, void* buffer , int toCopy );
-
     /**
      * Query the capture device for number of bytes available in the hardware ring buffer
      * @return int The number of bytes available
@@ -93,45 +71,21 @@ class PulseLayer : public AudioLayer {
      */
     int getMic(void *, int);
     
-    /**
-     * Flush the mic ringbuffer
-     */
-    void flushMic();
-
-    /**
-     * UNUSED in pulseaudio layer
-     */
-    int playSamples(void* buffer, int toCopy, bool isTalking) ;
-
-    //static void audioCallback ( pa_stream* s, size_t bytes, void* userdata );
     static void overflow ( pa_stream* s, void* userdata );
     static void underflow ( pa_stream* s, void* userdata );
     static void stream_state_callback( pa_stream* s, void* user_data );	
     static void context_state_callback( pa_context* c, void* user_data );	
 
-    /**
-     * UNUSED in pulseaudio layer
-     */
-    std::vector<std::string> getSoundCardsInfo( int stream UNUSED ) { 
-      std::vector<std::string> tmp;
-      return tmp; 
-    }
+    bool isCaptureActive (void){return true;}
 
     /**
      * UNUSED in pulseaudio layer
      */
-    bool soundCardIndexExist( int card UNUSED, int stream UNUSED ) { return true; }
-    
-    /**
-     * UNUSED in pulseaudio layer
-     */
-    int soundCardGetIndex( std::string description UNUSED ) { return 0;}
+    //std::vector<std::string> getSoundCardsInfo( int stream UNUSED ) { 
+      //std::vector<std::string> tmp;
+      //return tmp; 
+    //}
 
-    /**
-     * UNUSED in pulseaudio layer
-     */
-    std::string getAudioPlugin( void ) { return "default"; }
-    
     /**
      * Reduce volume of every audio applications connected to the same sink
      */
@@ -218,21 +172,6 @@ class PulseLayer : public AudioLayer {
      */
     void serverinfo( void );
 
-    /** 
-     * Ringbuffer for incoming voice data (playback)
-     */
-    RingBuffer _mainSndRingBuffer;
-
-    /** 
-     * Ringbuffer for dtmf data
-     */
-    RingBuffer _urgentRingBuffer;
-
-    /** 
-     * Ringbuffer for outgoing voice data (mic)
-     */
-    RingBuffer _micRingBuffer;
-
     /** PulseAudio context and asynchronous loop */
     pa_context* context;
     pa_threaded_mainloop* m;
@@ -247,11 +186,6 @@ class PulseLayer : public AudioLayer {
      */
     AudioStream* record;
 
-    /**
-     * A stream object to handle the pulseaudio upload stream
-     */
-    AudioStream* cache;
-
     int spkrVolume;
     int micVolume;
 
diff --git a/src/dbus/Makefile.am b/src/dbus/Makefile.am
index ee8355dbe90728906ece7ac3acf18622f5e9cecb..7e97ffc2dcd3771ed31fc020c23e1eb76b3bad0c 100644
--- a/src/dbus/Makefile.am
+++ b/src/dbus/Makefile.am
@@ -7,7 +7,6 @@ noinst_LTLIBRARIES = libdbus.la
 libdbus_la_SOURCES = \
 	callmanager.cpp \
 	configurationmanager.cpp  \
-	contactmanager.cpp \
 	instance.cpp  \
 	dbusmanagerimpl.cpp
 
@@ -20,8 +19,6 @@ noinst_HEADERS = \
 	callmanager.h  \
 	configurationmanager.h  \
 	configurationmanager-glue.h \
-	contactmanager.h \
-	contactmanager-glue.h \
 	instance.h  \
 	instance-glue.h \
 	dbusmanager.h \
diff --git a/src/dbus/configurationmanager-glue.h b/src/dbus/configurationmanager-glue.h
index 292756cdb7e2c1c6b476b25432d1d56ac29322df..673a0f5f4efe0240bc7d5a90673ae6ac30ba8381 100644
--- a/src/dbus/configurationmanager-glue.h
+++ b/src/dbus/configurationmanager-glue.h
@@ -73,6 +73,10 @@ public:
         register_method(ConfigurationManager_adaptor, getPulseAppVolumeControl, _getPulseAppVolumeControl_stub);
         register_method(ConfigurationManager_adaptor, setSipPort, _setSipPort_stub);
         register_method(ConfigurationManager_adaptor, getSipPort, _getSipPort_stub);
+        register_method(ConfigurationManager_adaptor, setStunServer, _setStunServer_stub);
+        register_method(ConfigurationManager_adaptor, getStunServer, _getStunServer_stub);
+        register_method(ConfigurationManager_adaptor, enableStun, _enableStun_stub);
+        register_method(ConfigurationManager_adaptor, isStunEnabled, _isStunEnabled_stub);
     }
 
     ::DBus::IntrospectedInterface *const introspect() const 
@@ -338,6 +342,25 @@ public:
             { "port", "i", false },
             { 0, 0, 0 }
         };
+        static ::DBus::IntrospectedArgument setStunServer_args[] = 
+        {
+            { "server", "s", true },
+            { 0, 0, 0 }
+        };
+        static ::DBus::IntrospectedArgument getStunServer_args[] = 
+        {
+            { "server", "s", false },
+            { 0, 0, 0 }
+        };
+        static ::DBus::IntrospectedArgument enableStun_args[] = 
+        {
+            { 0, 0, 0 }
+        };
+        static ::DBus::IntrospectedArgument isStunEnabled_args[] = 
+        {
+            { "state", "i", false },
+            { 0, 0, 0 }
+        };
         static ::DBus::IntrospectedArgument parametersChanged_args[] = 
         {
             { "list", "a{ss}", false },
@@ -407,6 +430,10 @@ public:
             { "getPulseAppVolumeControl", getPulseAppVolumeControl_args },
             { "setSipPort", setSipPort_args },
             { "getSipPort", getSipPort_args },
+            { "setStunServer", setStunServer_args },
+            { "getStunServer", getStunServer_args },
+            { "enableStun", enableStun_args },
+            { "isStunEnabled", isStunEnabled_args },
             { 0, 0 }
         };
         static ::DBus::IntrospectedMethod ConfigurationManager_adaptor_signals[] = 
@@ -494,6 +521,10 @@ public:
     virtual int32_t getPulseAppVolumeControl() = 0;
     virtual void setSipPort(const int32_t& port) = 0;
     virtual int32_t getSipPort() = 0;
+    virtual void setStunServer(const std::string& server) = 0;
+    virtual std::string getStunServer() = 0;
+    virtual void enableStun() = 0;
+    virtual int32_t isStunEnabled() = 0;
 
 public:
 
@@ -1027,6 +1058,43 @@ private:
         wi << argout1;
         return reply;
     }
+    ::DBus::Message _setStunServer_stub(const ::DBus::CallMessage &call)
+    {
+        ::DBus::MessageIter ri = call.reader();
+
+        std::string argin1; ri >> argin1;
+        setStunServer(argin1);
+        ::DBus::ReturnMessage reply(call);
+        return reply;
+    }
+    ::DBus::Message _getStunServer_stub(const ::DBus::CallMessage &call)
+    {
+        ::DBus::MessageIter ri = call.reader();
+
+        std::string argout1 = getStunServer();
+        ::DBus::ReturnMessage reply(call);
+        ::DBus::MessageIter wi = reply.writer();
+        wi << argout1;
+        return reply;
+    }
+    ::DBus::Message _enableStun_stub(const ::DBus::CallMessage &call)
+    {
+        ::DBus::MessageIter ri = call.reader();
+
+        enableStun();
+        ::DBus::ReturnMessage reply(call);
+        return reply;
+    }
+    ::DBus::Message _isStunEnabled_stub(const ::DBus::CallMessage &call)
+    {
+        ::DBus::MessageIter ri = call.reader();
+
+        int32_t argout1 = isStunEnabled();
+        ::DBus::ReturnMessage reply(call);
+        ::DBus::MessageIter wi = reply.writer();
+        wi << argout1;
+        return reply;
+    }
 };
 
 } } } 
diff --git a/src/dbus/configurationmanager-introspec.xml b/src/dbus/configurationmanager-introspec.xml
index df72d96e79c6ecf77b4c47ca27c2a4a90b94106c..0990b1443c15a7f53cb2bfee5388885a67e48697 100644
--- a/src/dbus/configurationmanager-introspec.xml
+++ b/src/dbus/configurationmanager-introspec.xml
@@ -218,6 +218,21 @@
       <arg type="i" name="port" direction="out"/>
     </method>
 
+    <method name="setStunServer">
+      <arg type="s" name="server" direction="in"/>
+    </method>
+
+    <method name="getStunServer">
+      <arg type="s" name="server" direction="out"/>
+    </method>
+
+    <method name="enableStun">
+    </method>
+
+    <method name="isStunEnabled">
+      <arg type="i" name="state" direction="out"/>
+    </method>
+
   <!--        /////////////////////////////       -->
     <signal name="parametersChanged">
       <arg type="a{ss}" name="list" direction="out"/>
diff --git a/src/dbus/configurationmanager.cpp b/src/dbus/configurationmanager.cpp
index 547afded01e9912d0e65923bf0ce193ba8830cce..8c1e5af8f5712bae4224d5942a77a6da9d08247e 100644
--- a/src/dbus/configurationmanager.cpp
+++ b/src/dbus/configurationmanager.cpp
@@ -395,3 +395,22 @@ ConfigurationManager::setSipPort( const int32_t& portNum )
   Manager::instance().setSipPort(portNum);
 }
 
+std::string ConfigurationManager::getStunServer( void )
+{
+    return Manager::instance().getStunServer();
+}
+    
+void ConfigurationManager::setStunServer( const std::string& server )
+{
+    Manager::instance().setStunServer( server );
+}
+
+void ConfigurationManager::enableStun (void)
+{
+    Manager::instance().enableStun();
+}
+
+int32_t ConfigurationManager::isStunEnabled (void)
+{
+    return Manager::instance().isStunEnabled();
+}
diff --git a/src/dbus/configurationmanager.h b/src/dbus/configurationmanager.h
index 86c6ee7dec89ae7352a8ea423ea401cfa4edab8f..20f01317d075b974fe8a85e9927976b854e155a2 100644
--- a/src/dbus/configurationmanager.h
+++ b/src/dbus/configurationmanager.h
@@ -96,7 +96,11 @@ public:
     int32_t getPulseAppVolumeControl( void );
     void setPulseAppVolumeControl( void );
     int32_t getSipPort( void );
-    void setSipPort( const int32_t& portNum );
+    void setSipPort( const int32_t& portNum);
+    std::string getStunServer( void );
+    void setStunServer( const std::string& server );
+    void enableStun (void);
+    int32_t isStunEnabled (void);
 
 };
 
diff --git a/src/eventthread.cpp b/src/eventthread.cpp
index 66e6d441090be9d70a785ecc7fa0ff44a5256b44..b0378c57ec651746988f822f6206254ac6bec2bd 100644
--- a/src/eventthread.cpp
+++ b/src/eventthread.cpp
@@ -1,8 +1,7 @@
 /*
- *  Copyright (C) 2004, 2005, 2006 Savoir-Faire Linux inc.
- *  Author: Yan Morin <yan.morin@savoirfairelinux.com>
- *  Author : Laurielle Lea <laurielle.lea@savoirfairelinux.com>
- *                                                                              
+ *  Copyright (C) 2009 Savoir-Faire Linux inc.
+ *  Emmanuel Milou <emmanuel.milou@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
@@ -20,44 +19,41 @@
 
 #include "eventthread.h"
 #include "voiplink.h"
+#include "audio/alsalayer.h"
 
-EventThread::EventThread (VoIPLink* link) : Thread (),  _linkthread(link), stopIt(false)
+/********************************** Voiplink thread *************************************/
+EventThread::EventThread( VoIPLink *link ) 
+    : Thread(), _linkthread(link)
 {
-	setCancel(cancelDeferred);
+    setCancel( cancelDeferred );
 }
 
-EventThread::~EventThread (void) 
-{
-  terminate();
-}
 
 /**
  * Reimplementation of run() 
  */
-void
-EventThread::run (void) 
+void EventThread::run (void) 
 {
-  //stopIt = false;
   while(!testCancel()) {
     _linkthread->getEvent();
   }
-}
+}	
 
-void
-EventThread::stop( void )
-{
-  stopIt = true; 
-}
+/********************************************************************************************/
 
-void
-EventThread::startLoop( void )
+AudioThread::AudioThread (AlsaLayer *alsa)
+    : Thread(), _alsa(alsa)
 {
-  stopIt = false;
-  //start();
+    setCancel (cancelDeferred);
 }
 
-bool
-EventThread::isStopped( void )
+/**
+ * Reimplementation of run() 
+ */
+void AudioThread::run (void) 
 {
-  return stopIt;
+    while(!testCancel()) {
+        _alsa->audioCallback();
+    }
 }
+
diff --git a/src/eventthread.h b/src/eventthread.h
index 8772c72043fec8d719b7c50aecf706dbdb241396..0d631ef066254593e976e1837b1f1e54c2df7594 100644
--- a/src/eventthread.h
+++ b/src/eventthread.h
@@ -1,7 +1,6 @@
 /*
- *  Copyright (C) 2004-2005 Savoir-Faire Linux inc.
- *  Author: Yan Morin <yan.morin@savoirfairelinux.com>
- *  Author : Laurielle Lea <laurielle.lea@savoirfairelinux.com>
+ *  Copyright (C) 2009 Savoir-Faire Linux inc.
+ *  Emmanuel Milou <emmanuel.milou@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
@@ -24,6 +23,7 @@
 #include <cc++/thread.h>
 
 class VoIPLink;
+class AlsaLayer;
 
 /**
  * @file eventthread.h
@@ -31,24 +31,43 @@ class VoIPLink;
  */
 
 class EventThread : public ost::Thread {
-public:
-  /**
-   * Build a thread that call getEvents 
-   */
-	EventThread (VoIPLink*);
-	~EventThread (void);
-	virtual void 	 run ();
-	virtual void	 stop();
-	virtual void	 startLoop();
-	bool		 isStopped();
-
-private:
+
+    public:
+        /**
+         * Thread constructor 
+         */
+        EventThread (VoIPLink* link);        
+        
+        ~EventThread (void){
+            terminate();
+        }
+        
+        virtual void run () ;
+        
+    private:
         EventThread(const EventThread& rh); // copy constructor
         EventThread& operator=(const EventThread& rh);  // assignment operator	
 
         /** VoIPLink is the object being called by getEvents() method  */
-	VoIPLink*	_linkthread;
-	bool		stopIt;
+        VoIPLink*	_linkthread;
+};
+
+class AudioThread : public ost::Thread {
+
+    public:
+        AudioThread (AlsaLayer *alsa);
+
+        ~AudioThread (void){
+            terminate();
+        }
+
+        virtual void run (void);
+
+    private:
+        AudioThread (const AudioThread& at);
+        AudioThread& operator=(const AudioThread& at);
+
+        AlsaLayer* _alsa;
 };
 
 #endif // __EVENT_THREAD_H__
diff --git a/src/global.h b/src/global.h
index e752d41b2f5ee4be78392cd0dd67308e19bf2b93..45332563dc0bbb28a0f22a777d997deafa5c32f5 100644
--- a/src/global.h
+++ b/src/global.h
@@ -26,6 +26,11 @@
 #include <stdio.h>
 #include <libintl.h>
 #include <locale.h>
+#include <string>
+#include <stdlib.h>
+#include <sstream>
+#include <map>
+#include <vector>
 
 #define SFLPHONED_VERSION "0.9.2-4"		/** Version number */
 
@@ -98,6 +103,7 @@ typedef short int16;
 #define WINDOW_POPUP		  1		/** Popup mode */
 #define NOTIFY_ALL		  1		/** Desktop notification level 0: never notify */
 #define NOTIFY_MAILS		  1		/** Desktop mail notification level 0: never notify */
+#define STUN_ENABLED         1
 
 // Error codes for error handling
 #define NO_ERROR		      0x0000	/** No error - Everything alright */
diff --git a/src/iaxaccount.cpp b/src/iaxaccount.cpp
index 364f0ab31b028944112bc177ce85e2b45e6e3b81..504a1cc7106dfa7d1c441a64b7a186fc584152bd 100644
--- a/src/iaxaccount.cpp
+++ b/src/iaxaccount.cpp
@@ -22,8 +22,8 @@
 #include "iaxaccount.h"
 #include "iaxvoiplink.h"
 
-    IAXAccount::IAXAccount(const AccountID& accountID)
-: Account(accountID)
+IAXAccount::IAXAccount(const AccountID& accountID)
+    : Account(accountID, "iax2")
 {
     _link = new IAXVoIPLink(accountID);
 }
@@ -35,22 +35,16 @@ IAXAccount::~IAXAccount()
     _link = NULL;
 }
 
-    int
-IAXAccount::registerVoIPLink()
+int IAXAccount::registerVoIPLink()
 {
-    IAXVoIPLink *thislink;
-
     _link->init();
 
-    thislink = dynamic_cast<IAXVoIPLink*> (_link);
-    if (thislink) {
-        // Stuff needed for IAX registration
-        thislink->setHost(Manager::instance().getConfigString(_accountID, HOSTNAME));
-        thislink->setUser(Manager::instance().getConfigString(_accountID, USERNAME));
-        thislink->setPass(Manager::instance().getConfigString(_accountID, PASSWORD));
-    }
+    // Stuff needed for IAX registration
+    setHostname(Manager::instance().getConfigString(_accountID, HOSTNAME));
+    setUsername(Manager::instance().getConfigString(_accountID, USERNAME));
+    setPassword(Manager::instance().getConfigString(_accountID, PASSWORD));
 
-    _link->sendRegister();
+    _link->sendRegister( _accountID );
 
     return SUCCESS;
 }
@@ -58,7 +52,7 @@ IAXAccount::registerVoIPLink()
     int
 IAXAccount::unregisterVoIPLink()
 {
-    _link->sendUnregister();
+    _link->sendUnregister( _accountID );
     _link->terminate();
 
     return SUCCESS;
diff --git a/src/iaxvoiplink.cpp b/src/iaxvoiplink.cpp
index 6d04dffcaeae225d5d75207136262f3a36705b1c..f085ea1544981952c128c736071261fca0d7ceed 100644
--- a/src/iaxvoiplink.cpp
+++ b/src/iaxvoiplink.cpp
@@ -18,14 +18,12 @@
  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 #include "iaxvoiplink.h"
-#include "global.h" // for _debug
 #include "iaxcall.h"
 #include "eventthread.h"
-
+#include "iaxaccount.h"
 #include "manager.h"
 #include "audio/audiolayer.h"
 
-//#include <iax/iax-client.h>
 #include <math.h>
 #include <dlfcn.h>
 
@@ -40,182 +38,182 @@
 #define MUSIC_ONHOLD true
 
 #define CHK_VALID_CALL   if (call == NULL) { _debug("IAX: Call doesn't exists\n"); \
-  return false; }
+    return false; }
 
-  IAXVoIPLink::IAXVoIPLink(const AccountID& accountID)
+    IAXVoIPLink::IAXVoIPLink(const AccountID& accountID)
 : VoIPLink(accountID)
 {
-  _evThread = new EventThread(this);
-  _regSession = NULL;
-  _nextRefreshStamp = 0;
+    _evThread = new EventThread(this);
+    _regSession = NULL;
+    _nextRefreshStamp = 0;
 
-  // to get random number for RANDOM_PORT
-  srand (time(NULL));
+    // to get random number for RANDOM_PORT
+    srand (time(NULL));
 
-  audiolayer = NULL;
+    audiolayer = NULL;
 
-  converter = new SamplerateConverter();
+    converter = new SamplerateConverter();
 
-  int nbSamplesMax = (int) ( converter->getFrequence() * converter->getFramesize() / 1000 );
+    int nbSamplesMax = (int) ( converter->getFrequence() * converter->getFramesize() / 1000 );
 
-  micData = new SFLDataFormat[nbSamplesMax];
-  micDataConverted = new SFLDataFormat[nbSamplesMax];
-  micDataEncoded = new unsigned char[nbSamplesMax];
+    micData = new SFLDataFormat[nbSamplesMax];
+    micDataConverted = new SFLDataFormat[nbSamplesMax];
+    micDataEncoded = new unsigned char[nbSamplesMax];
 
-  spkrDataConverted = new SFLDataFormat[nbSamplesMax];
-  spkrDataDecoded = new SFLDataFormat[nbSamplesMax];
+    spkrDataConverted = new SFLDataFormat[nbSamplesMax];
+    spkrDataDecoded = new SFLDataFormat[nbSamplesMax];
 }
 
 
 IAXVoIPLink::~IAXVoIPLink()
 {
-  delete _evThread; _evThread = NULL;
-  _regSession = NULL; // shall not delete it
-  terminate();
+    delete _evThread; _evThread = NULL;
+    _regSession = NULL; // shall not delete it
+    terminate();
 
-  audiolayer = NULL;
+    audiolayer = NULL;
 
-  delete [] micData;  micData = NULL;
-  delete [] micDataConverted;  micDataConverted = NULL;
-  delete [] micDataEncoded;  micDataEncoded = NULL;
+    delete [] micData;  micData = NULL;
+    delete [] micDataConverted;  micDataConverted = NULL;
+    delete [] micDataEncoded;  micDataEncoded = NULL;
 
-  delete [] spkrDataDecoded; spkrDataDecoded = NULL;
-  delete [] spkrDataConverted; spkrDataConverted = NULL;
+    delete [] spkrDataDecoded; spkrDataDecoded = NULL;
+    delete [] spkrDataConverted; spkrDataConverted = NULL;
 }
 
-  bool
+    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;
+    // 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);
     }
-    nbTry--;
-
-    _initDone = true;
-  }
-  if (port == IAX_FAILURE || nbTry==0) {
-    _debug("Fail to initialize iax\n");
+    if (port == IAX_FAILURE || nbTry==0) {
+        _debug("Fail to initialize iax\n");
 
-    _initDone = false;
-  }
+        initDone(false);
+    }
 
-  return returnValue;
+    return returnValue;
 }
 
-  void
+    void
 IAXVoIPLink::terminate()
 {
-  // If it was done, don't do it again, until we call init()
-  if (!_initDone)
-    return;
+    // If it was done, don't do it again, until we call init()
+    if (!initDone())
+        return;
 
-  // iaxc_shutdown();  
+    // iaxc_shutdown();  
 
-  // Hangup all calls
-  terminateIAXCall();
+    // Hangup all calls
+    terminateIAXCall();
 
-  _initDone = false;
+    initDone(false);
 }
 
-  void
+    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;
+    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++;
     }
-    iter++;
-  }
-  _callMap.clear();
+    _callMap.clear();
 }
 
-  void
+    void
 IAXVoIPLink::getEvent() 
 {
-  IAXCall* call = NULL;
-
-  // lock iax_ stuff..
-  _mutexIAX.enterMutex();
-  iax_event* event = NULL;
+    IAXCall* call = 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;
+    // 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();
 
-    //_debug ("Receive IAX Event: %d (0x%x)\n", event->etype, event->etype);
-
-    call = iaxFindCallBySession(event->session);
+    // Do the doodle-moodle to send audio from the microphone to the IAX channel.
+    sendAudioFromMic();
 
-    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);
+    // Refresh registration.
+    if (_nextRefreshStamp && _nextRefreshStamp - 2 < time(NULL)) {
+        sendRegister("");
     }
-    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);
-  free(event);
+    // thread wait 3 millisecond
+    _evThread->sleep(3);
+    free(event);
 }
 
-  void
+    void
 IAXVoIPLink::sendAudioFromMic(void)
 {
     int maxBytesToGet, availBytesFromMic, bytesAvail, nbSample, compSize;
@@ -226,7 +224,7 @@ IAXVoIPLink::sendAudioFromMic(void)
     updateAudiolayer();
 
     IAXCall* currentCall = getIAXCall(Manager::instance().getCurrentCallId());
-  
+
     if (!currentCall) {
         // Let's mind our own business.
         return;
@@ -235,546 +233,542 @@ IAXVoIPLink::sendAudioFromMic(void)
     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());
+    // 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;
-  }
+    if (currentCall->getConnectionState() != Call::Connected ||
+            currentCall->getState() != Call::Active) {
+        return;
+    }
 
-  ac = currentCall->getCodecMap().getCodec( currentCall -> getAudioCodec() );
-  if (!ac) {
-    // Audio codec still not determined.
-    if (audiolayer) {
-      // To keep latency low..
-      //audiolayer->flushMic();
+    ac = currentCall->getCodecMap().getCodec( currentCall -> getAudioCodec() );
+    if (!ac) {
+        // Audio codec still not determined.
+        if (audiolayer) {
+            // To keep latency low..
+            //audiolayer->flushMic();
+        }
+        return;
     }
-    return;
-  }
 
-  // Send sound here
-  if (audiolayer) {
+    // 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
-    maxBytesToGet = audiolayer->getSampleRate()* audiolayer->getFrameSize() / 1000 * sizeof(SFLDataFormat);
-    
-    // available bytes inside ringbuffer
-    availBytesFromMic = audiolayer->canGetMic();
+        // we have to get 20ms of data from the mic *20/1000 = /50
+        // rate/50 shall be lower than IAX__20S_48KHZ_MAX
+        maxBytesToGet = audiolayer->getSampleRate()* audiolayer->getFrameSize() / 1000 * sizeof(SFLDataFormat);
 
-    if (availBytesFromMic < maxBytesToGet) {
-      // We need packets full!
-      return;
-    }
+        // available bytes inside ringbuffer
+        availBytesFromMic = audiolayer->canGetMic();
 
-    // take the lowest
-    bytesAvail = (availBytesFromMic < maxBytesToGet) ? availBytesFromMic : maxBytesToGet;
-    //_debug("available = %d, maxBytesToGet = %d\n", availBytesFromMic, maxBytesToGet);
+        if (availBytesFromMic < maxBytesToGet) {
+            // We need packets full!
+            return;
+        }
 
-    // Get bytes from micRingBuffer to data_from_mic
-    nbSample = audiolayer->getMic( micData, bytesAvail ) / sizeof(SFLDataFormat);
+        // take the lowest
+        bytesAvail = (availBytesFromMic < maxBytesToGet) ? availBytesFromMic : maxBytesToGet;
+        //_debug("available = %d, maxBytesToGet = %d\n", availBytesFromMic, maxBytesToGet);
 
-    // resample
-    nbSample = converter->downsampleData( micData , micDataConverted , (int)ac ->getClockRate() ,  (int)audiolayer->getSampleRate() , nbSample );
+        // Get bytes from micRingBuffer to data_from_mic
+        nbSample = audiolayer->getMic( micData, bytesAvail ) / sizeof(SFLDataFormat);
 
-    // for the mono: range = 0 to IAX_FRAME2SEND * sizeof(int16)
-    compSize = ac->codecEncode( micDataEncoded, micDataConverted , nbSample*sizeof(int16));
+        // resample
+        nbSample = converter->downsampleData( micData , micDataConverted , (int)ac ->getClockRate() ,  (int)audiolayer->getSampleRate() , nbSample );
 
-    // 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");
-      }
+        // for the mono: range = 0 to IAX_FRAME2SEND * sizeof(int16)
+        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();
     }
-    _mutexIAX.leaveMutex();
-  }
 }
 
 
-  IAXCall* 
+    IAXCall* 
 IAXVoIPLink::getIAXCall(const CallID& id) 
 {
-  Call* call = getCall(id);
-  if (call) {
-    return dynamic_cast<IAXCall*>(call);
-  }
-  return NULL;
+    Call* call = getCall(id);
+    if (call) {
+        return dynamic_cast<IAXCall*>(call);
+    }
+    return NULL;
 }
 
 
- int 
-IAXVoIPLink::sendRegister() 
+    int 
+IAXVoIPLink::sendRegister(AccountID id) 
 {
-  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;
-}
+    IAXAccount *account;
+    bool result;
+
+    result = false;
+    account = dynamic_cast<IAXAccount *> (getAccountPtr());
+    if (account->getHostname().empty()) {
+        return false;
+    }
+    if (account->getUsername().empty()) {
+        return false;
+    }
+
+    // lock
+    _mutexIAX.enterMutex();
 
+    // Always use a brand new session
+    if (_regSession) {
+        iax_destroy(_regSession);
+    }
 
+    _regSession = iax_session_new();
 
- int 
-IAXVoIPLink::sendUnregister()
+    if (!_regSession) {
+        _debug("Error when generating new session for register");
+    } else {
+        _debug("IAX Sending registration to %s with user %s\n", account->getHostname().c_str() , account->getUsername().c_str() );
+        int val = iax_register(_regSession, account->getHostname().data(), account->getUsername().data(), account->getPassword().data(), 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;
+
+        account->setRegistrationState(Trying);
+    }
+
+    // unlock
+    _mutexIAX.leaveMutex();
+
+    return result;
+}
+
+    int 
+IAXVoIPLink::sendUnregister(AccountID id)
 {
-  _mutexIAX.enterMutex();
-  if (_regSession) {
-    /** @todo Should send a REGREL in sendUnregister()... */
+    IAXAccount *account;
 
-    //iax_send_regrel(); doesn't exist yet :)
-    iax_destroy(_regSession);
+    account = dynamic_cast<IAXAccount*>(getAccountPtr());
+    if(!account)
+        return 1;
 
-    _regSession = NULL;
-  }
-  _mutexIAX.leaveMutex();
+    _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;
+    _nextRefreshStamp = 0;
 
-  _debug("IAX2 send unregister\n");
-  setRegistrationState(Unregistered);
+    _debug("IAX2 send unregister\n");
+    account->setRegistrationState(Unregistered);
 
-  return SUCCESS;
+    return SUCCESS;
 }
 
-  Call* 
+    Call* 
 IAXVoIPLink::newOutgoingCall(const CallID& id, const std::string& toUrl)
 {
-  IAXCall* call = new IAXCall(id, Call::Outgoing);
-  call->setCodecMap(Manager::instance().getCodecDescriptorMap());
-
+    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;
+    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;
+    return call;
 }
 
 
-  bool 
+    bool 
 IAXVoIPLink::answer(const CallID& id)
 {
-  IAXCall* call = getIAXCall(id);
-  call->setCodecMap(Manager::instance().getCodecDescriptorMap());
+    IAXCall* call = getIAXCall(id);
+    call->setCodecMap(Manager::instance().getCodecDescriptorMap());
 
-  CHK_VALID_CALL;
+    CHK_VALID_CALL;
 
-  _mutexIAX.enterMutex();
-  iax_answer(call->getSession());
-  _mutexIAX.leaveMutex();
+    _mutexIAX.enterMutex();
+    iax_answer(call->getSession());
+    _mutexIAX.leaveMutex();
 
-  call->setState(Call::Active);
-  call->setConnectionState(Call::Connected);
-  // Start audio
-  audiolayer->startStream();
-  //audiolayer->flushMic();
+    call->setState(Call::Active);
+    call->setConnectionState(Call::Connected);
+    // Start audio
+    audiolayer->startStream();
+    //audiolayer->flushMic();
 
-  return true;
+    return true;
 }
 
-  bool 
+    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
-    audiolayer->stopStream();
-  }
-  removeCall(id);
-  return true;	
+    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
+        audiolayer->stopStream();
+    }
+    removeCall(id);
+    return true;	
 }
 
-  bool 
+    bool 
 IAXVoIPLink::onhold(const CallID& id) 
 {
-  IAXCall* call = getIAXCall(id);
+    IAXCall* call = getIAXCall(id);
 
-  CHK_VALID_CALL;
+    CHK_VALID_CALL;
 
-  //if (call->getState() == Call::Hold) { _debug("Call is already on hold\n"); return false; }
+    //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();
+    _mutexIAX.enterMutex();
+    iax_quelch_moh(call->getSession() , MUSIC_ONHOLD);
+    _mutexIAX.leaveMutex();
 
-  call->setState(Call::Hold);
-  return true;
+    call->setState(Call::Hold);
+    return true;
 }
 
-  bool 
+    bool 
 IAXVoIPLink::offhold(const CallID& id)
 {
-  IAXCall* call = getIAXCall(id);
+    IAXCall* call = getIAXCall(id);
 
-  CHK_VALID_CALL;
+    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;
+    //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 
+    bool 
 IAXVoIPLink::transfer(const CallID& id, const std::string& to)
 {
-  IAXCall* call = getIAXCall(id);
+    IAXCall* call = getIAXCall(id);
 
-  CHK_VALID_CALL;
+    CHK_VALID_CALL;
 
-  char callto[to.length()+1];
-  strcpy(callto, to.c_str());
+    char callto[to.length()+1];
+    strcpy(callto, to.c_str());
 
-  _mutexIAX.enterMutex();
-  iax_transfer(call->getSession(), callto); 
-  _mutexIAX.leaveMutex();
+    _mutexIAX.enterMutex();
+    iax_transfer(call->getSession(), callto); 
+    _mutexIAX.leaveMutex();
 
-  return true;
+    return true;
 
-  // should we remove it?
-  // removeCall(id);
+    // should we remove it?
+    // removeCall(id);
 }
 
-  bool 
+    bool 
 IAXVoIPLink::refuse(const CallID& id)
 {
-  IAXCall* call = getIAXCall(id);
-  std::string reason = "Call rejected manually.";
+    IAXCall* call = getIAXCall(id);
+    std::string reason = "Call rejected manually.";
 
-  CHK_VALID_CALL;
+    CHK_VALID_CALL;
 
-  _mutexIAX.enterMutex();
-  iax_reject(call->getSession(), (char*) reason.c_str());
-  _mutexIAX.leaveMutex();
-  removeCall(id);
+    _mutexIAX.enterMutex();
+    iax_reject(call->getSession(), (char*) reason.c_str());
+    _mutexIAX.leaveMutex();
+    removeCall(id);
 
-  return true;
+    return true;
 }
 
-  bool
+    bool
 IAXVoIPLink::carryingDTMFdigits(const CallID& id, char code)
 {
-  IAXCall* call = getIAXCall(id);
+    IAXCall* call = getIAXCall(id);
 
-  CHK_VALID_CALL;
+    CHK_VALID_CALL;
 
-  _mutexIAX.enterMutex();
-  iax_send_dtmf(call->getSession(), code);
-  _mutexIAX.leaveMutex();
+    _mutexIAX.enterMutex();
+    iax_send_dtmf(call->getSession(), code);
+    _mutexIAX.leaveMutex();
 
-  return true;
+    return true;
 }
 
 
 
-  bool
+    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());
+    struct iax_session *newsession;
+    ost::MutexLock m(_mutexIAX);
+    std::string username, strNum;
+    char *lang=NULL;
+    int wait, audio_format_preferred, audio_format_capability;
+    IAXAccount *account;
+
+    newsession = iax_session_new();
+    if (!newsession) {
+        _debug("IAX Error: Can't make new session for a new call\n");
+        return false;
+    }
+    call->setSession(newsession);
 
-  char num[strNum.length()+1];
-  strcpy(num, strNum.c_str());
+    account = dynamic_cast<IAXAccount*> (getAccountPtr());
+    username = account->getUsername();
+    strNum = username + ":" + account->getPassword() + "@" + account->getHostname() + "/" + call->getPeerNumber();  
 
-  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();
+    wait = 0;
+    /** @todo Make preference dynamic, and configurable */
+    audio_format_preferred =  call->getFirstMatchingFormat(call->getSupportedFormat());
+    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);
+    _debug("IAX New call: %s\n", strNum.c_str());
+    iax_call(newsession, username.c_str(), username.c_str(), strNum.c_str(), lang, wait, audio_format_preferred, audio_format_capability);
 
-  return true;
+    return true;
 }
 
 
-  IAXCall* 
+    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;
+    // 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++;
     }
-    iter++;
-  }
-  return NULL; // not found
+    return NULL; // not found
 }
 
-  void
+    void
 IAXVoIPLink::iaxHandleCallEvent(iax_event* event, IAXCall* call) 
 {
-  // call should not be 0
-  // note activity?
-  //
-  CallID id = call->getCallId();
-
-  switch(event->etype) {
-    case IAX_EVENT_HANGUP:
-      if (Manager::instance().isCurrentCall(id)) {
-	// stop audio
-	audiolayer->stopStream();
-      }
-      Manager::instance().peerHungupCall(id); 
-      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);
-
-  }
+    // call should not be 0
+    // note activity?
+    //
+    CallID id = call->getCallId();
+
+    switch(event->etype) {
+        case IAX_EVENT_HANGUP:
+            if (Manager::instance().isCurrentCall(id)) {
+                // stop audio
+                audiolayer->stopStream();
+            }
+            Manager::instance().peerHungupCall(id); 
+            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:
+            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
+    void
 IAXVoIPLink::iaxHandleVoiceEvent(iax_event* event, IAXCall* call)
 { 
 
-
     unsigned char *data;
     unsigned int size, max, nbInt16;
     int expandedSize, nbSample;    
     AudioCodec *ac;
 
-  // 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);
+    // 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;
     }
-    //_debug("Receive: len=%d, format=%d, _receiveDataDecoded=%p\n", event->datalen, call->getFormat(), _receiveDataDecoded);
-    ac = call->getCodecMap().getCodec( call -> getAudioCodec() );
 
-    data = (unsigned char*)event->data;
-    size   = event->datalen;
+    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);
+        ac = call->getCodecMap().getCodec( call -> getAudioCodec() );
 
-    // Decode data with relevant codec
-    max = (int)( ac->getClockRate() * audiolayer->getFrameSize() / 1000 );
+        data = (unsigned char*)event->data;
+        size   = event->datalen;
 
-    if (size > max) {
-      _debug("The size %d is bigger than expected %d. Packet cropped. Ouch!\n", size, max);
-      size = max;
-    }
+        // Decode data with relevant codec
+        max = (int)( ac->getClockRate() * audiolayer->getFrameSize() / 1000 );
 
-    expandedSize = ac->codecDecode( spkrDataDecoded , data , size );
-    nbInt16      = expandedSize/sizeof(int16);
+        if (size > max) {
+            _debug("The size %d is bigger than expected %d. Packet cropped. Ouch!\n", size, max);
+            size = max;
+        }
 
-    if (nbInt16 > max) {
-      _debug("We have decoded an IAX VOICE packet larger than expected: %i VS %i. Cropping.\n", nbInt16, max);
-      nbInt16 = max;
-    }
+        expandedSize = ac->codecDecode( spkrDataDecoded , data , size );
+        nbInt16      = expandedSize/sizeof(int16);
 
-    nbSample = nbInt16;
-    // resample
-    nbInt16 = converter->upsampleData( spkrDataDecoded , spkrDataConverted , ac->getClockRate() , audiolayer->getSampleRate() , nbSample);
+        if (nbInt16 > max) {
+            _debug("We have decoded an IAX VOICE packet larger than expected: %i VS %i. Cropping.\n", nbInt16, max);
+            nbInt16 = max;
+        }
 
-    audiolayer->playSamples( spkrDataConverted , nbInt16 * sizeof(SFLDataFormat), true);
+        nbSample = nbInt16;
+        // resample
+        nbInt16 = converter->upsampleData( spkrDataDecoded , spkrDataConverted , ac->getClockRate() , audiolayer->getSampleRate() , nbSample);
 
-  } else {
-    _debug("IAX: incoming audio, but no sound card open");
-  }
+        //audiolayer->playSamples( spkrDataConverted , nbInt16 * sizeof(SFLDataFormat), true);
+        audiolayer->putMain (spkrDataConverted , nbInt16 * sizeof(SFLDataFormat));
+
+    } else {
+        _debug("IAX: incoming audio, but no sound card open");
+    }
 
 }
 
 /**
  * Handle the registration process
  */
-  void
+    void
 IAXVoIPLink::iaxHandleRegReply(iax_event* event) 
 {
 
     int new_voicemails;
     std::string account_id;
- 
+    IAXAccount *account;
+    
+    account_id = getAccountID();
+    account = dynamic_cast<IAXAccount *>(Manager::instance().getAccount(account_id));
+
     if (event->etype == IAX_EVENT_REGREJ) {
         /* Authentication failed! */
         _mutexIAX.enterMutex();
         iax_destroy(_regSession);
         _mutexIAX.leaveMutex();
         _regSession = NULL;
-        setRegistrationState(ErrorAuth);
+        // Update the account registration state
+        account->setRegistrationState(ErrorAuth);
     }
-    
+
     else if (event->etype == IAX_EVENT_REGACK) {
         /* Authentication succeeded */
         _mutexIAX.enterMutex();
 
         // Looking for the voicemail information
         //if( event->ies != 0 )        
-        new_voicemails = processIAXMsgCount(event->ies.msgcount);
-        _debug("iax voicemail number notification: %i\n", new_voicemails);
+        //new_voicemails = processIAXMsgCount(event->ies.msgcount);
+        //_debug("iax voicemail number notification: %i\n", new_voicemails);
         // Notify the client if new voicemail waiting for the current account
-	    account_id = getAccountID();
-        Manager::instance().startVoiceMessageNotification(account_id.c_str(), new_voicemails);
+        //account_id = getAccountID();
+        //Manager::instance().startVoiceMessageNotification(account_id.c_str(), new_voicemails);
 
         iax_destroy(_regSession);
         _mutexIAX.leaveMutex();
@@ -783,13 +777,13 @@ IAXVoIPLink::iaxHandleRegReply(iax_event* event)
         // 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);
+        account->setRegistrationState(Registered);
     }
 }
 
 int IAXVoIPLink::processIAXMsgCount( int msgcount )
 {
-    
+
     // IAX sends the message count under a specific format:
     //                       1
     //  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
@@ -803,120 +797,112 @@ int IAXVoIPLink::processIAXMsgCount( int msgcount )
     // Thus: 
     // 0 <= msgcount <= 255   => msgcount new messages, 0 old messages
     // msgcount >= 256        => msgcount/256 old messages , msgcount%256 new messages (RULES)
-    
+
     return msgcount%256;
 
 }
 
 
-  void
+    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;
+    IAXCall* call = NULL;
+    CallID   id;
+    std::string reason = "Error ringing user.";
 
-    case IAX_EVENT_CONNECT:
-      // We've got an incoming call! Yikes!
-      _debug("> IAX_EVENT_CONNECT (receive)\n");
+    switch(event->etype) {
+        case IAX_EVENT_REGACK:
+        case IAX_EVENT_REGREJ:
+            _debug("IAX Registration Event in a pre-call setup\n");
+            break;
 
-      id = Manager::instance().getNewCallID();
+        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");
 
-      call = new IAXCall(id, Call::Incoming);
+            id = Manager::instance().getNewCallID();
 
-      if (!call) {
-	_debug("! IAX Failure: unable to create an incoming call");
-	return;
-      }
+            call = new IAXCall(id, Call::Incoming);
 
-      // Setup the new IAXCall
-      // Associate the call to the session.
-      call->setSession(event->session);
+            if (!call) {
+                _debug("! IAX Failure: unable to create an incoming call");
+                return;
+            }
 
-      // setCallAudioLocal(call);
-      call->setCodecMap(Manager::instance().getCodecDescriptorMap());
-      call->setConnectionState(Call::Progressing);
+            // 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 */
+            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));
 
-	// 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);
+            if (Manager::instance().incomingCall(call, getAccountID())) {
+                /** @todo Faudra considérer éventuellement le champ CODEC PREFS pour
+                 * l'établissement du codec de transmission */
 
-	// 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;
+                // 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);
 
-	iax_accept(event->session, format);
-	iax_ring_announce(event->session);
+                // 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;
 
-	addCall(call);
-      } else {
-	// reject call, unable to add it
-	iax_reject(event->session, (char*)reason.c_str());
+                iax_accept(event->session, format);
+                iax_ring_announce(event->session);
 
-	delete call; call = NULL;
-      }
+                addCall(call);
+            } else {
+                // reject call, unable to add it
+                iax_reject(event->session, (char*)reason.c_str());
 
-      break;
+                delete call; call = NULL;
+            }
 
-    case IAX_EVENT_HANGUP:
-      // Remote peer hung up
-      call = iaxFindCallBySession(event->session);
-      id = call->getCallId();
+            break;
 
-      Manager::instance().peerHungupCall(id);
-      removeCall(id);
-      break;
+        case IAX_EVENT_HANGUP:
+            // Remote peer hung up
+            call = iaxFindCallBySession(event->session);
+            id = call->getCallId();
 
-    case IAX_EVENT_TIMEOUT: // timeout for an unknown session
+            Manager::instance().peerHungupCall(id);
+            removeCall(id);
+            break;
 
-      break;
+        case IAX_EVENT_TIMEOUT: // timeout for an unknown session
 
-    case IAX_IE_MSGCOUNT:	
-      //_debug("messssssssssssssssssssssssssssssssssssssssssssssssages\n");
-      break;
+            break;
 
-    default:
-      _debug("Unknown event type (in precall): %d\n", event->etype);
-  }
+        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;
 }
 
-
 void IAXVoIPLink::updateAudiolayer( void )
 {
+    _mutexIAX.enterMutex();
     audiolayer = NULL;
     audiolayer = Manager::instance().getAudioDriver();
+    _mutexIAX.leaveMutex();
 }
diff --git a/src/iaxvoiplink.h b/src/iaxvoiplink.h
index fe8978c1b390724ea8a8d2e172a4e15ee359fc25..b82949f640760b474913204c596616018ece1c98 100644
--- a/src/iaxvoiplink.h
+++ b/src/iaxvoiplink.h
@@ -76,7 +76,7 @@ class IAXVoIPLink : public VoIPLink
      * Send out registration
      * @return bool The new registration state (are we registered ?)
      */
-    int sendRegister (void);
+    int sendRegister (AccountID id);
 
     /**
      * Destroy registration session
@@ -85,7 +85,7 @@ class IAXVoIPLink : public VoIPLink
      * @return bool true if we're registered upstream
      *		  false otherwise
      */
-    int sendUnregister (void);
+    int sendUnregister (AccountID id);
 
     /**
      * Create a new outgoing call
@@ -166,23 +166,11 @@ class IAXVoIPLink : public VoIPLink
     bool isContactPresenceSupported() { return false; }
 
   public: // iaxvoiplink only
-    /**
-     * @param host Set the host name 
-     */
-    void setHost(const std::string& host) { _host = host; }
-
-    /**
-     * @param user Set the user name 
-     */
-    void setUser(const std::string& user) { _user = user; }
-    
-    /**
-     * @param pass Set the password
-     */
-    void setPass(const std::string& pass) { _pass = pass; }
-
+   
     void updateAudiolayer( void ); 
 
+    void setStunServer( const std::string &server ) {};
+
   private:
 
     /* 
@@ -192,7 +180,7 @@ class IAXVoIPLink : public VoIPLink
      * @param msgcount  The value sent by IAX in the REGACK message
      * @return int  The number of new messages waiting for the current registered user
      */
-       int processIAXMsgCount( int msgcount );
+     int processIAXMsgCount( int msgcount );
 
 
     /**
@@ -251,28 +239,12 @@ class IAXVoIPLink : public VoIPLink
      */
     bool iaxOutgoingInvite(IAXCall* call);
 
-
-    /**
-     * Convert CodecMap to IAX format using IAX constants
-     * @return `format` ready to go into iax_* calls
-     */
-    int iaxCodecMapToFormat(IAXCall* call);
-
     /** Threading object */
     EventThread* _evThread;
 
     /** registration session : 0 if not register */
     struct iax_session* _regSession;
 
-    /** IAX Host */
-    std::string _host;
-
-    /** IAX User */
-    std::string _user;
-
-    /** IAX Password */
-    std::string _pass;
-
     /** Timestamp of when we should refresh the registration up with
      * the registrar.  Values can be: EPOCH timestamp, 0 if we want no registration, 1
      * to force a registration. */
diff --git a/src/managerimpl.cpp b/src/managerimpl.cpp
index c6177f35fc920738250824a767cd0f07635b32f2..e5292532c720e874939a541b2bc6c4ee436bc915 100644
--- a/src/managerimpl.cpp
+++ b/src/managerimpl.cpp
@@ -46,15 +46,8 @@
 #include "accountcreator.h" // create new account
 #include "sipvoiplink.h"
 
-#include "useragent.h"
-
 #include "user_cfg.h"
 
-#ifdef USE_ZEROCONF
-#include "zeroconf/DNSService.h"
-#include "zeroconf/DNSServiceTXTRecord.h"
-#endif
-
 #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) \
@@ -88,26 +81,10 @@ ManagerImpl::ManagerImpl (void)
         , _callAccountMap()
         , _callAccountMapMutex()
         , _accountMap()
-        , _userAgent(NULL)
-        , _userAgentInitlized(false)
-        , _sipThreadStop()
- 
 {
-  /* Init private variables 
-     setup:    _path, _exist, _setupLoaded , _dbus
-     sound:    _audiodriver, _dtmfKey, 
-               _spkr_volume,_mic_volume  = 0;  // Initialize after by init() -> initVolume()
-     Call:     _nbIncomingWaitingCall, _hasTriedToRegister
-     SIP Link: _userAgent, _userAgentInitlized
-  */
-
-#ifdef USE_ZEROCONF
-  _hasZeroconf = true;
-  _DNSService = new DNSService();
-#endif
-
-  // initialize random generator for call id
-  srand (time(NULL));
+  
+    // initialize random generator for call id
+    srand (time(NULL));
 
 #ifdef TEST
   testAccountMap();
@@ -123,93 +100,68 @@ ManagerImpl::ManagerImpl (void)
 // never call if we use only the singleton...
 ManagerImpl::~ManagerImpl (void) 
 {
-  terminate();
-
-#ifdef USE_ZEROCONF
-  delete _DNSService; _DNSService = 0;
-#endif
-
-  _debug("%s stop correctly.\n", PROGNAME);
+    terminate();
+    _debug("%s stop correctly.\n", PROGNAME);
 }
 
   void 
 ManagerImpl::init() 
 {
-  // Load accounts, init map
-  loadAccountMap();
+    // Load accounts, init map
+    loadAccountMap();
  
-  //Initialize sip manager 
-  if(_userAgentInitlized) {
-    _userAgent->sipCreate();
-    _userAgent->sipInit();
-  }
-
-  initVolume();
-
-  if (_exist == 0) {
-    _debug("Cannot create config file in your home directory\n");
-  }
-
-  initAudioDriver();
-  selectAudioDriver();
+    initVolume();
 
-  // Initialize the list of supported audio codecs
-  initAudioCodec();
+    if (_exist == 0) {
+        _debug("Cannot create config file in your home directory\n");
+    }
 
-  getAudioInputDeviceList();
+    initAudioDriver();
+    selectAudioDriver();
 
-  AudioLayer *audiolayer = getAudioDriver();
-  if (audiolayer!=0) {
-    unsigned int sampleRate = audiolayer->getSampleRate();
+    // Initialize the list of supported audio codecs
+    initAudioCodec();
 
-    _debugInit("Load Telephone Tone");
-    std::string country = getConfigString(PREFERENCES, ZONE_TONE);
-    _telephoneTone = new TelephoneTone(country, sampleRate);
+    AudioLayer *audiolayer = getAudioDriver();
+    
+    if (audiolayer!=0) {
+        unsigned int sampleRate = audiolayer->getSampleRate();
 
-    _debugInit("Loading DTMF key");
-    _dtmfKey = new DTMF(sampleRate);
-  }
+        _debugInit("Load Telephone Tone");
+        std::string country = getConfigString(PREFERENCES, ZONE_TONE);
+        _telephoneTone = new TelephoneTone(country, sampleRate);
 
-  // initRegisterAccounts 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
-  initZeroconf();
-  
+        _debugInit("Loading DTMF key");
+        _dtmfKey = new DTMF(sampleRate);
+    }
 }
 
 void ManagerImpl::terminate()
 {
-  saveConfig();
+    saveConfig();
 
-  unloadAccountMap();
+    unloadAccountMap();
   
-  if(_userAgentInitlized) {
-      delete _userAgent;
-      _userAgent = NULL;
-      _userAgentInitlized = false;
-  }
-
-  _debug("Unload DTMF Key\n");
-  delete _dtmfKey;
+    _debug("Unload DTMF Key\n");
+    delete _dtmfKey;
 
-  _debug("Unload Audio Driver\n");
-  delete _audiodriver; _audiodriver = NULL;
+    _debug("Unload Audio Driver\n");
+    delete _audiodriver; _audiodriver = NULL;
 
-  _debug("Unload Telephone Tone\n");
-  delete _telephoneTone; _telephoneTone = NULL;
+    _debug("Unload Telephone Tone\n");
+    delete _telephoneTone; _telephoneTone = NULL;
 
-  _debug("Unload Audio Codecs\n");
-  _codecDescriptorMap.deleteHandlePointer();
+    _debug("Unload Audio Codecs\n");
+    _codecDescriptorMap.deleteHandlePointer();
 }
 
 bool
 ManagerImpl::isCurrentCall(const CallID& callId) {
-  ost::MutexLock m(_currentCallMutex);
   return (_currentCallId2 == callId ? true : false);
 }
 
 bool
 ManagerImpl::hasCurrentCall() {
-  ost::MutexLock m(_currentCallMutex);
   _debug("Current call ID = %s\n", _currentCallId2.c_str());
   if ( _currentCallId2 != "") {
     return true;
@@ -219,7 +171,6 @@ ManagerImpl::hasCurrentCall() {
 
 const CallID& 
 ManagerImpl::getCurrentCallId() {
-  ost::MutexLock m(_currentCallMutex);
   return _currentCallId2;
 }
 
@@ -237,27 +188,31 @@ ManagerImpl::switchCall(const CallID& id ) {
   bool
 ManagerImpl::outgoingCall(const std::string& accountid, const CallID& id, const std::string& to)
 {
-  if (!accountExists(accountid)) {
-    _debug("! Manager Error: Outgoing Call: account doesn't exist\n");
-    return false;
-  }
-  if (getAccountFromCall(id) != AccountNULL) {
-    _debug("! Manager Error: Outgoing Call: call id already exists\n");
-    return false;
-  }
-  if (hasCurrentCall()) {
-    _debug("* Manager Info: there is currently a call, try to hold it\n");
-    onHoldCall(getCurrentCallId());
-  }
-  _debug("- Manager Action: Adding Outgoing Call %s on account %s\n", id.data(), accountid.data());
-  if ( getAccountLink(accountid)->newOutgoingCall(id, to) ) {
+    if (!accountExists(accountid)) {
+        _debug("! Manager Error: Outgoing Call: account doesn't exist\n");
+        return false;
+    }
+  
+    if (getAccountFromCall(id) != AccountNULL) {
+        _debug("! Manager Error: Outgoing Call: call id already exists\n");
+        return false;
+    }
+  
+    if (hasCurrentCall()) {
+        _debug("* Manager Info: there is currently a call, try to hold it\n");
+        onHoldCall(getCurrentCallId());
+    }
+  
+    _debug("- Manager Action: Adding Outgoing Call %s on account %s\n", id.data(), accountid.data());
     associateCallToAccount( id, accountid );
-    switchCall(id);
-    return true;
-  } else {
-    _debug("! Manager Error: An error occur, the call was not created\n");
-  }
-  return false;
+    if ( getAccountLink(accountid)->newOutgoingCall(id, to) ) {
+        switchCall(id);
+        return true;
+    } else {
+        callFailure(id);
+        _debug("! Manager Error: An error occur, the call was not created\n");
+    }
+    return false;
 }
 
 //THREAD=Main : for outgoing Call
@@ -294,26 +249,35 @@ ManagerImpl::answerCall(const CallID& id)
   bool
 ManagerImpl::hangupCall(const CallID& id)
 {
-  stopTone(true);
-  if (_dbus) _dbus->getCallManager()->callStateChanged(id, "HUNGUP");
-  AccountID accountid = getAccountFromCall( id );
-  if (accountid == AccountNULL) {
-    /** @todo We should tell the GUI that the call doesn't exist, so
-     * it clears up. This can happen. */
-    _debug("! Manager Hangup Call: Call doesn't exists\n");
-    return false;
-  }
+    PulseLayer *pulselayer;
+    AccountID accountid;
+    bool returnValue;
 
-  bool returnValue = getAccountLink(accountid)->hangup(id);
-  _debug("After voip link hungup!\n");
-  removeCallAccount(id);
-  switchCall("");
+    stopTone(true);
 
-  if( getConfigInt( PREFERENCES , CONFIG_PA_VOLUME_CTRL ) )
-    _audiodriver->restorePulseAppsVolume();
+    /* Broadcast a signal over DBus */
+    if (_dbus) _dbus->getCallManager()->callStateChanged(id, "HUNGUP");
+  
+    accountid = getAccountFromCall( id );
+    if (accountid == AccountNULL) {
+        /** @todo We should tell the GUI that the call doesn't exist, so
+        * it clears up. This can happen. */
+        _debug("! Manager Hangup Call: Call doesn't exists\n");
+        return false;
+    }
 
-  _debug("Before hungup return!\n");
-  return returnValue;
+    returnValue = getAccountLink(accountid)->hangup(id);
+
+    _debug("After voip link hungup!\n");
+    removeCallAccount(id);
+    switchCall("");
+
+    if( _audiodriver->getLayerType() == PULSEAUDIO && getConfigInt( PREFERENCES , CONFIG_PA_VOLUME_CTRL ) ) {
+        pulselayer = dynamic_cast<PulseLayer *> (getAudioDriver());
+        if(pulselayer)  pulselayer->restorePulseAppsVolume();
+    }
+  
+    return returnValue;
 }
 
 //THREAD=Main
@@ -440,7 +404,6 @@ ManagerImpl::saveConfig (void)
  int 
 ManagerImpl::initRegisterAccounts() 
 {
-
     int status; 
     bool flag = true;
     AccountMap::iterator iter;
@@ -448,17 +411,21 @@ ManagerImpl::initRegisterAccounts()
     _debugInit("Initiate VoIP Links Registration");
     iter = _accountMap.begin();
 
+    /* Loop on the account map previously loaded */
     while( iter != _accountMap.end() ) {
-      if ( iter->second ) {
-        iter->second->loadConfig();
-        if ( iter->second->isEnabled() ) {
-	  status = iter->second->registerVoIPLink();
-	  if (status != SUCCESS)
-		flag = false;
+        if ( iter->second ) {
+            iter->second->loadConfig();
+            /* If the account is set as enabled, try to register */
+            if ( iter->second->isEnabled() ) {
+	            status = iter->second->registerVoIPLink();
+	            if (status != SUCCESS){
+		            flag = false;
+                }
+            }
         }
-      }
-      iter++;
+        iter++;
     }
+
     // calls the client notification here in case of errors at startup...
     if( _audiodriver -> getErrorMessage() != -1 )
       notifyErrClient( _audiodriver -> getErrorMessage() );
@@ -500,68 +467,63 @@ ManagerImpl::sendDtmf(const CallID& id, char code)
   bool
 ManagerImpl::playDtmf(char code, bool isTalking)
 {
-  // HERE are the variable:
-  // - boolean variable to play or not (config)
-  // - length in milliseconds to play
-  // - sample of audiolayer
-  stopTone(false);
-  int hasToPlayTone = getConfigInt(SIGNALISATION, PLAY_DTMF);
-  if (!hasToPlayTone) return false;
-
-  // 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
-  AudioLayer* audiolayer = getAudioDriver();
-  int layer = audiolayer->getLayerType();
-
-  // fast return, no sound, so no dtmf
-  if (audiolayer==0 || _dtmfKey == 0) { return false; }
-  // number of data sampling in one pulselen depends on samplerate
-  // size (n sampling) = time_ms * sampling/s 
-  //                     ---------------------
-  //                            ms/s
-  int size = (int)(pulselen * ((float)audiolayer->getSampleRate()/1000));
-
-  // this buffer is for mono
-  // TODO <-- this should be global and hide if same size
-  SFLDataFormat* _buf = new SFLDataFormat[size];
-  bool returnValue = false;
-
-  // Handle dtmf
-  _dtmfKey->startTone(code);
+    int hasToPlayTone, pulselen, layer, size;
+    bool ret = false;
+    AudioLayer *audiolayer;
+    SFLDataFormat *buf;
+  
+    stopTone(false);
+    
+    hasToPlayTone = getConfigInt(SIGNALISATION, PLAY_DTMF);
+    if (!hasToPlayTone) 
+        return false;
 
-  // copy the sound
-  if ( _dtmfKey->generateDTMF(_buf, size) ) {
+    // length in milliseconds
+    pulselen = getConfigInt(SIGNALISATION, PULSE_LENGTH);
+    if (!pulselen)
+        return false;
 
-    // Put buffer to urgentRingBuffer 
-    // put the size in bytes...
-    // so size * 1 channel (mono) * sizeof (bytes for the data)
-    if(CHECK_INTERFACE( layer , ALSA ))
-      audiolayer->playSamples(_buf, size * sizeof(SFLDataFormat), isTalking);
-    else
-      _debug("DTMF disabled\n");
-      audiolayer->putUrgent( _buf, size * sizeof(SFLDataFormat) );
+    // numbers of int = length in milliseconds / 1000 (number of seconds)
+    //                = number of seconds * SAMPLING_RATE by SECONDS
+    audiolayer = getAudioDriver();
+    layer = audiolayer->getLayerType();
+
+    // fast return, no sound, so no dtmf
+    if (audiolayer==0 || _dtmfKey == 0)
+        return false;
+
+    // number of data sampling in one pulselen depends on samplerate
+    // size (n sampling) = time_ms * sampling/s 
+    //                     ---------------------
+    //                            ms/s
+    size = (int)(pulselen * ((float)audiolayer->getSampleRate()/1000));
+
+    // this buffer is for mono
+    // TODO <-- this should be global and hide if same size
+    buf = new SFLDataFormat[size];
+
+    // Handle dtmf
+    _dtmfKey->startTone(code);
+
+    // copy the sound
+    if ( _dtmfKey->generateDTMF(buf, size) ) {
+        // Put buffer to urgentRingBuffer 
+        // put the size in bytes...
+        // so size * 1 channel (mono) * sizeof (bytes for the data)
+        audiolayer->putUrgent (buf, size * sizeof(SFLDataFormat));
+    }
+    ret = true;
 
-  }
-  returnValue = true;
+    // TODO Cache the DTMF
 
-  if( CHECK_INTERFACE( layer , PULSEAUDIO ))
-  {
-  // Cache the samples on the sound server
-  // (PulseLayer*)audiolayer->putInCache( code, _buf , size * sizeof(SFLDataFormat) );
-  }
-
-  delete[] _buf; _buf = 0;
-  return returnValue;
+    delete[] buf; buf = 0;
+    
+    return ret;
 }
 
 // Multi-thread 
 bool
 ManagerImpl::incomingCallWaiting() {
-  ost::MutexLock m(_waitingCallMutex);
   return (_nbIncomingWaitingCall > 0) ? true : false;
 }
 
@@ -583,7 +545,6 @@ ManagerImpl::removeWaitingCall(const CallID& id) {
 
 bool
 ManagerImpl::isWaitingCall(const CallID& id) {
-  ost::MutexLock m(_waitingCallMutex);
   CallIDSet::iterator iter = _waitingCall.find(id);
   if (iter != _waitingCall.end()) {
     return false;
@@ -598,38 +559,44 @@ ManagerImpl::isWaitingCall(const CallID& id) {
   bool 
 ManagerImpl::incomingCall(Call* call, const AccountID& accountId) 
 {
-  _debug("Incoming call %s\n", call->getCallId().data());
+    PulseLayer *pulselayer;
+    std::string from, number;
 
-  associateCallToAccount(call->getCallId(), accountId);
+    _debug("Incoming call %s\n", call->getCallId().data());
 
-  if ( !hasCurrentCall() ) {
-    call->setConnectionState(Call::Ringing);
-    ringtone();
-    switchCall(call->getCallId());
-  } else {
-    addWaitingCall(call->getCallId());
-  }
+    associateCallToAccount(call->getCallId(), accountId);
 
-  std::string from = call->getPeerName();
-  std::string number = call->getPeerNumber();
+    if ( !hasCurrentCall() ) {
+        call->setConnectionState(Call::Ringing);
+        ringtone();
+        switchCall(call->getCallId());
+    } else {
+        addWaitingCall(call->getCallId());
+    }
 
-  if (from != "" && number != "") {
-    from.append(" <");
-    from.append(number);
-    from.append(">");
-  } else if ( from.empty() ) {
-    from.append("<");
-    from.append(number);
-    from.append(">");
-  }
+    from = call->getPeerName();
+    number = call->getPeerNumber();
+
+    if (from != "" && number != "") {
+        from.append(" <");
+        from.append(number);
+        from.append(">");
+    } else if ( from.empty() ) {
+        from.append("<");
+        from.append(number);
+        from.append(">");
+    }
   
-  _dbus->getCallManager()->incomingCall(accountId, call->getCallId(), from);
+    /* Broadcast a signal over DBus */
+    _dbus->getCallManager()->incomingCall(accountId, call->getCallId(), from);
   
-  // Reduce volume of the other pulseaudio-connected audio applications
-  if( getConfigInt( PREFERENCES , CONFIG_PA_VOLUME_CTRL ) )
-    _audiodriver->reducePulseAppsVolume();
+    // Reduce volume of the other pulseaudio-connected audio applications
+    if( _audiodriver->getLayerType() == PULSEAUDIO && getConfigInt( PREFERENCES , CONFIG_PA_VOLUME_CTRL ) ) {
+        pulselayer = dynamic_cast<PulseLayer *> (getAudioDriver());
+        if(pulselayer)  pulselayer->reducePulseAppsVolume();
+    }
   
-  return true;
+    return true;
 }
 
 //THREAD=VoIP
@@ -664,22 +631,30 @@ ManagerImpl::peerRingingCall(const CallID& id)
   void
 ManagerImpl::peerHungupCall(const CallID& id)
 {
-  AccountID accountid = getAccountFromCall( id );
-  if (accountid == AccountNULL) {
-    _debug("peerHungupCall: Call doesn't exists\n");
-    return;
-  }
+    PulseLayer *pulselayer;
+    AccountID accountid;
+
+    accountid = getAccountFromCall( id );
+    if (accountid == AccountNULL) {
+        _debug("peerHungupCall: Call doesn't exists\n");
+        return;
+    }
   
-  if (_dbus) _dbus->getCallManager()->callStateChanged(id, "HUNGUP");
-  if (isCurrentCall(id)) {
-    stopTone(true);
-    switchCall("");
-  }
-  removeWaitingCall(id);
-  removeCallAccount(id);
+    /* Broadcast a signal over DBus */
+    if (_dbus) _dbus->getCallManager()->callStateChanged(id, "HUNGUP");
+    
+    if (isCurrentCall(id)) {
+        stopTone(true);
+        switchCall("");
+    }
+
+    removeWaitingCall(id);
+    removeCallAccount(id);
   
-  if( getConfigInt( PREFERENCES , CONFIG_PA_VOLUME_CTRL ) )
-    _audiodriver->restorePulseAppsVolume();
+    if( _audiodriver->getLayerType() == PULSEAUDIO && getConfigInt( PREFERENCES , CONFIG_PA_VOLUME_CTRL ) ) {
+        pulselayer = dynamic_cast<PulseLayer *> (getAudioDriver());
+        if(pulselayer)  pulselayer->restorePulseAppsVolume();
+    }
 }
 
 //THREAD=VoIP
@@ -718,7 +693,7 @@ ManagerImpl::startVoiceMessageNotification(const AccountID& accountId, int nb_ms
   if (_dbus) _dbus->getCallManager()->voiceMailNotify(accountId, nb_msg) ;
 }
 
-void ManagerImpl::connectionStatusNotification( void )
+void ManagerImpl::connectionStatusNotification(  )
 {
     if (_dbus)
         _dbus->getConfigurationManager()->accountsChanged();
@@ -729,30 +704,32 @@ void ManagerImpl::connectionStatusNotification( void )
 /**
  * Multi Thread
  */
-bool 
-ManagerImpl::playATone(Tone::TONEID toneId) {
-  int hasToPlayTone = getConfigInt(SIGNALISATION, PLAY_TONES);
-  if (!hasToPlayTone) return false;
+bool ManagerImpl::playATone(Tone::TONEID toneId) 
+{
+    int hasToPlayTone;
+    AudioLoop *audioloop;
+    AudioLayer *audiolayer;
+    unsigned int nbSamples;
 
-  if (_telephoneTone != 0) {
-    _toneMutex.enterMutex();
-    _telephoneTone->setCurrentTone(toneId);
-    _toneMutex.leaveMutex();
+    hasToPlayTone = getConfigInt(SIGNALISATION, PLAY_TONES);
+    if (!hasToPlayTone) 
+        return false;
+    
+    audiolayer = getAudioDriver();
 
-    AudioLoop* audioloop = getTelephoneTone();
-    unsigned int nbSampling = audioloop->getSize();
-    AudioLayer* audiolayer = getAudioDriver();
-    SFLDataFormat buf[nbSampling];
-    if ( audiolayer ) {
-      int layer = audiolayer->getLayerType(); 
-    if(CHECK_INTERFACE( layer , ALSA ) )
-      audiolayer->putUrgent( buf, nbSampling );
-    else{
-      audiolayer->startStream();
-    }
-    }
-    else 
-      return false;
+    if (_telephoneTone != 0) {
+        _toneMutex.enterMutex();
+        _telephoneTone->setCurrentTone(toneId);
+        _toneMutex.leaveMutex();
+
+        audioloop = getTelephoneTone();
+        nbSamples = audioloop->getSize();
+        SFLDataFormat buf[nbSamples];
+    
+        if ( audiolayer ){ 
+            audiolayer->putUrgent( buf, nbSamples );
+        } else 
+            return false;
   }
   return true;
 }
@@ -760,30 +737,30 @@ ManagerImpl::playATone(Tone::TONEID toneId) {
 /**
  * Multi Thread
  */
-void 
-ManagerImpl::stopTone(bool stopAudio=true) {
-  int hasToPlayTone = getConfigInt(SIGNALISATION, PLAY_TONES);
-  if (!hasToPlayTone) return;
+void ManagerImpl::stopTone (bool stopAudio=true)
+{
+    int hasToPlayTone;
+    AudioLayer *audiolayer;
 
-  if (stopAudio) {
-    AudioLayer* audiolayer = getAudioDriver();
-    int layer = audiolayer->getLayerType();
-    if(CHECK_INTERFACE( layer , ALSA ) ){}
-    else{}
-  //if (audiolayer) { audiolayer->stopStream(); }
+    hasToPlayTone = getConfigInt(SIGNALISATION, PLAY_TONES);
+    if (!hasToPlayTone) 
+        return;
 
-  }
+    if (stopAudio) {
+        audiolayer = getAudioDriver();
+        if (audiolayer) audiolayer->stopStream();
+    }
 
-  _toneMutex.enterMutex();
-  if (_telephoneTone != 0) {
-    _telephoneTone->setCurrentTone(Tone::TONE_NULL);
-  }
-  _toneMutex.leaveMutex();
+    _toneMutex.enterMutex();
+    if (_telephoneTone != 0) {
+        _telephoneTone->setCurrentTone(Tone::TONE_NULL);
+    }
+    _toneMutex.leaveMutex();
 
-  // for ringing tone..
-  _toneMutex.enterMutex();
-  _audiofile.stop();
-  _toneMutex.leaveMutex();
+    // for ringing tone..
+    _toneMutex.enterMutex();
+    _audiofile.stop();
+    _toneMutex.leaveMutex();
 }
 
 /**
@@ -820,7 +797,6 @@ ManagerImpl::congestion () {
 void
 ManagerImpl::ringback () {
   playATone(Tone::TONE_RINGTONE);
-  getAudioDriver()->trigger_thread();
 }
 
 /**
@@ -829,38 +805,42 @@ ManagerImpl::ringback () {
   void
 ManagerImpl::ringtone() 
 {
+    std::string ringchoice;
+    AudioLayer *audiolayer;
+    AudioCodec *codecForTone;
+    int layer, samplerate;
+    bool loadFile;
+
     if( isRingtoneEnabled() )
     {
         //TODO Comment this because it makes the daemon crashes since the main thread
         //synchronizes the ringtone thread.
         
-        std::string ringchoice = getConfigString(AUDIO, RING_CHOICE);
+        ringchoice = getConfigString(AUDIO, RING_CHOICE);
         //if there is no / inside the path
         if ( ringchoice.find(DIR_SEPARATOR_CH) == std::string::npos ) {
             // check inside global share directory
             ringchoice = std::string(PROGSHAREDIR) + DIR_SEPARATOR_STR + RINGDIR + DIR_SEPARATOR_STR + ringchoice; 
         }
 
-        AudioLayer* audiolayer = getAudioDriver();
-        int layer = audiolayer->getLayerType();
-        if (audiolayer==0) { return; }
-        int sampleRate  = audiolayer->getSampleRate();
-        AudioCodec* codecForTone = _codecDescriptorMap.getFirstCodecAvailable();
+        audiolayer = getAudioDriver();
+        layer = audiolayer->getLayerType();
+        if (audiolayer == 0)
+            return;
+
+        samplerate  = audiolayer->getSampleRate();
+        codecForTone = _codecDescriptorMap.getFirstCodecAvailable();
 
         _toneMutex.enterMutex(); 
-         bool loadFile = _audiofile.loadFile(ringchoice, codecForTone , sampleRate);
+        loadFile = _audiofile.loadFile(ringchoice, codecForTone , samplerate);
         _toneMutex.leaveMutex(); 
+
         if (loadFile) {
             _toneMutex.enterMutex(); 
             _audiofile.start();
             _toneMutex.leaveMutex(); 
             if(CHECK_INTERFACE( layer, ALSA )){
-                /*int size = _audiofile.getSize();
-                SFLDataFormat output[ size ];
-                _audiofile.getNext(output, size , 100);
-                audiolayer->putUrgent( output , size );
-                audiolayer->trigger_thread();*/
-                ringback();
+                //ringback();
             }
             else{
                 audiolayer->startStream();
@@ -899,26 +879,23 @@ ManagerImpl::getTelephoneFile()
   }
 }
 
-void
-ManagerImpl::notificationIncomingCall(void) {
-
-  AudioLayer* audiolayer = getAudioDriver();
-  if (audiolayer != 0) {
-    int layer = audiolayer->getLayerType();
-    unsigned int samplerate = audiolayer->getSampleRate();
+void ManagerImpl::notificationIncomingCall(void) 
+{
+    AudioLayer *audiolayer;
     std::ostringstream frequency;
-    frequency << "440/" << FRAME_PER_BUFFER;
-
-    Tone tone(frequency.str(), samplerate);
-    unsigned int nbSampling = tone.getSize();
-    SFLDataFormat buf[nbSampling];
-    tone.getNext(buf, tone.getSize());
-    if(CHECK_INTERFACE( layer , ALSA ))
-      audiolayer->playSamples(buf, sizeof(SFLDataFormat)*nbSampling, true);
-    else
-      audiolayer->putUrgent( buf, sizeof(SFLDataFormat)*nbSampling );
-  
-  }
+    unsigned int samplerate, nbSampling;
+
+    audiolayer = getAudioDriver();
+    if (audiolayer != 0) {
+        samplerate = audiolayer->getSampleRate();
+        frequency << "440/" << FRAME_PER_BUFFER;
+        Tone tone(frequency.str(), samplerate);
+        nbSampling = tone.getSize();
+        SFLDataFormat buf[nbSampling];
+        tone.getNext(buf, tone.getSize());
+        /* Put the data in the urgent ring buffer */
+        audiolayer->putUrgent (buf, sizeof(SFLDataFormat)*nbSampling);
+    }
 }
 
 /**
@@ -1009,15 +986,17 @@ ManagerImpl::initConfigFile ( bool load_user_value )
   std::string type_int("int");
 
   std::string section;
-  section = SIGNALISATION;
 
   // Default values, that will be overwritten by the call to
   // 'populateFromFile' below.
+  section = SIGNALISATION;
   fill_config_int(SYMMETRIC, YES_STR);
   fill_config_int(PLAY_DTMF, YES_STR);
   fill_config_int(PLAY_TONES, YES_STR);
   fill_config_int(PULSE_LENGTH, DFT_PULSE_LENGTH_STR);
   fill_config_int(SEND_DTMF_AS, SIP_INFO_STR);
+  fill_config_int(STUN_ENABLE, DFT_STUN_ENABLE);
+  fill_config_int(STUN_SERVER, DFT_STUN_SERVER);
 
   section = AUDIO;
   fill_config_int(ALSA_CARD_ID_IN, ALSA_DFT_CARD);
@@ -1266,7 +1245,10 @@ ManagerImpl::setOutputAudioPlugin(const std::string& audioPlugin)
 ManagerImpl::getAudioOutputDeviceList(void)
 {
   _debug("Get audio output device list\n");
-  return _audiodriver -> getSoundCardsInfo(SFL_PCM_PLAYBACK);
+  AlsaLayer *layer;
+
+  layer = dynamic_cast<AlsaLayer*> (getAudioDriver ());
+  if (layer)    return layer -> getSoundCardsInfo(SFL_PCM_PLAYBACK);
 }
 
 /**
@@ -1275,19 +1257,22 @@ ManagerImpl::getAudioOutputDeviceList(void)
   void
 ManagerImpl::setAudioOutputDevice(const int index)
 {
-  //int layer = _audiodriver -> getLayerType();
-  _debug("Set audio output device: %i\n", index);
-  _audiodriver -> setErrorMessage( -1 );
-  _audiodriver->openDevice(_audiodriver->getIndexIn(), 
-      index, 
-      _audiodriver->getSampleRate(), 
-      _audiodriver->getFrameSize(), 
-      SFL_PCM_PLAYBACK,
-      _audiodriver->getAudioPlugin());
-  if( _audiodriver -> getErrorMessage() != -1)
-    notifyErrClient( _audiodriver -> getErrorMessage() );
-  // set config
-  setConfig( AUDIO , ALSA_CARD_ID_OUT , index );
+    AlsaLayer *alsalayer;
+    std::string alsaplugin;
+    _debug("Set audio output device: %i\n", index);
+  
+    _audiodriver -> setErrorMessage( -1 );
+    
+    alsalayer = dynamic_cast<AlsaLayer*> (getAudioDriver ());
+    alsaplugin = alsalayer->getAudioPlugin ();
+
+    _audiodriver->openDevice(_audiodriver->getIndexIn(), index, _audiodriver->getSampleRate(), _audiodriver->getFrameSize(), SFL_PCM_PLAYBACK, alsaplugin );
+  
+    if( _audiodriver -> getErrorMessage() != -1)
+        notifyErrClient( _audiodriver -> getErrorMessage() );
+    
+    // set config
+    setConfig( AUDIO , ALSA_CARD_ID_OUT , index );
 }
 
 /**
@@ -1297,7 +1282,10 @@ ManagerImpl::setAudioOutputDevice(const int index)
 ManagerImpl::getAudioInputDeviceList(void)
 {
   _debug("Get audio input device list\n");
-  return _audiodriver->getSoundCardsInfo(SFL_PCM_CAPTURE);
+  AlsaLayer *audiolayer;
+
+  audiolayer = dynamic_cast<AlsaLayer *> ( getAudioDriver());
+  if(audiolayer)    return audiolayer->getSoundCardsInfo(SFL_PCM_CAPTURE);
 }
 
 /**
@@ -1306,19 +1294,23 @@ ManagerImpl::getAudioInputDeviceList(void)
   void
 ManagerImpl::setAudioInputDevice(const int index)
 {
-  //int layer = _audiodriver -> getLayerType();
-  _debug("Set audio input device %i\n", index);
-  _audiodriver -> setErrorMessage( -1 );
-  _audiodriver->openDevice(index, 
-      _audiodriver->getIndexOut(), 
-      _audiodriver->getSampleRate(), 
-      _audiodriver->getFrameSize(), 
-      SFL_PCM_CAPTURE,
-      _audiodriver->getAudioPlugin());
-  if( _audiodriver -> getErrorMessage() != -1)
-    notifyErrClient( _audiodriver -> getErrorMessage() );
-  // set config
-  setConfig( AUDIO , ALSA_CARD_ID_IN , index );
+    AlsaLayer *alsalayer;
+    std::string alsaplugin;
+  
+    _debug("Set audio input device %i\n", index);
+  
+    _audiodriver -> setErrorMessage( -1 );
+  
+    alsalayer = dynamic_cast<AlsaLayer*> (getAudioDriver ());
+    alsaplugin = alsalayer->getAudioPlugin ();
+    
+    _audiodriver->openDevice(index, _audiodriver->getIndexOut(), _audiodriver->getSampleRate(), _audiodriver->getFrameSize(), SFL_PCM_CAPTURE, alsaplugin );
+
+    if( _audiodriver -> getErrorMessage() != -1)
+        notifyErrClient( _audiodriver -> getErrorMessage() );
+  
+    // set config
+    setConfig( AUDIO , ALSA_CARD_ID_IN , index );
 }
 
 /**
@@ -1399,7 +1391,27 @@ ManagerImpl::setDialpad( void )
   ( getConfigInt( PREFERENCES , CONFIG_DIALPAD ) == DISPLAY_DIALPAD )? setConfig(PREFERENCES , CONFIG_DIALPAD , NO_STR ) : setConfig( PREFERENCES , CONFIG_DIALPAD , YES_STR );
 }
 
-int
+std::string ManagerImpl::getStunServer( void )
+{
+  return getConfigString(SIGNALISATION , STUN_SERVER);
+}
+
+void ManagerImpl::setStunServer( const std::string &server )
+{
+  setConfig(SIGNALISATION , STUN_SERVER, server );
+}
+
+int ManagerImpl::isStunEnabled (void)
+{
+    return getConfigInt(SIGNALISATION , STUN_ENABLE);
+}
+
+void ManagerImpl::enableStun (void)
+{
+  ( getConfigInt( SIGNALISATION , STUN_ENABLE ) == STUN_ENABLED )? setConfig(SIGNALISATION , STUN_ENABLE , NO_STR ) : setConfig( SIGNALISATION , STUN_ENABLE , YES_STR );
+}
+
+    int
 ManagerImpl::getVolumeControls( void )
 {
   return getConfigInt( PREFERENCES , CONFIG_VOLUME );
@@ -1543,16 +1555,23 @@ ManagerImpl::notifyErrClient( const int32_t& errCode )
   int
 ManagerImpl::getAudioDeviceIndex(const std::string name)
 {
-  _debug("Get audio device index\n");
-  int num = _audiodriver -> soundCardGetIndex( name );
-  return num;
+    AlsaLayer *alsalayer;
+
+    _debug("Get audio device index\n");
+    
+    alsalayer = dynamic_cast<AlsaLayer *> (getAudioDriver());
+    if(alsalayer)   return alsalayer -> soundCardGetIndex( name );
 }
 
   std::string 
 ManagerImpl::getCurrentAudioOutputPlugin( void )
 {
-  _debug("Get alsa plugin\n");
-  return _audiodriver -> getAudioPlugin();
+    AlsaLayer *alsalayer;
+  
+    _debug("Get alsa plugin\n");
+    
+    alsalayer = dynamic_cast<AlsaLayer *> (getAudioDriver());
+    if(alsalayer)   return alsalayer -> getAudioPlugin ();
 }
 
 int ManagerImpl::app_is_running( std::string process )
@@ -1610,104 +1629,88 @@ ManagerImpl::initAudioDriver(void)
   void
 ManagerImpl::selectAudioDriver (void)
 {
-  int layer = _audiodriver->getLayerType();
-  _debug("Audio layer type: %i\n" , layer);
-
-  std::string alsaPlugin = getConfigString( AUDIO , ALSA_PLUGIN );
-  int numCardIn  = getConfigInt( AUDIO , ALSA_CARD_ID_IN );
-  int numCardOut = getConfigInt( AUDIO , ALSA_CARD_ID_OUT );
-  int sampleRate = getConfigInt( AUDIO , ALSA_SAMPLE_RATE );
-  if (sampleRate <=0 || sampleRate > 48000) {
-    sampleRate = 44100;
-  }
-  int frameSize = getConfigInt( AUDIO , ALSA_FRAME_SIZE );
-
-  if( !_audiodriver -> soundCardIndexExist( numCardIn , SFL_PCM_CAPTURE ) )
-  {
-    _debug(" Card with index %i doesn't exist or cannot capture. Switch to 0.\n", numCardIn);
-    numCardIn = ALSA_DFT_CARD_ID ;
-    setConfig( AUDIO , ALSA_CARD_ID_IN , ALSA_DFT_CARD_ID );
-  }
-  if( !_audiodriver -> soundCardIndexExist( numCardOut , SFL_PCM_PLAYBACK ) )
-  {  
-    _debug(" Card with index %i doesn't exist or cannot playback . Switch to 0.\n", numCardOut);
-    numCardOut = ALSA_DFT_CARD_ID ;
-    setConfig( AUDIO , ALSA_CARD_ID_OUT , ALSA_DFT_CARD_ID );
-  }
+    int layer, numCardIn, numCardOut, sampleRate, frameSize;
+    std::string alsaPlugin;
+    AlsaLayer *alsalayer;
 
+    layer = _audiodriver->getLayerType();
+    _debug("Audio layer type: %i\n" , layer);
 
-  if(CHECK_INTERFACE( layer , ALSA ))
-  {
-  delete _audiodriver;
-  _audiodriver = new AlsaLayer( this );
-  _debugInit(" ALSA audio driver \n");
-  _audiodriver->setErrorMessage(-1);
-  _audiodriver->openDevice( numCardIn , numCardOut, sampleRate, frameSize, SFL_PCM_BOTH, alsaPlugin ); 
-  if( _audiodriver -> getErrorMessage() != -1 )
-    notifyErrClient( _audiodriver -> getErrorMessage());
-  }else{
-    delete _audiodriver;
-    _audiodriver = new PulseLayer( this );
-  _debug(" Pulse audio driver \n");
-  _audiodriver->setErrorMessage(-1);
-  _audiodriver->openDevice( numCardIn , numCardOut, sampleRate, frameSize, SFL_PCM_BOTH, alsaPlugin ); 
-  if( _audiodriver -> getErrorMessage() != -1 )
-    notifyErrClient( _audiodriver -> getErrorMessage());
-  }
+    /* Retrieve the global devices info from the user config */
+    alsaPlugin = getConfigString( AUDIO , ALSA_PLUGIN );
+    numCardIn  = getConfigInt( AUDIO , ALSA_CARD_ID_IN );
+    numCardOut = getConfigInt( AUDIO , ALSA_CARD_ID_OUT );
+    sampleRate = getConfigInt( AUDIO , ALSA_SAMPLE_RATE );
+    if (sampleRate <=0 || sampleRate > 48000) {
+        sampleRate = 44100;
+    }
+    frameSize = getConfigInt( AUDIO , ALSA_FRAME_SIZE );
 
+    /* Only for the ALSA layer, we check the sound card information */
+    if (layer == ALSA)
+    {
+        alsalayer = dynamic_cast<AlsaLayer*> (getAudioDriver ());
+        if( !alsalayer -> soundCardIndexExist( numCardIn , SFL_PCM_CAPTURE ) )
+        {
+            _debug(" Card with index %i doesn't exist or cannot capture. Switch to 0.\n", numCardIn);
+            numCardIn = ALSA_DFT_CARD_ID ;
+            setConfig( AUDIO , ALSA_CARD_ID_IN , ALSA_DFT_CARD_ID );
+        }
+        if( !alsalayer -> soundCardIndexExist( numCardOut , SFL_PCM_PLAYBACK ) )
+        {  
+            _debug(" Card with index %i doesn't exist or cannot playback . Switch to 0.\n", numCardOut);
+            numCardOut = ALSA_DFT_CARD_ID ;
+            setConfig( AUDIO , ALSA_CARD_ID_OUT , ALSA_DFT_CARD_ID );
+        }
+    }
+  
+    _audiodriver->setErrorMessage(-1);
+    /* Open the audio devices */
+    _audiodriver->openDevice( numCardIn , numCardOut, sampleRate, frameSize, SFL_PCM_BOTH, alsaPlugin ); 
+    /* Notify the error if there is one */
+    if( _audiodriver -> getErrorMessage() != -1 )
+        notifyErrClient( _audiodriver -> getErrorMessage());
 }
 
-void
-ManagerImpl::switchAudioManager( void ) 
+void ManagerImpl::switchAudioManager (void) 
 {
-  _debug( "Switching audio manager \n");
+    int type, samplerate, framesize, numCardIn, numCardOut;
+    std::string alsaPlugin;
 
-  int type = _audiodriver->getLayerType();
-  int samplerate = getConfigInt( AUDIO , ALSA_SAMPLE_RATE );
-  int framesize = getConfigInt( AUDIO , ALSA_FRAME_SIZE );
-  std::string alsaPlugin = getConfigString( AUDIO , ALSA_PLUGIN );
-  int numCardIn  = getConfigInt( AUDIO , ALSA_CARD_ID_IN );
-  int numCardOut = getConfigInt( AUDIO , ALSA_CARD_ID_OUT );
+    _debug( "Switching audio manager \n");
 
-  _debug("Deleting current layer... \n" );
-  _audiodriver->closeLayer();
-  delete _audiodriver; _audiodriver = NULL;
-  
-  switch( type ){
-    case ALSA:
-      _debug("Creating Pulseaudio layer...\n");
-      _audiodriver = new PulseLayer( this );
-      break;
-    case PULSEAUDIO:
-      _debug("Creating ALSA layer...\n");
-      _audiodriver = new AlsaLayer( this );
-      break;
-    default:
-      _debug("Error: audio layer unknown\n");
-  }
-  _audiodriver->setErrorMessage(-1);
-  _audiodriver->openDevice( numCardIn , numCardOut, samplerate, framesize, SFL_PCM_BOTH, alsaPlugin ); 
-  if( _audiodriver -> getErrorMessage() != -1 )
-    notifyErrClient( _audiodriver -> getErrorMessage());
-} 
+    if(!_audiodriver)
+        return;
 
-/**
- * Initialize the Zeroconf scanning services loop
- * Informations will be store inside a map DNSService->_services
- * Initialization: Main Thread
- */
-  void 
-ManagerImpl::initZeroconf(void) 
-{
-#ifdef USE_ZEROCONF
-  _debugInit("Zeroconf Initialization");
-  int useZeroconf = getConfigInt(PREFERENCES, CONFIG_ZEROCONF);
+    type = _audiodriver->getLayerType();
+    samplerate = getConfigInt( AUDIO , ALSA_SAMPLE_RATE );
+    framesize = getConfigInt( AUDIO , ALSA_FRAME_SIZE );
+    alsaPlugin = getConfigString( AUDIO , ALSA_PLUGIN );
+    numCardIn  = getConfigInt( AUDIO , ALSA_CARD_ID_IN );
+    numCardOut = getConfigInt( AUDIO , ALSA_CARD_ID_OUT );
 
-  if (useZeroconf) {
-    _DNSService->startScanServices();
-  }
-#endif
-}
+    _debug("Deleting current layer... \n" );
+    //_audiodriver->closeLayer();
+    delete _audiodriver; _audiodriver = NULL;
+  
+    switch( type ){
+        case ALSA:
+            _debug("Creating Pulseaudio layer...\n");
+            _audiodriver = new PulseLayer( this );
+            break;
+        case PULSEAUDIO:
+            _debug("Creating ALSA layer...\n");
+            _audiodriver = new AlsaLayer( this );
+            break;
+        default:
+            _debug("Error: audio layer unknown\n");
+    }
+  
+    _audiodriver->setErrorMessage(-1);
+    _audiodriver->openDevice( numCardIn , numCardOut, samplerate, framesize, SFL_PCM_BOTH, alsaPlugin ); 
+    if( _audiodriver -> getErrorMessage() != -1 )
+        notifyErrClient( _audiodriver -> getErrorMessage());
+} 
 
 /**
  * Init the volume for speakers/micro from 0 to 100 value
@@ -1724,111 +1727,37 @@ ManagerImpl::initVolume()
 
 void ManagerImpl::setSpkrVolume(unsigned short spkr_vol) 
 {  
-    AudioLayer *audiolayer = NULL;
+    PulseLayer *pulselayer = NULL;
 
+    /* Set the manager sound volume */
     _spkr_volume = spkr_vol; 
-    audiolayer = getAudioDriver();
-    if( audiolayer )
+
+    /* Only for PulseAudio */
+    pulselayer = dynamic_cast<PulseLayer*> (getAudioDriver());
+    if (pulselayer)
     {
-        audiolayer->setPlaybackVolume( spkr_vol );
+        if( pulselayer->getLayerType() == PULSEAUDIO )
+        {
+            if(pulselayer)  pulselayer->setPlaybackVolume (spkr_vol);
+        }
     }
-    
 }
 
 void ManagerImpl::setMicVolume(unsigned short mic_vol) 
 {    
-    //AudioLayer *audiolayer = NULL;
-
     _mic_volume = mic_vol;   
-    //audiolayer = getAudioDriver();
-    //if( audiolayer )
-    //{
-      //  audiolayer->setCaptureVolume( mic_vol );
-    //}
 }
 
-/**
- * configuration function requests
- * Main Thread
- */
-  bool 
-ManagerImpl::getZeroconf(const std::string& sequenceId)
+void ManagerImpl::setSipPort( int port )
 {
-  bool returnValue = false;
-#ifdef USE_ZEROCONF
-  int useZeroconf = getConfigInt(PREFERENCES, CONFIG_ZEROCONF);
-  if (useZeroconf && _dbus != NULL) {
-    TokenList arg;
-    TokenList argTXT;
-    std::string newService = "new service";
-    std::string newTXT = "new txt record";
-    if (!_DNSService->isStart()) { _DNSService->startScanServices(); }
-    DNSServiceMap services = _DNSService->getServices();
-    DNSServiceMap::iterator iter = services.begin();
-    arg.push_back(newService);
-    while(iter!=services.end()) {
-      arg.push_front(iter->first);
-      //_gui->sendMessage("100",sequenceId,arg);
-      arg.pop_front(); // remove the first, the name
-
-      TXTRecordMap record = iter->second.getTXTRecords();
-      TXTRecordMap::iterator iterTXT = record.begin();
-      while(iterTXT!=record.end()) {
-	argTXT.clear();
-	argTXT.push_back(iter->first);
-	argTXT.push_back(iterTXT->first);
-	argTXT.push_back(iterTXT->second);
-	argTXT.push_back(newTXT);
-	// _gui->sendMessage("101",sequenceId,argTXT);
-	iterTXT++;
-      }
-      iter++;
-    }
-    returnValue = true;
-  }
-#else
-  (void)sequenceId;
-#endif
-  return returnValue;
 }
 
-/**
- * Main Thread
- */
-  bool 
-ManagerImpl::attachZeroconfEvents(const std::string& sequenceId, Pattern::Observer& observer)
+int ManagerImpl::getSipPort( void )
 {
-  bool returnValue = false;
-  // don't need the _gui like getZeroconf function
-  // because Observer is here
-#ifdef USE_ZEROCONF
-  int useZeroconf = getConfigInt(PREFERENCES, CONFIG_ZEROCONF);
-  if (useZeroconf) {
-    if (!_DNSService->isStart()) { _DNSService->startScanServices(); }
-    _DNSService->attach(observer);
-    returnValue = true;
-  }
-#else
-  (void)sequenceId;
-  (void)observer;
-#endif
-  return returnValue;
-}
-  bool
-ManagerImpl::detachZeroconfEvents(Pattern::Observer& observer)
-{
-  bool returnValue = false;
-#ifdef USE_ZEROCONF
-  if (_DNSService) {
-    _DNSService->detach(observer);
-    returnValue = true;
-  }
-#else
-  (void)observer;
-#endif
-  return returnValue;
+    return 5060;
 }
 
+
 // TODO: rewrite this
 /**
  * Main Thread
@@ -1961,7 +1890,7 @@ std::map< std::string, std::string > ManagerImpl::getAccountDetails(const Accoun
 
   std::map<std::string, std::string> a;
   std::string accountType;
-  enum VoIPLink::RegistrationState state;
+  RegistrationState state;
   
   state = _accountMap[accountID]->getRegistrationState();
   accountType = getConfigString(accountID, CONFIG_ACCOUNT_TYPE);
@@ -1970,15 +1899,15 @@ std::map< std::string, std::string > ManagerImpl::getAccountDetails(const Accoun
   a.insert( std::pair<std::string, std::string>( CONFIG_ACCOUNT_ENABLE, getConfigString(accountID, CONFIG_ACCOUNT_ENABLE) == "1" ? "TRUE": "FALSE"));
   a.insert( std::pair<std::string, std::string>(
 	"Status", 
-	(state == VoIPLink::Registered ? "REGISTERED":
-	(state == VoIPLink::Unregistered ? "UNREGISTERED":
-	(state == VoIPLink::Trying ? "TRYING":
-	(state == VoIPLink::ErrorAuth ? "ERROR_AUTH": 
-	(state == VoIPLink::ErrorNetwork ? "ERROR_NETWORK": 
-	(state == VoIPLink::ErrorHost ? "ERROR_HOST": 
-	(state == VoIPLink::ErrorExistStun ? "ERROR_EXIST_STUN": 
-	(state == VoIPLink::ErrorConfStun ? "ERROR_CONF_STUN": 
-	(state == VoIPLink::Error ? "ERROR": "ERROR")))))))))
+	(state == Registered ? "REGISTERED":
+	(state == Unregistered ? "UNREGISTERED":
+	(state == Trying ? "TRYING":
+	(state == ErrorAuth ? "ERROR_AUTH": 
+	(state == ErrorNetwork ? "ERROR_NETWORK": 
+	(state == ErrorHost ? "ERROR_HOST": 
+	(state == ErrorExistStun ? "ERROR_EXIST_STUN": 
+	(state == ErrorConfStun ? "ERROR_CONF_STUN": 
+	(state == Error ? "ERROR": "ERROR")))))))))
 	)
       );
  
@@ -2003,6 +1932,7 @@ void ManagerImpl::setAccountDetails( const std::string& accountID, const std::ma
 
     std::string accountType;
     Account *acc;
+    VoIPLink *link;
   
     accountType = (*details.find(CONFIG_ACCOUNT_TYPE)).second;
 
@@ -2016,28 +1946,28 @@ void ManagerImpl::setAccountDetails( const std::string& accountID, const std::ma
   
     // SIP SPECIFIC
     if (accountType == "SIP") {
+    
+        link =  Manager::instance().getAccountLink( accountID );
+        
+        if( link==0 )
+        {
+            _debug("Can not retrieve SIP link...\n");
+            return;
+        }
+    
         setConfig(accountID, SIP_STUN_SERVER,(*details.find(SIP_STUN_SERVER)).second);
         setConfig(accountID, SIP_USE_STUN, (*details.find(SIP_USE_STUN)).second == "TRUE" ? "1" : "0");
-	
-	if(!_userAgentInitlized) {
-        	_userAgentInitlized = true;
 
-        	if((*details.find(SIP_USE_STUN)).second == "TRUE")
-            		_userAgent->setStunServer((*details.find(SIP_STUN_SERVER)).second.data());
-        	else
-            		_userAgent->setStunServer(NULL);
-
-        	_userAgent->sipCreate();
-        	_userAgent->sipInit();
-    	} else {
-        	if((*details.find(SIP_USE_STUN)).second == "TRUE")
-            		_userAgent->setStunServer((*details.find(SIP_STUN_SERVER)).second.data());
-        	else
-            		_userAgent->setStunServer(NULL);
-
-        	restartPjsip();
-    	}
-  }
+        if((*details.find(SIP_USE_STUN)).second == "TRUE")
+        {
+           link->setStunServer((*details.find(SIP_STUN_SERVER)).second.data());
+        }
+        else
+        {
+            link->setStunServer("");
+        }
+        //restartPjsip();
+    }
 
     saveConfig();
   
@@ -2053,6 +1983,8 @@ void ManagerImpl::setAccountDetails( const std::string& accountID, const std::ma
     // Update account details to the client side
     if (_dbus) _dbus->getConfigurationManager()->accountsChanged();
 
+    //delete link; link=0;
+
 }
 
 void
@@ -2079,38 +2011,30 @@ ManagerImpl::sendRegister( const std::string& accountID , const int32_t& expire
 ManagerImpl::addAccount(const std::map< std::string, std::string >& details)
 {
 
-  /** @todo Deal with both the _accountMap and the Configuration */
-  std::string accountType = (*details.find(CONFIG_ACCOUNT_TYPE)).second;
-  Account* newAccount;
-  std::stringstream accountID;
-  accountID << "Account:" << time(NULL);
-  AccountID newAccountID = accountID.str();
-  /** @todo Verify the uniqueness, in case a program adds accounts, two in a row. */
-
-  if (accountType == "SIP") {
-     if(!_userAgentInitlized) {
-        // Initialize the SIP Manager
-        _userAgent = new UserAgent();
-        _userAgent->setSipPort(Manager::instance().getConfigInt(PREFERENCES , CONFIG_SIP_PORT));
-      }
+    /** @todo Deal with both the _accountMap and the Configuration */
+    std::string accountType = (*details.find(CONFIG_ACCOUNT_TYPE)).second;
+    Account* newAccount;
+    std::stringstream accountID;
+    accountID << "Account:" << time(NULL);
+    AccountID newAccountID = accountID.str();
+    /** @todo Verify the uniqueness, in case a program adds accounts, two in a row. */
 
-      newAccount = AccountCreator::createAccount(AccountCreator::SIP_ACCOUNT, newAccountID);
-  }
-  else if (accountType == "IAX") {
-    newAccount = AccountCreator::createAccount(AccountCreator::IAX_ACCOUNT, newAccountID);
-  }
-  else {
-    _debug("Unknown %s param when calling addAccount(): %s\n", CONFIG_ACCOUNT_TYPE, accountType.c_str());
-    return;
-  }
-  _accountMap[newAccountID] = newAccount;
-  setAccountDetails(accountID.str(), details);
-
-  saveConfig();
+    if (accountType == "SIP") {
+        newAccount = AccountCreator::createAccount(AccountCreator::SIP_ACCOUNT, newAccountID);
+    }
+    else if (accountType == "IAX") {
+        newAccount = AccountCreator::createAccount(AccountCreator::IAX_ACCOUNT, newAccountID);
+    }
+    else {
+        _debug("Unknown %s param when calling addAccount(): %s\n", CONFIG_ACCOUNT_TYPE, accountType.c_str());
+        return;
+    }
+    _accountMap[newAccountID] = newAccount;
+    setAccountDetails(accountID.str(), details);
 
-  if (_dbus) _dbus->getConfigurationManager()->accountsChanged();
+    saveConfig();
 
-  //restartPjsip();
+    if (_dbus) _dbus->getConfigurationManager()->accountsChanged();
 }
 
   void 
@@ -2189,20 +2113,6 @@ ManagerImpl::getNewCallID()
   return random_id.str();
 }
 
-  void 
-ManagerImpl::restartPjsip()
-{
-  if ( _userAgentInitlized ){
-    unregisterCurSIPAccounts();
-    _userAgent->sipDestory();
-    //_userAgent->setSipPort(Manager::instance().getConfigInt(PREFERENCES , CONFIG_SIP_PORT));
-
-    _userAgent->sipCreate();
-    _userAgent->sipInit();
-    registerCurSIPAccounts();
-  } 
-}
-
   short
 ManagerImpl::loadAccountMap()
 {
@@ -2211,7 +2121,6 @@ ManagerImpl::loadAccountMap()
   TokenList sections = _config.getSections();
   std::string accountType;
   Account* tmpAccount;
-  std::string port;
 
   TokenList::iterator iter = sections.begin();
   while(iter != sections.end()) {
@@ -2223,28 +2132,7 @@ ManagerImpl::loadAccountMap()
 
     accountType = getConfigString(*iter, CONFIG_ACCOUNT_TYPE);
     if (accountType == "SIP") {
-      if(!_userAgentInitlized) {
-        // Initialize the SIP Manager
-        _userAgent = new UserAgent();
-        _userAgentInitlized = true;
-        _userAgent->setSipPort(Manager::instance().getConfigInt(PREFERENCES , CONFIG_SIP_PORT));
-      }
-
       tmpAccount = AccountCreator::createAccount(AccountCreator::SIP_ACCOUNT, *iter);
-     
-      // Determine whether to use stun for the current account or not 
-      int useStun = Manager::instance().getConfigInt(tmpAccount->getAccountID(),SIP_USE_STUN);
-  
-      if(useStun == 1) {
-        _userAgent->setStunServer(Manager::instance().getConfigString(tmpAccount->getAccountID(), SIP_STUN_SERVER).data());
-      }
-      
-      /*// Set registration port for all accounts, The last non-5060 port will be recorded in _userAgent.
-      port = Manager::instance().getConfigString(tmpAccount->getAccountID(), SIP_PORT);
-      std::istringstream is(port);
-      is >> iPort;
-      if (iPort != DEFAULT_SIP_PORT)
-      	_userAgent->setRegPort(iPort);  */
     }
     else if (accountType == "IAX") {
       tmpAccount = AccountCreator::createAccount(AccountCreator::IAX_ACCOUNT, *iter);
@@ -2259,8 +2147,6 @@ ManagerImpl::loadAccountMap()
       nbAccount++;
     }
 
-    _debug("\n");
-
     iter++;
   }
 
@@ -2328,8 +2214,25 @@ ManagerImpl::getAccountIdFromNameAndServer(const std::string& userName, const st
   return AccountNULL;
 }
 
-  VoIPLink* 
-ManagerImpl::getAccountLink(const AccountID& accountID)
+AccountMap ManagerImpl::getSipAccountMap( void )
+{
+    
+    AccountMap::iterator iter;
+    AccountMap sipaccounts;
+    AccountID id;
+    Account *account;
+
+    for(iter = _accountMap.begin(); iter != _accountMap.end(); ++iter) {
+        if( iter->second->getType() == "sip" ){
+            //id = iter->first;
+            //account = iter->second;
+            //sipaccounts.insert( std::pair<id, account> );
+        }
+    }
+    return sipaccounts;
+}
+
+VoIPLink* ManagerImpl::getAccountLink(const AccountID& accountID)
 {
   Account* acc = getAccount(accountID);
   if ( acc ) {
@@ -2348,37 +2251,6 @@ pjsip_regc
     return NULL;
 }
 
-
-/** 
- * Return the instance of sip manager
- */
-UserAgent *ManagerImpl::getUserAgent()
-{
-    return _userAgent;
-}
-
-int 
-ManagerImpl::getSipPort()
-{
-    if( _userAgent )
-        return _userAgent->getSipPort();
-    else
-    {
-        // It means that no SIP accounts are configured, so return a default value
-        return 0;
-    }
-}
-
-void 
-ManagerImpl::setSipPort(int portNum)
-{
-    if(portNum != _userAgent->getSipPort()) {
-        _userAgent->setSipPort(portNum);
-        restartPjsip();
-        setConfig( PREFERENCES , CONFIG_SIP_PORT , portNum );
-    }
-}
-
 void ManagerImpl::unregisterCurSIPAccounts()
 {
   AccountMap::iterator iter = _accountMap.begin();
diff --git a/src/managerimpl.h b/src/managerimpl.h
index a76987d758b48188f60e853759be06a51d5b75de..cc3411f3ade26470030f558b6cba32e18795bfdd 100644
--- a/src/managerimpl.h
+++ b/src/managerimpl.h
@@ -47,7 +47,6 @@ class CodecDescriptor;
 class GuiFramework;
 class TelephoneTone;
 class VoIPLink;
-class UserAgent;
 
 #ifdef USE_ZEROCONF
 class DNSService;
@@ -272,9 +271,6 @@ class ManagerImpl {
      */
     void sendRegister( const ::std::string& accountId , const int32_t& expire );
 
-    bool getZeroconf(const std::string& sequenceId);
-    bool attachZeroconfEvents(const std::string& sequenceId, Pattern::Observer& observer);
-    bool detachZeroconfEvents(Pattern::Observer& observer);
     bool getCallStatus(const std::string& sequenceId);
 
     /** 
@@ -795,14 +791,15 @@ class ManagerImpl {
      */
     void restartPjsip();
 
-    int getSipPort();
-    
-    void setSipPort(int port);
-    
     void unregisterCurSIPAccounts();
     
     void registerCurSIPAccounts();
     
+    /**
+     * Returns a map with only the existing SIP accounts
+     */
+    AccountMap getSipAccountMap( void );
+
   private:
     
     /**
@@ -1019,6 +1016,15 @@ public:
 
     AccountID getAccountIdFromNameAndServer(const std::string& userName, const std::string& server);
 
+    int getSipPort();
+
+    void setSipPort( int port );
+
+    std::string getStunServer (void);
+    void setStunServer (const std::string &server);
+
+    int isStunEnabled (void);
+    void enableStun (void);
 private:
 
     // Copy Constructor
@@ -1027,32 +1033,12 @@ private:
     // Assignment Operator
     ManagerImpl& operator=( const ManagerImpl& rh);
 
-    /**
-     * The UserAgent provides sip operation facilities for all sip accounts
-     */
-    UserAgent *_userAgent;
-
-    /** Whether the _UserAgent has been initialized */
-    bool _userAgentInitlized;
-    
-    bool _sipThreadStop;
-
 #ifdef TEST
     bool testCallAccountMap();
     bool testAccountMap();
 #endif
 
     friend class ConfigurationTest;
-
-public:
-    /**
-     * Retuun the instance of sip manager
-     */
-    UserAgent *getUserAgent();
-    
-    void setSipThreadStatus(bool status) {_sipThreadStop = status;}
-    
-    bool getSipThreadStatus() {return _sipThreadStop;}
 };
 
 #endif // __MANAGER_H__
diff --git a/src/samplerateconverter.cpp b/src/samplerateconverter.cpp
index 3c6d0ed90db1902bc1e1ee0f29224f1e767453b4..52d047ca4cb5c5da507b1d91b4a7851b49cea9b9 100644
--- a/src/samplerateconverter.cpp
+++ b/src/samplerateconverter.cpp
@@ -78,6 +78,7 @@ void SamplerateConverter::init( void ) {
 int SamplerateConverter::upsampleData(  SFLDataFormat* dataIn , SFLDataFormat* dataOut, int samplerate1 , int samplerate2 , int nbSamples ){
   
   double upsampleFactor = (double)samplerate2 / samplerate1 ;
+  //_debug("factor = %f\n" , upsampleFactor);
   int nbSamplesMax = (int) ( samplerate2 * getFramesize() / 1000 );
   if( upsampleFactor != 1 && dataIn != NULL )
   {
@@ -106,7 +107,7 @@ int SamplerateConverter::downsampleData(  SFLDataFormat* dataIn , SFLDataFormat*
   double downsampleFactor = (double)samplerate1 / samplerate2;
   //_debug("factor = %f\n" , downsampleFactor);
   int nbSamplesMax = (int) ( samplerate1 * getFramesize() / 1000 );
-  if ( downsampleFactor != 1)
+  if ( downsampleFactor != 1 )
   {
     SRC_DATA src_data;	
     src_data.data_in = _floatBufferUpMic;
diff --git a/src/sipaccount.cpp b/src/sipaccount.cpp
index acce1bb66ed5fff56fad4d6a3d20b77c6ba146a0..61c8bfd05b2a762891c61ebd8fee8f22fd3f2dda 100644
--- a/src/sipaccount.cpp
+++ b/src/sipaccount.cpp
@@ -2,8 +2,6 @@
  *  Copyright (C) 2006-2009 Savoir-Faire Linux inc.
  *  
  *  Author: Emmanuel Milou <emmanuel.milou@savoirfairelinux.com>
- *  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
@@ -23,80 +21,71 @@
 #include "sipaccount.h"
 #include "manager.h"
 #include "user_cfg.h"
-#include "useragent.h"
 
 SIPAccount::SIPAccount(const AccountID& accountID)
- : Account(accountID)
- , _userName("")
- , _server("")
+ : Account(accountID, "sip")
  , _cred(NULL)
  , _contact("")
+ , _bRegister(false)
+ , _regc()
 {
-  _link = new SIPVoIPLink(accountID);
+    /* SIPVoIPlink is used as a singleton, because we want to have only one link for all the SIP accounts created */
+    /* So instead of creating a new instance, we just fetch the static instance, or create one if it is not yet */
+    /* The SIP library initialization is done in the SIPVoIPLink constructor */
+    /* The SIP voip link is now independant of the account ID as it can manage several SIP accounts */
+    _link = SIPVoIPLink::instance("");
+    
+    /* Represents the number of SIP accounts connected the same link */
+    dynamic_cast<SIPVoIPLink*> (_link)->incrementClients();
+    
 }
 
 
 SIPAccount::~SIPAccount()
 {
-  delete _link;
-  _link = NULL;
-  delete _cred;
-  _cred = NULL;
+    /* One SIP account less connected to the sip voiplink */
+    dynamic_cast<SIPVoIPLink*> (_link)->decrementClients();
+    /* Delete accounts-related information */
+    _regc = NULL;
+    delete _cred; _cred = NULL;
 }
 
-int
-SIPAccount::registerVoIPLink()
+int SIPAccount::registerVoIPLink()
 {
+    int status;
 
-    int status, useStun;
-    SIPVoIPLink *thislink;
-
-    _link->setHostname(Manager::instance().getConfigString(_accountID,HOSTNAME));
-    useStun = Manager::instance().getConfigInt(_accountID,SIP_USE_STUN);
-  
-    thislink = dynamic_cast<SIPVoIPLink*> (_link);
-    thislink->setStunServer(Manager::instance().getConfigString(_accountID,SIP_STUN_SERVER));
-    thislink->setUseStun( useStun!=0 ? true : false);
-    
-    _link->init();
-  
-    // Stuff needed for SIP registration.
-    thislink->setUsername(Manager::instance().getConfigString(_accountID, USERNAME));
-    thislink->setPassword(Manager::instance().getConfigString(_accountID, PASSWORD));
-    thislink->setHostname(Manager::instance().getConfigString(_accountID, HOSTNAME));
+    /* Retrieve the account information */
+    /* Stuff needed for SIP registration */
+    setHostname(Manager::instance().getConfigString(_accountID,HOSTNAME));
+    setUsername(Manager::instance().getConfigString(_accountID, USERNAME));
+    setPassword(Manager::instance().getConfigString(_accountID, PASSWORD));
 
-    status = _link->sendRegister();
+    /* Start registration */
+    status = _link->sendRegister( _accountID );
     ASSERT( status , SUCCESS );
 
     return SUCCESS;
 }
 
-int
-SIPAccount::unregisterVoIPLink()
+int SIPAccount::unregisterVoIPLink()
 {
   _debug("SIPAccount: unregister account %s\n" , getAccountID().c_str());
-  _link->sendUnregister();
-  _link->terminate();
-  
-  return SUCCESS;
+  return _link->sendUnregister( _accountID );
 }
 
-void
-SIPAccount::loadConfig() 
+void SIPAccount::loadConfig() 
 {
   // Account generic
   Account::loadConfig();
 }
 
-bool 
-SIPAccount::fullMatch(const std::string& userName, const std::string& server)
+bool SIPAccount::fullMatch(const std::string& username, const std::string& hostname)
 {
-  return (userName == _userName && server == _server);
+  return (username == getUsername() && hostname == getHostname());
 }
 
-bool 
-SIPAccount::userMatch(const std::string& userName)
+bool SIPAccount::userMatch(const std::string& username)
 {
-  return (userName == _userName);
+  return (username == getUsername());
 }
 
diff --git a/src/sipaccount.h b/src/sipaccount.h
index 549d1a6d0d857326720e81b9863df9a4ca045083..a49af2d00864a29c674a2ac152dcd2663d75620c 100644
--- a/src/sipaccount.h
+++ b/src/sipaccount.h
@@ -26,76 +26,86 @@
 #include "account.h"
 #include "sipvoiplink.h"
 
-struct pjsip_cred_info;
-
 class SIPVoIPLink;
 
 /**
  * @file sipaccount.h
  * @brief A SIP Account specify SIP specific functions and object (SIPCall/SIPVoIPLink)
-*/
+ */
 
 class SIPAccount : public Account
 {
-public:
-  /**
-   * Constructor
-   * @param accountID The account identifier
-   */
-  SIPAccount(const AccountID& accountID);
-
-  /* Copy Constructor */
-  SIPAccount(const SIPAccount& rh);
-
-  /* Assignment Operator */
-  SIPAccount& operator=( const SIPAccount& rh);
-  
-  /**
-   * Virtual destructor
-   */
-  virtual ~SIPAccount();
-
-  /** 
-   * Actually unuseful, since config loading is done in init() 
-   */
-  void loadConfig();
-
-  /**
-   * Initialize the SIP voip link with the account parameters and send registration
-   */ 
-  int registerVoIPLink();
-
-  /**
-   * Send unregistration and clean all related stuff ( calls , thread )
-   */
-  int unregisterVoIPLink();
-
-
-  void setUserName(const std::string &name) {_userName = name;}
-
-  std::string getUserName() {return _userName;}
-
-  void setServer(const std::string &server) {_server = server;}
-
-  std::string getServer() {return _server;}
-
-  void setCredInfo(pjsip_cred_info *cred) {_cred = cred;}
-
-  pjsip_cred_info *getCredInfo() {return _cred;}
-
-  void setContact(const std::string contact) {_contact = contact;}
-
-  std::string getContact() {return _contact;}
-
-  bool fullMatch(const std::string& userName, const std::string& server);
-
-  bool userMatch(const std::string& userName);
-
-private:
-  std::string _userName;
-  std::string _server;
-  pjsip_cred_info *_cred;
-  std::string _contact;
+    public:
+        /**
+         * Constructor
+         * @param accountID The account identifier
+         */
+        SIPAccount(const AccountID& accountID);
+
+        /* Copy Constructor */
+        SIPAccount(const SIPAccount& rh);
+
+        /* Assignment Operator */
+        SIPAccount& operator=( const SIPAccount& rh);
+
+        /**
+         * Virtual destructor
+         */
+        virtual ~SIPAccount();
+
+        /** 
+         * Actually unuseful, since config loading is done in init() 
+         */
+        void loadConfig();
+
+        /**
+         * Initialize the SIP voip link with the account parameters and send registration
+         */ 
+        int registerVoIPLink();
+
+        /**
+         * Send unregistration and clean all related stuff ( calls , thread )
+         */
+        int unregisterVoIPLink();
+
+        inline void setCredInfo(pjsip_cred_info *cred) {_cred = cred;}
+        inline pjsip_cred_info *getCredInfo() {return _cred;}
+
+        inline void setContact(const std::string &contact) {_contact = contact;}
+        inline std::string getContact() {return _contact;}
+
+        bool fullMatch(const std::string& username, const std::string& hostname);
+        bool userMatch(const std::string& username);
+
+        pjsip_regc* getRegistrationInfo( void ) { return _regc; }
+        void setRegistrationInfo( pjsip_regc *regc ) { _regc = regc; }
+
+        /* Registration flag */
+        bool isRegister() {return _bRegister;}
+        void setRegister(bool result) {_bRegister = result;}
+
+
+    private:
+
+        /**
+         * Credential information
+         */
+        pjsip_cred_info *_cred;
+
+        /**
+         * The pjsip client registration information
+         */
+        pjsip_regc *_regc;
+        
+        /**
+         * To check if the account is registered
+         */
+        bool _bRegister;
+        
+        /*
+         * SIP address
+         */
+        std::string _contact;
 };
 
 #endif
diff --git a/src/sipcall.cpp b/src/sipcall.cpp
index 0e53bdd013d066744d80db93204ffbf14a46549f..d43ea938ac230ce691722de456a39a3dcaa7c32a 100644
--- a/src/sipcall.cpp
+++ b/src/sipcall.cpp
@@ -22,8 +22,6 @@
 
 #include "sipcall.h"
 #include "global.h" // for _debug
-#include <sstream> // for media buffer
-#include <string>
 
 #define _SENDRECV 0
 #define _SENDONLY 1
@@ -51,13 +49,13 @@ SIPCall::SIPCallInvite(pjsip_rx_data *rdata, pj_pool_t *pool)
 {
   pj_status_t status;
   
+  // We retrieve the remote sdp offer in the rdata struct to begin the negociation
   pjmedia_sdp_session* remote_sdp = getRemoteSDPFromRequest(rdata);
   if (remote_sdp == 0) {
     return false;
   }
 
   // Have to do some stuff here with the SDP
-  // We retrieve the remote sdp offer in the rdata struct to begin the negociation
   _localSDP = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_session);
   _localSDP->conn =  PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_conn);
   
@@ -68,7 +66,6 @@ SIPCall::SIPCallInvite(pjsip_rx_data *rdata, pj_pool_t *pool)
   _localSDP->time.start = _localSDP->time.stop = 0;
   sdpAddMediaDescription(pool);
   
-  _debug("Before validate SDP!\n");
   status = pjmedia_sdp_validate( _localSDP );
   if (status != PJ_SUCCESS) {
     _debug("Can not generate valid local sdp\n");
diff --git a/src/sipcall.h b/src/sipcall.h
index fe23553d5dcdd5edda45b80c6466ea3d6b124725..2ef3d2793451e85bd1fd48151428959cfd7db854 100644
--- a/src/sipcall.h
+++ b/src/sipcall.h
@@ -22,8 +22,8 @@
 #define SIPCALL_H
 
 #include "call.h"
+#include "sipvoiplink.h"
 #include "audio/codecDescriptor.h"
-#include "useragent.h"
 
 class AudioCodec;
 
diff --git a/src/sipvoiplink.cpp b/src/sipvoiplink.cpp
index d70e1221216de4257fe15373b637d39446152286..e3fc11b7920e38dd1e813a486f4fdae20ac110f4 100644
--- a/src/sipvoiplink.cpp
+++ b/src/sipvoiplink.cpp
@@ -2,8 +2,7 @@
  *  Copyright (C) 2004-2009 Savoir-Faire Linux inc.
  *
  *  Author: Emmanuel Milou <emmanuel.milou@savoirfairelinux.com>
- *  Author: Yan Morin <yan.morin@savoirfairelinux.com>
- *  Author : Laurielle Lea <laurielle.lea@savoirfairelinux.com>
+ *  Author: Yun Liu <yun.liu@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
@@ -19,261 +18,577 @@
  *  along with this program; if not, write to the Free Software
  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
-/*
- * YM: 2006-11-15: changes unsigned int to std::string::size_type, thanks to Pierre Pomes (AMD64 compilation)
- */
+
 #include "sipvoiplink.h"
 #include "eventthread.h"
 #include "sipcall.h"
-#include <sstream> // for istringstream
 #include "sipaccount.h"
-#include "useragent.h"
 #include "audio/audiortp.h"
-        
-#include "manager.h"
-#include "user_cfg.h" // SIGNALISATION / PULSE #define
-
-#define RANDOM_LOCAL_PORT ((rand() % 27250) + 5250)*2
-
-// 1XX responses
-#define DIALOG_ESTABLISHED 101
-// see: osip_const.h
-
-// need for hold/unhold
-#define INVITE_METHOD "INVITE"
-
-SIPVoIPLink::SIPVoIPLink(const AccountID& accountID)
- : VoIPLink(accountID)
- , _initDone(false)
- , _nbTryListenAddr(2) // number of times to try to start SIP listener
- , _useStun(false)
- , _stunServer("")
- , _localExternAddress("") 
- , _localExternPort(0)
- , _audiortp(new AudioRtp())
- , _regc()
- , _bRegister(false)
+
+/**************** EXTERN VARIABLES AND FUNCTIONS (callbacks) **************************/
+
+/*
+ *  The global pool factory
+ */
+pj_caching_pool _cp;
+
+/*
+ * The pool to allocate memory
+ */
+pj_pool_t *_pool;    
+
+/*
+ *	The SIP endpoint
+ */
+pjsip_endpoint *_endpt;
+
+/*
+ *	The SIP module
+ */
+pjsip_module _mod_ua;  
+
+/*
+ * Thread related
+ */
+pj_thread_t *thread;
+pj_thread_desc desc;
+
+
+/**
+ * Get the number of voicemail waiting in a SIP message
+ */
+void set_voicemail_info( AccountID account, pjsip_msg_body *body );
+
+/**
+ * Set audio (SDP) configuration for a call
+ * localport, localip, localexternalport
+ * @param call a SIPCall valid pointer
+ * @return bool True
+ */
+bool setCallAudioLocal(SIPCall* call, std::string localIP, bool stun, std::string server);
+
+// Documentated from the PJSIP Developer's Guide, available on the pjsip website/
+
+/*
+ * Session callback
+ * Called when the invite session state has changed.
+ *
+ * @param	inv	A pointer on a pjsip_inv_session structure
+ * @param	e	A pointer on a pjsip_event structure
+ */
+void call_on_state_changed( pjsip_inv_session *inv, pjsip_event *e);
+
+/*
+ * Session callback
+ * Called after SDP offer/answer session has completed.
+ *
+ * @param	inv	A pointer on a pjsip_inv_session structure
+ * @param	status	A pj_status_t structure
+ */
+void call_on_media_update( pjsip_inv_session *inv UNUSED, pj_status_t status UNUSED);
+
+/*
+ * Called when the invote usage module has created a new dialog and invite
+ * because of forked outgoing request.
+ *
+ * @param	inv	A pointer on a pjsip_inv_session structure
+ * @param	e	A pointer on a pjsip_event structure
+ */
+void call_on_forked(pjsip_inv_session *inv, pjsip_event *e);
+
+/*
+ * Session callback
+ * Called whenever any transactions within the session has changed their state.
+ * Useful to monitor the progress of an outgoing request.
+ *
+ * @param	inv	A pointer on a pjsip_inv_session structure
+ * @param	tsx	A pointer on a pjsip_transaction structure
+ * @param	e	A pointer on a pjsip_event structure
+ */
+void call_on_tsx_changed(pjsip_inv_session *inv, pjsip_transaction *tsx, pjsip_event *e);
+
+/*
+ * Registration callback
+ */
+void regc_cb(struct pjsip_regc_cbparam *param);
+
+/*
+ * Called to handle incoming requests outside dialogs
+ * @param   rdata
+ * @return  pj_bool_t
+ */
+pj_bool_t mod_on_rx_request(pjsip_rx_data *rdata);
+
+/*
+ * Called to handle incoming response
+ * @param	rdata
+ * @return	pj_bool_t
+ */
+pj_bool_t mod_on_rx_response(pjsip_rx_data *rdata UNUSED) ;
+
+/*
+ * Transfer callbacks
+ */
+void xfer_func_cb( pjsip_evsub *sub, pjsip_event *event);
+void xfer_svr_cb(pjsip_evsub *sub, pjsip_event *event);
+void onCallTransfered(pjsip_inv_session *inv, pjsip_rx_data *rdata);
+
+/*************************************************************************************************/
+
+SIPVoIPLink* SIPVoIPLink::_instance = NULL;
+
+
+    SIPVoIPLink::SIPVoIPLink(const AccountID& accountID)
+    : VoIPLink(accountID)
+      , _nbTryListenAddr(2) // number of times to try to start SIP listener
+      , _stunServer("")
+    , _localExternAddress("") 
+    , _localExternPort(0)
+    , _audiortp(new AudioRtp())
+    ,_regPort(DEFAULT_SIP_PORT)
+    , _useStun(false)
+    , _clients(0)
 {
-  // to get random number for RANDOM_PORT
-  srand (time(NULL));
+    // to get random number for RANDOM_PORT
+    srand (time(NULL));
+
+    /* Instanciate the C++ thread */
+    _evThread = new EventThread(this);
+
+    /* Start pjsip initialization step */
+    init();
 }
 
 SIPVoIPLink::~SIPVoIPLink()
 {
-  terminate();
+    terminate();
+}
+
+SIPVoIPLink* SIPVoIPLink::instance( const AccountID& id)
+{
+
+    if(!_instance ){
+        _instance = new SIPVoIPLink( id );
+    }
+
+    return _instance;
+}
+
+void SIPVoIPLink::decrementClients (void)
+{
+    _clients--;
+    if(_clients == 0){
+        terminate();
+        SIPVoIPLink::_instance=NULL;
+    }
 }
 
-bool 
-SIPVoIPLink::init()
+bool SIPVoIPLink::init()
 {
-  _regc = NULL;
-  _initDone = true;
-  return true;
+    if(initDone())
+        return false;
+    /* Initialize the pjsip library */
+    pjsip_init();
+    initDone(true);
+
+    return true;
 }
 
-void 
+    void 
 SIPVoIPLink::terminate()
 {
-  _initDone = false;
+    delete _evThread; _evThread = NULL;
+
+    /* Clean shutdown of pjsip library */
+    if( initDone() )
+    {
+        pjsip_shutdown();
+    }
+    initDone(false);
 }
 
-void
+    void
 SIPVoIPLink::terminateSIPCall()
 {
-  
-  ost::MutexLock m(_callMapMutex);
-  CallMap::iterator iter = _callMap.begin();
-  SIPCall *call;
-  while( iter != _callMap.end() ) {
-    call = dynamic_cast<SIPCall*>(iter->second);
-    if (call) {
-      //TODO terminate the sip call
-      delete call; call = 0;
+
+    ost::MutexLock m(_callMapMutex);
+    CallMap::iterator iter = _callMap.begin();
+    SIPCall *call;
+    while( iter != _callMap.end() ) {
+        call = dynamic_cast<SIPCall*>(iter->second);
+        if (call) {
+            // terminate the sip call
+            delete call; call = 0;
+        }
+        iter++;
     }
-    iter++;
-  }
-  _callMap.clear();
+    _callMap.clear();
 }
 
-void
+    void
 SIPVoIPLink::getEvent()
 {
-    // Nothing anymore. PJSIP is based on asynchronous events
+    // We have to register the external thread so it could access the pjsip framework
+    if(!pj_thread_is_registered())
+        pj_thread_register( NULL, desc, &thread );
+
+    // PJSIP polling
+    pj_time_val timeout = {0, 10};
+    pjsip_endpt_handle_events( _endpt, &timeout);
 }
 
-int
-SIPVoIPLink::sendRegister()
+int SIPVoIPLink::sendRegister( AccountID id )
 {
-  AccountID id;
-  pj_status_t status;
-  
-  id = getAccountID();
+    pj_status_t status;
+    int expire_value;
+    char contactTmp[256];
+    pj_str_t svr, aor, contact;
+    pjsip_tx_data *tdata;
+    std::string tmp, hostname, username, password;
+    SIPAccount *account;
+    pjsip_regc *regc;
+
+    account = dynamic_cast<SIPAccount *> (Manager::instance().getAccount(id));
+    hostname = account->getHostname();
+    username = account->getUsername();
+    password = account->getPassword();
+
+    _mutexSIP.enterMutex(); 
+
+    /* Get the client registration information for this particular account */
+    regc = account->getRegistrationInfo();
+    /* If the registration already exists, delete it */
+    if(regc) {
+        status = pjsip_regc_destroy(regc);
+        regc = NULL;
+        PJ_ASSERT_RETURN( status == PJ_SUCCESS, 1 );
+    }
 
-  if(_regc) {
-      status = pjsip_regc_destroy(_regc);
-      _regc = NULL;
-      PJ_ASSERT_RETURN( status == PJ_SUCCESS, 1 );
-  }
+    account->setRegister(true);
 
-  _bRegister = true;
-  
-  int expire_value = Manager::instance().getRegistrationExpireValue();
-  _debug("SIP Registration Expire Value = %i\n" , expire_value);
+    /* Set the expire value of the message from the config file */
+    expire_value = Manager::instance().getRegistrationExpireValue();
 
-  setRegistrationState(Trying);
+    /* Update the state of the voip link */
+    account->setRegistrationState(Trying);
 
-  return Manager::instance().getUserAgent()->addAccount(id, &_regc, getHostname(), getUsername(), getPassword(), expire_value);
-}
+    if (!validStunServer) {
+        account->setRegistrationState(ErrorExistStun);
+        account->setRegister(false);
+        _mutexSIP.leaveMutex(); 
+        return false;
+    }
 
-std::string
-SIPVoIPLink::SIPFromHeader(const std::string& userpart, const std::string& hostpart) 
-{
-  return ("\"" + getFullName() + "\"" + " <sip:" + userpart + "@" + hostpart + ">");
-}
+    /* Create the registration according to the account ID */
+    status = pjsip_regc_create(_endpt, (void*)account, &regc_cb, &regc);
+    if (status != PJ_SUCCESS) {
+        _debug("UserAgent: Unable to create regc.\n");
+        _mutexSIP.leaveMutex(); 
+        return false;
+    }
 
-bool
-SIPVoIPLink::sendSIPAuthentification() 
-{
-  if (getUsername().empty()) {
-    /** @todo Ajouter ici un call à setRegistrationState(Error, "Fill balh") ? */
-    return false;
-  }
-  if (getPassword().empty()) {
-    /** @todo Même chose ici  ? */
-    return false;
-  }
+    tmp = "sip:" + hostname;
+    pj_strdup2(_pool, &svr, tmp.data());
+
+    tmp = "<sip:" + username + "@" + hostname + ">";
+    pj_strdup2(_pool, &aor, tmp.data());
+
+    sprintf(contactTmp, "<sip:%s@%s:%d>", username.data(), _localExternAddress.data(), _localExternPort);
+    pj_strdup2(_pool, &contact, contactTmp);
+    account->setContact(contactTmp);
 
-  return true;
+    status = pjsip_regc_init(regc, &svr, &aor, &aor, 1, &contact, 600); //timeout);
+    if (status != PJ_SUCCESS) {
+        _debug("UserAgent: Unable to initialize regc. %d\n", status); //, regc->str_srv_url.ptr);
+        _mutexSIP.leaveMutex(); 
+        return false;
+    }
+
+    pjsip_cred_info *cred = account->getCredInfo();
+
+    if(!cred)
+        cred = new pjsip_cred_info();
+
+    pj_bzero(cred, sizeof (pjsip_cred_info));
+    pj_strdup2(_pool, &cred->username, username.data());
+    cred->data_type = PJSIP_CRED_DATA_PLAIN_PASSWD;
+    pj_strdup2(_pool, &cred->data, password.data());
+    pj_strdup2(_pool, &cred->realm, "*");
+    pj_strdup2(_pool, &cred->scheme, "digest");
+    pjsip_regc_set_credentials(regc, 1, cred);
+
+    account->setCredInfo(cred);
+
+    status = pjsip_regc_register(regc, PJ_TRUE, &tdata);
+    if (status != PJ_SUCCESS) {
+        _debug("UserAgent: Unable to register regc.\n");
+        _mutexSIP.leaveMutex(); 
+        return false;
+    }
+
+    status = pjsip_regc_send(regc, tdata);
+    if (status != PJ_SUCCESS) {
+        _debug("UserAgent: Unable to send regc request.\n");
+        _mutexSIP.leaveMutex(); 
+        return false;
+    }
+
+    _mutexSIP.leaveMutex(); 
+
+    account->setRegistrationInfo(regc);
+
+    return true;
 }
 
-int
-SIPVoIPLink::sendUnregister()
+    int 
+SIPVoIPLink::sendUnregister( AccountID id )
 {
-  _debug("SEND UNREGISTER for account %s\n" , getAccountID().c_str());
-
-  if(!_bRegister){
-      setRegistrationState(VoIPLink::Unregistered); 
-      return true;
-  }
-  
-  _bRegister = false;
-  
-  Manager::instance().getUserAgent()->removeAccount(_regc);
-  
-  return true;
+    pj_status_t status = 0;
+    pjsip_tx_data *tdata = NULL;
+    SIPAccount *account;
+    pjsip_regc *regc;
+
+    account = dynamic_cast<SIPAccount *> (Manager::instance().getAccount(id));
+    regc = account->getRegistrationInfo();
+
+    if(!account->isRegister()){
+        account->setRegistrationState(Unregistered); 
+        return true;
+    }
+
+    if(regc) {
+        status = pjsip_regc_unregister(regc, &tdata);
+        if(status != PJ_SUCCESS) {
+            _debug("UserAgent: Unable to unregister regc.\n");
+            return false;
+        }
+
+        status = pjsip_regc_send( regc, tdata );
+        if(status != PJ_SUCCESS) {
+            _debug("UserAgent: Unable to send regc request.\n");
+            return false;
+        }
+    } else {
+        _debug("UserAgent: regc is null!\n");
+        return false;
+    }
+
+    account->setRegistrationInfo(regc);
+    account->setRegister(false);
+
+    return true;
 }
 
-Call* 
+    Call* 
 SIPVoIPLink::newOutgoingCall(const CallID& id, const std::string& toUrl)
 {
-  SIPCall* call = new SIPCall(id, Call::Outgoing);
-  if (call) {
-    //call->setPeerNumber(toUrl);
-    call->setPeerNumber(getSipTo(toUrl));
-    _debug("Try to make a call to: %s with call ID: %s\n", toUrl.data(), id.data());
-    // we have to add the codec before using it in SIPOutgoingInvite...
-    call->setCodecMap(Manager::instance().getCodecDescriptorMap());
-    if ( SIPOutgoingInvite(call) ) {
-      call->setConnectionState(Call::Progressing);
-      call->setState(Call::Active);
-      addCall(call);
-    } else {
-      delete call; call = 0;
+    Account* account;
+
+    SIPCall* call = new SIPCall(id, Call::Outgoing);
+
+    if (call) {
+        account = dynamic_cast<SIPAccount *>(Manager::instance().getAccount(Manager::instance().getAccountFromCall(id)));
+        if(!account)
+        {
+            _debug("Error retrieving the account to the make the call with\n");
+            call->setConnectionState(Call::Disconnected);
+            call->setState(Call::Error);
+            delete call; call=0;
+            return call;
+        }
+        //call->setPeerNumber(toUrl);
+        call->setPeerNumber(getSipTo(toUrl, account->getHostname()));
+        _debug("Try to make a call to: %s with call ID: %s\n", toUrl.data(), id.data());
+        // we have to add the codec before using it in SIPOutgoingInvite...
+        call->setCodecMap(Manager::instance().getCodecDescriptorMap());
+        if ( SIPOutgoingInvite(call) ) {
+            call->setConnectionState(Call::Progressing);
+            call->setState(Call::Active);
+            addCall(call);
+        } else {
+            delete call; call = 0;
+        }
     }
-  }
-  return call;
+    return call;
 }
 
-bool
+    bool
 SIPVoIPLink::answer(const CallID& id)
 {
-  _debug("- SIP Action: start answering\n");
 
-  SIPCall* call = getSIPCall(id);
-  if (call==0) {
-    _debug("! SIP Failure: SIPCall doesn't exists\n");
-    return false;
-  }
-
-  int i = Manager::instance().getUserAgent()->answer(call);
-  
-  if (i != 0) {
-    _debug("< SIP Building Error: send 400 Bad Request\n");
-  } else {
-    // use exosip, bug locked
-    i = 0;
-    _debug("* SIP Info: Starting AudioRTP when answering\n");
-    if (_audiortp->createNewSession(call) >= 0) {
-      call->setAudioStart(true);
-      call->setConnectionState(Call::Connected);
-      call->setState(Call::Active);
-      return true;
-    } else {
-      _debug("! SIP Failure: Unable to start sound when answering %s/%d\n", __FILE__, __LINE__);
+    int i;
+    SIPCall *call;
+    pj_status_t status;
+    pjsip_tx_data *tdata;
+
+    _debug("- SIP Action: start answering\n");
+
+    call = getSIPCall(id);
+
+    if (call==0) {
+        _debug("! SIP Failure: SIPCall doesn't exists\n");
+        return false;
     }
-  }
-  removeCall(call->getCallId());
-  return false;
+
+    // User answered the incoming call, tell peer this news
+    if (call->startNegociation(_pool)) {
+        // Create and send a 200(OK) response
+        _debug("UserAgent: Negociation success!\n");
+        status = pjsip_inv_answer(call->getInvSession(), PJSIP_SC_OK, NULL, NULL, &tdata);
+        PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
+        status = pjsip_inv_send_msg(call->getInvSession(), tdata);
+        PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
+
+        _debug("* SIP Info: Starting AudioRTP when answering\n");
+        if (_audiortp->createNewSession(call) >= 0) {
+            call->setAudioStart(true);
+            call->setConnectionState(Call::Connected);
+            call->setState(Call::Active);
+            return true;
+        } else {
+            _debug("! SIP Failure: Unable to start sound when answering %s/%d\n", __FILE__, __LINE__);
+        }
+    }
+    removeCall(call->getCallId());
+    return false;
 }
 
-bool
+    bool
 SIPVoIPLink::hangup(const CallID& id)
 {
-  SIPCall* call = getSIPCall(id);
-  if (call==0) { _debug("! SIP Error: Call doesn't exist\n"); return false; }  
-
-    Manager::instance().getUserAgent()->hangup(call);
-  
-  // Release RTP thread
-  if (Manager::instance().isCurrentCall(id)) {
-    _debug("* SIP Info: Stopping AudioRTP for hangup\n");
-    _audiortp->closeRtpSession();
-  }
-  removeCall(id);
-  return true;
+    pj_status_t status;
+    pjsip_tx_data *tdata = NULL;
+    SIPCall* call;
+
+    call = getSIPCall(id);
+
+    if (call==0) { _debug("! SIP Error: Call doesn't exist\n"); return false; }  
+
+    // User hangup current call. Notify peer
+    status = pjsip_inv_end_session(call->getInvSession(), 404, NULL, &tdata);
+    if(status != PJ_SUCCESS)
+        return false;
+
+    if(tdata == NULL)
+        return true;
+
+    status = pjsip_inv_send_msg(call->getInvSession(), tdata);
+    if(status != PJ_SUCCESS)
+        return false;
+
+    call->getInvSession()->mod_data[getModId()] = NULL;
+    return true;
+
+    // Release RTP thread
+    if (Manager::instance().isCurrentCall(id)) {
+        _debug("* SIP Info: Stopping AudioRTP for hangup\n");
+        _audiortp->closeRtpSession();
+    }
+
+    removeCall(id);
+
+    return true;
 }
 
-bool
+    bool
 SIPVoIPLink::cancel(const CallID& id)
 {
-  SIPCall* call = getSIPCall(id);
-  if (call==0) { _debug("! SIP Error: Call doesn't exist\n"); return false; }  
+    SIPCall* call = getSIPCall(id);
+    if (call==0) { _debug("! SIP Error: Call doesn't exist\n"); return false; }  
 
-  _debug("- SIP Action: Cancel call %s [cid: %3d]\n", id.data(), call->getCid()); 
+    _debug("- SIP Action: Cancel call %s [cid: %3d]\n", id.data(), call->getCid()); 
 
-  removeCall(id);
+    removeCall(id);
 
-  return true;
+    return true;
 }
 
-bool
+    bool
 SIPVoIPLink::onhold(const CallID& id)
 {
-  SIPCall* call = getSIPCall(id);
-  if (call==0) { _debug("! SIP Error: call doesn't exist\n"); return false; }  
 
+    pj_status_t status;
+    pjsip_tx_data *tdata;
+    pjmedia_sdp_attr *attr;
+    pjmedia_sdp_session* local_sdp;
+    SIPCall* call;
+
+    call = getSIPCall(id);
+
+    if (call==0) { _debug("! SIP Error: call doesn't exist\n"); return false; }  
+
+
+    // Stop sound
+    call->setAudioStart(false);
+    call->setState(Call::Hold);
+    _debug("* SIP Info: Stopping AudioRTP for onhold action\n");
+    //_mutexSIP.enterMutex();
+        _audiortp->closeRtpSession();
+    //_mutexSIP.leaveMutex();
+    
+    local_sdp = call->getLocalSDPSession();
+
+    if( local_sdp == NULL ){
+        _debug("! SIP Failure: unable to find local_sdp\n");
+        return false;
+    }
 
-  // Stop sound
-  call->setAudioStart(false);
-  call->setState(Call::Hold);
-  _debug("* SIP Info: Stopping AudioRTP for onhold action\n");
-  _audiortp->closeRtpSession();
+    /* Create re-INVITE with new offer */
+    // Remove all the attributes with the specified name
+    pjmedia_sdp_media_remove_all_attr(local_sdp->media[0], "sendrecv");
+    attr = pjmedia_sdp_attr_create(_pool, "sendonly", NULL);
+    pjmedia_sdp_media_add_attr(local_sdp->media[0], attr);
 
-  return Manager::instance().getUserAgent()->onhold(call);
+    status = pjsip_inv_reinvite( call->getInvSession(), NULL, local_sdp, &tdata);
+    if( status != PJ_SUCCESS )
+    {
+        _debug("On hold: creation of the Re-invite request failed\n");
+        return false;
+    }
+    /* Send the request */
+    status = pjsip_inv_send_msg( call->getInvSession(), tdata);
+
+    return (status == PJ_SUCCESS);
 }
 
-bool 
+    bool 
 SIPVoIPLink::offhold(const CallID& id)
 {
     SIPCall *call;
+    pj_status_t status;
+    pjsip_tx_data *tdata;
+    pjmedia_sdp_attr *attr;
+    pjmedia_sdp_session* local_sdp;
 
     call = getSIPCall(id);
+
     if (call==0) { 
         _debug("! SIP Error: Call doesn't exist\n"); 
         return false; 
     }
 
-    if(!Manager::instance().getUserAgent()->offhold(call))
+    local_sdp = call->getLocalSDPSession();
+    if( local_sdp == NULL ){
+        _debug("! SIP Failure: unable to find local_sdp\n");
+        return false;
+    }
+
+    /* Create re-INVITE with new offer */
+    // Remove all the attributes with the specified name
+    pjmedia_sdp_media_remove_all_attr(local_sdp->media[0], "sendonly");
+    attr = pjmedia_sdp_attr_create(_pool, "sendrecv", NULL);
+    pjmedia_sdp_media_add_attr(local_sdp->media[0], attr);
+
+    status = pjsip_inv_reinvite( call->getInvSession(), NULL, local_sdp , &tdata);
+    if( status != PJ_SUCCESS )
+    {
+        _debug("Off hold: creation of the Re-invite request failed\n");
+        return false;
+    }
+
+    /* Send the request */
+    status = pjsip_inv_send_msg( call->getInvSession(), tdata);
+    if( status != PJ_SUCCESS )
         return false;
 
     // Enable audio
@@ -284,17 +599,28 @@ SIPVoIPLink::offhold(const CallID& id)
         _debug("! SIP Failure: Unable to start sound (%s:%d)\n", __FILE__, __LINE__);
         return false;
     }
-    
+
     return true;
 }
 
-bool 
+    bool 
 SIPVoIPLink::transfer(const CallID& id, const std::string& to)
 {
     SIPCall *call;
     std::string tmp_to;
+    pjsip_evsub *sub;
+    pjsip_tx_data *tdata;
+    struct pjsip_evsub_user xfer_cb;
+    pj_status_t status;
+    pj_str_t dest;
+    AccountID account_id;
+    Account* account;
+
 
     call = getSIPCall(id);
+    account_id = Manager::instance().getAccountFromCall(id);
+    account = dynamic_cast<SIPAccount *>(Manager::instance().getAccount(account_id));
+
     if (call==0) { 
         _debug("! SIP Failure: Call doesn't exist\n"); 
         return false; 
@@ -302,16 +628,48 @@ SIPVoIPLink::transfer(const CallID& id, const std::string& to)
 
     tmp_to = SIPToHeader(to);
     if (tmp_to.find("@") == std::string::npos) {
-        tmp_to = tmp_to + "@" + getHostname();
+        tmp_to = tmp_to + "@" + account->getHostname();
     }
 
     _debug("In transfer, tmp_to is %s\n", tmp_to.data());
 
-    return Manager::instance().getUserAgent()->transfer(call, tmp_to);
+    pj_strdup2(_pool, &dest, to.data());
+
+    /* Create xfer client subscription. */
+    pj_bzero(&xfer_cb, sizeof(xfer_cb));
+    xfer_cb.on_evsub_state = &xfer_func_cb;
+
+    status = pjsip_xfer_create_uac(call->getInvSession()->dlg, &xfer_cb, &sub);
+    if (status != PJ_SUCCESS) {
+        _debug("UserAgent: Unable to create xfer -- %d\n", status);
+        return false;
+    }
+
+    /* Associate this voiplink of call with the client subscription 
+     * We can not just associate call with the client subscription
+     * because after this function, we can not find the cooresponding
+     * voiplink from the call any more. But the voiplink is useful!
+     */
+    AccountID accId = Manager::instance().getAccountFromCall(call->getCallId());
+    pjsip_evsub_set_mod_data(sub, getModId(), this);
+
+    /*
+     * Create REFER request.
+     */
+    status = pjsip_xfer_initiate(sub, &dest, &tdata);
+    if (status != PJ_SUCCESS) {
+        _debug("UserAgent: Unable to create REFER request -- %d\n", status);
+        return false;
+    }
+
+    /* Send. */
+    status = pjsip_xfer_send_request(sub, tdata);
+    if (status != PJ_SUCCESS) {
+        _debug("UserAgent: Unable to send REFER request -- %d\n", status);
+        return false;
+    }
 
-  //_audiortp->closeRtpSession();
-  // shall we delete the call?
-  //removeCall(id);
+    return true;
 }
 
 bool SIPVoIPLink::transferStep2()
@@ -320,10 +678,13 @@ bool SIPVoIPLink::transferStep2()
     return true;
 }
 
-bool
+    bool
 SIPVoIPLink::refuse (const CallID& id)
 {
     SIPCall *call;
+    pj_status_t status;
+    pjsip_tx_data *tdata;
+
 
     call = getSIPCall(id);
 
@@ -338,10 +699,20 @@ SIPVoIPLink::refuse (const CallID& id)
         return false; 
     }
 
-    return Manager::instance().getUserAgent()->refuse(call);
+    // User refuse current call. Notify peer
+    status = pjsip_inv_end_session(call->getInvSession(), PJSIP_SC_DECLINE, NULL, &tdata); //603
+    if(status != PJ_SUCCESS)
+        return false;
+
+    status = pjsip_inv_send_msg(call->getInvSession(), tdata);
+    if(status != PJ_SUCCESS)
+        return false;
+
+    call->getInvSession()->mod_data[getModId()] = NULL;
+    return true;
 }
 
-bool 
+    bool 
 SIPVoIPLink::carryingDTMFdigits(const CallID& id, char code)
 {
 
@@ -349,8 +720,14 @@ SIPVoIPLink::carryingDTMFdigits(const CallID& id, char code)
     int duration;
     const int body_len = 1000;
     char *dtmf_body;
+    pj_status_t status;
+    pjsip_tx_data *tdata;
+    pj_str_t methodName, content;
+    pjsip_method method;
+    pjsip_media_type ctype;
 
     call = getSIPCall(id);
+
     if (call==0) { 
         _debug("Call doesn't exist\n"); 
         return false; 
@@ -358,210 +735,1431 @@ SIPVoIPLink::carryingDTMFdigits(const CallID& id, char code)
 
     duration = Manager::instance().getConfigInt(SIGNALISATION, PULSE_LENGTH);
     dtmf_body = new char[body_len];
- 
+
     snprintf(dtmf_body, body_len - 1, "Signal=%c\r\nDuration=%d\r\n", code, duration);
- 
-    return Manager::instance().getUserAgent()->carryingDTMFdigits(call, dtmf_body);
+
+    pj_strdup2(_pool, &methodName, "INFO");
+    pjsip_method_init_np(&method, &methodName);
+
+    /* Create request message. */
+    status = pjsip_dlg_create_request( call->getInvSession()->dlg, &method, -1, &tdata);
+    if (status != PJ_SUCCESS) {
+        _debug("UserAgent: Unable to create INFO request -- %d\n", status);
+        return false;
+    }
+
+    /* Get MIME type */
+    pj_strdup2(_pool, &ctype.type, "application");
+    pj_strdup2(_pool, &ctype.subtype, "dtmf-relay");
+
+    /* Create "application/dtmf-relay" message body. */
+    pj_strdup2(_pool, &content, dtmf_body);
+    tdata->msg->body = pjsip_msg_body_create( tdata->pool, &ctype.type, &ctype.subtype, &content);
+    if (tdata->msg->body == NULL) {
+        _debug("UserAgent: Unable to create msg body!\n");
+        pjsip_tx_data_dec_ref(tdata);
+        return false;
+    }
+
+    /* Send the request. */
+    status = pjsip_dlg_send_request( call->getInvSession()->dlg, tdata, getModId(), NULL);
+    if (status != PJ_SUCCESS) {
+        _debug("UserAgent: Unable to send MESSAGE request -- %d\n", status);
+        return false;
+    }
+
+    return true;
 }
 
-bool
+    bool
 SIPVoIPLink::SIPOutgoingInvite(SIPCall* call) 
 {
-  // If no SIP proxy setting for direct call with only IP address
-  if (!SIPStartCall(call, "")) {
-    _debug("! SIP Failure: call not started\n");
-    return false;
-  }
-  return true;
+    // If no SIP proxy setting for direct call with only IP address
+    if (!SIPStartCall(call, "")) {
+        _debug("! SIP Failure: call not started\n");
+        return false;
+    }
+    return true;
 }
 
-bool
+    bool
 SIPVoIPLink::SIPStartCall(SIPCall* call, const std::string& subject UNUSED) 
 {
-    std::string to;
+    std::string strTo, strFrom;
+    pj_status_t status;
+    pjsip_dialog *dialog;
+    pjsip_tx_data *tdata;
+    pj_str_t from, to, contact;
+    AccountID id;
+    SIPAccount *account;
 
     if (!call) 
         return false;
 
-    to = getSipTo(call->getPeerNumber());
-    _debug("            To: %s\n", to.data());
+    id = Manager::instance().getAccountFromCall(call->getCallId());
+    // Get the basic information about the callee account
+    account = dynamic_cast<SIPAccount *>(Manager::instance().getAccount(id));
 
-    return Manager::instance().getUserAgent()->makeOutgoingCall(to, call, getAccountID());
-}
+    strTo = getSipTo(call->getPeerNumber(), account->getHostname());
+    _debug("            To: %s\n", strTo.data());
+
+    // Generate the from URI
+    strFrom = "sip:" + account->getUsername() + "@" + account->getHostname();
+
+    // pjsip need the from and to information in pj_str_t format
+    pj_strdup2(_pool, &from, strFrom.data());
+    pj_strdup2(_pool, &to, strTo.data());
+    pj_strdup2(_pool, &contact, account->getContact().data());
+
+    // create the dialog (UAC)
+    status = pjsip_dlg_create_uac(pjsip_ua_instance(), &from,
+            &contact,
+            &to,
+            NULL,
+            &dialog);
+    PJ_ASSERT_RETURN(status == PJ_SUCCESS, false);
+
+    setCallAudioLocal(call, getLocalIPAddress(), useStun(), getStunServer());
+    call->setIp(getLocalIP());
+
+    // Building the local SDP offer
+    call->createInitialOffer(_pool);
+
+    // Create the invite session for this call
+    pjsip_inv_session *inv;
+    status = pjsip_inv_create_uac(dialog, call->getLocalSDPSession(), 0, &inv);
+    PJ_ASSERT_RETURN(status == PJ_SUCCESS, false);
 
-std::string
-SIPVoIPLink::getSipFrom() {
+    // Set auth information
+    pjsip_auth_clt_set_credentials(&dialog->auth_sess, 1, account->getCredInfo());
 
-  // Form the From header field basis on configuration panel
-  std::string hostname;
-  
-  hostname = getHostname();
+    // Associate current call in the invite session
+    inv->mod_data[getModId()] = call;
 
-  if ( hostname.empty() ) {
-    hostname = _localIPAddress;
-  }
-  return SIPFromHeader(getUsername(), hostname);
+    status = pjsip_inv_invite(inv, &tdata);
+    PJ_ASSERT_RETURN(status == PJ_SUCCESS, false);
+
+    // Associate current invite session in the call
+    call->setInvSession(inv);
+
+    status = pjsip_inv_send_msg(inv, tdata);
+    if(status != PJ_SUCCESS) {
+        return false;
+    }
+
+    return true;
 }
 
-std::string
-SIPVoIPLink::getSipTo(const std::string& to_url) {
-  // Form the From header field basis on configuration panel
-  //bool isRegistered = (_eXosipRegID == EXOSIP_ERROR_STD) ? false : true;
+std::string SIPVoIPLink::getSipTo(const std::string& to_url, std::string hostname) {
+    // Form the From header field basis on configuration panel
+    //bool isRegistered = (_eXosipRegID == EXOSIP_ERROR_STD) ? false : true;
 
-  // add a @host if we are registered and there is no one inside the url
+    // add a @host if we are registered and there is no one inside the url
     if (to_url.find("@") == std::string::npos) {// && isRegistered) {
-    std::string host = getHostname();
-    if(!host.empty()) {
-      return SIPToHeader(to_url + "@" + host);
+        if(!hostname.empty()) {
+            return SIPToHeader(to_url + "@" + hostname);
+        }
+    }
+    return SIPToHeader(to_url);
     }
-  }
-  return SIPToHeader(to_url);
-}
 
-std::string
-SIPVoIPLink::SIPToHeader(const std::string& to) 
-{
-  if (to.find("sip:") == std::string::npos) {
-    return ("sip:" + to );
-  } else {
-    return to;
-  }
-}
+    std::string SIPVoIPLink::SIPToHeader(const std::string& to) 
+    {
+        if (to.find("sip:") == std::string::npos) {
+            return ("sip:" + to );
+        } else {
+            return to;
+        }
+    }
 
-bool
-SIPVoIPLink::SIPCheckUrl(const std::string& url UNUSED)
-{
-  return true;
-}
+    bool
+        SIPVoIPLink::SIPCheckUrl(const std::string& url UNUSED)
+        {
+            return true;
+        }
+
+    bool setCallAudioLocal(SIPCall* call, std::string localIP, bool stun, std::string server) 
+    {
+        // Setting Audio
+        unsigned int callLocalAudioPort = RANDOM_LOCAL_PORT;
+        unsigned int callLocalExternAudioPort = callLocalAudioPort;
+        if (stun) {
+            // If use Stun server
+            if (Manager::instance().behindNat(server, callLocalAudioPort)) {
+                callLocalExternAudioPort = Manager::instance().getFirewallPort();
+            }
+        }
+        _debug("            Setting local audio port to: %d\n", callLocalAudioPort);
+        _debug("            Setting local audio port (external) to: %d\n", callLocalExternAudioPort);
+
+        // Set local audio port for SIPCall(id)
+        call->setLocalIp(localIP);
+        call->setLocalAudioPort(callLocalAudioPort);
+        call->setLocalExternAudioPort(callLocalExternAudioPort);
+
+        return true;
+    }
 
-bool
-SIPVoIPLink::setCallAudioLocal(SIPCall* call) 
-{
-  // Setting Audio
-  unsigned int callLocalAudioPort = RANDOM_LOCAL_PORT;
-  unsigned int callLocalExternAudioPort = callLocalAudioPort;
-  if (_useStun) {
-    // If use Stun server
-    if (Manager::instance().behindNat(_stunServer, callLocalAudioPort)) {
-      callLocalExternAudioPort = Manager::instance().getFirewallPort();
-    }
-  }
-  _debug("            Setting local audio port to: %d\n", callLocalAudioPort);
-  _debug("            Setting local audio port (external) to: %d\n", callLocalExternAudioPort);
-  
-  // Set local audio port for SIPCall(id)
-  call->setLocalIp(_localIPAddress);
-  call->setLocalAudioPort(callLocalAudioPort);
-  call->setLocalExternAudioPort(callLocalExternAudioPort);
-
-  return true;
-}
+    void
+        SIPVoIPLink::SIPCallServerFailure(SIPCall *call) 
+        {
+            //if (!event->response) { return; }
+            //switch(event->response->status_code) {
+            //case SIP_SERVICE_UNAVAILABLE: // 500
+            //case SIP_BUSY_EVRYWHERE:     // 600
+            //case SIP_DECLINE:             // 603
+            //SIPCall* call = findSIPCallWithCid(event->cid);
+            if (call != 0) {
+                _debug("Server error!\n");
+                CallID id = call->getCallId();
+                Manager::instance().callFailure(id);
+                removeCall(id);
+            }
+            //break;
+            //}
+        }
+
+    void
+        SIPVoIPLink::SIPCallClosed(SIPCall *call) 
+        {
+            // it was without did before
+            //SIPCall* call = findSIPCallWithCid(event->cid);
+            if (!call) { return; }
+
+            CallID id = call->getCallId();
+            //call->setDid(event->did);
+            if (Manager::instance().isCurrentCall(id)) {
+                call->setAudioStart(false);
+                _debug("* SIP Info: Stopping AudioRTP when closing\n");
+                _audiortp->closeRtpSession();
+            }
+            _debug("After close RTP\n");
+            Manager::instance().peerHungupCall(id);
+            removeCall(id);
+            _debug("After remove call ID\n");
+        }
+
+    void
+        SIPVoIPLink::SIPCallReleased(SIPCall *call)
+        {
+            // do cleanup if exists
+            // only cid because did is always 0 in these case..
+            //SIPCall* call = findSIPCallWithCid(event->cid);
+            if (!call) { return; }
+
+            // if we are here.. something when wrong before...
+            _debug("SIP call release\n");
+            CallID id = call->getCallId();
+            Manager::instance().callFailure(id);
+            removeCall(id);
+        }
+
+    void
+        SIPVoIPLink::SIPCallAnswered(SIPCall *call, pjsip_rx_data *rdata)
+        {
+            //SIPCall* call = dynamic_cast<SIPCall *>(theCall);//findSIPCallWithCid(event->cid);
+            if (!call) {
+                _debug("! SIP Failure: unknown call\n");
+                return;
+            }
+            //call->setDid(event->did);
+
+            if (call->getConnectionState() != Call::Connected) {
+                //call->SIPCallAnswered(event);
+                call->SIPCallAnsweredWithoutHold(rdata);
+
+                call->setConnectionState(Call::Connected);
+                call->setState(Call::Active);
+
+                Manager::instance().peerAnsweredCall(call->getCallId());
+                if (Manager::instance().isCurrentCall(call->getCallId())) {
+                    _debug("* SIP Info: Starting AudioRTP when answering\n");
+                    if ( _audiortp->createNewSession(call) < 0) {
+                        _debug("RTP Failure: unable to create new session\n");
+                    } else {
+                        call->setAudioStart(true);
+                    }
+                }
+            } else {
+                _debug("* SIP Info: Answering call (on/off hold to send ACK)\n");
+                //call->SIPCallAnswered(event);
+            }
+        }
+
+
+    SIPCall*
+        SIPVoIPLink::getSIPCall(const CallID& id) 
+        {
+            Call* call = getCall(id);
+            if (call) {
+                return dynamic_cast<SIPCall*>(call);
+            }
+            return NULL;
+        }
+
+    void SIPVoIPLink::setStunServer( const std::string &server )
+    {
+         if(server != "") {
+            useStun(true);
+            _stunServer = server;
+        } else {
+            useStun(false);
+            _stunServer = std::string("");
+        }
+    }
 
-void
-SIPVoIPLink::SIPCallServerFailure(SIPCall *call) 
-{
-  //if (!event->response) { return; }
-  //switch(event->response->status_code) {
-  //case SIP_SERVICE_UNAVAILABLE: // 500
-  //case SIP_BUSY_EVRYWHERE:     // 600
-  //case SIP_DECLINE:             // 603
-    //SIPCall* call = findSIPCallWithCid(event->cid);
-    if (call != 0) {
-        _debug("Server error!\n");
-        CallID id = call->getCallId();
-        Manager::instance().callFailure(id);
-        removeCall(id);
-    }
-  //break;
-  //}
-}
+    ///////////////////////////////////////////////////////////////////////////////
+    // Private functions
+    ///////////////////////////////////////////////////////////////////////////////
+
+    bool SIPVoIPLink::pjsip_init()
+    {
+        pj_status_t status;
+        int errPjsip = 0;
+        int port;
+        pjsip_inv_callback inv_cb;
+        pj_str_t accepted;
+        std::string name_mod;
+        bool useStun;
+        validStunServer = true;
+
+        name_mod = "sflphone";
+
+        // Init PJLIB: must be called before any call to the pjsip library
+        status = pj_init();
+        // Use pjsip macros for sanity check
+        PJ_ASSERT_RETURN( status == PJ_SUCCESS, 1 );
+
+        // Init PJLIB-UTIL library 
+        status = pjlib_util_init();
+        PJ_ASSERT_RETURN( status == PJ_SUCCESS, 1 );
+
+        // Set the pjsip log level
+        pj_log_set_level( PJ_LOG_LEVEL );
+
+        // Init PJNATH 
+        status = pjnath_init();
+        PJ_ASSERT_RETURN( status == PJ_SUCCESS, 1 );
+
+        // Create a pool factory to allocate memory
+        pj_caching_pool_init(&_cp, &pj_pool_factory_default_policy, 0);
+
+        // Create memory pool for application. 
+        _pool = pj_pool_create(&_cp.factory, "sflphone", 4000, 4000, NULL);
+
+        if (!_pool) {
+            _debug("UserAgent: Could not initialize memory pool\n");
+            return PJ_ENOMEM;
+        }
+
+        // Create the SIP endpoint 
+        status = pjsip_endpt_create(&_cp.factory, pj_gethostname()->ptr, &_endpt);
+        PJ_ASSERT_RETURN( status == PJ_SUCCESS, 1 );
+
+        /* Start resolving STUN server */
+        // if we useStun and we failed to receive something on port 5060, we try a random port
+        // If use STUN server, firewall address setup
+        if (!loadSIPLocalIP()) {
+            _debug("UserAgent: Unable to determine network capabilities\n");
+            return false;
+        }
+
+        port = _regPort;
+
+        /* Retrieve the STUN configuration */
+        useStun = Manager::instance().getConfigInt( SIGNALISATION, SIP_USE_STUN );
+        this->setStunServer(Manager::instance().getConfigString( SIGNALISATION, SIP_STUN_SERVER ));
+        this->useStun( useStun!=0 ? true : false);
+
+        if (useStun && !Manager::instance().behindNat(getStunServer(), port)) {
+            port = RANDOM_SIP_PORT;
+            if (!Manager::instance().behindNat(getStunServer(), port)) {
+                _debug("UserAgent: Unable to check NAT setting\n");
+                validStunServer = false;		
+                return false; // hoho we can't use the random sip port too...
+            }
+        }
+
+        _localPort = port;
+        if (useStun) {
+            // set by last behindNat() call (ish)...
+            stunServerResolve();
+            _localExternAddress = Manager::instance().getFirewallAddress();
+            _localExternPort = Manager::instance().getFirewallPort();
+            errPjsip = createUDPServer();
+            if (errPjsip != 0) {
+                _debug("UserAgent: Could not initialize SIP listener on port %d\n", port);
+                return errPjsip;
+            }
+        } else {
+            _localExternAddress = _localIPAddress;
+            _localExternPort = _localPort;
+            errPjsip = createUDPServer();
+            if (errPjsip != 0) {
+                _debug("UserAgent: Could not initialize SIP listener on port %d\n", _localExternPort);
+                _localExternPort = _localPort = RANDOM_SIP_PORT;
+                _debug("UserAgent: Try to initialize SIP listener on port %d\n", _localExternPort);
+                errPjsip = createUDPServer();
+                if (errPjsip != 0) {
+                    _debug("UserAgent: Fail to initialize SIP listener on port %d\n", _localExternPort);
+                    return errPjsip;
+                }
+            }
+        }
+
+        _debug("UserAgent: SIP Init -- listening on port %d\n", _localExternPort);
+
+        // Initialize transaction layer
+        status = pjsip_tsx_layer_init_module(_endpt);
+        PJ_ASSERT_RETURN( status == PJ_SUCCESS, 1 );
+
+        // Initialize UA layer module
+        status = pjsip_ua_init_module(_endpt, NULL);
+        PJ_ASSERT_RETURN( status == PJ_SUCCESS, 1 );
+
+        // Initialize Replaces support. See the Replaces specification in RFC 3891
+        status = pjsip_replaces_init_module(_endpt);
+        PJ_ASSERT_RETURN( status == PJ_SUCCESS, 1 );
+
+        // Initialize 100rel support 
+        status = pjsip_100rel_init_module(_endpt);
+        PJ_ASSERT_RETURN( status == PJ_SUCCESS, 1 );
+
+        // Initialize and register sflphone module
+        _mod_ua.name = pj_str((char*)name_mod.c_str());
+        _mod_ua.id = -1;
+        _mod_ua.priority = PJSIP_MOD_PRIORITY_APPLICATION;
+        _mod_ua.on_rx_request = &mod_on_rx_request;
+        _mod_ua.on_rx_response = &mod_on_rx_response;
+
+        status = pjsip_endpt_register_module(_endpt, &_mod_ua);
+        PJ_ASSERT_RETURN( status == PJ_SUCCESS, 1 );
+
+        // Init the event subscription module.
+        // It extends PJSIP by supporting SUBSCRIBE and NOTIFY methods
+        status = pjsip_evsub_init_module(_endpt);
+        PJ_ASSERT_RETURN( status == PJ_SUCCESS, 1 );
+
+        // Init xfer/REFER module
+        status = pjsip_xfer_init_module(_endpt);
+        PJ_ASSERT_RETURN( status == PJ_SUCCESS, 1 );
+
+        // Init the callback for INVITE session: 
+        pj_bzero(&inv_cb, sizeof (inv_cb));
+
+        inv_cb.on_state_changed = &call_on_state_changed;
+        inv_cb.on_new_session = &call_on_forked;
+        inv_cb.on_media_update = &call_on_media_update;
+        inv_cb.on_tsx_state_changed = &call_on_tsx_changed;
+
+        // Initialize session invite module 
+        status = pjsip_inv_usage_init(_endpt, &inv_cb);
+        PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
+
+        _debug("UserAgent: VOIP callbacks initialized\n");
+
+        // Add endpoint capabilities (INFO, OPTIONS, etc) for this UA
+        pj_str_t allowed[] = { {(char*)"INFO", 4}, {(char*)"REGISTER", 8} }; //  //{"INVITE", 6}, {"ACK",3}, {"BYE",3}, {"CANCEL",6},  {"OPTIONS", 7}, 
+        accepted = pj_str((char*)"application/sdp");
+
+        // Register supported methods
+        pjsip_endpt_add_capability(_endpt, &_mod_ua, PJSIP_H_ALLOW, NULL, PJ_ARRAY_SIZE(allowed), allowed);
+
+        // Register "application/sdp" in ACCEPT header
+        pjsip_endpt_add_capability(_endpt, &_mod_ua, PJSIP_H_ACCEPT, NULL, 1, &accepted);
+
+        _debug("UserAgent: pjsip version %s for %s initialized\n", pj_get_version(), PJ_OS_NAME);
+
+        // Create the secondary thread to poll sip events
+        _evThread->start();
+
+        /* Done! */
+        return PJ_SUCCESS;
+    }
 
-void
-SIPVoIPLink::SIPCallClosed(SIPCall *call) 
-{
-  // it was without did before
-  //SIPCall* call = findSIPCallWithCid(event->cid);
-  if (!call) { return; }
+    pj_status_t SIPVoIPLink::stunServerResolve( void )
+    {
+        pj_str_t stun_adr;
+        pj_hostent he;
+        pj_stun_config stunCfg;
+        pj_status_t stun_status;
+        pj_sockaddr stun_srv;
+        size_t pos;
+        std::string serverName, serverPort;
+        int nPort;
+        std::string stun_server;
+
+        stun_server = getStunServer();
+
+        // Initialize STUN configuration
+        pj_stun_config_init(&stunCfg, &_cp.factory, 0, pjsip_endpt_get_ioqueue(_endpt), pjsip_endpt_get_timer_heap(_endpt));
+
+        stun_status = PJ_EPENDING;
+
+        // Init STUN socket
+        pos = stun_server.find(':');
+        if(pos == std::string::npos) {
+            pj_strdup2(_pool, &stun_adr, stun_server.data());
+            stun_status = pj_sockaddr_in_init(&stun_srv.ipv4, &stun_adr, (pj_uint16_t) 3478);
+        } else {
+            serverName = stun_server.substr(0, pos);
+            serverPort = stun_server.substr(pos + 1);
+            nPort = atoi(serverPort.data());
+            pj_strdup2(_pool, &stun_adr, serverName.data());
+            stun_status = pj_sockaddr_in_init(&stun_srv.ipv4, &stun_adr, (pj_uint16_t) nPort);
+        }
+
+        if (stun_status != PJ_SUCCESS) {
+            _debug("UserAgent: Unresolved stun server!\n");
+            stun_status = pj_gethostbyname(&stun_adr, &he);
+
+            if (stun_status == PJ_SUCCESS) {
+                pj_sockaddr_in_init(&stun_srv.ipv4, NULL, 0);
+                stun_srv.ipv4.sin_addr = *(pj_in_addr*) he.h_addr;
+                stun_srv.ipv4.sin_port = pj_htons((pj_uint16_t) 3478);
+            }
+        }
+
+        return stun_status;
+    }
 
-  CallID id = call->getCallId();
-  //call->setDid(event->did);
-  if (Manager::instance().isCurrentCall(id)) {
-    call->setAudioStart(false);
-    _debug("* SIP Info: Stopping AudioRTP when closing\n");
-    _audiortp->closeRtpSession();
-  }
-  _debug("After close RTP\n");
-  Manager::instance().peerHungupCall(id);
-  removeCall(id);
-  _debug("After remove call ID\n");
-}
+    int SIPVoIPLink::createUDPServer( void ) 
+    {
+
+        pj_status_t status;
+        pj_sockaddr_in bound_addr;
+        pjsip_host_port a_name;
+        char tmpIP[32];
+        pj_sock_t sock;
+
+        // Init bound address to ANY
+        pj_memset(&bound_addr, 0, sizeof (bound_addr));
+        bound_addr.sin_addr.s_addr = PJ_INADDR_ANY;
+
+        // Create UDP server socket
+        status = pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, &sock);
+        if (status != PJ_SUCCESS) {
+            _debug("UserAgent: (%d) UDP socket() error\n", status);
+            return status;
+        }
+
+        status = pj_sock_bind_in(sock, pj_ntohl(bound_addr.sin_addr.s_addr), (pj_uint16_t) _localPort);
+        if (status != PJ_SUCCESS) {
+            _debug("UserAgent: (%d) UDP bind() error\n", status);
+            pj_sock_close(sock);
+            return status;
+        }
+
+        _debug("UserAgent: Use IP: %s\n", _localExternAddress.data());
+
+        // Create UDP-Server (default port: 5060)
+        strcpy(tmpIP, _localExternAddress.data());
+        pj_strdup2(_pool, &a_name.host, tmpIP);
+        a_name.port = (pj_uint16_t) _localExternPort;
+
+        _debug("a_name: host: %s  - port : %i\n", a_name.host.ptr, a_name.port);
+
+        status = pjsip_udp_transport_attach(_endpt, sock, &a_name, 1, NULL);
+        if (status != PJ_SUCCESS) {
+            _debug("UserAgent: (%d) Unable to start UDP transport!\n", status);
+            return -1;
+        } else {
+            _debug("UserAgent: UDP server listening on port %d\n", _localExternPort);
+        }
+
+        return PJ_SUCCESS;
+    }
 
-void
-SIPVoIPLink::SIPCallReleased(SIPCall *call)
-{
-  // do cleanup if exists
-  // only cid because did is always 0 in these case..
-  //SIPCall* call = findSIPCallWithCid(event->cid);
-  if (!call) { return; }
-
-  // if we are here.. something when wrong before...
-  _debug("SIP call release\n");
-  CallID id = call->getCallId();
-  Manager::instance().callFailure(id);
-  removeCall(id);
-}
+    bool SIPVoIPLink::loadSIPLocalIP() {
+
+        bool returnValue = true;
+
+        if (_localIPAddress == "127.0.0.1") {
+            pj_sockaddr ip_addr;
+            if (pj_gethostip(pj_AF_INET(), &ip_addr) != PJ_SUCCESS) {
+                // Update the registration state if no network capabilities found
+                _debug("UserAgent: Get host ip failed!\n");
+                returnValue = false;
+            } else {
+                _localIPAddress = std::string(pj_inet_ntoa(ip_addr.ipv4.sin_addr));
+                _debug("UserAgent: Checking network, setting local IP address to: %s\n", _localIPAddress.data());
+            }
+        }
+        return returnValue;
+    }
 
-void
-SIPVoIPLink::SIPCallAnswered(SIPCall *call, pjsip_rx_data *rdata)
-{
-  //SIPCall* call = dynamic_cast<SIPCall *>(theCall);//findSIPCallWithCid(event->cid);
-  if (!call) {
-    _debug("! SIP Failure: unknown call\n");
-    return;
-  }
-  //call->setDid(event->did);
-
-  if (call->getConnectionState() != Call::Connected) {
-    //call->SIPCallAnswered(event);
-    call->SIPCallAnsweredWithoutHold(rdata);
-
-    call->setConnectionState(Call::Connected);
-    call->setState(Call::Active);
+    bool SIPVoIPLink::pjsip_shutdown( void )
+    {
+        /* Destroy endpoint. */
+        if (_endpt) {
+            pjsip_endpt_destroy(_endpt);
+            _endpt = NULL;
+        }
+
+        /* Destroy pool and pool factory. */
+        if (_pool) {
+            pj_pool_release(_pool);
+            _pool = NULL;
+            pj_caching_pool_destroy(&_cp);
+        }
+
+        /* Shutdown PJLIB */
+        pj_shutdown();
+
+        /* Done. */    
+    }
 
-    Manager::instance().peerAnsweredCall(call->getCallId());
-    if (Manager::instance().isCurrentCall(call->getCallId())) {
-      _debug("* SIP Info: Starting AudioRTP when answering\n");
-      if ( _audiortp->createNewSession(call) < 0) {
-        _debug("RTP Failure: unable to create new session\n");
-      } else {
-        call->setAudioStart(true);
-      }
-    }
-  } else {
-     _debug("* SIP Info: Answering call (on/off hold to send ACK)\n");
-     //call->SIPCallAnswered(event);
-  }
-}
+    int SIPVoIPLink::getModId(){
+        return _mod_ua.id;
+    }
 
+    void set_voicemail_info( AccountID account, pjsip_msg_body *body ){
 
-SIPCall*
-SIPVoIPLink::getSIPCall(const CallID& id) 
-{
-  Call* call = getCall(id);
-  if (call) {
-    return dynamic_cast<SIPCall*>(call);
-  }
-  return NULL;
-}
+        int voicemail, pos_begin, pos_end;
+        std::string voice_str = "Voice-Message: ";
+        std::string delimiter = "/";
+        std::string msg_body, voicemail_str;
 
-///////////////////////////////////////////////////////////////////////////////
-// Private functions
-///////////////////////////////////////////////////////////////////////////////
+        _debug("UserAgent: checking the voice message!\n");
+        // The voicemail message is formated like that:
+        // Voice-Message: 1/0  . 1 is the number we want to retrieve in this case
 
-pj_str_t SIPVoIPLink::string2PJStr(const std::string &value)
-{
-    char tmp[256];
-    
-    strcpy(tmp, value.data());
-    return pj_str(tmp);
-}
+        // We get the notification body
+        msg_body = (char*)body->data;
+
+        // We need the position of the first character of the string voice_str
+        pos_begin = msg_body.find(voice_str); 
+        // We need the position of the delimiter
+        pos_end = msg_body.find(delimiter); 
+
+        // So our voicemail number between the both index
+        try {
+
+            voicemail_str = msg_body.substr(pos_begin + voice_str.length(), pos_end - ( pos_begin + voice_str.length()));
+            std::cout << "voicemail number : " << voicemail_str << std::endl;
+            voicemail = atoi( voicemail_str.c_str() );
+        }
+        catch( std::out_of_range& e ){
+            std::cerr << e.what() << std::endl;
+        }
+
+        // We need now to notify the manager 
+        if( voicemail != 0 )
+            Manager::instance().startVoiceMessageNotification(account, voicemail);
+    }
+
+    /*******************************/
+    /*   CALLBACKS IMPLEMENTATION  */
+    /*******************************/
+
+    void call_on_state_changed( pjsip_inv_session *inv, pjsip_event *e){
+
+        PJ_UNUSED_ARG(inv);
+
+        SIPCall *call = reinterpret_cast<SIPCall*> (inv->mod_data[_mod_ua.id]);
+        if(!call)
+            return;
+
+        /* If this is an outgoing INVITE that was created because of
+         * REFER/transfer, send NOTIFY to transferer.
+         */
+        if (call->getXferSub() && e->type==PJSIP_EVENT_TSX_STATE)  {
+            int st_code = -1;
+            pjsip_evsub_state ev_state = PJSIP_EVSUB_STATE_ACTIVE;
+
+            switch (call->getInvSession()->state) {
+                case PJSIP_INV_STATE_NULL:
+                case PJSIP_INV_STATE_CALLING:
+                    /* Do nothing */
+                    break;
+
+                case PJSIP_INV_STATE_EARLY:
+                case PJSIP_INV_STATE_CONNECTING:
+                    st_code = e->body.tsx_state.tsx->status_code;
+                    ev_state = PJSIP_EVSUB_STATE_ACTIVE;
+                    break;
+
+                case PJSIP_INV_STATE_CONFIRMED:
+                    /* When state is confirmed, send the final 200/OK and terminate
+                     * subscription.
+                     */
+                    st_code = e->body.tsx_state.tsx->status_code;
+                    ev_state = PJSIP_EVSUB_STATE_TERMINATED;
+                    break;
+
+                case PJSIP_INV_STATE_DISCONNECTED:
+                    st_code = e->body.tsx_state.tsx->status_code;
+                    ev_state = PJSIP_EVSUB_STATE_TERMINATED;
+                    break;
+
+                case PJSIP_INV_STATE_INCOMING:
+                    /* Nothing to do. Just to keep gcc from complaining about
+                     * unused enums.
+                     */
+                    break;
+            }
+
+            if (st_code != -1) {
+                pjsip_tx_data *tdata;
+                pj_status_t status;
+
+                status = pjsip_xfer_notify( call->getXferSub(),
+                        ev_state, st_code,
+                        NULL, &tdata);
+                if (status != PJ_SUCCESS) {
+                    _debug("UserAgent: Unable to create NOTIFY -- %d\n", status);
+                } else {
+                    status = pjsip_xfer_send_request(call->getXferSub(), tdata);
+                    if (status != PJ_SUCCESS) {
+                        _debug("UserAgent: Unable to send NOTIFY -- %d\n", status);
+                    }
+                }
+            }
+        }
+    }
+
+    void call_on_media_update( pjsip_inv_session *inv UNUSED, pj_status_t status UNUSED) {
+        _debug("call_on_media_updated\n");
+    }
+
+    void call_on_forked(pjsip_inv_session *inv, pjsip_event *e){
+        _debug("call_on_forked\n");
+    }
+
+    void call_on_tsx_changed(pjsip_inv_session *inv, pjsip_transaction *tsx, pjsip_event *e){
+
+        pjsip_rx_data *rdata;
+        AccountID accId;
+        SIPCall *call;
+        SIPVoIPLink *link;
+        pjsip_msg *msg;
+
+        if(pj_strcmp2(&tsx->method.name, "INFO") == 0) {
+            // Receive a INFO message, ingore it!
+            return;
+        }
+
+        //Retrieve the body message
+        rdata = e->body.tsx_state.src.rdata;
+
+        if (tsx->role == PJSIP_ROLE_UAC) {
+            switch (tsx->state) {
+                case PJSIP_TSX_STATE_TERMINATED:
+                    if (tsx->status_code == 200 &&
+                            pjsip_method_cmp(&tsx->method, pjsip_get_refer_method()) != 0) {
+                        // Peer answered the outgoing call
+                        _debug("UserAgent: Peer answered the outgoing call!\n");
+                        call = reinterpret_cast<SIPCall *> (inv->mod_data[_mod_ua.id]);
+                        if (call == NULL)
+                            return;
+
+                        //_debug("UserAgent: The call id is %s\n", call->getCallId().data());
+
+                        accId = Manager::instance().getAccountFromCall(call->getCallId());
+                        link = dynamic_cast<SIPVoIPLink *> (Manager::instance().getAccountLink(accId));
+                        if (link)
+                            link->SIPCallAnswered(call, rdata);
+                    } else if (tsx->status_code / 100 == 5) {
+                        _debug("UserAgent: 5xx error message received\n");
+                    }
+                    break;
+                case PJSIP_TSX_STATE_PROCEEDING:
+                    // Peer is ringing for the outgoing call
+                    msg = rdata->msg_info.msg;
+
+                    call = reinterpret_cast<SIPCall *> (inv->mod_data[_mod_ua.id]);
+                    if (call == NULL)
+                        return;
+
+                    if (msg->line.status.code == 180) {
+                        _debug("UserAgent: Peer is ringing!\n");
+
+                        call->setConnectionState(Call::Ringing);
+                        Manager::instance().peerRingingCall(call->getCallId());
+                    }
+                    break;
+                case PJSIP_TSX_STATE_COMPLETED:
+                    if (tsx->status_code == 407 || tsx->status_code == 401) //FIXME
+                        break;
+                    if (tsx->status_code / 100 == 6 || tsx->status_code / 100 == 4) {
+                        // We get error message of outgoing call from server
+                        _debug("UserAgent: Server error message is received!\n");
+                        call = reinterpret_cast<SIPCall *> (inv->mod_data[_mod_ua.id]);
+                        if (call == NULL) {
+                            _debug("UserAgent: Call has been removed!\n");
+                            return;
+                        }
+                        accId = Manager::instance().getAccountFromCall(call->getCallId());
+                        link = dynamic_cast<SIPVoIPLink *> (Manager::instance().getAccountLink(accId));
+                        if (link) {
+                            link->SIPCallServerFailure(call);
+                        }
+                    }
+                    break;
+                default:
+                    break;
+            } // end of switch
+
+        } else {
+            switch (tsx->state) {
+                case PJSIP_TSX_STATE_TRYING:
+                    if (pjsip_method_cmp(&tsx->method, pjsip_get_refer_method()) == 0) {
+                        // Peer ask me to transfer call to another number.
+                        _debug("UserAgent: Incoming REFER request!\n");
+                        //onCallTransfered(inv, e->body.tsx_state.src.rdata);
+                    }
+                    break;
+                case PJSIP_TSX_STATE_COMPLETED:
+                    if (tsx->status_code == 200 && tsx->method.id == PJSIP_BYE_METHOD) {
+                        // Peer hangup the call
+                        _debug("UserAgent: Peer hangup(bye) message is received!\n");
+                        call = reinterpret_cast<SIPCall *> (inv->mod_data[_mod_ua.id]);
+                        if (call == NULL) {
+                            _debug("UserAgent: Call has been removed!\n");
+                            return;
+                        }
+                        accId = Manager::instance().getAccountFromCall(call->getCallId());
+                        link = dynamic_cast<SIPVoIPLink *> (Manager::instance().getAccountLink(accId));
+                        if (link) {
+                            link->SIPCallClosed(call);
+                        }
+                    } else if (tsx->status_code == 200 && tsx->method.id == PJSIP_CANCEL_METHOD) {
+                        // Peer refuse the call
+                        _debug("UserAgent: Cancel message is received!\n");
+                        call = reinterpret_cast<SIPCall *> (inv->mod_data[_mod_ua.id]);
+                        if (call == NULL) {
+                            _debug("UserAgent: Call has been removed!\n");
+                            return;
+                        }
+
+                        accId = Manager::instance().getAccountFromCall(call->getCallId());
+                        link = dynamic_cast<SIPVoIPLink *> (Manager::instance().getAccountLink(accId));
+                        if (link) {
+                            link->SIPCallClosed(call);
+                        }
+                    }
+                    break;
+                default:
+                    break;
+            } // end of switch
+        }
+    }
+
+    void regc_cb(struct pjsip_regc_cbparam *param){
+
+        //AccountID *id = static_cast<AccountID *> (param->token);
+        SIPAccount *account;
+
+        //_debug("UserAgent: Account ID is %s, Register result: %d, Status: %d\n", id->data(), param->status, param->code);
+        account = static_cast<SIPAccount *>(param->token);
+        if(!account)
+            return;
+
+        if (param->status == PJ_SUCCESS) {
+            if (param->code < 0 || param->code >= 300) {
+                /* Sometimes, the status is OK, but we still failed.
+                 * So checking the code for real result
+                 */
+                _debug("UserAgent: The error is: %d\n", param->code);
+                switch(param->code) {
+                    case 408:
+                    case 606:
+                        account->setRegistrationState(ErrorConfStun);
+                        break;
+                    case 503:
+                        account->setRegistrationState(ErrorHost);
+                        break;
+                    case 401:
+                    case 403:
+                    case 404:
+                        account->setRegistrationState(ErrorAuth);
+                        break;
+                    default:
+                        account->setRegistrationState(Error);
+                        break;
+                }
+                account->setRegister(false);
+            } else {
+                // Registration/Unregistration is success
+
+                if(account->isRegister())
+                    account->setRegistrationState(Registered);
+                else {
+                    account->setRegistrationState(Unregistered);
+                    account->setRegister(false);
+                }
+            }
+        } else {
+            account->setRegistrationState(ErrorAuth);
+            account->setRegister(false);
+        }
+
+    }
+
+    pj_bool_t 
+        mod_on_rx_request(pjsip_rx_data *rdata)
+        {
+
+            pj_status_t status;
+            pj_str_t reason;
+            unsigned options = 0;
+            pjsip_dialog* dialog;
+            pjsip_tx_data *tdata;
+            AccountID account_id;
+            pjsip_uri *uri;
+            pjsip_sip_uri *sip_uri;
+            std::string userName, server, caller, callerServer, peerNumber;
+            SIPVoIPLink *link;
+            CallID id;
+            SIPCall* call;
+
+            // voicemail part
+            std::string method_name;
+            std::string request;
+
+            // Handle the incoming call invite in this function 
+            _debug("UserAgent: Callback on_rx_request is involved!\n");
+
+            /* First, let's got the username and server name from the invite.
+             * We will use them to detect which account is the callee.
+             */ 
+            uri = rdata->msg_info.to->uri;
+            sip_uri = (pjsip_sip_uri *) pjsip_uri_get_uri(uri);
+
+            userName = std::string(sip_uri->user.ptr, sip_uri->user.slen);
+            server = std::string(sip_uri->host.ptr, sip_uri->host.slen) ;
+
+            // Get the account id of callee from username and server
+            account_id = Manager::instance().getAccountIdFromNameAndServer(userName, server);
+
+            /* If we don't find any account to receive the call */
+            if(account_id == AccountNULL) {
+                _debug("UserAgent: Username %s doesn't match any account!\n",userName.c_str());
+                return false;
+            }
+
+            /* Get the voip link associated to the incoming call */
+            /* The account must before have been associated to the call in ManagerImpl */
+            link = dynamic_cast<SIPVoIPLink *> (Manager::instance().getAccountLink(account_id));
+            
+            /* If we can't find any voIP link to handle the incoming call */
+            if( link == 0 )
+            {
+                _debug("ERROR: can not retrieve the voiplink from the account ID...\n");
+                return false;
+            }
+
+            _debug("UserAgent: The receiver is : %s@%s\n", userName.data(), server.data());
+            _debug("UserAgent: The callee account id is %s\n", account_id.c_str());
+
+            /* Now, it is the time to find the information of the caller */
+            uri = rdata->msg_info.from->uri;
+            sip_uri = (pjsip_sip_uri *) pjsip_uri_get_uri(uri);
+
+            /* Retrieve only the fisrt characters */
+            caller = std::string(sip_uri->user.ptr, sip_uri->user.slen);
+            callerServer = std::string(sip_uri->host.ptr, sip_uri->host.slen);
+            peerNumber = caller + "@" + callerServer;
+
+            // Get the server voicemail notification
+            // Catch the NOTIFY message
+            if( rdata->msg_info.msg->line.req.method.id == PJSIP_OTHER_METHOD )
+            {
+                method_name = "NOTIFY";
+                // Retrieve all the message. Should contains only the method name but ...
+                request =  rdata->msg_info.msg->line.req.method.name.ptr;
+                // Check if the message is a notification
+                if( request.find( method_name ) != (size_t)-1 ) {
+                    /* Notify the right account */
+                    set_voicemail_info( account_id, rdata->msg_info.msg->body );
+                }
+                pjsip_endpt_respond_stateless(_endpt, rdata, PJSIP_SC_OK, NULL, NULL, NULL);
+                return true;
+            }
+
+            // Respond statelessly any non-INVITE requests with 500
+            if (rdata->msg_info.msg->line.req.method.id != PJSIP_INVITE_METHOD) {
+                if (rdata->msg_info.msg->line.req.method.id != PJSIP_ACK_METHOD) {
+                    pj_strdup2(_pool, &reason, "user agent unable to handle this request ");
+                    pjsip_endpt_respond_stateless( _endpt, rdata, PJSIP_SC_METHOD_NOT_ALLOWED, &reason, NULL,
+                            NULL);
+                    return true;
+                }
+            }
+
+            // Verify that we can handle the request
+            status = pjsip_inv_verify_request(rdata, &options, NULL, NULL, _endpt, NULL);
+            if (status != PJ_SUCCESS) {
+                pj_strdup2(_pool, &reason, "user agent unable to handle this INVITE ");
+                pjsip_endpt_respond_stateless( _endpt, rdata, PJSIP_SC_METHOD_NOT_ALLOWED, &reason, NULL,
+                        NULL);
+                return true;
+            }
+
+            // Generate a new call ID for the incoming call!
+            id = Manager::instance().getNewCallID();
+            call = new SIPCall(id, Call::Incoming);
+            
+            /* If an error occured at the call creation */
+            if (!call) {
+                _debug("UserAgent: unable to create an incoming call");
+                return false;
+            }
+
+            // Set the codec map, IP, peer number and so on... for the SIPCall object
+            setCallAudioLocal(call, link->getLocalIPAddress(), link->useStun(), link->getStunServer());
+            call->setCodecMap(Manager::instance().getCodecDescriptorMap());
+            call->setConnectionState(Call::Progressing);
+            call->setIp(link->getLocalIPAddress());
+            call->setPeerNumber(peerNumber);
+
+            /* Call the SIPCallInvite function to generate the local sdp,
+             * remote sdp and negociator.
+             * This function is also used to set the parameters of audio RTP, including:
+             *     local IP and port number 
+             *     remote IP and port number
+             *     possilbe audio codec will be used in this call
+             */
+            if (call->SIPCallInvite(rdata, _pool)) {
+
+                // Notify UI there is an incoming call
+                if (Manager::instance().incomingCall(call, account_id)) {
+                    // Add this call to the callAccountMap in ManagerImpl
+                    Manager::instance().getAccountLink(account_id)->addCall(call);
+                } else {
+                    // Fail to notify UI
+                    delete call;
+                    call = NULL;
+                    _debug("UserAgent: Fail to notify UI!\n");
+                    return false;
+                }
+            } else {
+                // Fail to collect call information
+                delete call;
+                call = NULL;
+                _debug("UserAgent: Call SIPCallInvite failed!\n");
+                return false;
+            }
+
+            /* Create the local dialog (UAS) */
+            status = pjsip_dlg_create_uas(pjsip_ua_instance(), rdata, NULL, &dialog);
+            if (status != PJ_SUCCESS) {
+                pjsip_endpt_respond_stateless( _endpt, rdata, PJSIP_SC_INTERNAL_SERVER_ERROR, &reason, NULL,
+                        NULL);
+                return true;
+            }
+
+            // Specify media capability during invite session creation
+            pjsip_inv_session *inv;
+            status = pjsip_inv_create_uas(dialog, rdata, call->getLocalSDPSession(), 0, &inv);
+            PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
+
+            // Associate the call in the invite session
+            inv->mod_data[_mod_ua.id] = call;
+
+            // Send a 180/Ringing response
+            status = pjsip_inv_initial_answer(inv, rdata, PJSIP_SC_RINGING, NULL, NULL, &tdata);
+            PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
+            status = pjsip_inv_send_msg(inv, tdata);
+            PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
+
+            // Associate invite session to the current call
+            call->setInvSession(inv);
+
+            // Update the connection state
+            call->setConnectionState(Call::Ringing);
+
+            /* Done */
+            return true;
+
+        }
+
+    pj_bool_t mod_on_rx_response(pjsip_rx_data *rdata UNUSED) {
+        _debug("mod_on_rx_response\n");
+        return PJ_SUCCESS;
+    }
+
+    void onCallTransfered(pjsip_inv_session *inv, pjsip_rx_data *rdata)
+    {
+        pj_status_t status;
+        pjsip_tx_data *tdata;
+        SIPCall *existing_call;
+        const pj_str_t str_refer_to = { (char*)"Refer-To", 8};
+        const pj_str_t str_refer_sub = { (char*)"Refer-Sub", 9 };
+        const pj_str_t str_ref_by = { (char*)"Referred-By", 11 };
+        pjsip_generic_string_hdr *refer_to;
+        pjsip_generic_string_hdr *refer_sub;
+        pjsip_hdr *ref_by_hdr;
+        pj_bool_t no_refer_sub = PJ_FALSE;
+        char *uri;
+        std::string tmp;
+        pjsip_status_code code;
+        pjsip_evsub *sub;
+
+        existing_call = (SIPCall *) inv->mod_data[_mod_ua.id];
+
+        /* Find the Refer-To header */
+        refer_to = (pjsip_generic_string_hdr*)
+            pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &str_refer_to, NULL);
+
+        if (refer_to == NULL) {
+            /* Invalid Request.
+             * No Refer-To header!
+             */
+            _debug("UserAgent: Received REFER without Refer-To header!\n");
+            pjsip_dlg_respond( inv->dlg, rdata, 400, NULL, NULL, NULL);
+            return;
+        }
+
+        /* Find optional Refer-Sub header */
+        refer_sub = (pjsip_generic_string_hdr*)
+            pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &str_refer_sub, NULL);
+
+        if (refer_sub) {
+            if (!pj_strnicmp2(&refer_sub->hvalue, "true", 4)==0)
+                no_refer_sub = PJ_TRUE;
+        }
+
+        /* Find optional Referred-By header (to be copied onto outgoing INVITE
+         * request.
+         */
+        ref_by_hdr = (pjsip_hdr*)
+            pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &str_ref_by,
+                    NULL);
+
+        /* Notify callback */
+        code = PJSIP_SC_ACCEPTED;
+
+        _debug("UserAgent: Call to %.*s is being transfered to %.*s\n",
+                (int)inv->dlg->remote.info_str.slen,
+                inv->dlg->remote.info_str.ptr,
+                (int)refer_to->hvalue.slen,
+                refer_to->hvalue.ptr);
+
+        if (no_refer_sub) {
+            /*
+             * Always answer with 2xx.
+             */
+            pjsip_tx_data *tdata;
+            const pj_str_t str_false = { (char*)"false", 5};
+            pjsip_hdr *hdr;
+
+            status = pjsip_dlg_create_response(inv->dlg, rdata, code, NULL,
+                    &tdata);
+            if (status != PJ_SUCCESS) {
+                _debug("UserAgent: Unable to create 2xx response to REFER -- %d\n", status);
+                return;
+            }
+
+            /* Add Refer-Sub header */
+            hdr = (pjsip_hdr*)
+                pjsip_generic_string_hdr_create(tdata->pool, &str_refer_sub,
+                        &str_false);
+            pjsip_msg_add_hdr(tdata->msg, hdr);
+
+
+            /* Send answer */
+            status = pjsip_dlg_send_response(inv->dlg, pjsip_rdata_get_tsx(rdata),
+                    tdata);
+            if (status != PJ_SUCCESS) {
+                _debug("UserAgent: Unable to create 2xx response to REFER -- %d\n", status);
+                return;
+            }
+
+            /* Don't have subscription */
+            sub = NULL;
+
+        } else {
+            struct pjsip_evsub_user xfer_cb;
+            pjsip_hdr hdr_list;
+
+            /* Init callback */
+            pj_bzero(&xfer_cb, sizeof(xfer_cb));
+            xfer_cb.on_evsub_state = &xfer_svr_cb;
+
+            /* Init addiTHIS_FILE, THIS_FILE, tional header list to be sent with REFER response */
+            pj_list_init(&hdr_list);
+
+            /* Create transferee event subscription */
+            status = pjsip_xfer_create_uas( inv->dlg, &xfer_cb, rdata, &sub);
+            if (status != PJ_SUCCESS) {
+                _debug("UserAgent: Unable to create xfer uas -- %d\n", status);
+                pjsip_dlg_respond( inv->dlg, rdata, 500, NULL, NULL, NULL);
+                return;
+            }
+
+            /* If there's Refer-Sub header and the value is "true", send back
+             * Refer-Sub in the response with value "true" too.
+             */
+            if (refer_sub) {
+                const pj_str_t str_true = { (char*)"true", 4 };
+                pjsip_hdr *hdr;
+
+                hdr = (pjsip_hdr*)
+                    pjsip_generic_string_hdr_create(inv->dlg->pool,
+                            &str_refer_sub,
+                            &str_true);
+                pj_list_push_back(&hdr_list, hdr);
+
+            }
+
+            /* Accept the REFER request, send 2xx. */
+            pjsip_xfer_accept(sub, rdata, code, &hdr_list);
+
+            /* Create initial NOTIFY request */
+            status = pjsip_xfer_notify( sub, PJSIP_EVSUB_STATE_ACTIVE,
+                    100, NULL, &tdata);
+            if (status != PJ_SUCCESS) {
+                _debug("UserAgent: Unable to create NOTIFY to REFER -- %d", status);
+                return;
+            }
+
+            /* Send initial NOTIFY request */
+            status = pjsip_xfer_send_request( sub, tdata);
+            if (status != PJ_SUCCESS) {
+                _debug("UserAgent: Unable to send NOTIFY to REFER -- %d\n", status);
+                return;
+            }
+        }
+
+        /* We're cheating here.
+         * We need to get a null terminated string from a pj_str_t.
+         * So grab the pointer from the hvalue and NULL terminate it, knowing
+         * that the NULL position will be occupied by a newline. 
+         */
+        uri = refer_to->hvalue.ptr;
+        uri[refer_to->hvalue.slen] = '\0';
+
+        /* Now make the outgoing call. */
+        tmp = std::string(uri);
+
+        if(existing_call == NULL) {
+            _debug("UserAgent: Call doesn't exist!\n");
+            return;
+        }
+
+        AccountID accId = Manager::instance().getAccountFromCall(existing_call->getCallId());
+        CallID newCallId = Manager::instance().getNewCallID();
+
+        if(!Manager::instance().outgoingCall(accId, newCallId, tmp)) {
+
+            /* Notify xferer about the error (if we have subscription) */
+            if (sub) {
+                status = pjsip_xfer_notify(sub, PJSIP_EVSUB_STATE_TERMINATED,
+                        500, NULL, &tdata);
+                if (status != PJ_SUCCESS) {
+                    _debug("UserAgent: Unable to create NOTIFY to REFER -- %d\n", status);
+                    return;
+                }
+                status = pjsip_xfer_send_request(sub, tdata);
+                if (status != PJ_SUCCESS) {
+                    _debug("UserAgent: Unable to send NOTIFY to REFER -- %d\n", status);
+                    return;
+                }
+            }
+            return;
+        }
+
+        SIPCall* newCall;
+        SIPVoIPLink *link = dynamic_cast<SIPVoIPLink *> (Manager::instance().getAccountLink(accId));
+        if(link) {
+            newCall = dynamic_cast<SIPCall *>(link->getCall(newCallId));
+            if(!newCall) {
+                _debug("UserAgent: can not find the call from sipvoiplink!\n");
+                return;
+            }
+        }
+
+        if (sub) {
+            /* Put the server subscription in inv_data.
+             * Subsequent state changed in pjsua_inv_on_state_changed() will be
+             * reported back to the server subscription.
+             */
+            newCall->setXferSub(sub);
+
+            /* Put the invite_data in the subscription. */
+            pjsip_evsub_set_mod_data(sub, _mod_ua.id,
+                    newCall);
+        }    
+    }
+
+
+
+
+    void xfer_func_cb( pjsip_evsub *sub, pjsip_event *event){
+
+        PJ_UNUSED_ARG(event);
+
+        _debug("UserAgent: Transfer callback is involved!\n");
+        /*
+         * When subscription is accepted (got 200/OK to REFER), check if 
+         * subscription suppressed.
+         */
+        if (pjsip_evsub_get_state(sub) == PJSIP_EVSUB_STATE_ACCEPTED) {
+
+            pjsip_rx_data *rdata;
+            pjsip_generic_string_hdr *refer_sub;
+            const pj_str_t REFER_SUB = {(char*)"Refer-Sub", 9 };
+
+            SIPVoIPLink *link = reinterpret_cast<SIPVoIPLink *> (pjsip_evsub_get_mod_data(sub,
+                        _mod_ua.id));
+
+            /* Must be receipt of response message */
+            pj_assert(event->type == PJSIP_EVENT_TSX_STATE &&
+                    event->body.tsx_state.type == PJSIP_EVENT_RX_MSG);
+            rdata = event->body.tsx_state.src.rdata;
+
+            /* Find Refer-Sub header */
+            refer_sub = (pjsip_generic_string_hdr*)
+                pjsip_msg_find_hdr_by_name(rdata->msg_info.msg,
+                        &REFER_SUB, NULL);
+
+            /* Check if subscription is suppressed */
+            if (refer_sub && pj_stricmp2(&refer_sub->hvalue, "false")==0) {
+                /* Since no subscription is desired, assume that call has been
+                 * transfered successfully.
+                 */
+                if (link) {
+                    // It's the time to stop the RTP
+                    link->transferStep2();
+                }
+
+                /* Yes, subscription is suppressed.
+                 * Terminate our subscription now.
+                 */
+                _debug("UserAgent: Xfer subscription suppressed, terminating event subcription...\n");
+                pjsip_evsub_terminate(sub, PJ_TRUE);
+
+            } else {
+                /* Notify application about call transfer progress. 
+                 * Initially notify with 100/Accepted status.
+                 */
+                _debug("UserAgent: Xfer subscription 100/Accepted received...\n");
+            }
+        }
+        /*
+         * On incoming NOTIFY, notify application about call transfer progress.
+         */
+        else if (pjsip_evsub_get_state(sub) == PJSIP_EVSUB_STATE_ACTIVE ||
+                pjsip_evsub_get_state(sub) == PJSIP_EVSUB_STATE_TERMINATED)
+        {
+            pjsip_msg *msg;
+            pjsip_msg_body *body;
+            pjsip_status_line status_line;
+            pj_bool_t is_last;
+            pj_bool_t cont;
+            pj_status_t status;
+
+            SIPVoIPLink *link = reinterpret_cast<SIPVoIPLink *> (pjsip_evsub_get_mod_data(sub, 
+                        _mod_ua.id));
+
+            /* When subscription is terminated, clear the xfer_sub member of 
+             * the inv_data.
+             */
+            if (pjsip_evsub_get_state(sub) == PJSIP_EVSUB_STATE_TERMINATED) {
+                pjsip_evsub_set_mod_data(sub, _mod_ua.id, NULL);
+                _debug("UserAgent: Xfer client subscription terminated\n");
+
+            }
+
+            if (!link || !event) {
+                /* Application is not interested with call progress status */
+                _debug("UserAgent: Either link or event is empty!\n");
+                return;
+            }
+
+            // Get current call
+            SIPCall *call = dynamic_cast<SIPCall *>(link->getCall(Manager::instance().getCurrentCallId()));
+            if(!call) {
+                _debug("UserAgent: Call doesn't exit!\n");
+                return;
+            }
+
+            /* This better be a NOTIFY request */
+            if (event->type == PJSIP_EVENT_TSX_STATE &&
+                    event->body.tsx_state.type == PJSIP_EVENT_RX_MSG)
+            {
+                pjsip_rx_data *rdata;
+
+                rdata = event->body.tsx_state.src.rdata;
+
+                /* Check if there's body */
+                msg = rdata->msg_info.msg;
+                body = msg->body;
+                if (!body) {
+                    _debug("UserAgent: Warning! Received NOTIFY without message body\n");
+                    return;
+                }
+
+                /* Check for appropriate content */
+                if (pj_stricmp2(&body->content_type.type, "message") != 0 ||
+                        pj_stricmp2(&body->content_type.subtype, "sipfrag") != 0)
+                {
+                    _debug("UserAgent: Warning! Received NOTIFY with non message/sipfrag content\n");
+                    return;
+                }
+
+                /* Try to parse the content */
+                status = pjsip_parse_status_line((char*)body->data, body->len,
+                        &status_line);
+                if (status != PJ_SUCCESS) {
+                    _debug("UserAgent: Warning! Received NOTIFY with invalid message/sipfrag content\n");
+                    return;
+                }
+
+            } else {
+                _debug("UserAgent: Set code to 500!\n");
+                status_line.code = 500;
+                status_line.reason = *pjsip_get_status_text(500);
+            }
+
+            /* Notify application */
+            is_last = (pjsip_evsub_get_state(sub)==PJSIP_EVSUB_STATE_TERMINATED);
+            cont = !is_last;
+
+            if(status_line.code/100 == 2) {
+                _debug("UserAgent: Try to stop rtp!\n");
+                pjsip_tx_data *tdata;
+
+                status = pjsip_inv_end_session(call->getInvSession(), PJSIP_SC_GONE, NULL, &tdata);
+                if(status != PJ_SUCCESS) {
+                    _debug("UserAgent: Fail to create end session msg!\n");
+                } else {
+                    status = pjsip_inv_send_msg(call->getInvSession(), tdata);
+                    if(status != PJ_SUCCESS) 
+                        _debug("UserAgent: Fail to send end session msg!\n");
+                }
+
+                link->transferStep2();
+                cont = PJ_FALSE;
+            }
+
+            if (!cont) {
+                pjsip_evsub_set_mod_data(sub, _mod_ua.id, NULL);
+            }
+        }
+
+    }
+
+
+    void xfer_svr_cb(pjsip_evsub *sub, pjsip_event *event)
+    {
+        PJ_UNUSED_ARG(event);
+
+        /*
+         * When subscription is terminated, clear the xfer_sub member of 
+         * the inv_data.
+         */
+        if (pjsip_evsub_get_state(sub) == PJSIP_EVSUB_STATE_TERMINATED) {
+            SIPCall *call;
+
+            call = (SIPCall*) pjsip_evsub_get_mod_data(sub, _mod_ua.id);
+            if (!call)
+                return;
+
+            pjsip_evsub_set_mod_data(sub, _mod_ua.id, NULL);
+            call->setXferSub(NULL);
+
+            _debug("UserAgent: Xfer server subscription terminated\n");
+        }    
+    }
diff --git a/src/sipvoiplink.h b/src/sipvoiplink.h
index 865703e2151eb4345c40e178b5fa2187aa06230a..03b12e6c38ba2d0dc8eae5dd73f3a9a9916f5720 100644
--- a/src/sipvoiplink.h
+++ b/src/sipvoiplink.h
@@ -2,7 +2,7 @@
  *  Copyright (C) 2004-2009 Savoir-Faire Linux inc.
  *
  *  Author: Emmanuel Milou <emmanuel.milou@savoirfairelinux.com>
- *  Author: Yan Morin <yan.morin@savoirfairelinux.com>
+ *  Author: Yun Liu <yun.liu@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
@@ -23,284 +23,316 @@
 #define SIPVOIPLINK_H
 
 #include "voiplink.h"
-#include "useragent.h"
+
+//////////////////////////////
+/* PJSIP imports */
+#include <pjsip.h>
+#include <pjlib.h>
+#include <pjsip_ua.h>
+#include <pjlib-util.h>
+#include <pjnath/stun_config.h>
+///////////////////////////////
+
 
 class EventThread;
 class SIPCall;
 class AudioRtp;
 
+#define RANDOM_LOCAL_PORT ((rand() % 27250) + 5250)*2
+#define RANDOM_SIP_PORT   rand() % 64000 + 1024
+
+// To set the verbosity. From 0 (min) to 6 (max)
+#define PJ_LOG_LEVEL 1
+
 /**
  * @file sipvoiplink.h
- * @brief Specific VoIPLink for SIP (SIP core for incoming and outgoing events)
+ * @brief Specific VoIPLink for SIP (SIP core for incoming and outgoing events).
+ *          This class is based on the singleton design pattern.
+ *          One SIPVoIPLink can handle multiple SIP accounts, but all the SIP accounts have all the same SIPVoIPLink
  */
 
 class SIPVoIPLink : public VoIPLink
 {
-  public:
-
-    /**
-     * Constructor
-     * @param accountID The account identifier
-     */
-    SIPVoIPLink(const AccountID& accountID);
-
-    /**
-     * Destructor
-     */
-    ~SIPVoIPLink();
-
-    /* Copy Constructor */
-    SIPVoIPLink(const SIPVoIPLink& rh);
-
-    /* Assignment Operator */
-    SIPVoIPLink& operator=( const SIPVoIPLink& rh);
-   
-    /** 
-     * Try to initiate the pjsip engine/thread and set config 
-     * @return bool True if OK
-     */
-    bool init(void);
-
-    /**
-     * Delete link-related stuuf like calls
-     */
-    void terminate(void);
-
-    /**
-     * Event listener. Each event send by the call manager is received and handled from here
-     */
-    void getEvent(void);
-
-    /**
-     * Build and send SIP registration request
-     * @return bool True on success
-     *		  false otherwise
-     */
-    int sendRegister(void);
-
-    /**
-     * Build and send SIP unregistration request
-     * @return bool True on success
-     *		  false otherwise
-     */
-    int sendUnregister(void);
-
-    /**
-     * Place a new call
-     * @param id  The call identifier
-     * @param toUrl  The Sip address of the recipient of the call
-     * @return Call* The current call
-     */
-    Call* newOutgoingCall(const CallID& id, const std::string& toUrl);
-
-    /**
-     * Answer the call
-     * @param id The call identifier
-     * @return bool True on success
-     */
-    bool answer(const CallID& id);
-
-    /**
-     * Hang up the call
-     * @param id The call identifier
-     * @return bool True on success
-     */
-    bool hangup(const CallID& id);
-
-    /**
-     * Cancel the call
-     * @param id The call identifier
-     * @return bool True on success
-     */
-    bool cancel(const CallID& id);
-
-    /**
-     * Put the call on hold
-     * @param id The call identifier
-     * @return bool True on success
-     */
-    bool onhold(const CallID& id);
-
-    /**
-     * Put the call off hold
-     * @param id The call identifier
-     * @return bool True on success
-     */
-    bool offhold(const CallID& id);
-
-    /**
-     * Transfer the call
-     * @param id The call identifier
-     * @param to The recipient of the transfer
-     * @return bool True on success
-     */
-    bool transfer(const CallID& id, const std::string& to);
-
-    /** Handle the incoming refer msg, not finished yet */
-    bool transferStep2();
-
-    /**
-     * Refuse the call
-     * @param id The call identifier
-     * @return bool True on success
-     */
-    bool refuse (const CallID& id);
-
-    /**
-     * Send DTMF
-     * @param id The call identifier
-     * @param code  The char code
-     * @return bool True on success
-     */
-    bool carryingDTMFdigits(const CallID& id, char code);
-
-    /** 
-     * If set to true, we check for a firewall
-     * @param use true if we use STUN
-     */
-    void setUseStun(bool use) { _useStun = use; }
-
-    /** 
-     * The name of the STUN server
-     * @param server Server FQDN/IP
-     */
-    void setStunServer(const std::string& server) { _stunServer = server; }
-
-    bool isRegister() {return _bRegister;}
-    
-    void setRegister(bool result) {_bRegister = result;}
-
-  public:
-
-    /** 
-     * Terminate every call not hangup | brutal | Protected by mutex 
-     */
-    void terminateSIPCall(); 
-    
-    /**
-     * send SIP authentification
-     * @return bool true if sending succeed
-     */
-    bool sendSIPAuthentification();
-
-    /**
-     * Get a SIP From header ("fullname" <sip:userpart@hostpart>)
-     * @param userpart User part
-     * @param hostpart Host name
-     * @return std::string  SIP URI for from Header
-     */
-    std::string SIPFromHeader(const std::string& userpart, const std::string& hostpart);
-
-    /**
-     * Build a sip address with the number that you want to call
-     * Example: sip:124@domain.com
-     * @param to  The header of the recipient
-     * @return std::string  Result as a string
-     */
-    std::string SIPToHeader(const std::string& to);
-
-    /**
-     * Check if an url is sip-valid
-     * @param url The url to check
-     * @return bool True if osip tell that is valid
-     */
-    bool SIPCheckUrl(const std::string& url);
-
-
-    /**
-     * Send an outgoing call invite
-     * @param call  The current call
-     * @return bool True if all is correct
-     */
-    bool SIPOutgoingInvite(SIPCall* call);
-
-    /**
-     * Start a SIP Call
-     * @param call  The current call
-     * @param subject Undocumented
-     * @return true if all is correct
-     */
-    bool SIPStartCall(SIPCall* call, const std::string& subject);
-
-    /**
-     * Get the Sip FROM url (add sip:, add @host, etc...)
-     * @return std::string  The From url
-     */
-    std::string getSipFrom();
-
-    /**
-     * Get the Sip TO url (add sip:, add @host, etc...)
-     * @param to_url  The To url
-     * @return std::string  The SIP to address
-     */
-    std::string getSipTo(const std::string& to_url);
-
-    /**
-     * Set audio (SDP) configuration for a call
-     * localport, localip, localexternalport
-     * @param call a SIPCall valid pointer
-     * @return bool True
-     */
-    bool setCallAudioLocal(SIPCall* call);
-
-    /**
-     * Tell the user that the call was answered
-     * @param
-     */
-    void SIPCallAnswered(SIPCall *call, pjsip_rx_data *rdata);
-    
-    /**
-     * Handling 5XX/6XX error
-     * @param 
-     */
-    void SIPCallServerFailure(SIPCall *call);
-
-    /**
-     * Peer close the connection
-     * @param
-     */
-    void SIPCallClosed(SIPCall *call);
-
-    /**
-     * The call pointer was released
-     * If the call was not cleared before, report an error
-     * @param
-     */
-    void SIPCallReleased(SIPCall *call);
-
-    /**
-     * SIPCall accessor
-     * @param id  The call identifier
-     * @return SIPCall*	  A pointer on SIPCall object
-     */
-    SIPCall* getSIPCall(const CallID& id);
-
-    /** Tell if the initialisation was done */
-    bool _initDone;
-
-    /** when we init the listener, how many times we try to bind a port? */
-    int _nbTryListenAddr;
-
-    /** Do we use stun? */
-    bool _useStun;
-
-    /** What is the stun server? */
-    std::string _stunServer;
-
-    /** Local Extern Address is the IP address seen by peers for SIP listener */
-    std::string _localExternAddress;
-
-    /** Local Extern Port is the port seen by peers for SIP listener */
-    unsigned int _localExternPort;  
-
-    /** Starting sound */
-    AudioRtp* _audiortp;
-    
-    pj_str_t string2PJStr(const std::string &value);
-
-private:
-    pjsip_regc *_regc;
-    bool _bRegister;
+    public:
+
+        /**
+         * Singleton method. Enable to retrieve the unique static instance
+         * @return SIPVoIPLink* A pointer on the object
+         */
+        static SIPVoIPLink* instance( const AccountID& id );
+
+        /**
+         * Destructor
+         */
+        ~SIPVoIPLink();
+
+        /* Copy Constructor */
+        SIPVoIPLink(const SIPVoIPLink& rh);
+
+        /* Assignment Operator */
+        SIPVoIPLink& operator=( const SIPVoIPLink& rh);
+
+        /** 
+         * Try to initiate the pjsip engine/thread and set config 
+         * @return bool True if OK
+         */
+        bool init(void);
+
+        /**
+         * Shut the library and clean up
+         */
+        void terminate( void );
+
+        /**
+         * Event listener. Each event send by the call manager is received and handled from here
+         */
+        void getEvent(void);
+
+        /**
+         * Build and send SIP registration request
+         * @return bool True on success
+         *		  false otherwise
+         */
+        int sendRegister(AccountID id);
+
+        /**
+         * Build and send SIP unregistration request
+         * @return bool True on success
+         *		  false otherwise
+         */
+        int sendUnregister(AccountID id);
+
+        /**
+         * Place a new call
+         * @param id  The call identifier
+         * @param toUrl  The Sip address of the recipient of the call
+         * @return Call* The current call
+         */
+        Call* newOutgoingCall(const CallID& id, const std::string& toUrl);
+
+        /**
+         * Answer the call
+         * @param id The call identifier
+         * @return bool True on success
+         */
+        bool answer(const CallID& id);
+
+        /**
+         * Hang up the call
+         * @param id The call identifier
+         * @return bool True on success
+         */
+        bool hangup(const CallID& id);
+
+        /**
+         * Cancel the call
+         * @param id The call identifier
+         * @return bool True on success
+         */
+        bool cancel(const CallID& id);
+
+        /**
+         * Put the call on hold
+         * @param id The call identifier
+         * @return bool True on success
+         */
+        bool onhold(const CallID& id);
+
+        /**
+         * Put the call off hold
+         * @param id The call identifier
+         * @return bool True on success
+         */
+        bool offhold(const CallID& id);
+
+        /**
+         * Transfer the call
+         * @param id The call identifier
+         * @param to The recipient of the transfer
+         * @return bool True on success
+         */
+        bool transfer(const CallID& id, const std::string& to);
+
+        /** Handle the incoming refer msg, not finished yet */
+        bool transferStep2();
+
+        /**
+         * Refuse the call
+         * @param id The call identifier
+         * @return bool True on success
+         */
+        bool refuse (const CallID& id);
+
+        /**
+         * Send DTMF
+         * @param id The call identifier
+         * @param code  The char code
+         * @return bool True on success
+         */
+        bool carryingDTMFdigits(const CallID& id, char code);
+
+        /** 
+         * If set to true, we check for a firewall
+         * @param use true if we use STUN
+         */
+        inline void useStun(bool use) { _useStun=use; }
+
+        inline bool useStun( void ) { return _useStun; }
+
+        /** 
+         * The name of the STUN server
+         * @param server Server FQDN/IP
+         */
+        void setStunServer(const std::string& server);
+
+        std::string getStunServer (void) { return _stunServer; }
+
+        /** 
+         * Terminate every call not hangup | brutal | Protected by mutex 
+         */
+        void terminateSIPCall(); 
+
+        /**
+         * Build a sip address with the number that you want to call
+         * Example: sip:124@domain.com
+         * @param to  The header of the recipient
+         * @return std::string  Result as a string
+         */
+        std::string SIPToHeader(const std::string& to);
+
+        /**
+         * Check if an url is sip-valid
+         * @param url The url to check
+         * @return bool True if osip tell that is valid
+         */
+        bool SIPCheckUrl(const std::string& url);
+
+
+        /**
+         * Send an outgoing call invite
+         * @param call  The current call
+         * @return bool True if all is correct
+         */
+        bool SIPOutgoingInvite(SIPCall* call);
+
+        /**
+         * Start a SIP Call
+         * @param call  The current call
+         * @param subject Undocumented
+         * @return true if all is correct
+         */
+        bool SIPStartCall(SIPCall* call, const std::string& subject);
+
+        /**
+         * Get the Sip TO url (add sip:, add @host, etc...)
+         * @param to_url  The To url
+         * @return std::string  The SIP to address
+         */
+        std::string getSipTo(const std::string& to_url, std::string hostname);
+
+        /**
+         * Tell the user that the call was answered
+         * @param
+         */
+        void SIPCallAnswered(SIPCall *call, pjsip_rx_data *rdata);
+
+        /**
+         * Handling 5XX/6XX error
+         * @param 
+         */
+        void SIPCallServerFailure(SIPCall *call);
+
+        /**
+         * Peer close the connection
+         * @param
+         */
+        void SIPCallClosed(SIPCall *call);
+
+        /**
+         * The call pointer was released
+         * If the call was not cleared before, report an error
+         * @param
+         */
+        void SIPCallReleased(SIPCall *call);
+
+        /**
+         * SIPCall accessor
+         * @param id  The call identifier
+         * @return SIPCall*	  A pointer on SIPCall object
+         */
+        SIPCall* getSIPCall(const CallID& id);
+
+        /** when we init the listener, how many times we try to bind a port? */
+        int _nbTryListenAddr;
+
+        /** Starting sound */
+        AudioRtp* _audiortp;
+
+        /** Increment the number of SIP account connected to this link */
+        void incrementClients (void) { _clients++; }
+
+        /** Decrement the number of SIP account connected to this link */
+        void decrementClients (void);
+
+    private:
+        /**
+         * Constructor
+         * @param accountID The account identifier
+         */
+        SIPVoIPLink(const AccountID& accountID);
+
+        /* The singleton instance */
+        static SIPVoIPLink* _instance;
+
+        int getModId();
+
+        /** 
+         * Initialize the PJSIP library
+         * Must be called before any other calls to the SIP layer
+         *
+         * @return bool True on success
+         */
+        bool pjsip_init();
+
+        /**
+         * Delete link-related stuuf like calls
+         */
+        bool pjsip_shutdown(void);
+
+        /** Do we use stun? */
+        bool _useStun;
+
+        pj_status_t stunServerResolve();
+
+        /** Create SIP UDP Listener */
+        int createUDPServer();
+
+        bool loadSIPLocalIP();
+
+        std::string getLocalIP() {return _localExternAddress;}
+
+        /** For registration use only */
+        int _regPort;
+
+        /* Flag to check if the STUN server is valid or not */
+        bool validStunServer;
+
+        /** The current STUN server address */
+        std::string _stunServer;
+
+        /** Local Extern Address is the IP address seen by peers for SIP listener */
+        std::string _localExternAddress;
+
+        /** Local Extern Port is the port seen by peers for SIP listener */
+        unsigned int _localExternPort;
+
+        /** Threading object */
+        EventThread* _evThread;
+        ost::Mutex _mutexSIP;
+
+        /* Number of SIP accounts connected to the link */
+        int _clients;
+
 };
 
 #endif
diff --git a/src/user_cfg.h b/src/user_cfg.h
index 57201f084be7353e84750920d6b4aa74909b64f6..438911822771e894d8c42decabc4a88c8c46be28 100644
--- a/src/user_cfg.h
+++ b/src/user_cfg.h
@@ -69,6 +69,8 @@
 #define PULSE_LENGTH		"DTMF.pulseLength"    /** Length of the DTMF in millisecond */
 #define SEND_DTMF_AS		"DTMF.sendDTMFas"     /** DTMF send mode */
 #define SYMMETRIC		"VoIPLink.symmetric"  /** VoIP link type */
+#define STUN_ENABLE     "STUN.enable"
+#define STUN_SERVER     "STUN.server"
 
 #define EMPTY_FIELD		""			/** Default value for empty field */
 #define DFT_STUN_SERVER 	"stun.fwdnet.net:3478"	/** Default STUN server address */
@@ -89,6 +91,7 @@
 #define DFT_EXPIRE_VALUE	"180"			/** Default expire value for registration */
 #define DFT_AUDIO_MANAGER	"1"			/** Default audio manager */
 #define DFT_SIP_PORT            "5060"
+#define DFT_STUN_ENABLE     "0"
 
 #ifdef USE_ZEROCONF
 #define CONFIG_ZEROCONF_DEFAULT_STR "1"			/** Default Zero configuration networking module value */
diff --git a/src/useragent.cpp b/src/useragent.cpp
deleted file mode 100644
index fb527784e0a41d0754228debb329860589370d0c..0000000000000000000000000000000000000000
--- a/src/useragent.cpp
+++ /dev/null
@@ -1,1704 +0,0 @@
-/*
- *  Copyright (C) 2004-2005 Savoir-Faire Linux inc.
- *  Author: Yun Liu <yun.liu@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 <string>
-#include <iostream>
-
-#include "manager.h"
-#include "sipcall.h"
-#include "useragent.h"
-#include "sipvoiplink.h"
-#include "sipaccount.h"
-
-#define RANDOM_SIP_PORT   rand() % 64000 + 1024
-#define RANDOM_LOCAL_PORT ((rand() % 27250) + 5250)*2
-
-UserAgent *UserAgent::_current;
-
-UserAgent::UserAgent():_endpt(NULL) ,_sock(NULL), _cp(), _pool(NULL), _mutex(NULL), _mod(), _useStun(false), _stunHost(),
-        _stunServer(""), _localExternAddress(""), _localIPAddress("127.0.0.1"), _localExternPort(0), _localPort(0), _regPort(DEFAULT_SIP_PORT), _thread(NULL) {
-    //_useStun = false;
-    //_localIPAddress = "127.0.0.1";
-    UserAgent::_current = this;
-}
-
-UserAgent::~UserAgent() {
-    _debug("UserAgent: In dtor!\n");
-    sipDestory();
-}
-
-pj_status_t UserAgent::sipCreate() {
-
-    pj_status_t status;
-
-    // Init PJLIB: must be called before any call to the pjsip library
-    status = pj_init();
-    // Use pjsip macros for sanity check
-    PJ_ASSERT_RETURN( status == PJ_SUCCESS, 1 );
-
-    // Init PJLIB-UTIL library 
-    status = pjlib_util_init();
-    PJ_ASSERT_RETURN( status == PJ_SUCCESS, 1 );
-
-    // Set the pjsip log level
-    pj_log_set_level( PJ_LOG_LEVEL );
-
-    // Init PJNATH 
-    status = pjnath_init();
-    PJ_ASSERT_RETURN( status == PJ_SUCCESS, 1 );
-    
-    // Create a pool factory to allocate memory
-    pj_caching_pool_init(&_cp, &pj_pool_factory_default_policy, 0);
-
-    // Create memory pool for application. 
-    _pool = pj_pool_create(&_cp.factory, "sflphone", 4000, 4000, NULL);
-
-    if (!_pool) {
-        _debug("UserAgent: Could not initialize memory pool\n");
-        return PJ_ENOMEM;
-    }
-
-    // Create a recursive mutex. Simple wrapper for pj_mutex_create 
-    status = pj_mutex_create_recursive(_pool, "sflphone", &_mutex);
-    PJ_ASSERT_RETURN( status == PJ_SUCCESS, 1 );
-
-    // Create the SIP endpoint 
-    status = pjsip_endpt_create(&_cp.factory, pj_gethostname()->ptr, &_endpt);
-    PJ_ASSERT_RETURN( status == PJ_SUCCESS, 1 );
-
-    return PJ_SUCCESS;
-}
-
-pj_status_t UserAgent::sipInit() {
-    
-    pj_status_t status;
-    int errPjsip = 0;
-    int port;
-    
-    validStunServer = true;
-    /* Init SIP UA: */
-
-    //FIXME! DNS initialize here! */
-
-    /* Start resolving STUN server */
-    // if we useStun and we failed to receive something on port 5060, we try a random port
-    // If use STUN server, firewall address setup
-    if (!loadSIPLocalIP()) {
-        _debug("UserAgent: Unable to determine network capabilities\n");
-        return false;
-    }
-    errPjsip = 0;
-    port = _regPort;
-
-    //_debug("stun host is %s\n", _stunHost.ptr);
-    if (_useStun && !Manager::instance().behindNat(_stunServer, port)) {
-        port = RANDOM_SIP_PORT;
-        if (!Manager::instance().behindNat(_stunServer, port)) {
-            _debug("UserAgent: Unable to check NAT setting\n");
-	    validStunServer = false;		
-            return false; // hoho we can't use the random sip port too...
-        }
-    }
-
-    _localPort = port;
-    if (_useStun) {
-        // set by last behindNat() call (ish)...
-        stunServerResolve();
-        _localExternAddress = Manager::instance().getFirewallAddress();
-        _localExternPort = Manager::instance().getFirewallPort();
-        errPjsip = createUDPServer();
-        if (errPjsip != 0) {
-            _debug("UserAgent: Could not initialize SIP listener on port %d\n", port);
-            return errPjsip;
-        }
-    } else {
-        _localExternAddress = _localIPAddress;
-        _localExternPort = _localPort;
-        errPjsip = createUDPServer();
-        if (errPjsip != 0) {
-            _debug("UserAgent: Could not initialize SIP listener on port %d\n", _localExternPort);
-            _localExternPort = _localPort = RANDOM_SIP_PORT;
-            _debug("UserAgent: Try to initialize SIP listener on port %d\n", _localExternPort);
-            errPjsip = createUDPServer();
-            if (errPjsip != 0) {
-                _debug("UserAgent: Fail to initialize SIP listener on port %d\n", _localExternPort);
-                return errPjsip;
-            }
-        }
-    }
-    
-    _debug("UserAgent: SIP Init -- listening on port %d\n", _localExternPort);
-
-    // Initialize transaction layer
-    status = pjsip_tsx_layer_init_module(_endpt);
-    PJ_ASSERT_RETURN( status == PJ_SUCCESS, 1 );
-
-    // Initialize UA layer module
-    status = pjsip_ua_init_module(_endpt, NULL);
-    PJ_ASSERT_RETURN( status == PJ_SUCCESS, 1 );
-
-    // Initialize Replaces support. See the Replaces specification in RFC 3891
-    status = pjsip_replaces_init_module(_endpt);
-    PJ_ASSERT_RETURN( status == PJ_SUCCESS, 1 );
-
-    // Initialize 100rel support 
-    status = pjsip_100rel_init_module(_endpt);
-    PJ_ASSERT_RETURN( status == PJ_SUCCESS, 1 );
-
-    // Initialize and register sflphone module
-    {
-        const pjsip_module mod_initializer ={
-            NULL, NULL, 			// prev, next.			
-            { (char*)"mod-sflphone", 9}, 	// Name.				
-            -1,		 			// Id				
-            PJSIP_MOD_PRIORITY_APPLICATION, 	// Priority			
-            NULL, 				// load()				
-            NULL, 				// start()				
-            NULL, 				// stop()				
-            NULL, 				// unload()				
-            &mod_on_rx_request, 		// on_rx_request()			
-            &mod_on_rx_response, 		// on_rx_response()			
-            NULL, 				// on_tx_request.			
-            NULL, 				// on_tx_response()			
-            NULL, 				// on_tsx_state()			
-        };
-
-        _mod = mod_initializer;
-
-        status = pjsip_endpt_register_module(_endpt, &_mod);
-    	PJ_ASSERT_RETURN( status == PJ_SUCCESS, 1 );
-        
-    }
-
-    // Init the event subscription module.
-    // It extends PJSIP by supporting SUBSCRIBE and NOTIFY methods
-    status = pjsip_evsub_init_module(_endpt);
-    PJ_ASSERT_RETURN( status == PJ_SUCCESS, 1 );
-
-    // Init presence module. 
-    // TODO We probably do not need that extension
-    status = pjsip_pres_init_module(_endpt, pjsip_evsub_instance());
-    PJ_ASSERT_RETURN( status == PJ_SUCCESS, 1 );
-    
-    // Init PUBLISH module 
-    // Provide an implementation of SIP Extension for Event State Publication (RFC 3903)
-    // TODO Check if it is necessary
-    status = pjsip_publishc_init_module(_endpt);
-    PJ_ASSERT_RETURN( status == PJ_SUCCESS, 1 );
-
-    // Init xfer/REFER module
-    status = pjsip_xfer_init_module(_endpt);
-    PJ_ASSERT_RETURN( status == PJ_SUCCESS, 1 );
-        
-    // Initialize invite session module
-    // These callbacks will be called on incoming requests, media session state, etc.
-    {
-        pjsip_inv_callback inv_cb;
-
-        // Init the callback for INVITE session: 
-        pj_bzero(&inv_cb, sizeof (inv_cb));
-
-        inv_cb.on_state_changed = &call_on_state_changed;
-        inv_cb.on_new_session = &call_on_forked;
-        inv_cb.on_media_update = &call_on_media_update;
-        inv_cb.on_tsx_state_changed = &call_on_tsx_changed;
-
-        _debug("UserAgent: VOIP callbacks initialized\n");
-
-        // Initialize session invite module 
-        status = pjsip_inv_usage_init(_endpt, &inv_cb);
-        PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
-    }
-
-
-    // Add endpoint capabilities (INFO, OPTIONS, etc) for this UA
-    {
-        pj_str_t allowed[] = {
-            			{(char*)"INFO", 4},
-            			{(char*)"REGISTER", 8}
-			      }; //  //{"INVITE", 6}, {"ACK",3}, {"BYE",3}, {"CANCEL",6},  {"OPTIONS", 7}, 
-        pj_str_t accepted = {(char*)"application/sdp", 15};
-
-        // Register supported methods
-        pjsip_endpt_add_capability(_endpt, &_mod, PJSIP_H_ALLOW, NULL, PJ_ARRAY_SIZE(allowed), allowed);
-
-        // Register "application/sdp" in ACCEPT header
-        pjsip_endpt_add_capability(_endpt, &_mod, PJSIP_H_ACCEPT, NULL, 1, &accepted);
-    }
-
-    _debug("UserAgent: pjsip version %s for %s initialized\n", pj_get_version(), PJ_OS_NAME);
-
-    Manager::instance().setSipThreadStatus(false);
-    
-    // Create the secondary thread to poll sip events
-    status = pj_thread_create(_pool, "sflphone", &start_thread, NULL, PJ_THREAD_DEFAULT_STACK_SIZE, 0, 
-			    	&_thread);
-    PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
-
-    /* Done! */
-    return PJ_SUCCESS;
-
-}
-
-void UserAgent::sipDestory() {
-    /* Signal threads to quit: */
-    Manager::instance().setSipThreadStatus(true);
-
-    /* Wait worker thread to quit: */
-    if (_thread) {
-        pj_thread_join(_thread);
-        pj_thread_destroy(_thread);
-        _thread = NULL;
-    }
-
-    if (_endpt) {
-        /* Terminate all presence subscriptions. */
-        //pjsua_pres_shutdown();
-
-        /* Wait for some time to allow unregistration to complete: */
-        _debug("UserAgent: Shutting down...\n");
-        busy_sleep(1000);
-    }
-
-    /* Destroy endpoint. */
-    if (_endpt) {
-        pjsip_endpt_destroy(_endpt);
-        _endpt = NULL;
-    }
-
-    /* Destroy mutex */
-    if (_mutex) {
-        pj_mutex_destroy(_mutex);
-        _mutex = NULL;
-    }
-
-    /* Destroy pool and pool factory. */
-    if (_pool) {
-        pj_pool_release(_pool);
-        _pool = NULL;
-        pj_caching_pool_destroy(&_cp);
-
-        /* Shutdown PJLIB */
-        pj_shutdown();
-    }
-
-    /* Done. */    
-}
-
-void UserAgent::busy_sleep(unsigned msec)
-{
-#if defined(PJ_SYMBIAN) && PJ_SYMBIAN != 0
-    /* Ideally we shouldn't call pj_thread_sleep() and rather
-     * CActiveScheduler::WaitForAnyRequest() here, but that will
-     * drag in Symbian header and it doesn't look pretty.
-     */
-    pj_thread_sleep(msec);
-#else
-    pj_time_val timeout, now, tv;
-
-    pj_gettimeofday(&timeout);
-    timeout.msec += msec;
-    pj_time_val_normalize(&timeout);
-
-    tv.sec = 0;
-    tv.msec = 10;
-    pj_time_val_normalize(&tv);
-    
-    do {
-        pjsip_endpt_handle_events(_endpt, &tv);
-        pj_gettimeofday(&now);
-    } while (PJ_TIME_VAL_LT(now, timeout));
-#endif
-}
-
-bool UserAgent::addAccount(AccountID id, pjsip_regc **regc2, const std::string& server, const std::string& user, const std::string& passwd, const int& timeout UNUSED) {
-    
-    pj_status_t status;
-    AccountID *currentId = new AccountID(id);
-    char contactTmp[256];
-    pjsip_regc *regc;
-    pj_str_t svr;
-    pj_str_t aor;
-    pj_str_t contact;
-    pjsip_tx_data *tdata;
-
-    //pj_mutex_lock(_mutex);
-    std::string tmp;
-
-
-    SIPAccount *account;
-
-    if (!validStunServer) {
-
-    	SIPVoIPLink *voipLink;
-        voipLink = dynamic_cast<SIPVoIPLink *>(Manager::instance().getAccountLink(id));
-        Manager::instance().getAccountLink(id)->setRegistrationState(VoIPLink::ErrorExistStun);
-        voipLink->setRegister(false);
-	return false;
-    }
-
-    status = pjsip_regc_create(_endpt, (void *) currentId, &regc_cb, &regc);
-    if (status != PJ_SUCCESS) {
-        _debug("UserAgent: Unable to create regc.\n");
-        return false;
-    }
-
-    tmp = "sip:" + server;
-    pj_strdup2(_pool, &svr, tmp.data());
-    
-    tmp = "<sip:" + user + "@" + server + ">";
-    pj_strdup2(_pool, &aor, tmp.data());
-
-
-    sprintf(contactTmp, "<sip:%s@%s:%d>", user.data(), _localExternAddress.data(), _localExternPort);
-    pj_strdup2(_pool, &contact, contactTmp);
-
-    //_debug("UserAgent: Get in %s %d %s\n", svr.ptr, svr.slen, aor.ptr);
-    status = pjsip_regc_init(regc, &svr, &aor, &aor, 1, &contact, 600); //timeout);
-    if (status != PJ_SUCCESS) {
-        _debug("UserAgent: Unable to initialize regc. %d\n", status); //, regc->str_srv_url.ptr);
-        //pj_mutex_unlock(_mutex);
-        return false;
-    }
-
-
-    account = dynamic_cast<SIPAccount *> (Manager::instance().getAccount(id));
-    pjsip_cred_info *cred = account->getCredInfo();
-
-    if(!cred)
-        cred = new pjsip_cred_info();
-
-    pj_bzero(cred, sizeof (pjsip_cred_info));
-    pj_strdup2(_pool, &cred->username, user.data());
-    cred->data_type = PJSIP_CRED_DATA_PLAIN_PASSWD;
-    pj_strdup2(_pool, &cred->data, passwd.data());
-    pj_strdup2(_pool, &cred->realm, "*");
-    pj_strdup2(_pool, &cred->scheme, "digest");
-    pjsip_regc_set_credentials(regc, 1, cred);
-
-    account->setCredInfo(cred);
-
-    status = pjsip_regc_register(regc, PJ_TRUE, &tdata);
-    if (status != PJ_SUCCESS) {
-        _debug("UserAgent: Unable to register regc.\n");
-        //pj_mutex_unlock(_mutex);
-        return false;
-    }
-
-    status = pjsip_regc_send(regc, tdata);
-    if (status != PJ_SUCCESS) {
-        _debug("UserAgent: Unable to send regc request.\n");
-        //pj_mutex_unlock(_mutex);
-        return false;
-    }
-
-    account->setUserName(user);
-    account->setServer(server);
-    account->setContact(contactTmp);
-
-    // associate regc with account
-    *regc2 = regc;
-    
-    //pj_mutex_unlock(_mutex);
-
-    return true;
-}
-
-bool UserAgent::removeAccount(pjsip_regc *regc)
-{
-    pj_status_t status = 0;
-    pjsip_tx_data *tdata = NULL;
-    
-    //pj_mutex_lock(_mutex);
-    if(regc) {
-        status = pjsip_regc_unregister(regc, &tdata);
-        if(status != PJ_SUCCESS) {
-            _debug("UserAgent: Unable to unregister regc.\n");
-            //pj_mutex_unlock(_mutex);
-            return false;
-        }
-        
-        status = pjsip_regc_send( regc, tdata );
-        if(status != PJ_SUCCESS) {
-            _debug("UserAgent: Unable to send regc request.\n");
-            //pj_mutex_unlock(_mutex);
-            return false;
-        }
-    } else {
-        _debug("UserAgent: regc is null!\n");
-        //pj_mutex_unlock(_mutex);
-        return false;
-    }
-    
-    //pj_mutex_unlock(_mutex);
-    return true;
-}
-
-pj_str_t UserAgent::buildContact(char *userName) {
-    //pj_str_t contact;
-    char tmp[256];
-
-    //FIXME: IPV6 issue!!
-    _debug("In build Contact %s %s %d\n", userName, _localExternAddress.data(), _localExternPort);
-    sprintf(tmp, "<sip:%s@%s:%d>", userName, _localExternAddress.data(), _localExternPort);
-    //_debug("get tmp\n");
-    return pj_str(tmp);
-}
-
-pj_status_t UserAgent::stunServerResolve() {
-    pj_str_t stun_adr;
-    pj_hostent he;
-    pj_stun_config stunCfg;
-    pj_status_t stun_status;
-    pj_sockaddr stun_srv;
-
-    // Initialize STUN configuration
-    pj_stun_config_init(&stunCfg, &_cp.factory, 0, pjsip_endpt_get_ioqueue(_endpt), pjsip_endpt_get_timer_heap(_endpt));
-
-    stun_status = PJ_EPENDING;
-
-    // Init STUN socket
-    size_t pos = _stunServer.find(':');
-    if(pos == std::string::npos) {
-        pj_strdup2(_pool, &stun_adr, _stunServer.data());
-        stun_status = pj_sockaddr_in_init(&stun_srv.ipv4, &stun_adr, (pj_uint16_t) 3478);
-    } else {
-        std::string serverName = _stunServer.substr(0, pos);
-        std::string serverPort = _stunServer.substr(pos + 1);
-        int nPort = atoi(serverPort.data());
-        pj_strdup2(_pool, &stun_adr, serverName.data());
-        stun_status = pj_sockaddr_in_init(&stun_srv.ipv4, &stun_adr, (pj_uint16_t) nPort);
-    }
-    
-    if (stun_status != PJ_SUCCESS) {
-        _debug("UserAgent: Unresolved stun server!\n");
-        stun_status = pj_gethostbyname(&stun_adr, &he);
-
-        if (stun_status == PJ_SUCCESS) {
-            pj_sockaddr_in_init(&stun_srv.ipv4, NULL, 0);
-            stun_srv.ipv4.sin_addr = *(pj_in_addr*) he.h_addr;
-            stun_srv.ipv4.sin_port = pj_htons((pj_uint16_t) 3478);
-        }
-    }
-
-    return stun_status;
-}
-
-int UserAgent::createUDPServer() {
-    pj_status_t status;
-    //pj_str_t ipAddr;
-    pj_sockaddr_in bound_addr;
-    pjsip_host_port a_name;
-    char tmpIP[32];
-
-    // Init bound address to ANY
-    pj_memset(&bound_addr, 0, sizeof (bound_addr));
-    bound_addr.sin_addr.s_addr = PJ_INADDR_ANY;
-
-    // Create UDP server socket
-    status = pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, &_sock);
-    if (status != PJ_SUCCESS) {
-        _debug("UserAgent: (%d) UDP socket() error\n", status);
-        return status;
-    }
-
-    status = pj_sock_bind_in(_sock, pj_ntohl(bound_addr.sin_addr.s_addr), (pj_uint16_t) _localPort);
-    if (status != PJ_SUCCESS) {
-        _debug("UserAgent: (%d) UDP bind() error\n", status);
-        pj_sock_close(_sock);
-        return status;
-    }
-
-    _debug("UserAgent: Use IP: %s\n", _localExternAddress.data());
-
-    // Create UDP-Server (default port: 5060)
-    strcpy(tmpIP, _localExternAddress.data());
-    pj_strdup2(_pool, &a_name.host, tmpIP);
-    a_name.port = (pj_uint16_t) _localExternPort;
-
-    status = pjsip_udp_transport_attach(_endpt, _sock, &a_name, 1, NULL);
-    if (status != PJ_SUCCESS) {
-        _debug("UserAgent: (%d) Unable to start UDP transport!\n", status);
-        return -1;
-    } else {
-        _debug("UserAgent: UDP server listening on port %d\n", _localExternPort);
-    }
-
-    return 0;
-}
-
-void UserAgent::setStunServer(const char *server) {
-    if(server != NULL) {
-        _useStun = true;
-        _stunServer = std::string(server);
-    } else {
-        _useStun = false;
-        _stunServer = std::string("");
-    }
-}
-
-void UserAgent::regc_cb(struct pjsip_regc_cbparam *param) {
-    
-    AccountID *id = static_cast<AccountID *> (param->token);
-    SIPVoIPLink *voipLink;
-    
-    _debug("UserAgent: Account ID is %s, Register result: %d, Status: %d\n", id->data(), param->status, param->code);
-    voipLink = dynamic_cast<SIPVoIPLink *>(Manager::instance().getAccountLink(*id));
-    if(!voipLink)
-        return;
-   
-    if (param->status == PJ_SUCCESS) {
-        if (param->code < 0 || param->code >= 300) {
-            /* Sometimes, the status is OK, but we still failed.
-             * So checking the code for real result
-             */
-            _debug("UserAgent: The error is: %d\n", param->code);
-            switch(param->code) {
-		case 408:
-                case 606:
-                     Manager::instance().getAccountLink(*id)->setRegistrationState(VoIPLink::ErrorConfStun);
-                     break;
-                case 503:
-                     Manager::instance().getAccountLink(*id)->setRegistrationState(VoIPLink::ErrorHost);
-                     break;
-                case 401:
-		case 403:
-		case 404:
-		     Manager::instance().getAccountLink(*id)->setRegistrationState(VoIPLink::ErrorAuth);
-		     break;
-                default:
-                     Manager::instance().getAccountLink(*id)->setRegistrationState(VoIPLink::Error);
-                     break;
-            }
-            voipLink->setRegister(false);
-        } else {
-            // Registration/Unregistration is success
-        
-            if(voipLink->isRegister())
-                Manager::instance().getAccountLink(*id)->setRegistrationState(VoIPLink::Registered);
-            else {
-                Manager::instance().getAccountLink(*id)->setRegistrationState(VoIPLink::Unregistered);
-                voipLink->setRegister(false);
-            }
-        }
-    } else {
-        Manager::instance().getAccountLink(*id)->setRegistrationState(VoIPLink::ErrorAuth);
-        voipLink->setRegister(false);
-    }
-}
-
-bool
-UserAgent::loadSIPLocalIP() {
-    bool returnValue = true;
-    if (_localIPAddress == "127.0.0.1") {
-        pj_sockaddr ip_addr;
-        if (pj_gethostip(pj_AF_INET(), &ip_addr) != PJ_SUCCESS) {
-            // Update the registration state if no network capabilities found
-            _debug("UserAgent: Get host ip failed!\n");
-            returnValue = false;
-        } else {
-            _localIPAddress = std::string(pj_inet_ntoa(ip_addr.ipv4.sin_addr));
-            _debug("UserAgent: Checking network, setting local IP address to: %s\n", _localIPAddress.data());
-        }
-    }
-    return returnValue;
-}
-
-/* Thread entry point function. */
-int UserAgent::start_thread(void *arg) {
-
-    PJ_UNUSED_ARG(arg);
-
-    // FIXME! maybe we should add a flag for exiting!
-    // TODO Add the flag. We have to stop the thread when destroying the instance 
-    while (!Manager::instance().getSipThreadStatus()) {
-        pj_time_val timeout = {0, 10};
-        pjsip_endpt_handle_events(getInstance()->getEndPoint(), &timeout);
-    }
-
-    return 0;
-}
-
-void UserAgent::set_voicemail_info( AccountID account, pjsip_msg_body *body ){
-
-    int voicemail, pos_begin, pos_end;
-    std::string voice_str = "Voice-Message: ";
-    std::string delimiter = "/";
-    std::string msg_body, voicemail_str;
-
-    _debug("UserAgent: checking the voice message!\n");
-    // The voicemail message is formated like that:
-    // Voice-Message: 1/0  . 1 is the number we want to retrieve in this case
-
-    // We get the notification body
-    msg_body = (char*)body->data;
-
-    // We need the position of the first character of the string voice_str
-    pos_begin = msg_body.find(voice_str); 
-    // We need the position of the delimiter
-    pos_end = msg_body.find(delimiter); 
-
-    // So our voicemail number between the both index
-    try {
-
-    	voicemail_str = msg_body.substr(pos_begin + voice_str.length(), pos_end - ( pos_begin + voice_str.length()));
-	std::cout << "voicemail number : " << voicemail_str << std::endl;
-	voicemail = atoi( voicemail_str.c_str() );
-    }
-    catch( std::out_of_range& e ){
-	std::cerr << e.what() << std::endl;
-    }
-
-    // We need now to notify the manager 
-    if( voicemail != 0 )
-	Manager::instance().startVoiceMessageNotification(account, voicemail);
-}
-
-
-pj_bool_t UserAgent::mod_on_rx_request(pjsip_rx_data *rdata) {
-
-    pj_status_t status;
-    pj_str_t reason;
-    unsigned options = 0;
-    pjsip_dialog* dialog;
-    pjsip_tx_data *tdata;
-    //pjmedia_sdp_session *r_sdp;
-    AccountID account_id;
-
-    // voicemail part
-    std::string method_name;
-    std::string request;
-
-    // Handle the incoming call invite in this function 
-    _debug("UserAgent: Callback on_rx_request is involved!\n");
-
-    /* First, let's got the username and server name from the invite.
-     * We will use them to detect which account is the callee.
-     */ 
-    pjsip_uri *uri = rdata->msg_info.to->uri;
-    pjsip_sip_uri *sip_uri = (pjsip_sip_uri *) pjsip_uri_get_uri(uri);
-
-    std::string userName = std::string(sip_uri->user.ptr, sip_uri->user.slen);
-    std::string server = std::string(sip_uri->host.ptr, sip_uri->host.slen);
-
-    // Get the account id of callee from username and server
-    account_id = Manager::instance().getAccountIdFromNameAndServer(userName, server);
-    if(account_id == AccountNULL) {
-            _debug("UserAgent: Username %s doesn't match any account!\n",userName.c_str());
-            return PJ_FALSE;
-    }
-    _debug("UserAgent: The receiver is : %s@%s\n", userName.data(), server.data());
-    _debug("UserAgent: The callee account id is %s\n", account_id.c_str());
-
-    /* Now, it is the time to find the information of the caller */
-    uri = rdata->msg_info.from->uri;
-    sip_uri = (pjsip_sip_uri *) pjsip_uri_get_uri(uri);
-    
-    std::string caller = std::string(sip_uri->user.ptr, sip_uri->user.slen);
-    std::string callerServer = std::string(sip_uri->host.ptr, sip_uri->host.slen);
-    std::string peerNumber = caller + "@" + callerServer;
-    
-    
-    // Get the server voicemail notification
-    // Catch the NOTIFY message
-    if( rdata->msg_info.msg->line.req.method.id == PJSIP_OTHER_METHOD )
-    {
-	method_name = "NOTIFY";
-	// Retrieve all the message. Should contains only the method name but ...
-	request =  rdata->msg_info.msg->line.req.method.name.ptr;
-	// Check if the message is a notification
-	if( request.find( method_name ) != (size_t)-1 ) {
-    		set_voicemail_info( account_id, rdata->msg_info.msg->body );
-	}
-        pjsip_endpt_respond_stateless(getInstance()->getEndPoint(), rdata, PJSIP_SC_OK, NULL, NULL, NULL);
-	return PJ_SUCCESS;
-    }
-
-    // Respond statelessly any non-INVITE requests with 500
-    if (rdata->msg_info.msg->line.req.method.id != PJSIP_INVITE_METHOD) {
-        if (rdata->msg_info.msg->line.req.method.id != PJSIP_ACK_METHOD) {
-            pj_strdup2(getInstance()->getAppPool(), &reason, "user agent unable to handle this request ");
-            pjsip_endpt_respond_stateless(getInstance()->getEndPoint(), rdata, PJSIP_SC_METHOD_NOT_ALLOWED, &reason, NULL,
-                    NULL);
-            return PJ_TRUE;
-        }
-    }
-    
-    // Verify that we can handle the request
-    status = pjsip_inv_verify_request(rdata, &options, NULL, NULL, getInstance()->getEndPoint(), NULL);
-    if (status != PJ_SUCCESS) {
-        pj_strdup2(getInstance()->getAppPool(), &reason, "user agent unable to handle this INVITE ");
-        pjsip_endpt_respond_stateless(getInstance()->getEndPoint(), rdata, PJSIP_SC_METHOD_NOT_ALLOWED, &reason, NULL,
-                NULL);
-        return PJ_TRUE;
-    }
-
-    // Generate a new call ID for the incoming call!
-    CallID id = Manager::instance().getNewCallID();
-
-    _debug("UserAgent: The call id of the incoming call is %s\n", id.c_str());
-    SIPCall* call = new SIPCall(id, Call::Incoming);
-    if (!call) {
-        _debug("UserAgent: unable to create an incoming call");
-        return PJ_FALSE;
-    }
-
-    // Set the codec map, IP, peer number and so on... for the SIPCall object
-    getInstance()->setCallAudioLocal(call);
-    call->setCodecMap(Manager::instance().getCodecDescriptorMap());
-    call->setConnectionState(Call::Progressing);
-    call->setIp(getInstance()->getLocalIP());
-    call->setPeerNumber(peerNumber);
-    
-    /* Call the SIPCallInvite function to generate the local sdp,
-     * remote sdp and negociator.
-     * This function is also used to set the parameters of audio RTP, including:
-     *     local IP and port number 
-     *     remote IP and port number
-     *     possilbe audio codec will be used in this call
-     */
-    if (call->SIPCallInvite(rdata, getInstance()->getAppPool())) {
-                
-        // Notify UI there is an incoming call
-        if (Manager::instance().incomingCall(call, account_id)) {
-            // Add this call to the callAccountMap in ManagerImpl
-            Manager::instance().getAccountLink(account_id)->addCall(call);
-            _debug("UserAgent: Notify UI success!\n");
-        } else {
-            // Fail to notify UI
-            delete call;
-            call = NULL;
-            _debug("UserAgent: Fail to notify UI!\n");
-            return PJ_FALSE;
-        }
-    } else {
-        // Fail to collect call information
-        delete call;
-        call = NULL;
-        _debug("UserAgent: Call SIPCallInvite failed!\n");
-        return PJ_FALSE;
-    }
-
-    /* Create the local dialog (UAS) */
-    status = pjsip_dlg_create_uas(pjsip_ua_instance(), rdata, NULL, &dialog);
-    if (status != PJ_SUCCESS) {
-        pjsip_endpt_respond_stateless(getInstance()->getEndPoint(), rdata, PJSIP_SC_INTERNAL_SERVER_ERROR, &reason, NULL,
-                NULL);
-        return PJ_TRUE;
-    }
-    
-    // Specify media capability during invite session creation
-    pjsip_inv_session *inv;
-    status = pjsip_inv_create_uas(dialog, rdata, call->getLocalSDPSession(), 0, &inv);
-    PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
-
-    // Associate the call in the invite session
-    inv->mod_data[getInstance()->getModId()] = call;
-    
-    // Send a 180/Ringing response
-    status = pjsip_inv_initial_answer(inv, rdata, PJSIP_SC_RINGING, NULL, NULL, &tdata);
-    PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
-    status = pjsip_inv_send_msg(inv, tdata);
-    PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
-
-    // Associate invite session to the current call
-    call->setInvSession(inv);
-
-    // Update the connection state
-    call->setConnectionState(Call::Ringing);
-
-    /* Done */
-    return PJ_SUCCESS;
-}
-
-bool UserAgent::setCallAudioLocal(SIPCall* call) {
-    // Firstly, we use the local IP and port number
-    unsigned int callLocalAudioPort = RANDOM_LOCAL_PORT;
-    unsigned int callLocalExternAudioPort = callLocalAudioPort;
-    
-    if (_useStun) {
-        // If use Stun server, modify them
-        if (Manager::instance().behindNat(_stunServer, callLocalAudioPort)) {
-            callLocalExternAudioPort = Manager::instance().getFirewallPort();
-        }
-    }
-    _debug("UserAgent: Setting local audio port to: %d\n", callLocalAudioPort);
-    _debug("UserAgent: Setting local audio port (external) to: %d\n", callLocalExternAudioPort);
-
-    // Set local audio port for SIPCall(id)
-    call->setLocalIp(_localIPAddress);
-    call->setLocalAudioPort(callLocalAudioPort);
-    call->setLocalExternAudioPort(callLocalExternAudioPort);
-
-    return true;
-}
-
-int UserAgent::answer(SIPCall *call) {
-    pj_status_t status;
-    pjsip_tx_data *tdata;
-
-    // User answered the incoming call, tell peer this news
-    if (call->startNegociation(_pool)) {
-        // Create and send a 200(OK) response
-        _debug("UserAgent: Negociation success!\n");
-        status = pjsip_inv_answer(call->getInvSession(), PJSIP_SC_OK, NULL, NULL, &tdata);
-        PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
-        status = pjsip_inv_send_msg(call->getInvSession(), tdata);
-        PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
-
-        return 0;
-    }
-
-    return 1;
-}
-
-bool UserAgent::makeOutgoingCall(const std::string& strTo, SIPCall* call, const AccountID& id) {
-    pj_status_t status;
-    pjsip_dialog *dialog;
-    pjsip_tx_data *tdata;
-    pj_str_t from, to, contact;
-
-    _debug("*******************AccountId is %s\n", id.data());
-    // Get the basic information about the callee account
-    SIPAccount* account = dynamic_cast<SIPAccount *>(Manager::instance().getAccount(id));
-    
-    // Generate the from URI
-    std::string strFrom = "sip:" + account->getUserName() + "@" + account->getServer();
-
-    _debug("UserAgent: Make a new call from:%s to %s. Contact is %s\n", 
-            strFrom.data(), strTo.data(), account->getContact().data());
-
-    // pjsip need the from and to information in pj_str_t format
-    pj_strdup2(_pool, &from, strFrom.data());
-    pj_strdup2(_pool, &to, strTo.data());
-    pj_strdup2(_pool, &contact, account->getContact().data());
-
-    // create the dialog (UAC)
-    status = pjsip_dlg_create_uac(pjsip_ua_instance(), &from,
-                                    &contact,
-                                    &to,
-                                    NULL,
-                                    &dialog);
-    PJ_ASSERT_RETURN(status == PJ_SUCCESS, false);
-
-    setCallAudioLocal(call);
-    call->setIp(getInstance()->getLocalIP());
-
-    // Building the local SDP offer
-    call->createInitialOffer(_pool);
-
-    // Create the invite session for this call
-    pjsip_inv_session *inv;
-    status = pjsip_inv_create_uac(dialog, call->getLocalSDPSession(), 0, &inv);
-    PJ_ASSERT_RETURN(status == PJ_SUCCESS, false);
-
-    // Set auth information
-    pjsip_auth_clt_set_credentials(&dialog->auth_sess, 1, account->getCredInfo());
-
-    // Associate current call in the invite session
-    inv->mod_data[_mod.id] = call;
-
-    status = pjsip_inv_invite(inv, &tdata);
-    PJ_ASSERT_RETURN(status == PJ_SUCCESS, false);
-
-    // Associate current invite session in the call
-    call->setInvSession(inv);
-    
-    status = pjsip_inv_send_msg(inv, tdata);
-    //PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
-    if(status != PJ_SUCCESS) {
-	return false;
-    }
-
-    return true;
-}
-
-void UserAgent::call_on_forked(pjsip_inv_session *inv, pjsip_event *e) {
-    PJ_UNUSED_ARG(inv);
-    PJ_UNUSED_ARG(e);
-}
-
-void UserAgent::call_on_tsx_changed(pjsip_inv_session *inv, pjsip_transaction *tsx, pjsip_event *e) {
-
-    pjsip_rx_data *rdata;
-    AccountID accId;
-    SIPCall *call;
-    SIPVoIPLink *link;
-    pjsip_msg *msg;
-
-    _debug("UserAgent: TSX Changed! The tsx->state is %d; tsx->role is %d; code is %d; method id is %.*s.\n",
-            tsx->state, tsx->role, tsx->status_code, (int)tsx->method.name.slen, tsx->method.name.ptr);
-
-    if(pj_strcmp2(&tsx->method.name, "INFO") == 0) {
-	// Receive a INFO message, ingore it!
-	return;
-    }
-
-    //Retrieve the body message
-    rdata = e->body.tsx_state.src.rdata;
-
-    if (tsx->role == PJSIP_ROLE_UAC) {
-        switch (tsx->state) {
-            case PJSIP_TSX_STATE_TERMINATED:
-                if (tsx->status_code == 200 &&
-                        pjsip_method_cmp(&tsx->method, pjsip_get_refer_method()) != 0) {
-                    // Peer answered the outgoing call
-                    _debug("UserAgent: Peer answered the outgoing call!\n");
-                    call = reinterpret_cast<SIPCall *> (inv->mod_data[getInstance()->getModId()]);
-                    if (call == NULL)
-                        return;
-
-                    //_debug("UserAgent: The call id is %s\n", call->getCallId().data());
-
-                    accId = Manager::instance().getAccountFromCall(call->getCallId());
-                    link = dynamic_cast<SIPVoIPLink *> (Manager::instance().getAccountLink(accId));
-                    if (link)
-                        link->SIPCallAnswered(call, rdata);
-                } else if (tsx->status_code / 100 == 5) {
-		    _debug("UserAgent: 5xx error message received\n");
-                }
-                break;
-            case PJSIP_TSX_STATE_PROCEEDING:
-                // Peer is ringing for the outgoing call
-                msg = rdata->msg_info.msg;
-
-                call = reinterpret_cast<SIPCall *> (inv->mod_data[getInstance()->getModId()]);
-                if (call == NULL)
-                    return;
-
-                if (msg->line.status.code == 180) {
-                    _debug("UserAgent: Peer is ringing!\n");
-
-                    call->setConnectionState(Call::Ringing);
-                    Manager::instance().peerRingingCall(call->getCallId());
-                }
-                break;
-            case PJSIP_TSX_STATE_COMPLETED:
-		if (tsx->status_code == 407 || tsx->status_code == 401) //FIXME
-                    break;
-                if (tsx->status_code / 100 == 6 || tsx->status_code / 100 == 4) {
-                    // We get error message of outgoing call from server
-                    _debug("UserAgent: Server error message is received!\n");
-                    call = reinterpret_cast<SIPCall *> (inv->mod_data[getInstance()->getModId()]);
-                    if (call == NULL) {
-                        _debug("UserAgent: Call has been removed!\n");
-                        return;
-                    }
-                    accId = Manager::instance().getAccountFromCall(call->getCallId());
-                    link = dynamic_cast<SIPVoIPLink *> (Manager::instance().getAccountLink(accId));
-                    if (link) {
-                        link->SIPCallServerFailure(call);
-                    }
-                }
-                break;
-            default:
-                break;
-        } // end of switch
-        
-    } else {
-        switch (tsx->state) {
-            case PJSIP_TSX_STATE_TRYING:
-                if (pjsip_method_cmp(&tsx->method, pjsip_get_refer_method()) == 0) {
-                    // Peer ask me to transfer call to another number.
-                    _debug("UserAgent: Incoming REFER request!\n");
-                    getInstance()->onCallTransfered(inv, e->body.tsx_state.src.rdata);
-                }
-                break;
-            case PJSIP_TSX_STATE_COMPLETED:
-                if (tsx->status_code == 200 && tsx->method.id == PJSIP_BYE_METHOD) {
-                    // Peer hangup the call
-                    _debug("UserAgent: Peer hangup(bye) message is received!\n");
-                    call = reinterpret_cast<SIPCall *> (inv->mod_data[getInstance()->getModId()]);
-                    if (call == NULL) {
-                        _debug("UserAgent: Call has been removed!\n");
-                        return;
-                    }
-                    accId = Manager::instance().getAccountFromCall(call->getCallId());
-                    link = dynamic_cast<SIPVoIPLink *> (Manager::instance().getAccountLink(accId));
-                    if (link) {
-                        link->SIPCallClosed(call);
-                    }
-                } else if (tsx->status_code == 200 && tsx->method.id == PJSIP_CANCEL_METHOD) {
-                    // Peer refuse the call
-                    _debug("UserAgent: Cancel message is received!\n");
-                    call = reinterpret_cast<SIPCall *> (inv->mod_data[getInstance()->getModId()]);
-                    if (call == NULL) {
-                        _debug("UserAgent: Call has been removed!\n");
-                        return;
-                    }
-
-                    accId = Manager::instance().getAccountFromCall(call->getCallId());
-                    link = dynamic_cast<SIPVoIPLink *> (Manager::instance().getAccountLink(accId));
-                    if (link) {
-                        link->SIPCallClosed(call);
-                    }
-                }
-                break;
-            default:
-                break;
-        } // end of switch
-    }
-
-}
-
-void UserAgent::call_on_state_changed(pjsip_inv_session *inv, pjsip_event *e) {
-
-    PJ_UNUSED_ARG(inv);
-    
-    SIPCall *call = reinterpret_cast<SIPCall*> (inv->mod_data[getInstance()->getModId()]);
-    if(!call)
-        return;
-    
-    /* If this is an outgoing INVITE that was created because of
-     * REFER/transfer, send NOTIFY to transferer.
-     */
-    if (call->getXferSub() && e->type==PJSIP_EVENT_TSX_STATE)  {
-        int st_code = -1;
-        pjsip_evsub_state ev_state = PJSIP_EVSUB_STATE_ACTIVE;
-
-
-        switch (call->getInvSession()->state) {
-            case PJSIP_INV_STATE_NULL:
-            case PJSIP_INV_STATE_CALLING:
-                /* Do nothing */
-                break;
-
-            case PJSIP_INV_STATE_EARLY:
-            case PJSIP_INV_STATE_CONNECTING:
-                st_code = e->body.tsx_state.tsx->status_code;
-                ev_state = PJSIP_EVSUB_STATE_ACTIVE;
-                break;
-
-            case PJSIP_INV_STATE_CONFIRMED:
-                /* When state is confirmed, send the final 200/OK and terminate
-                 * subscription.
-                 */
-                st_code = e->body.tsx_state.tsx->status_code;
-                ev_state = PJSIP_EVSUB_STATE_TERMINATED;
-                break;
-
-            case PJSIP_INV_STATE_DISCONNECTED:
-                st_code = e->body.tsx_state.tsx->status_code;
-                ev_state = PJSIP_EVSUB_STATE_TERMINATED;
-                break;
-
-            case PJSIP_INV_STATE_INCOMING:
-                /* Nothing to do. Just to keep gcc from complaining about
-                 * unused enums.
-                 */
-                break;
-        }
-
-        if (st_code != -1) {
-            pjsip_tx_data *tdata;
-            pj_status_t status;
-
-            status = pjsip_xfer_notify( call->getXferSub(),
-                                        ev_state, st_code,
-                                        NULL, &tdata);
-            if (status != PJ_SUCCESS) {
-                _debug("UserAgent: Unable to create NOTIFY -- %d\n", status);
-            } else {
-                status = pjsip_xfer_send_request(call->getXferSub(), tdata);
-                if (status != PJ_SUCCESS) {
-                    _debug("UserAgent: Unable to send NOTIFY -- %d\n", status);
-                }
-            }
-        }
-    }
-
-}
-
-bool UserAgent::onhold(SIPCall *call) {
-
-    pj_status_t status;
-    pjsip_tx_data *tdata;
-    pjmedia_sdp_attr *attr;
-    pjmedia_sdp_session* local_sdp;
-
-    local_sdp = call->getLocalSDPSession();
-    if( local_sdp == NULL ){
-        _debug("! SIP Failure: unable to find local_sdp\n");
-        return false;
-    }
-
-    /* Create re-INVITE with new offer */
-    // Remove all the attributes with the specified name
-    pjmedia_sdp_media_remove_all_attr(local_sdp->media[0], "sendrecv");
-    attr = pjmedia_sdp_attr_create(_pool, "sendonly", NULL);
-    pjmedia_sdp_media_add_attr(local_sdp->media[0], attr);
-
-    status = pjsip_inv_reinvite( call->getInvSession(), NULL, local_sdp, &tdata);
-    if( status != PJ_SUCCESS )
-    {
-        _debug("On hold: creation of the Re-invite request failed\n");
-        return false;
-    }
-    /* Send the request */
-    status = pjsip_inv_send_msg( call->getInvSession(), tdata);
- 
-    return (status == PJ_SUCCESS);
-}
-
-bool UserAgent::offhold(SIPCall *call) {
-
-    pj_status_t status;
-    pjsip_tx_data *tdata;
-    pjmedia_sdp_attr *attr;
-    pjmedia_sdp_session* local_sdp;
-
-    local_sdp = call->getLocalSDPSession();
-    if( local_sdp == NULL ){
-        _debug("! SIP Failure: unable to find local_sdp\n");
-        return false;
-    }
-
-    /* Create re-INVITE with new offer */
-    // Remove all the attributes with the specified name
-    pjmedia_sdp_media_remove_all_attr(local_sdp->media[0], "sendonly");
-    attr = pjmedia_sdp_attr_create(_pool, "sendrecv", NULL);
-    pjmedia_sdp_media_add_attr(local_sdp->media[0], attr);
-
-    status = pjsip_inv_reinvite( call->getInvSession(), NULL, local_sdp , &tdata);
-    if( status != PJ_SUCCESS )
-    {
-        _debug("Off hold: creation of the Re-invite request failed\n");
-        return false;
-    }
-
-    /* Send the request */
-    status = pjsip_inv_send_msg( call->getInvSession(), tdata);
- 
-    return (status == PJ_SUCCESS);
-}
-
-bool UserAgent::hangup(SIPCall* call) {
-    pj_status_t status;
-    pjsip_tx_data *tdata = NULL;
-    
-    // User hangup current call. Notify peer
-    status = pjsip_inv_end_session(call->getInvSession(), 404, NULL, &tdata);
-    if(status != PJ_SUCCESS)
-	return false;
-
-    _debug("UserAgent: Before send msg!\n");
-
-    if(tdata == NULL)
-	return true;
-
-    status = pjsip_inv_send_msg(call->getInvSession(), tdata);
-    if(status != PJ_SUCCESS)
-	return false;
-
-    call->getInvSession()->mod_data[getInstance()->getModId()] = NULL;
-    return true;
-}
-
-bool UserAgent::refuse(SIPCall* call)
-{
-    pj_status_t status;
-    pjsip_tx_data *tdata;
-    
-    // User refuse current call. Notify peer
-    status = pjsip_inv_end_session(call->getInvSession(), PJSIP_SC_DECLINE, NULL, &tdata); //603
-    if(status != PJ_SUCCESS)
-        return false;
-
-    status = pjsip_inv_send_msg(call->getInvSession(), tdata);
-    if(status != PJ_SUCCESS)
-        return false;
-
-    call->getInvSession()->mod_data[getInstance()->getModId()] = NULL;
-    return true;
-}
-
-
-bool UserAgent::carryingDTMFdigits(SIPCall* call, char *msgBody)
-{
-    pj_status_t status;
-    pjsip_tx_data *tdata;
-    pj_str_t methodName, content;
-    pjsip_method method;
-    pjsip_media_type ctype;
-
-    pj_strdup2(_pool, &methodName, "INFO");
-    pjsip_method_init_np(&method, &methodName);
-   
-    /* Create request message. */
-    status = pjsip_dlg_create_request( call->getInvSession()->dlg, &method,
-                                       -1, &tdata);
-    if (status != PJ_SUCCESS) {
-        _debug("UserAgent: Unable to create INFO request -- %d\n", status);
-        return false;
-    }
-
-    /* Get MIME type */
-    pj_strdup2(_pool, &ctype.type, "application");
-    pj_strdup2(_pool, &ctype.subtype, "dtmf-relay");
-
-    /* Create "application/dtmf-relay" message body. */
-    pj_strdup2(_pool, &content, msgBody);
-    tdata->msg->body = pjsip_msg_body_create( tdata->pool, &ctype.type,
-                                              &ctype.subtype, &content);
-    if (tdata->msg->body == NULL) {
-        _debug("UserAgent: Unable to create msg body!\n");
-        pjsip_tx_data_dec_ref(tdata);
-        return false;
-    }
-
-    /* Send the request. */
-    status = pjsip_dlg_send_request( call->getInvSession()->dlg, tdata,
-                                     _mod.id, NULL);
-    if (status != PJ_SUCCESS) {
-        _debug("UserAgent: Unable to send MESSAGE request -- %d\n", status);
-        return false;
-    }
-   
-    return true;
-
-}
-
-bool UserAgent::transfer(SIPCall *call, const std::string& to)
-{
-    pjsip_evsub *sub;
-    pjsip_tx_data *tdata;
-    struct pjsip_evsub_user xfer_cb;
-    pj_status_t status;
-    pj_str_t dest;
-    
-    pj_strdup2(_pool, &dest, to.data());
-
-    /* Create xfer client subscription. */
-    pj_bzero(&xfer_cb, sizeof(xfer_cb));
-    xfer_cb.on_evsub_state = &xfer_func_cb;
-    
-    status = pjsip_xfer_create_uac(call->getInvSession()->dlg, &xfer_cb, &sub);
-    if (status != PJ_SUCCESS) {
-        _debug("UserAgent: Unable to create xfer -- %d\n", status);
-        return false;
-    }
-    
-    /* Associate this voiplink of call with the client subscription 
-     * We can not just associate call with the client subscription
-     * because after this function, we can not find the cooresponding
-     * voiplink from the call any more. But the voiplink is useful!
-     */
-    AccountID accId = Manager::instance().getAccountFromCall(call->getCallId());
-    SIPVoIPLink *link = dynamic_cast<SIPVoIPLink *> (Manager::instance().getAccountLink(accId));
-    pjsip_evsub_set_mod_data(sub, _mod.id, link);
-
-    /*
-     * Create REFER request.
-     */
-    status = pjsip_xfer_initiate(sub, &dest, &tdata);
-    if (status != PJ_SUCCESS) {
-        _debug("UserAgent: Unable to create REFER request -- %d\n", status);
-        return false;
-    }
-
-    /* Send. */
-    status = pjsip_xfer_send_request(sub, tdata);
-    if (status != PJ_SUCCESS) {
-        _debug("UserAgent: Unable to send REFER request -- %d\n", status);
-        return false;
-    }
-
-    return true;
-}
-
-void UserAgent::xfer_func_cb( pjsip_evsub *sub, pjsip_event *event)
-{
-    PJ_UNUSED_ARG(event);
-
-    _debug("UserAgent: Transfer callback is involved!\n");
-    /*
-     * When subscription is accepted (got 200/OK to REFER), check if 
-     * subscription suppressed.
-     */
-    if (pjsip_evsub_get_state(sub) == PJSIP_EVSUB_STATE_ACCEPTED) {
-
-        pjsip_rx_data *rdata;
-        pjsip_generic_string_hdr *refer_sub;
-        const pj_str_t REFER_SUB = {(char*)"Refer-Sub", 9 };
-
-        SIPVoIPLink *link = reinterpret_cast<SIPVoIPLink *> (pjsip_evsub_get_mod_data(sub,
-                getInstance()->getModId()));
-
-        /* Must be receipt of response message */
-        pj_assert(event->type == PJSIP_EVENT_TSX_STATE &&
-                  event->body.tsx_state.type == PJSIP_EVENT_RX_MSG);
-        rdata = event->body.tsx_state.src.rdata;
-
-        /* Find Refer-Sub header */
-        refer_sub = (pjsip_generic_string_hdr*)
-                    pjsip_msg_find_hdr_by_name(rdata->msg_info.msg,
-                                               &REFER_SUB, NULL);
-
-        /* Check if subscription is suppressed */
-        if (refer_sub && pj_stricmp2(&refer_sub->hvalue, "false")==0) {
-            /* Since no subscription is desired, assume that call has been
-             * transfered successfully.
-             */
-            if (link) {
-                // It's the time to stop the RTP
-                link->transferStep2();
-            }
-
-            /* Yes, subscription is suppressed.
-             * Terminate our subscription now.
-             */
-            _debug("UserAgent: Xfer subscription suppressed, terminating event subcription...\n");
-            pjsip_evsub_terminate(sub, PJ_TRUE);
-
-        } else {
-            /* Notify application about call transfer progress. 
-             * Initially notify with 100/Accepted status.
-             */
-            _debug("UserAgent: Xfer subscription 100/Accepted received...\n");
-        }
-    }
-    /*
-     * On incoming NOTIFY, notify application about call transfer progress.
-     */
-    else if (pjsip_evsub_get_state(sub) == PJSIP_EVSUB_STATE_ACTIVE ||
-             pjsip_evsub_get_state(sub) == PJSIP_EVSUB_STATE_TERMINATED)
-    {
-        pjsip_msg *msg;
-        pjsip_msg_body *body;
-        pjsip_status_line status_line;
-        pj_bool_t is_last;
-        pj_bool_t cont;
-        pj_status_t status;
-
-        SIPVoIPLink *link = reinterpret_cast<SIPVoIPLink *> (pjsip_evsub_get_mod_data(sub, 
-                getInstance()->getModId()));
-
-        /* When subscription is terminated, clear the xfer_sub member of 
-         * the inv_data.
-         */
-        if (pjsip_evsub_get_state(sub) == PJSIP_EVSUB_STATE_TERMINATED) {
-            pjsip_evsub_set_mod_data(sub, getInstance()->getModId(), NULL);
-            _debug("UserAgent: Xfer client subscription terminated\n");
-
-        }
-
-        if (!link || !event) {
-            /* Application is not interested with call progress status */
-            _debug("UserAgent: Either link or event is empty!\n");
-            return;
-        }
-
-        // Get current call
-        SIPCall *call = dynamic_cast<SIPCall *>(link->getCall(Manager::instance().getCurrentCallId()));
-        if(!call) {
-            _debug("UserAgent: Call doesn't exit!\n");
-            return;
-        }
-        
-        /* This better be a NOTIFY request */
-        if (event->type == PJSIP_EVENT_TSX_STATE &&
-            event->body.tsx_state.type == PJSIP_EVENT_RX_MSG)
-        {
-            pjsip_rx_data *rdata;
-
-            rdata = event->body.tsx_state.src.rdata;
-
-            /* Check if there's body */
-            msg = rdata->msg_info.msg;
-            body = msg->body;
-            if (!body) {
-                _debug("UserAgent: Warning! Received NOTIFY without message body\n");
-                return;
-            }
-
-            /* Check for appropriate content */
-            if (pj_stricmp2(&body->content_type.type, "message") != 0 ||
-                pj_stricmp2(&body->content_type.subtype, "sipfrag") != 0)
-            {
-                _debug("UserAgent: Warning! Received NOTIFY with non message/sipfrag content\n");
-                return;
-            }
-
-            /* Try to parse the content */
-            status = pjsip_parse_status_line((char*)body->data, body->len,
-                                             &status_line);
-            if (status != PJ_SUCCESS) {
-                _debug("UserAgent: Warning! Received NOTIFY with invalid message/sipfrag content\n");
-                return;
-            }
-
-        } else {
-            _debug("UserAgent: Set code to 500!\n");
-            status_line.code = 500;
-            status_line.reason = *pjsip_get_status_text(500);
-        }
-
-        /* Notify application */
-        is_last = (pjsip_evsub_get_state(sub)==PJSIP_EVSUB_STATE_TERMINATED);
-        cont = !is_last;
-        
-        if(status_line.code/100 == 2) {
-            _debug("UserAgent: Try to stop rtp!\n");
-            pjsip_tx_data *tdata;
-            
-            status = pjsip_inv_end_session(call->getInvSession(), PJSIP_SC_GONE, NULL, &tdata);
-            if(status != PJ_SUCCESS) {
-                _debug("UserAgent: Fail to create end session msg!\n");
-            } else {
-                status = pjsip_inv_send_msg(call->getInvSession(), tdata);
-                if(status != PJ_SUCCESS) 
-                    _debug("UserAgent: Fail to send end session msg!\n");
-            }
-            
-            link->transferStep2();
-            cont = PJ_FALSE;
-        }
-        
-        if (!cont) {
-            pjsip_evsub_set_mod_data(sub, getInstance()->getModId(), NULL);
-        }
-    }
-         
-}
-
-void UserAgent::onCallTransfered(pjsip_inv_session *inv, pjsip_rx_data *rdata)
-{
-    pj_status_t status;
-    pjsip_tx_data *tdata;
-    SIPCall *existing_call;
-    const pj_str_t str_refer_to = { (char*)"Refer-To", 8};
-    const pj_str_t str_refer_sub = { (char*)"Refer-Sub", 9 };
-    const pj_str_t str_ref_by = { (char*)"Referred-By", 11 };
-    pjsip_generic_string_hdr *refer_to;
-    pjsip_generic_string_hdr *refer_sub;
-    pjsip_hdr *ref_by_hdr;
-    pj_bool_t no_refer_sub = PJ_FALSE;
-    char *uri;
-    std::string tmp;
-    pjsip_status_code code;
-    pjsip_evsub *sub;
-
-    existing_call = (SIPCall *) inv->mod_data[getInstance()->getModId()];
-
-    /* Find the Refer-To header */
-    refer_to = (pjsip_generic_string_hdr*)
-        pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &str_refer_to, NULL);
-
-    if (refer_to == NULL) {
-        /* Invalid Request.
-         * No Refer-To header!
-         */
-        _debug("UserAgent: Received REFER without Refer-To header!\n");
-        pjsip_dlg_respond( inv->dlg, rdata, 400, NULL, NULL, NULL);
-        return;
-    }
-
-    /* Find optional Refer-Sub header */
-    refer_sub = (pjsip_generic_string_hdr*)
-        pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &str_refer_sub, NULL);
-
-    if (refer_sub) {
-        if (!pj_strnicmp2(&refer_sub->hvalue, "true", 4)==0)
-            no_refer_sub = PJ_TRUE;
-    }
-
-    /* Find optional Referred-By header (to be copied onto outgoing INVITE
-     * request.
-     */
-    ref_by_hdr = (pjsip_hdr*)
-                 pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &str_ref_by,
-                                            NULL);
-
-    /* Notify callback */
-    code = PJSIP_SC_ACCEPTED;
-
-    _debug("UserAgent: Call to %.*s is being transfered to %.*s\n",
-              (int)inv->dlg->remote.info_str.slen,
-              inv->dlg->remote.info_str.ptr,
-              (int)refer_to->hvalue.slen,
-              refer_to->hvalue.ptr);
-
-    if (no_refer_sub) {
-        /*
-         * Always answer with 2xx.
-         */
-        pjsip_tx_data *tdata;
-        const pj_str_t str_false = { (char*)"false", 5};
-        pjsip_hdr *hdr;
-
-        status = pjsip_dlg_create_response(inv->dlg, rdata, code, NULL,
-                                           &tdata);
-        if (status != PJ_SUCCESS) {
-            _debug("UserAgent: Unable to create 2xx response to REFER -- %d\n", status);
-            return;
-        }
-
-        /* Add Refer-Sub header */
-        hdr = (pjsip_hdr*)
-               pjsip_generic_string_hdr_create(tdata->pool, &str_refer_sub,
-                                              &str_false);
-        pjsip_msg_add_hdr(tdata->msg, hdr);
-
- 
-        /* Send answer */
-        status = pjsip_dlg_send_response(inv->dlg, pjsip_rdata_get_tsx(rdata),
-                                         tdata);
-        if (status != PJ_SUCCESS) {
-            _debug("UserAgent: Unable to create 2xx response to REFER -- %d\n", status);
-            return;
-        }
-
-        /* Don't have subscription */
-        sub = NULL;
-
-    } else {
-        struct pjsip_evsub_user xfer_cb;
-        pjsip_hdr hdr_list;
-
-        /* Init callback */
-        pj_bzero(&xfer_cb, sizeof(xfer_cb));
-        xfer_cb.on_evsub_state = &xfer_svr_cb;
-
-        /* Init addiTHIS_FILE, THIS_FILE, tional header list to be sent with REFER response */
-        pj_list_init(&hdr_list);
-
-        /* Create transferee event subscription */
-        status = pjsip_xfer_create_uas( inv->dlg, &xfer_cb, rdata, &sub);
-        if (status != PJ_SUCCESS) {
-            _debug("UserAgent: Unable to create xfer uas -- %d\n", status);
-            pjsip_dlg_respond( inv->dlg, rdata, 500, NULL, NULL, NULL);
-            return;
-        }
-
-        /* If there's Refer-Sub header and the value is "true", send back
-         * Refer-Sub in the response with value "true" too.
-         */
-        if (refer_sub) {
-            const pj_str_t str_true = { (char*)"true", 4 };
-            pjsip_hdr *hdr;
-
-            hdr = (pjsip_hdr*)
-                   pjsip_generic_string_hdr_create(inv->dlg->pool,
-                                                   &str_refer_sub,
-                                                   &str_true);
-            pj_list_push_back(&hdr_list, hdr);
-
-        }
-
-        /* Accept the REFER request, send 2xx. */
-        pjsip_xfer_accept(sub, rdata, code, &hdr_list);
-
-        /* Create initial NOTIFY request */
-        status = pjsip_xfer_notify( sub, PJSIP_EVSUB_STATE_ACTIVE,
-                                    100, NULL, &tdata);
-        if (status != PJ_SUCCESS) {
-            _debug("UserAgent: Unable to create NOTIFY to REFER -- %d", status);
-            return;
-        }
-
-        /* Send initial NOTIFY request */
-        status = pjsip_xfer_send_request( sub, tdata);
-        if (status != PJ_SUCCESS) {
-            _debug("UserAgent: Unable to send NOTIFY to REFER -- %d\n", status);
-            return;
-        }
-    }
-
-    /* We're cheating here.
-     * We need to get a null terminated string from a pj_str_t.
-     * So grab the pointer from the hvalue and NULL terminate it, knowing
-     * that the NULL position will be occupied by a newline. 
-     */
-    uri = refer_to->hvalue.ptr;
-    uri[refer_to->hvalue.slen] = '\0';
-
-    /* Now make the outgoing call. */
-    tmp = std::string(uri);
-
-    if(existing_call == NULL) {
-        _debug("UserAgent: Call doesn't exist!\n");
-        return;
-    }
-    
-    AccountID accId = Manager::instance().getAccountFromCall(existing_call->getCallId());
-    CallID newCallId = Manager::instance().getNewCallID();
-    
-    if(!Manager::instance().outgoingCall(accId, newCallId, tmp)) {
-        
-        /* Notify xferer about the error (if we have subscription) */
-        if (sub) {
-            status = pjsip_xfer_notify(sub, PJSIP_EVSUB_STATE_TERMINATED,
-                                       500, NULL, &tdata);
-            if (status != PJ_SUCCESS) {
-                _debug("UserAgent: Unable to create NOTIFY to REFER -- %d\n", status);
-                return;
-            }
-            status = pjsip_xfer_send_request(sub, tdata);
-            if (status != PJ_SUCCESS) {
-                _debug("UserAgent: Unable to send NOTIFY to REFER -- %d\n", status);
-                return;
-            }
-        }
-        return;
-    }
-
-    SIPCall* newCall;
-    SIPVoIPLink *link = dynamic_cast<SIPVoIPLink *> (Manager::instance().getAccountLink(accId));
-    if(link) {
-        newCall = dynamic_cast<SIPCall *>(link->getCall(newCallId));
-        if(!newCall) {
-            _debug("UserAgent: can not find the call from sipvoiplink!\n");
-            return;
-        }
-    }
-
-    if (sub) {
-        /* Put the server subscription in inv_data.
-         * Subsequent state changed in pjsua_inv_on_state_changed() will be
-         * reported back to the server subscription.
-         */
-        newCall->setXferSub(sub);
-
-        /* Put the invite_data in the subscription. */
-        pjsip_evsub_set_mod_data(sub, _mod.id,
-                                 newCall);
-    }    
-}
-
-void UserAgent::xfer_svr_cb(pjsip_evsub *sub, pjsip_event *event)
-{
-    PJ_UNUSED_ARG(event);
-
-    /*
-     * When subscription is terminated, clear the xfer_sub member of 
-     * the inv_data.
-     */
-    if (pjsip_evsub_get_state(sub) == PJSIP_EVSUB_STATE_TERMINATED) {
-        SIPCall *call;
-
-        call = (SIPCall*) pjsip_evsub_get_mod_data(sub, getInstance()->getModId());
-        if (!call)
-            return;
-
-        pjsip_evsub_set_mod_data(sub, getInstance()->getModId(), NULL);
-        call->setXferSub(NULL);
-
-        _debug("UserAgent: Xfer server subscription terminated\n");
-    }    
-}
diff --git a/src/useragent.h b/src/useragent.h
deleted file mode 100644
index b37257aeae33bd46bf9fae99a5a841fc655e013e..0000000000000000000000000000000000000000
--- a/src/useragent.h
+++ /dev/null
@@ -1,166 +0,0 @@
-/*
- *  Copyright (C) 2004-2005 Savoir-Faire Linux inc.
- *  Author: Yun Liu <yun.liu@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.
- */
-
-
-#ifndef _SIPMANAGER_H
-#define	_SIPMANAGER_H
-
-#include <pjsip.h>
-#include <pjlib-util.h>
-#include <pjlib.h>
-#include <pjnath/stun_config.h>
-
-//TODO Remove this include if we don't need anything from it
-#include <pjsip_simple.h>
-
-#include <pjsip_ua.h>
-#include <pjmedia/sdp.h>
-#include <pjmedia/sdp_neg.h>
-
-#include <string>
-#include <vector>
-
-#define PJ_LOG_LEVEL	1
-
-typedef std::string AccountID;
-
-class SIPCall;
-
-class UserAgent
-{
-private:
-    /** PJSIP Endpoint */
-    pjsip_endpoint *_endpt;
-    pj_sock_t _sock;
-    //pjsip_module _appMod;
-    pj_caching_pool _cp;
-    pj_pool_t *_pool;    
-    pj_mutex_t *_mutex;     /** Mutex protection for this data */
-    pjsip_module _mod;       /** PJSIP module. */
-    pjsip_module _options_handler;
-    bool _useStun;
-    pj_str_t _stunHost;
-    std::string _stunServer;
-    bool validStunServer;
-
-    /** Local Extern Address is the IP address seen by peers for SIP listener */
-    std::string _localExternAddress;
-    std::string _localIPAddress;
-
-    /** Local Extern Port is the port seen by peers for SIP listener */
-    unsigned int _localExternPort;
-    unsigned int _localPort;
-
-    /** For registration use only */
-    int _regPort;
-    
-    pj_thread_t *_thread;
-    
-    static UserAgent *_current;
-    
-    /* Sleep with polling */
-    void busy_sleep(unsigned msec);
-public:
-    UserAgent();
-    ~UserAgent();
-    
-    pj_status_t sipCreate();
-    
-    /**
-     * This method is used to initialize the pjsip
-     */
-    pj_status_t sipInit();
-
-
-    void sipDestory();
-
-    /** Create SIP UDP Listener */
-    int createUDPServer();
-
-    /** Set whether it will use stun server */
-    void setStunServer(const char *server); 
-
-    /** Set the port number user designated */
-    void setSipPort(int port) { _regPort = port; }
- 
-    int getSipPort() { return _regPort; }
-    
-    pj_str_t getStunServer() { return _stunHost; }
-    
-    bool addAccount(AccountID id, pjsip_regc **regc, const std::string& server, const std::string& user, const std::string& passwd
-						   , const int& timeout);
-    bool removeAccount(pjsip_regc *regc);
-    
-    pj_str_t buildContact(char *userName);
-    
-    bool loadSIPLocalIP();
-    
-    pj_status_t stunServerResolve();
-    
-    pjsip_endpoint* getEndPoint() {return _endpt;}
-    
-    std::string getLocalIP() {return _localExternAddress;}
-    
-    int getModId() {return _mod.id;}
-    
-    bool setCallAudioLocal(SIPCall* call);
-    
-    int answer(SIPCall* call);
-    
-    bool hangup(SIPCall* call);
-    
-    bool refuse(SIPCall* call);
-    
-    bool onhold(SIPCall *call);
-    bool offhold(SIPCall *call);
- 
-    bool transfer(SIPCall *call, const std::string& to);
-    
-    void onCallTransfered(pjsip_inv_session *inv, pjsip_rx_data *rdata);
-    
-    bool makeOutgoingCall(const std::string& to, SIPCall* call, const AccountID& id);
-
-    bool carryingDTMFdigits(SIPCall* call, char *msgBody);
-
-    pj_pool_t *getAppPool() {return _pool;}
-    static pj_bool_t mod_on_rx_request(pjsip_rx_data *rdata);
-    static pj_bool_t mod_on_rx_response(pjsip_rx_data *rdata UNUSED) {return PJ_SUCCESS;}
-    static void regc_cb(struct pjsip_regc_cbparam *param);
-    static void xfer_func_cb( pjsip_evsub *sub, pjsip_event *event);
-    static void xfer_svr_cb(pjsip_evsub *sub, pjsip_event *event);
-    static void call_on_media_update( pjsip_inv_session *inv UNUSED, pj_status_t status UNUSED) {}
-    static void call_on_state_changed( pjsip_inv_session *inv, pjsip_event *e);
-    static void call_on_forked(pjsip_inv_session *inv, pjsip_event *e);
-    static void call_on_tsx_changed(pjsip_inv_session *inv, pjsip_transaction *tsx, pjsip_event *e);
-    static int start_thread(void *arg);
-    static UserAgent* getInstance() {return _current;}
-
-    static void set_voicemail_info( AccountID account, pjsip_msg_body *body );
-private:
-
-    // Copy Constructor
-    UserAgent(const UserAgent& rh);
-
-    // Assignment Operator
-    UserAgent& operator=( const UserAgent& rh);
-};
-
-
-#endif /* _SIPMANAGER_H */
-
diff --git a/src/voiplink.cpp b/src/voiplink.cpp
index fe62b20467a1047fa2a1965618de1bff4abeea79..77a0c95ed11f7cc05646e0baa21a311501310ab8 100644
--- a/src/voiplink.cpp
+++ b/src/voiplink.cpp
@@ -26,7 +26,6 @@
 
 VoIPLink::VoIPLink(const AccountID& accountID) : _accountID(accountID), _localIPAddress("127.0.0.1"), _localPort(0),  _initDone(false) 
 {
-    setRegistrationState(VoIPLink::Unregistered);
 }
 
 VoIPLink::~VoIPLink (void) 
@@ -64,8 +63,7 @@ Call* VoIPLink::getCall(const CallID& id)
   return 0;
 }
 
-bool
-VoIPLink::clearCallMap()
+bool VoIPLink::clearCallMap()
 {
   ost::MutexLock m(_callMapMutex);
   CallMap::iterator iter = _callMap.begin();
@@ -78,9 +76,11 @@ VoIPLink::clearCallMap()
   return true;
 }
 
-void VoIPLink::setRegistrationState(const RegistrationState state)
+Account* VoIPLink::getAccountPtr(void)
 {
-    _registrationState = state;
-    // Notify the client
-    Manager::instance().connectionStatusNotification( );
+    Account* account;
+    AccountID id;
+
+    id = getAccountID();
+    return Manager::instance().getAccount(id);
 }
diff --git a/src/voiplink.h b/src/voiplink.h
index e095c1922ccc24af99754eddd5ed79b1d2ebc83a..4038394ccf6446663bba7e5d0d465d7cd955c2a8 100644
--- a/src/voiplink.h
+++ b/src/voiplink.h
@@ -24,8 +24,10 @@
 #define __VOIP_LINK_H__
 
 #include "call.h"
+#include "account.h"
 
 class AudioCodec;
+class Account;
 
 /** Define AccountID type */
 typedef std::string AccountID;
@@ -38,218 +40,189 @@ typedef std::map<CallID, Call*> CallMap;
  * @brief Listener and manager interface for each VoIP protocol
  */
 class VoIPLink {
-  public:
-
-    /**
-     * Constructor
-     * @param accountID The account identifier
-     */
-    VoIPLink(const AccountID& accountID);
-
-    /**
-     * Virtual destructor
-     */
-    virtual ~VoIPLink (void);
-
-    /** Contains all the state an Voip can be in */
-    enum RegistrationState {Unregistered, Trying, Registered, Error, ErrorAuth , ErrorNetwork , ErrorHost, ErrorExistStun, ErrorConfStun};
-    typedef enum RegistrationState RegistrationState;
-
-    /**
-     * Virtual method
-     * Event listener. Each event send by the call manager is received and handled from here
-     */
-    virtual void getEvent (void) = 0;
-
-    /** 
-     * Virtual method
-     * Try to initiate the pjsip engine/thread and set config 
-     * @return bool True if OK
-     */
-    virtual bool init (void) = 0;
-    
-    /**
-     * Virtual method
-     * Delete link-related stuuf like calls
-     */
-    virtual void terminate (void) = 0;
-    
-    /**
-     * Virtual method
-     * Build and send SIP registration request
-     * @return bool True on success
-     *		  false otherwise
-     */
-    virtual int sendRegister (void) = 0;
-    
-    /**
-     * Virtual method
-     * Build and send SIP unregistration request
-     * @return bool True on success
-     *		  false otherwise
-     */
-    virtual int sendUnregister (void) = 0;
-
-    /**
-     * Place a new call
-     * @param id  The call identifier
-     * @param toUrl  The Sip address of the recipient of the call
-     * @return Call* The current call
-     */
-    virtual Call* newOutgoingCall(const CallID& id, const std::string& toUrl) = 0;
-    /**
-     * Answer the call
-     * @param id The call identifier
-     * @return bool True on success
-     */
-    virtual bool answer(const CallID& id) = 0;
-
-    /**
-     * Hang up a call
-     * @param id The call identifier
-     * @return bool True on success
-     */
-    virtual bool hangup(const CallID& id) = 0;
-
-    /**
-     * Cancel the call dialing
-     * @param id The call identifier
-     * @return bool True on success
-     */
-    virtual bool cancel(const CallID& id) = 0;
-
-    /**
-     * Put a call on hold
-     * @param id The call identifier
-     * @return bool True on success
-     */
-    virtual bool onhold(const CallID& id) = 0;
-
-    /**
-     * Resume a call from hold state
-     * @param id The call identifier
-     * @return bool True on success
-     */
-    virtual bool offhold(const CallID& id) = 0;
-
-    /**
-     * Transfer a call to specified URI
-     * @param id The call identifier
-     * @param to The recipient of the call
-     * @return bool True on success
-     */
-    virtual bool transfer(const CallID& id, const std::string& to) = 0;
-
-    /**
-     * Refuse incoming call
-     * @param id The call identifier
-     * @return bool True on success
-     */
-    virtual bool refuse(const CallID& id) = 0;
-
-    /**
-     * Send DTMF
-     * @param id The call identifier
-     * @param code  The char code
-     * @return bool True on success
-     */
-    virtual bool carryingDTMFdigits(const CallID& id, char code) = 0;
-
-    /* Accessors */
-    std::string& getFullName (void) { return _fullname; }
-    void setFullName (const std::string& fullname) { _fullname = fullname; }
-
-    std::string& getHostname (void) { return _hostname; }
-    void setHostname (const std::string& hostname) {  _hostname = hostname; }
-
-    std::string& getUsername (void) { return _username; }
-    void setUsername (const std::string& username) {  _username = username; }
-
-    std::string& getPassword (void) { return _password; }
-    void setPassword (const std::string& password) {  _password = password; }
-
-    /**
-     * @return AccountID  parent Account's ID
-     */
-    AccountID& getAccountID(void) { return _accountID; }
-
-    /**
-     * @param accountID The account identifier
-     */
-    void setAccountID( const AccountID& accountID) { _accountID = accountID; }
-
-    /** Get the call pointer from the call map (protected by mutex)
-     * @param id A Call ID
-     * @return Call*  Call pointer or 0
-     */
-    Call* getCall(const CallID& id);
-
-    /**
-     * Get connection status
-     * @return Connection status
-     */
-    RegistrationState getRegistrationState() { return _registrationState; }
-
-    /**
-     * Set new registration state
-     * @param state The registration state
-     */
-    void setRegistrationState(const RegistrationState state);
-
-  private:
-    std::string _hostname;
-    std::string _username;
-    std::string _password;
-    std::string _fullname;
-
-    /**
-     * ID of parent's Account
-     */
-    AccountID _accountID;
-
-    /**
-     * State of registration
-     */
-    RegistrationState _registrationState;
-
-public:
-    /** Add a call to the call map (protected by mutex)
-     * @param call A call pointer with a unique pointer
-     * @return bool True if the call was unique and added
-     */
-    bool addCall(Call* call);
-
-    /** Remove a call from the call map (protected by mutex)
-     * @param id A Call ID
-     * @return bool True if the call was correctly removed
-     */
-    bool removeCall(const CallID& id);
-
-    /**
-     * Remove all the call from the map
-     * @return bool True on success
-     */
-    bool clearCallMap();
-    
-    
-protected:
-    /** Contains all the calls for this Link, protected by mutex */
-    CallMap _callMap;
-
-    /** Mutex to protect call map */
-    ost::Mutex _callMapMutex;
-
-    /** Get Local IP Address (ie: 127.0.0.1, 192.168.0.1, ...) */
-    std::string _localIPAddress;
-
-    /** Get local listening port (5060 for SIP, ...) */
-    unsigned int _localPort;
-
-    /** Whether init() was called already or not
-     * This should be used in [IAX|SIP]VoIPLink::init() and terminate(), to
-     * indicate that init() was called, or reset by terminate().
-     */
-    bool _initDone;
+
+    public:
+        /**
+         * Constructor
+         * @param accountID The account identifier
+         */
+        VoIPLink(const AccountID& accountID);
+
+        /**
+         * Virtual destructor
+         */
+        virtual ~VoIPLink (void);
+
+
+        /**
+         * Virtual method
+         * Event listener. Each event send by the call manager is received and handled from here
+         */
+        virtual void getEvent (void) = 0;
+
+        /** 
+         * Virtual method
+         * Try to initiate the communication layer and set config 
+         * @return bool True if OK
+         */
+        virtual bool init (void) = 0;
+
+        /**
+         * Virtual method
+         * Delete link-related stuff like calls
+         */
+        virtual void terminate (void) = 0;
+
+        /**
+         * Virtual method
+         * Build and send account registration request
+         * @return bool True on success
+         *		  false otherwise
+         */
+        virtual int sendRegister ( AccountID id ) = 0;
+
+        /**
+         * Virtual method
+         * Build and send account unregistration request
+         * @return bool True on success
+         *		  false otherwise
+         */
+        virtual int sendUnregister ( AccountID id ) = 0;
+
+        /**
+         * Place a new call
+         * @param id  The call identifier
+         * @param toUrl  The address of the recipient of the call
+         * @return Call* The current call
+         */
+        virtual Call* newOutgoingCall(const CallID& id, const std::string& toUrl) = 0;
+
+        /**
+         * Answer the call
+         * @param id The call identifier
+         * @return bool True on success
+         */
+        virtual bool answer(const CallID& id) = 0;
+
+        /**
+         * Hang up a call
+         * @param id The call identifier
+         * @return bool True on success
+         */
+        virtual bool hangup(const CallID& id) = 0;
+
+        /**
+         * Cancel the call dialing
+         * @param id The call identifier
+         * @return bool True on success
+         */
+        virtual bool cancel(const CallID& id) = 0;
+
+        /**
+         * Put a call on hold
+         * @param id The call identifier
+         * @return bool True on success
+         */
+        virtual bool onhold(const CallID& id) = 0;
+
+        /**
+         * Resume a call from hold state
+         * @param id The call identifier
+         * @return bool True on success
+         */
+        virtual bool offhold(const CallID& id) = 0;
+
+        /**
+         * Transfer a call to specified URI
+         * @param id The call identifier
+         * @param to The recipient of the call
+         * @return bool True on success
+         */
+        virtual bool transfer(const CallID& id, const std::string& to) = 0;
+
+        /**
+         * Refuse incoming call
+         * @param id The call identifier
+         * @return bool True on success
+         */
+        virtual bool refuse(const CallID& id) = 0;
+
+        /**
+         * Send DTMF
+         * @param id The call identifier
+         * @param code  The char code
+         * @return bool True on success
+         */
+        virtual bool carryingDTMFdigits(const CallID& id, char code) = 0;
+
+        bool initDone (void) { return _initDone; }
+        void initDone (bool state) { _initDone = state; }
+
+        std::string getLocalIPAddress (void) { return _localIPAddress; }
+
+        /** Add a call to the call map (protected by mutex)
+         * @param call A call pointer with a unique pointer
+         * @return bool True if the call was unique and added
+         */
+        bool addCall(Call* call);
+
+        /** Remove a call from the call map (protected by mutex)
+         * @param id A Call ID
+         * @return bool True if the call was correctly removed
+         */
+        bool removeCall(const CallID& id);
+
+        /**
+         * Remove all the call from the map
+         * @return bool True on success
+         */
+        bool clearCallMap();
+
+        /**
+         * @return AccountID  parent Account's ID
+         */
+        inline AccountID& getAccountID(void) { return _accountID; }
+
+        Account* getAccountPtr(void);
+
+        /**
+         * @param accountID The account identifier
+         */
+        inline void setAccountID( const AccountID& accountID) { _accountID = accountID; }
+
+        /** 
+         * Get the call pointer from the call map (protected by mutex)
+         * @param id A Call ID
+         * @return Call*  Call pointer or 0
+         */
+        Call* getCall(const CallID& id);
+
+        virtual void setStunServer( const std::string &server ) = 0;
+
+    private:
+        /**
+         * ID of parent's Account
+         */
+        AccountID _accountID;
+
+    protected:
+        /** Contains all the calls for this Link, protected by mutex */
+        CallMap _callMap;
+
+        /** Mutex to protect call map */
+        ost::Mutex _callMapMutex;
+
+        /** Get Local IP Address (ie: 127.0.0.1, 192.168.0.1, ...) */
+        std::string _localIPAddress;
+
+        /** Get local listening port (5060 for SIP, ...) */
+        unsigned int _localPort;
+
+        /** Whether init() was called already or not
+         * This should be used in [IAX|SIP]VoIPLink::init() and terminate(), to
+         * indicate that init() was called, or reset by terminate().
+         */
+        bool _initDone;
 };
 
 #endif // __VOIP_LINK_H__
diff --git a/src/zeroconf/DNSQueryThread.cpp b/src/zeroconf/DNSQueryThread.cpp
deleted file mode 100644
index a5e9dd3fd2208eb5466264ce7d5c078961a9eedc..0000000000000000000000000000000000000000
--- a/src/zeroconf/DNSQueryThread.cpp
+++ /dev/null
@@ -1,69 +0,0 @@
-/**
- *  Copyright (C) 2005 Savoir-Faire Linux inc.
- *  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 "DNSQueryThread.h"
-#include "DNSService.h"
-
-/**
- * Construct a DNSQueryThread and initialize the cancel to deferred
- */
-DNSQueryThread::DNSQueryThread(DNSService *parent, const char *regtype) : ost::Thread() 
-{
-  _parent = parent;
-  _regtype = regtype;
-  _serviceRef = NULL;
-  setCancel(cancelDeferred);
-}
-
-/**
- * Destruct a DNSQueryThread
- */
-DNSQueryThread::~DNSQueryThread() 
-{
-  if (_serviceRef) {
-    DNSServiceRefDeallocate(_serviceRef);
-  }
-  terminate();
-  _parent = NULL;
-  _regtype = NULL;
-  _serviceRef = NULL;
-}
-
-/**
- * Running loop
- */
-void
-DNSQueryThread::run() {
-  DNSServiceErrorType theErr=0; // NULL;
-  DNSServiceFlags     resultFlags=0;
-    
-  theErr = DNSServiceBrowse(&_serviceRef,
-            resultFlags,
-            0,  // all interfaces
-            _regtype,
-            NULL,
-            DNSServiceAddServicesCallback,
-            (void*)_parent);
-
-  if (theErr == kDNSServiceErr_NoError) {
-    while(!testCancel()) {
-      DNSServiceProcessResult(_serviceRef); // blockage if none...
-    }
-  }
-}
diff --git a/src/zeroconf/DNSQueryThread.h b/src/zeroconf/DNSQueryThread.h
deleted file mode 100644
index 2ea0bc2cab61d49f1493cccee103e8e8fddd9d33..0000000000000000000000000000000000000000
--- a/src/zeroconf/DNSQueryThread.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/**
- *  Copyright (C) 2005 Savoir-Faire Linux inc.
- *  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.
- */
-#ifndef __DNSSD_DNSQUERYTHREAD_H__
-#define __DNSSD_DNSQUERYTHREAD_H__
-
-#include <cc++/thread.h>
-#include <dns_sd.h>
-
-class DNSService;
-class DNSQueryThread : public ost::Thread
-{
-public:
-  DNSQueryThread(DNSService *parent, const char *regtype);
-  ~DNSQueryThread();
-  virtual void run(); // looking for services
-  
-private:
-  DNSService    *_parent;    // parent service
-  DNSServiceRef _serviceRef; // service reference 
-  const char    *_regtype;   // service type and socket type (_sip._udp by example)
-};
-
-
-#endif // __DNSSD_DNSQUERYTHREAD_H__
diff --git a/src/zeroconf/DNSService.cpp b/src/zeroconf/DNSService.cpp
deleted file mode 100644
index e2919fe27d93ec7c431ec7e30cb53d1469b462f2..0000000000000000000000000000000000000000
--- a/src/zeroconf/DNSService.cpp
+++ /dev/null
@@ -1,237 +0,0 @@
-/**
- *  Copyright (C) 2005 Savoir-Faire Linux inc.
- *  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.
- */
- 
- /**
-  * Inspired by http://braden.machacking.net/zerobrowse.cpp and
-  * http://developer.kde.org/documentation/library/3.4-api/dnssd/html/remoteservice_8cpp-source.html
-  */
-#include "DNSService.h"
-#include "DNSServiceTXTRecord.h"
-#include "DNSQueryThread.h"
-
-#include <cc++/thread.h>
-
-/**
- * Simple Empty Constructor
- */
-DNSService::DNSService()
-{
-  _start = false;
-  _regtypeList.push_back("_sip._udp");
-#ifdef USE_IAX2
-  _regtypeList.push_back("_iax._udp");
-#endif
-
-  // for the thread, the ifdef add a dynamic _regtypeList problem
-  for (std::list<std::string>::iterator iterThread=_regtypeList.begin();
-       iterThread!=_regtypeList.end();
-       iterThread++) {
-    _queryThread.push_back(new DNSQueryThread(this, (*iterThread).c_str()));
-  }
-}
-
-/**
- * Simple Empty Destructor
- */
-DNSService::~DNSService()
-{
-  int cntThread = _queryThread.size();
-  for (int iThread=0;iThread<cntThread;iThread++) {
-    delete _queryThread[iThread]; _queryThread[iThread] = NULL;
-  }
-}
-
-/**
- * Look for zeroconf services and add them to _services
- */
-void
-DNSService::startScanServices() 
-{
-  for (std::vector<DNSQueryThread *>::iterator iter = _queryThread.begin();iter!=_queryThread.end();iter++) {
-    (*iter)->start();
-  }
-  _start = true;
-}
-
-/**
- * Add one service to the list of actual services
- * @param service Service to add to the list
- */
-void DNSService::addService(const std::string &service) 
-{
-  DNSServiceTXTRecord txtRecord;
-  _mutex.enterMutex();
-  _services[service] = txtRecord;
-  // we leave before the queryService since, each 
-  // thread will modify a DNSServiceTXTRecord of a difference services
-  _mutex.leaveMutex();
-  notify();
-  queryService(service);
-}
-
-/**
- * Remove one service to the list of actual services
- * @param service Service to remove to the list
- */
-void DNSService::removeService(const std::string &service) 
-{
-  _mutex.enterMutex();
-  _services.erase(service);
-  _mutex.leaveMutex();
-  notify();
-}
-
-/**
- * Return every services
- */
-DNSServiceMap
-DNSService::getServices() 
-{
-  ost::MutexLock m(_mutex);
-  return _services;
-}
-
-
-/**
- * Query a service and wait for the anwser
- * the queryCallback will show the result
- * @param service The service full adress
- */
-void 
-DNSService::queryService(const std::string &service) 
-{
-  DNSServiceErrorType theErr=0;
-  DNSServiceRef       myServRef=0;
-  DNSServiceFlags     resultFlags=0;
-  
-  theErr = DNSServiceQueryRecord(&myServRef, 
-				 resultFlags, 
-				 0, 
-				 service.c_str(), 
-				 kDNSServiceType_TXT, 
-				 kDNSServiceClass_IN, 
-				 DNSServiceQueryRecordCallback, 
-				 (void*)this);
-  if (theErr == kDNSServiceErr_NoError) {
-    DNSServiceProcessResult(myServRef); // blockage...
-    DNSServiceRefDeallocate(myServRef);
-  }
-}
-
-/**
- * Overloadding queryService
- * @param service service name
- * @param regtype registred type of service
- * @param domain  domain (habitually local.)
- */
-void 
-DNSService::queryService(const char *service, const char *regtype, const char *domain) 
-{
-  char serviceName[kDNSServiceMaxDomainName+1];
-  DNSServiceConstructFullName(serviceName, service, regtype, domain);
-  queryService(std::string(serviceName));
-}
-
-/**
- * Add a txt record with the queryService callback answser data
- * @param rdlen the length of the txt record data
- * @param rdata txt record data
- */
-void 
-DNSService::addTXTRecord(const char *fullname, uint16_t rdlen, const void *rdata) 
-{
-  char key[256];
-  
-  const char *value;
-  uint8_t valueLen; // 0 to 256 by type restriction
-  char valueTab[256];
-  
-  
-  uint16_t keyCount = TXTRecordGetCount(rdlen, rdata);
-  for (int iKey=0; iKey<keyCount; iKey++) {
-    TXTRecordGetItemAtIndex (rdlen, rdata, iKey, 256, key, &valueLen, (const void **)(&value));
-    if (value) {
-      bcopy(value, valueTab, valueLen);
-      valueTab[valueLen]='\0';
-      _mutex.enterMutex(); // extra-careful
-      _services[fullname].addKeyValue(key, valueTab);
-      _mutex.leaveMutex();
-    } else {
-      _mutex.enterMutex();
-      _services[fullname].removeKey(key);
-      _mutex.leaveMutex();
-    }
-  }
-
-  notify();
-}
-
-void 
-DNSServiceAddServicesCallback(DNSServiceRef,
-						DNSServiceFlags flags,
-						uint32_t,
-						DNSServiceErrorType errorCode,
-						const char *serviceName,
-						const char *replyType,
-						const char *replyDomain,
-						void *context)
-{
-  if (errorCode==kDNSServiceErr_NoError) {
-  
-    if (flags) {
-      DNSService *service = (DNSService*)context;
-      std::string tempService;
-      tempService = std::string(serviceName) + "." + std::string(replyType) + std::string(replyDomain);
-      if (flags&kDNSServiceFlagsAdd) {
-//        _debug("DNSServiceAddServicesCallback call addService\n");
-        service->addService(tempService);
-      } else {
-//        _debug("DNSServiceAddServicesCallback call removeService\n");
-        service->removeService(tempService);
-      }
-    }
-  } else {
-     // TODO: error handling
-  }
-}
-
-void 
-DNSServiceQueryRecordCallback(
-	DNSServiceRef,
-	DNSServiceFlags flags,
-	uint32_t,
-	DNSServiceErrorType errorCode,
-	const char *fullname,
-	uint16_t,
-	uint16_t,
-	uint16_t rdlen,
-	const void *rdata,
-	uint32_t,
-	void *context)
-{
-  if (errorCode==kDNSServiceErr_NoError) {
-    if (flags&kDNSServiceFlagsAdd) {
-//      _debug("DNSServiceQueryRecordCallback call addTXTRecord\n");
-      ((DNSService *)context)->addTXTRecord(fullname, rdlen, rdata);
-    } else {
-//      _debug("DNSServiceQueryRecordCallback call removeService\n");
-      ((DNSService *)context)->removeService(fullname);
-    }
-  }
-}
diff --git a/src/zeroconf/DNSService.h b/src/zeroconf/DNSService.h
deleted file mode 100644
index b1a840bf1cf6bf5b8076d9fb79c2785f84cb6ae4..0000000000000000000000000000000000000000
--- a/src/zeroconf/DNSService.h
+++ /dev/null
@@ -1,92 +0,0 @@
-/**
- *  Copyright (C) 2005 Savoir-Faire Linux inc.
- *  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.
- */
-#ifndef __DNSSD_DNSSERVICE_H__
-#define __DNSSD_DNSSERVICE_H__
-
-#include <string>
-#include <map>
-#include <list>
-#include <vector>
-
-#include <dns_sd.h>
-#include <cc++/thread.h>
-#include "../observer.h"
-
-class DNSQueryThread;
-class DNSServiceTXTRecord;
-
-typedef std::map<std::string, DNSServiceTXTRecord> DNSServiceMap;
-class DNSService : public Pattern::Subject
-{
-public:
-  DNSService();
-  ~DNSService();
-  
-  void startScanServices(); // looking for services
-  void addService(const std::string &service); // adding every services
-  void removeService(const std::string &service); // remove a service
-  DNSServiceMap getServices(); // get all DNS Service
-  void stop(); // after the browsing loop stop
-  
-  void queryService(const std::string &service); // query the TXT record of a service
-  void queryService(const char *service, const char *regtype, const char *domain);
-  void addTXTRecord(const char *fullname, uint16_t rdlen, const void *rdata);
-  //void removeTXTRecord(const char *fullname);
-
-  bool isStart() const { return _start; }
-
-private:
-  DNSServiceMap _services; //map
-
-  std::vector<DNSQueryThread *> _queryThread;
-  /**
-   * Mutex to protect access to _services on add/erase
-   */
-  ost::Mutex _mutex;
-  /**
-   * RegType List contains zeroconf services to register, like sip, iax2, ...
-   * It will be use to initialize the DNSQueryThread
-   */
-  std::list<std::string> _regtypeList;
-
-  bool _start;
-};
-
-void DNSServiceAddServicesCallback(DNSServiceRef sdRef,
-						DNSServiceFlags flags,
-						uint32_t interfaceIndex,
-						DNSServiceErrorType errorCode,
-						const char *serviceName,
-						const char *replyType,
-						const char *replyDomain,
-						void *context);
-
-void DNSServiceQueryRecordCallback(DNSServiceRef DNSServiceRef,
-	DNSServiceFlags flags,
-	uint32_t interfaceIndex,
-	DNSServiceErrorType errorCode,
-	const char *fullname,
-	uint16_t rrtype,
-	uint16_t rrclass,
-	uint16_t rdlen,
-	const void *rdata,
-	uint32_t ttl,
-	void *context);
-
-#endif // __DNSSD_DNSSERVICE_H__
diff --git a/src/zeroconf/DNSServiceTXTRecord.cpp b/src/zeroconf/DNSServiceTXTRecord.cpp
deleted file mode 100644
index f12ed15f5b2b1f9468ffa72f8b71d3567102f5a2..0000000000000000000000000000000000000000
--- a/src/zeroconf/DNSServiceTXTRecord.cpp
+++ /dev/null
@@ -1,76 +0,0 @@
-/**
- *  Copyright (C) 2005 Savoir-Faire Linux inc.
- *  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 "DNSServiceTXTRecord.h"
-
-/**
- * Simple constructor
- */
-DNSServiceTXTRecord::DNSServiceTXTRecord() 
-{
-}
- 
-/**
- * Simple destructor
- */
-DNSServiceTXTRecord::~DNSServiceTXTRecord() 
-{
-}
-
-/**
- * add a pair of key/value inside the associative std::map
- * @param key    unique key inside the std::map
- * @param value  value associated to the key
- */
-void 
-DNSServiceTXTRecord::addKeyValue(const std::string &key, const std::string &value) 
-{
-  _map[key] = value;
-}
-
-/**
- * remove a key inside the map or do nothing if it doesn't exist
- * @param key    unique key inside the std::map
- */
-void 
-DNSServiceTXTRecord::removeKey(const std::string &key) 
-{
-  _map.erase(key);
-}
-
-/**
- * get a value from a key
- * @param key    unique key inside the std::map
- * @return the value or empty
- */
-const std::string &
-DNSServiceTXTRecord::getValue(const std::string &key) 
-{
-  return _map[key]; // return std::string("") if it's not there
-}
-
-/**
- * get a value from a key
- * @param key    unique key inside the std::map
- * @return the value or empty
- */
-const std::string &
-DNSServiceTXTRecord::getValue(const char* key) 
-{
-  return getValue(std::string(key));
-}
diff --git a/src/zeroconf/DNSServiceTXTRecord.h b/src/zeroconf/DNSServiceTXTRecord.h
deleted file mode 100644
index d6d2742fd6efa5091dc04f63064f3eb28e555397..0000000000000000000000000000000000000000
--- a/src/zeroconf/DNSServiceTXTRecord.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/**
- *  Copyright (C) 2005 Savoir-Faire Linux inc.
- *  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.
- */
-#ifndef __DNSSD_DNSSERVICETXTRECORD_H__
-#define __DNSSD_DNSSERVICETXTRECORD_H__
-
-#include <string>
-#include <map>
-
-typedef std::map<std::string, std::string> TXTRecordMap;
-class DNSServiceTXTRecord
-{
-public:
-  DNSServiceTXTRecord();
-  ~DNSServiceTXTRecord();
-  void addKeyValue(const std::string &key, const std::string &value);
-  void removeKey(const std::string &key);
-  const std::string &getValue(const std::string &key);
-  const std::string &getValue(const char *key);
-  inline void clear(void) { _map.clear(); };
-  inline int size(void) { return _map.size(); };
-  TXTRecordMap getTXTRecords() { return _map; }
-
-private:
-  TXTRecordMap _map;
-};
-
-#endif // __DNSSD_DNSSERVICETXTRECORD_H__
diff --git a/src/zeroconf/Makefile.am b/src/zeroconf/Makefile.am
deleted file mode 100644
index d2ed5b4e4a56d0330b7bad354ea7f2afec291086..0000000000000000000000000000000000000000
--- a/src/zeroconf/Makefile.am
+++ /dev/null
@@ -1,12 +0,0 @@
-SUBDIRS = 
-
-noinst_LTLIBRARIES = libzeroconf.la
-
-libzeroconf_la_SOURCES = \
-	DNSQueryThread.cpp  DNSQueryThread.h \
-	DNSService.cpp  DNSService.h  \
-	DNSServiceTXTRecord.cpp  DNSServiceTXTRecord.h
-
-AM_CXXFLAGS = $(libccext2_CFLAGS)
-libzeroconf_la_LIBADD = $(LIB_DNSSD) 
-