diff --git a/daemon/src/Makefile.am b/daemon/src/Makefile.am
index e7a13f7655ba1c0786271f77f4046d3383e9f94d..479d5164ce157af1f85376aaa17fcd6ba3e34a78 100644
--- a/daemon/src/Makefile.am
+++ b/daemon/src/Makefile.am
@@ -75,6 +75,7 @@ libsflphone_la_CFLAGS = \
 
 libsflphone_la_SOURCES = conference.cpp \
 		account_factory.cpp \
+		call_factory.cpp \
 		preferences.cpp \
 		managerimpl.cpp \
 		manager.cpp \
@@ -89,6 +90,7 @@ libsflphone_la_SOURCES = conference.cpp \
 		threadloop.h \
 		conference.h \
 		account factory.h \
+		call factory.h \
 		voiplink.h \
 		preferences.h \
 		managerimpl.h \
diff --git a/daemon/src/account.cpp b/daemon/src/account.cpp
index 093e5bb39f975e47451d7785943f2a76d854541d..825f8ee921412105f1a87c8b2df3aeb3d9d6dabb 100644
--- a/daemon/src/account.cpp
+++ b/daemon/src/account.cpp
@@ -108,11 +108,23 @@ Account::Account(const string &accountID)
 Account::~Account()
 {}
 
+void
+Account::attachCall(const string& id)
+{
+    callIDSet_.insert(id);
+}
+
+void
+Account::detachCall(const string& id)
+{
+    callIDSet_.erase(id);
+}
+
 void
 Account::freeAccount()
 {
-    for (const auto& call : getVoIPLink()->getCalls(accountID_))
-        Manager::instance().hangupCall(call->getCallId());
+    for (const auto& id : callIDSet_)
+        Manager::instance().hangupCall(id);
     unregisterVoIPLink();
 }
 
diff --git a/daemon/src/account.h b/daemon/src/account.h
index 998c470e8ed81f4e1f28eb389955aa833c73804d..c17e7ee1b3d92cac7a3e4de7d1a8f65e4661b356 100644
--- a/daemon/src/account.h
+++ b/daemon/src/account.h
@@ -1,7 +1,8 @@
 /*
- *  Copyright (C) 2004-2013 Savoir-Faire Linux Inc.
+ *  Copyright (C) 2004-2014 Savoir-Faire Linux Inc.
  *  Author: Emmanuel Milou <emmanuel.milou@savoirfairelinux.com>
  *  Author: Yan Morin <yan.morin@savoirfairelinux.com>
+ *  Author : Guillaume Roguez <guillaume.roguez@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
@@ -42,6 +43,7 @@
 #include <vector>
 #include <memory>
 #include <map>
+#include <set>
 
 class VoIPLink;
 class Call;
@@ -112,14 +114,21 @@ class Account : public Serializable {
         virtual void unregisterVoIPLink(std::function<void(bool)> cb = std::function<void(bool)>()) = 0;
 
         /**
-         * Create a new outgoing call
+         * Create a new outgoing call.
+         *
          * @param id  The ID of the call
          * @param toUrl The address to call
-         * @return Call*  A pointer on the call
+         * @return std::shared_ptr<Call> A pointer on the created call
          */
         virtual std::shared_ptr<Call> newOutgoingCall(const std::string& id,
                                                       const std::string& toUrl) = 0;
 
+        /* Note: we forbid incoming call creation from an instance of Account.
+         * This is why no newIncomingCall() method exist here.
+         */
+
+        std::vector<std::shared_ptr<Call> > getCalls();
+
         /**
          * Tell if the account is enable or not.
          * @return true if enabled
@@ -210,12 +219,17 @@ class Account : public Serializable {
             mailBox_ = mb;
         }
 
+        void attachCall(const std::string& id);
+
+        void detachCall(const std::string& id);
+
         static std::vector<std::string> split_string(std::string s);
 
         static const char * const VIDEO_CODEC_ENABLED;
         static const char * const VIDEO_CODEC_NAME;
         static const char * const VIDEO_CODEC_PARAMETERS;
         static const char * const VIDEO_CODEC_BITRATE;
+
     private:
         NON_COPYABLE(Account);
 
@@ -224,8 +238,12 @@ class Account : public Serializable {
          */
         void loadDefaultCodecs();
 
-    protected:
+        /**
+         * Set of call's ID attached to the account.
+         */
+        std::set<std::string> callIDSet_ = {};
 
+    protected:
         static void parseString(const std::map<std::string, std::string> &details, const char *key, std::string &s);
         static void parseBool(const std::map<std::string, std::string> &details, const char *key, bool &b);
 
diff --git a/daemon/src/call.cpp b/daemon/src/call.cpp
index dff059fcb1bd594321efa6c4df47cb787ea0381c..584d9f6ef65ff6320958ca8e2d09ab650cdb9963 100644
--- a/daemon/src/call.cpp
+++ b/daemon/src/call.cpp
@@ -1,7 +1,8 @@
 /*
- *  Copyright (C) 2004-2013 Savoir-Faire Linux Inc.
+ *  Copyright (C) 2004-2014 Savoir-Faire Linux Inc.
  *  Author: Yan Morin <yan.morin@savoirfairelinux.com>
  *  Author : Laurielle Lea <laurielle.lea@savoirfairelinux.com>
+ *  Author : Guillaume Roguez <guillaume.roguez@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
@@ -38,8 +39,10 @@
 #include "sip/sip_utils.h"
 #include "ip_utils.h"
 #include "array_size.h"
+#include "map_utils.h"
+#include "call_factory.h"
 
-Call::Call(const std::string& id, Call::CallType type, Account& account)
+Call::Call(Account& account, const std::string& id, Call::CallType type)
     : callMutex_()
     , localAddr_()
     , localAudioPort_(0)
@@ -57,12 +60,22 @@ Call::Call(const std::string& id, Call::CallType type, Account& account)
     , timestamp_stop_(0)
 {
     time(&timestamp_start_);
+    account_.attachCall(id_);
 }
 
 Call::~Call()
-{}
+{
+    account_.detachCall(id_);
+}
 
-std::string Call::getAccountId() const
+void
+Call::removeCall()
+{
+    Manager::instance().callFactory.removeCall(*this);
+}
+
+const std::string&
+Call::getAccountId() const
 {
     return account_.getAccountID();
 }
@@ -299,24 +312,3 @@ Call::getNullDetails()
     details["ACCOUNTID"] = "";
     return details;
 }
-
-std::shared_ptr<Call>
-Call::newOutgoingCall(const std::string& id,
-                      const std::string& toUrl,
-                      const std::string& preferredAccountId)
-{
-    std::shared_ptr<Call> call;
-    std::string toIP = toUrl;
-    sip_utils::stripSipUriPrefix(toIP);
-
-    if (!IpAddr::isValid(toIP)) {
-        auto account = Manager::instance().getAccount(preferredAccountId);
-        if (account)
-            return account->newOutgoingCall(id, toUrl);
-        else
-            WARN("Preferred account %s doesn't exist, using IP2IP account", preferredAccountId.c_str());
-    } else
-        WARN("IP Url detected, using IP2IP account");
-
-    return Manager::instance().getIP2IPAccount()->newOutgoingCall(id, toIP);
-}
diff --git a/daemon/src/call.h b/daemon/src/call.h
index e8278cbb3bf94c39f82d3f8f85c97be2b1d1c5ee..b2c1526b02ee67adee44c53e9f686fc49a231978 100644
--- a/daemon/src/call.h
+++ b/daemon/src/call.h
@@ -1,8 +1,9 @@
 /*
- *  Copyright (C) 2004-2013 Savoir-Faire Linux Inc.
+ *  Copyright (C) 2004-2014 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 : Guillaume Roguez <guillaume.roguez@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
@@ -29,6 +30,7 @@
  *  shall include the source code for the parts of OpenSSL used as well
  *  as that of the covered work.
  */
+
 #ifndef __CALL_H__
 #define __CALL_H__
 
@@ -40,10 +42,14 @@
 #include <mutex>
 #include <map>
 #include <sstream>
+#include <memory>
+#include <vector>
 
 class VoIPLink;
 class Account;
 
+template <class T> using CallMap = std::map<std::string, std::shared_ptr<T> >;
+
 /*
  * @file call.h
  * @brief A call is the base class for protocol-based calls
@@ -74,32 +80,13 @@ class Call : public Recordable {
          */
         enum CallState {INACTIVE, ACTIVE, HOLD, BUSY, ERROR};
 
-        /**
-         * Constructor of a call
-         * @param id Unique identifier of the call
-         * @param type set definitely this call as incoming/outgoing
-         */
-        Call(const std::string& id, Call::CallType type, Account& account);
         virtual ~Call();
 
         /**
-         * Create a new outgoing call
-         * @param id  The ID of the call
-         * @param toUrl The address to call
-         * @param preferredAccountId The IP of preferred account to use.
-         *   This is not necessary the account used.
-         * @return Call*  A shared pointer on a valid call.
-         * @note This function raises VoipLinkException() on errors.
-         */
-        static std::shared_ptr<Call> newOutgoingCall(const std::string& id,
-                                                     const std::string& toUrl,
-                                                     const std::string& preferredAccountId);
-
-        /**
-         * Return a copy of the call id
+         * Return a reference on the call id
          * @return call id
          */
-        std::string getCallId() const {
+        const std::string& getCallId() const {
             return id_;
         }
 
@@ -107,7 +94,7 @@ class Call : public Recordable {
          * Return a reference on the conference id
          * @return call id
          */
-        std::string getConfId() const {
+        const std::string& getConfId() const {
             return confID_;
         }
 
@@ -116,7 +103,7 @@ class Call : public Recordable {
         }
 
         Account& getAccount() const { return account_; }
-        std::string getAccountId() const;
+        const std::string& getAccountId() const;
 
         CallType getCallType() const {
             return type_;
@@ -313,6 +300,16 @@ class Call : public Recordable {
                                      const std::string &from) = 0;
 #endif
 
+        void removeCall();
+
+    protected:
+        /**
+         * Constructor of a call
+         * @param id Unique identifier of the call
+         * @param type set definitely this call as incoming/outgoing
+         */
+        Call(Account& account, const std::string& id, Call::CallType type);
+
     private:
         bool validTransition(CallState newState);
 
diff --git a/daemon/src/call_factory.cpp b/daemon/src/call_factory.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..3e29a2640a8005aba3d6caeef782a0a267f5f08b
--- /dev/null
+++ b/daemon/src/call_factory.cpp
@@ -0,0 +1,158 @@
+/*
+ *  Copyright (C) 2004-2014 Savoir-Faire Linux Inc.
+ *  Author : Guillaume Roguez <guillaume.roguez@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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA.
+ *
+ *  Additional permission under GNU GPL version 3 section 7:
+ *
+ *  If you modify this program, or any covered work, by linking or
+ *  combining it with the OpenSSL project's OpenSSL library (or a
+ *  modified version of that library), containing parts covered by the
+ *  terms of the OpenSSL or SSLeay licenses, Savoir-Faire Linux Inc.
+ *  grants you additional permission to convey the resulting work.
+ *  Corresponding Source for a non-source form of such a combination
+ *  shall include the source code for the parts of OpenSSL used as well
+ *  as that of the covered work.
+ */
+
+#include "call_factory.h"
+
+#include <stdexcept>
+
+void
+CallFactory::forbid()
+{
+    allowNewCall_ = false;
+}
+
+void
+CallFactory::removeCall(Call& call)
+{
+    std::lock_guard<std::recursive_mutex> lk(callMapsMutex_);
+
+    const auto& id = call.getCallId();
+    DEBUG("Removing call %s", id.c_str());
+    const auto& account = call.getAccount();
+    auto& map = callMaps_.at(account.getAccountType());
+    map.erase(id);
+    DEBUG("Remaining %u %s call(s)", map.size(), account.getAccountType());
+}
+
+void
+CallFactory::removeCall(const std::string& id)
+{
+    std::lock_guard<std::recursive_mutex> lk(callMapsMutex_);
+
+    if (auto call = getCall(id)) {
+        removeCall(*call);
+    } else
+        ERROR("No call with ID %s", id.c_str());
+}
+
+//==============================================================================
+// Template specializations (when T = Call)
+
+template <> bool
+CallFactory::hasCall<Call>(const std::string& id) const
+{
+    std::lock_guard<std::recursive_mutex> lk(callMapsMutex_);
+
+    for (const auto& item : callMaps_) {
+        const auto& map = item.second;
+        if (map.find(id) != map.cend())
+            return true;
+    }
+
+    return false;
+}
+
+template <> void
+CallFactory::clear<Call>()
+{
+    std::lock_guard<std::recursive_mutex> lk(callMapsMutex_);
+    callMaps_.clear();
+}
+
+template <> bool
+CallFactory::empty<Call>() const
+{
+    std::lock_guard<std::recursive_mutex> lk(callMapsMutex_);
+
+    for (const auto& item : callMaps_) {
+        const auto& map = item.second;
+        if (!map.empty())
+            return false;
+    }
+
+    return true;
+}
+
+template <> std::shared_ptr<Call>
+CallFactory::getCall<Call>(const std::string& id)
+{
+    std::lock_guard<std::recursive_mutex> lk(callMapsMutex_);
+
+    for (const auto& item : callMaps_) {
+        const auto& map = item.second;
+        const auto& iter = map.find(id);
+        if (iter != map.cend())
+            return iter->second;
+    }
+
+    return nullptr;
+}
+
+template <> std::vector<std::shared_ptr<Call> >
+CallFactory::getAllCalls<Call>()
+{
+    std::lock_guard<std::recursive_mutex> lk(callMapsMutex_);
+    std::vector<std::shared_ptr<Call> > v;
+
+    for (const auto& itemmap : callMaps_) {
+        const auto& map = itemmap.second;
+        for (const auto item : map)
+            v.push_back(item.second);
+    }
+
+    v.shrink_to_fit();
+    return v;
+}
+
+template <> std::vector<std::string>
+CallFactory::getCallIDs<Call>() const {
+    std::vector<std::string> v;
+
+    for (const auto& item : callMaps_) {
+        const auto& map = item.second;
+        for (const auto& it : map)
+            v.push_back(it.first);
+    }
+
+    v.shrink_to_fit();
+    return v;
+}
+
+template <> std::size_t
+CallFactory::callCount<Call>()
+{
+    std::lock_guard<std::recursive_mutex> lk(callMapsMutex_);
+    std::size_t count = 0;
+
+    for (const auto& itemmap : callMaps_)
+        count += itemmap.second.size();
+
+    return count;
+}
diff --git a/daemon/src/call_factory.h b/daemon/src/call_factory.h
new file mode 100644
index 0000000000000000000000000000000000000000..fbd6748645f2a06603df06d4078670a1c5452f10
--- /dev/null
+++ b/daemon/src/call_factory.h
@@ -0,0 +1,242 @@
+/*
+ *  Copyright (C) 2004-2014 Savoir-Faire Linux Inc.
+ *  Author : Guillaume Roguez <guillaume.roguez@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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA.
+ *
+ *  Additional permission under GNU GPL version 3 section 7:
+ *
+ *  If you modify this program, or any covered work, by linking or
+ *  combining it with the OpenSSL project's OpenSSL library (or a
+ *  modified version of that library), containing parts covered by the
+ *  terms of the OpenSSL or SSLeay licenses, Savoir-Faire Linux Inc.
+ *  grants you additional permission to convey the resulting work.
+ *  Corresponding Source for a non-source form of such a combination
+ *  shall include the source code for the parts of OpenSSL used as well
+ *  as that of the covered work.
+ */
+
+#ifndef CALL_FACTORY_H
+#define CALL_FACTORY_H
+
+#include <call.h>
+#include <account.h>
+
+#include <map>
+#include <memory>
+#include <mutex>
+#include <vector>
+#include <string>
+#include <utility>
+
+class CallFactory {
+    public:
+        /**
+         * Forbid creation of new calls.
+         */
+        void forbid();
+
+        /**
+         * Remove given call instance from call list.
+         */
+        void removeCall(Call& call);
+
+        /**
+         * Accessor on removeCall with callID than instance.
+         */
+        void removeCall(const std::string& id);
+
+        // Specializations of following template methods for T = Call
+        // are defined in call.cpp
+
+        /**
+         * Return if given call exists. Type can optionally be specified.
+         */
+        template <class T = Call>
+        bool hasCall(const std::string& id) const {
+            std::lock_guard<std::recursive_mutex> lk(callMapsMutex_);
+
+            const auto map = getMap_<T>();
+            return map and map->find(id) != map->cend();
+        }
+
+        /**
+         * Create a new call instance of Call class T, using Account class A.
+         * @param id Unique identifier of the call
+         * @param type set definitely this call as incoming/outgoing
+         * @param account account useed to create this call
+         */
+        template <class T, class A>
+        std::shared_ptr<T> newCall(A& account, const std::string& id, Call::CallType type) {
+            if (!allowNewCall_) {
+                WARN("newCall aborted : CallFactory in forbid state");
+                return nullptr;
+            }
+
+            // Trick: std::make_shared<T> can't build as T constructor is protected
+            // and not accessible from std::make_shared.
+            // We use a concrete class to bypass this restriction.
+            struct ConcreteCall : T {
+                    ConcreteCall(A& account, const std::string& id, Call::CallType type)
+                        : T(account, id, type) {}
+            };
+
+            if (hasCall(id)) {
+                ERROR("Call %s is already created", id.c_str());
+                return nullptr;
+            }
+
+            auto call = std::make_shared<ConcreteCall>(account, id, type);
+
+            {
+                std::lock_guard<std::recursive_mutex> lk(callMapsMutex_);
+                callMaps_[account.getAccountType()].insert(std::make_pair(id, call));
+            }
+
+            return call;
+        }
+
+        /**
+         * Return if calls exist. Type can optionally be specified.
+         */
+        template <class T = Call>
+        bool empty() const {
+            std::lock_guard<std::recursive_mutex> lk(callMapsMutex_);
+
+            const auto map = getMap_<T>();
+            return !map or map->empty();
+        }
+
+        /**
+         * Erase all calls. Type can optionally be specified.
+         */
+        template <class T = Call>
+        void clear() {
+            std::lock_guard<std::recursive_mutex> lk(callMapsMutex_);
+
+            auto map = getMap_<T>();
+            if (!map) return;
+
+            map->clear();
+        }
+
+        /**
+         * Return call pointer associated to given ID. Type can optionally be specified.
+         */
+        template <class T = Call>
+        std::shared_ptr<T> getCall(const std::string& id) {
+            std::lock_guard<std::recursive_mutex> lk(callMapsMutex_);
+
+            const auto map = getMap_<T>();
+            if (!map) return nullptr;
+
+            const auto& it = map->find(id);
+            if (it == map->cend())
+                return nullptr;
+
+            return std::static_pointer_cast<T>(it->second);
+        }
+
+        /**
+         * Return all calls. Type can optionally be specified.
+         */
+        template <class T = Call>
+        std::vector<std::shared_ptr<T> > getAllCalls() {
+            std::lock_guard<std::recursive_mutex> lk(callMapsMutex_);
+            std::vector<std::shared_ptr<T> > v;
+
+            const auto map = getMap_<T>();
+            if (map) {
+                for (const auto& it : *map)
+                    v.push_back(std::static_pointer_cast<T>(it.second));
+            }
+
+            v.shrink_to_fit();
+            return v;
+        }
+
+        /**
+         * Return all call's IDs. Type can optionally be specified.
+         */
+        template <class T = Call>
+        std::vector<std::string> getCallIDs() const {
+            std::lock_guard<std::recursive_mutex> lk(callMapsMutex_);
+            std::vector<std::string> v;
+
+            const auto map = getMap_<T>();
+            if (map) {
+                for (const auto& it : *map)
+                    v.push_back(it.first);
+            }
+
+            v.shrink_to_fit();
+            return v;
+        }
+
+        /**
+         * Return number of calls. Type can optionally be specified.
+         */
+        template <class T = Call>
+        std::size_t callCount() {
+            std::lock_guard<std::recursive_mutex> lk(callMapsMutex_);
+
+            const auto map = getMap_<T>();
+            if (!map) return 0;
+
+            return map->size();
+        }
+
+    private:
+        mutable std::recursive_mutex callMapsMutex_{};
+
+        std::atomic_bool allowNewCall_{true};
+
+        std::map<std::string, CallMap<Call> > callMaps_{};
+
+        template <class T>
+        const CallMap<Call>* getMap_() const {
+            const auto& itermap = callMaps_.find(T::LINK_TYPE);
+
+            if (itermap != callMaps_.cend())
+                return &itermap->second;
+
+            return nullptr;
+        }
+};
+
+// Specializations defined in call_factory.cpp
+
+template <> bool
+CallFactory::hasCall<Call>(const std::string& id) const;
+
+template <> void
+CallFactory::clear<Call>();
+
+template <> bool
+CallFactory::empty<Call>() const;
+
+template <> std::shared_ptr<Call>
+CallFactory::getCall<Call>(const std::string& id);
+
+template <> std::vector<std::shared_ptr<Call> >
+CallFactory::getAllCalls<Call>();
+
+template <> std::vector<std::string>
+CallFactory::getCallIDs<Call>() const;
+
+template <> std::size_t
+CallFactory::callCount<Call>();
+
+#endif // CALL_FACTORY_H
diff --git a/daemon/src/client/callmanager.cpp b/daemon/src/client/callmanager.cpp
index 05f3112302e39e5114fc4a4bc7068c63e7d94b54..d1c3ba17a4207d1d6a1e4d63fa38aee851cf2b71 100644
--- a/daemon/src/client/callmanager.cpp
+++ b/daemon/src/client/callmanager.cpp
@@ -32,6 +32,7 @@
 
 #include "global.h"
 #include "callmanager.h"
+#include "call_factory.h"
 
 #include "sip/sipcall.h"
 #include "sip/sipvoiplink.h"
@@ -285,7 +286,7 @@ CallManager::getAudioZrtpSession(const std::string& callID)
     if (!link)
         throw CallManagerException("Failed to get sip link");
 
-    auto call = link->getSipCall(callID);
+    const auto call = Manager::instance().callFactory.getCall<SIPCall>(callID);
     if (!call)
         throw CallManagerException("Call id " + callID + " is not valid");
 
diff --git a/daemon/src/conference.cpp b/daemon/src/conference.cpp
index 908b2397ce4e8e78d95d5794f0d892ab9ca6ed58..b681e9b4d4ba769b3ad9a877f121ba11f973fe71 100644
--- a/daemon/src/conference.cpp
+++ b/daemon/src/conference.cpp
@@ -1,7 +1,7 @@
 /*
- *  Copyright (C) 2004-2013 Savoir-Faire Linux Inc.
+ *  Copyright (C) 2004-2014 Savoir-Faire Linux Inc.
  *  Author : Alexandre Savard <alexandre.savard@savoirfairelinux.com>
- *
+ *  Author : Guillaume Roguez <guillaume.roguez@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
@@ -37,12 +37,13 @@
 #include "audio/mainbuffer.h"
 
 #ifdef SFL_VIDEO
-#include "sip/sipvoiplink.h"
 #include "sip/sipcall.h"
 #include "client/videomanager.h"
 #include "video/video_input.h"
 #endif
 
+#include "call_factory.h"
+
 #include "logger.h"
 
 
@@ -61,7 +62,7 @@ Conference::~Conference()
 {
 #ifdef SFL_VIDEO
     for (const auto &participant_id : participants_) {
-        if (auto call = SIPVoIPLink::instance().getSipCall(participant_id))
+        if (auto call = Manager::instance().callFactory.getCall<SIPCall>(participant_id))
             call->getVideoRtp().exitConference();
     }
 #endif // SFL_VIDEO
@@ -81,7 +82,7 @@ void Conference::add(const std::string &participant_id)
 {
     if (participants_.insert(participant_id).second) {
 #ifdef SFL_VIDEO
-        if (auto call = SIPVoIPLink::instance().getSipCall(participant_id))
+        if (auto call = Manager::instance().callFactory.getCall<SIPCall>(participant_id))
             call->getVideoRtp().enterConference(this);
 #endif // SFL_VIDEO
     }
@@ -91,7 +92,7 @@ void Conference::remove(const std::string &participant_id)
 {
     if (participants_.erase(participant_id)) {
 #ifdef SFL_VIDEO
-        if (auto call = SIPVoIPLink::instance().getSipCall(participant_id))
+        if (auto call = Manager::instance().callFactory.getCall<SIPCall>(participant_id))
             call->getVideoRtp().exitConference();
 #endif // SFL_VIDEO
     }
diff --git a/daemon/src/iax/iaxaccount.cpp b/daemon/src/iax/iaxaccount.cpp
index 2ceaf8e8df4bbbebdfb3035198ec363ca33c86e0..af09a370ba03f3604f3bbc17722a7010771a479b 100644
--- a/daemon/src/iax/iaxaccount.cpp
+++ b/daemon/src/iax/iaxaccount.cpp
@@ -1,9 +1,10 @@
 /*
- *  Copyright (C) 2004-2013 Savoir-Faire Linux Inc.
+ *  Copyright (C) 2004-2014 Savoir-Faire Linux Inc.
  *
  *  Author: Emmanuel Milou <emmanuel.milou@savoirfairelinux.com>
  *  Author: Alexandre Bourget <alexandre.bourget@savoirfairelinux.com>
  *  Author: Alexandre Savard <alexandre.savard@savoirfairelinux.com>
+ *  Author : Guillaume Roguez <guillaume.roguez@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
@@ -43,6 +44,7 @@
 #include "manager.h"
 #include "config/yamlnode.h"
 #include "config/yamlemitter.h"
+#include "call_factory.h"
 
 constexpr const char * const IAXAccount::ACCOUNT_TYPE;
 
@@ -169,10 +171,18 @@ IAXAccount::loadConfig()
 #endif
 }
 
-std::shared_ptr<Call>
+template <>
+std::shared_ptr<IAXCall>
+IAXAccount::newIncomingCall(const std::string& id)
+{
+    return Manager::instance().callFactory.newCall<IAXCall, IAXAccount>(*this, id, Call::INCOMING);
+}
+
+template <>
+std::shared_ptr<IAXCall>
 IAXAccount::newOutgoingCall(const std::string& id, const std::string& toUrl)
 {
-    auto call = std::make_shared<IAXCall>(id, Call::OUTGOING, *this, &link_);
+    auto call = Manager::instance().callFactory.newCall<IAXCall, IAXAccount>(*this, id, Call::OUTGOING);
 
     call->setPeerNumber(toUrl);
     call->initRecFilename(toUrl);
@@ -182,11 +192,15 @@ IAXAccount::newOutgoingCall(const std::string& id, const std::string& toUrl)
     call->setConnectionState(Call::PROGRESSING);
     call->setState(Call::ACTIVE);
 
-    IAXVoIPLink::addIaxCall(call);
-
     return call;
 }
 
+std::shared_ptr<Call>
+IAXAccount::newOutgoingCall(const std::string& id, const std::string& toUrl)
+{
+    return newOutgoingCall<IAXCall>(id, toUrl);
+}
+
 void
 IAXAccount::iaxOutgoingInvite(IAXCall* call)
 {
diff --git a/daemon/src/iax/iaxaccount.h b/daemon/src/iax/iaxaccount.h
index a74286f5602beadcf0ab214ca9d378a18b8fa056..3bea07d430e07bc1beb6803295402484c549d171 100644
--- a/daemon/src/iax/iaxaccount.h
+++ b/daemon/src/iax/iaxaccount.h
@@ -1,7 +1,8 @@
 /*
- *  Copyright (C) 2004-2013 Savoir-Faire Linux Inc.
+ *  Copyright (C) 2004-2014 Savoir-Faire Linux Inc.
  *  Author: Alexandre Bourget <alexandre.bourget@savoirfairelinux.com>
  *  Author: Yan Morin <yan.morin@savoirfairelinux.com>
+ *  Author : Guillaume Roguez <guillaume.roguez@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
@@ -35,6 +36,9 @@
 #include "account.h"
 #include "iaxvoiplink.h"
 #include "noncopyable.h"
+#include "sfl_types.h" // enable_if_base_of
+
+class IAXCall;
 
 /**
  * @file: iaxaccount.h
@@ -50,15 +54,6 @@ class IAXAccount : public Account {
             return ACCOUNT_TYPE;
         }
 
-        /**
-         * Create a new outgoing call
-         * @param id  The ID of the call
-         * @param toUrl The address to call
-         * @return Call*  A pointer on the call
-         */
-        std::shared_ptr<Call> newOutgoingCall(const std::string& id,
-                                              const std::string& toUrl);
-
         virtual void serialize(Conf::YamlEmitter &emitter);
         virtual void unserialize(const Conf::YamlNode &map);
 
@@ -105,6 +100,36 @@ class IAXAccount : public Account {
             return &link_;
         }
 
+        /**
+         * Implementation of Account::newOutgoingCall()
+         * Note: keep declaration before newOutgoingCall template.
+         */
+        std::shared_ptr<Call> newOutgoingCall(const std::string& id,
+                                              const std::string& toUrl);
+
+        /**
+         * Create outgoing IAXCall.
+         * @param[in] id The ID of the call
+         * @param[in] toUrl The address to call
+         * @return std::shared_ptr<T> A shared pointer on the created call.
+         *      The type of this instance is given in template argument.
+         *      This type can be any base class of IAXCall class (included).
+         */
+        template <class T=IAXCall>
+        std::shared_ptr<enable_if_base_of<T, IAXCall> >
+        newOutgoingCall(const std::string& id, const std::string& toUrl);
+
+        /**
+         * Create incoming IAXCall.
+         * @param[in] id The ID of the call
+         * @return std::shared_ptr<T> A shared pointer on the created call.
+         *      The type of this instance is given in template argument.
+         *      This type can be any base class of IAXCall class (included).
+         */
+        template <class T=IAXCall>
+        std::shared_ptr<enable_if_base_of<T, IAXCall> >
+        newIncomingCall(const std::string& id);
+
     private:
         NON_COPYABLE(IAXAccount);
 
diff --git a/daemon/src/iax/iaxcall.cpp b/daemon/src/iax/iaxcall.cpp
index b42710d990e47d0d2ffbe9fd612fb62fe4986159..761f5a3cd621b406a00c2ce132d95c5adeedf9d9 100644
--- a/daemon/src/iax/iaxcall.cpp
+++ b/daemon/src/iax/iaxcall.cpp
@@ -1,7 +1,8 @@
 /*
- *  Copyright (C) 2004-2013 Savoir-Faire Linux Inc.
+ *  Copyright (C) 2004-2014 Savoir-Faire Linux Inc.
  *  Author: Alexandre Bourget <alexandre.bourget@savoirfairelinux.com>
  *  Author: Yan Morin <yan.morin@savoirfairelinux.com>
+ *  Author : Guillaume Roguez <guillaume.roguez@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
@@ -44,6 +45,8 @@
 #include "im/instant_messaging.h"
 #endif
 
+const char* const IAXCall::LINK_TYPE = IAXAccount::ACCOUNT_TYPE;
+
 static int
 codecToASTFormat(int c)
 {
@@ -65,9 +68,11 @@ codecToASTFormat(int c)
     }
 }
 
-IAXCall::IAXCall(const std::string& id, Call::CallType type,
-                 IAXAccount& account, IAXVoIPLink* link) :
-    Call(id, type, account), format(0), session(NULL), link_(link)
+IAXCall::IAXCall(IAXAccount& account, const std::string& id, Call::CallType type)
+    : Call(account, id, type),
+      format(0),
+      session(NULL),
+      link_(static_cast<IAXVoIPLink*>(account.getVoIPLink()))
 {}
 
 int IAXCall::getSupportedFormat(const std::string &accountID) const
@@ -157,7 +162,7 @@ IAXCall::hangup(int reason UNUSED)
     iax_hangup(session, (char*) "Dumped Call");
     session = nullptr;
 
-    link_->removeIaxCall(getCallId());
+    removeCall();
 }
 
 void
@@ -168,7 +173,7 @@ IAXCall::refuse()
         iax_reject(session, (char*) "Call rejected manually.");
     }
 
-    link_->removeIaxCall(getCallId());
+    removeCall();
 }
 
 void
diff --git a/daemon/src/iax/iaxcall.h b/daemon/src/iax/iaxcall.h
index 5dfed54e5d879c465f52f3752e77f8d32f1f4be9..b2faf6139711bf91b2629f7589b6d049d5f4d516 100644
--- a/daemon/src/iax/iaxcall.h
+++ b/daemon/src/iax/iaxcall.h
@@ -1,7 +1,8 @@
 /*
- *  Copyright (C) 2004-2013 Savoir-Faire Linux Inc.
+ *  Copyright (C) 2004-2014 Savoir-Faire Linux Inc.
  *  Author: Alexandre Bourget <alexandre.bourget@savoirfairelinux.com>
  *  Author: Yan Morin <yan.morin@savoirfairelinux.com>
+ *  Author : Guillaume Roguez <guillaume.roguez@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
@@ -48,16 +49,20 @@ class IAXAccount;
  */
 class iax_session;
 
-class IAXCall : public Call {
+class IAXCall : public Call
+{
     public:
+        static const char* const LINK_TYPE;
+
+    protected:
         /**
          * Constructor
          * @param id  The unique ID of the call
          * @param type  The type of the call
          */
-        IAXCall(const std::string& id, Call::CallType type,
-                IAXAccount& account, IAXVoIPLink* link);
+        IAXCall(IAXAccount& account, const std::string& id, Call::CallType type);
 
+    public:
         /**
          * @return int  The bitwise list of supported formats
          */
diff --git a/daemon/src/iax/iaxvoiplink.cpp b/daemon/src/iax/iaxvoiplink.cpp
index 09487dbc01ac2778080123c0cb13e280487fe10e..d99c683641c3a646cfa143fdf1c377117bee5bc2 100644
--- a/daemon/src/iax/iaxvoiplink.cpp
+++ b/daemon/src/iax/iaxvoiplink.cpp
@@ -1,7 +1,8 @@
 /*
- *  Copyright (C) 2004-2013 Savoir-Faire Linux Inc.
+ *  Copyright (C) 2004-2014 Savoir-Faire Linux Inc.
  *  Author: Alexandre Bourget <alexandre.bourget@savoirfairelinux.com>
  *  Author: Yan Morin <yan.morin@savoirfairelinux.com>
+ *  Author : Guillaume Roguez <guillaume.roguez@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
@@ -28,6 +29,7 @@
  *  shall include the source code for the parts of OpenSSL used as well
  *  as that of the covered work.
  */
+
 #include "iaxvoiplink.h"
 #include <unistd.h>
 #include <cmath>
@@ -42,9 +44,8 @@
 #include "audio/resampler.h"
 #include "array_size.h"
 #include "map_utils.h"
+#include "call_factory.h"
 
-IAXCallMap IAXVoIPLink::iaxCallMap_;
-std::mutex IAXVoIPLink::iaxCallMapMutex_;
 std::mutex IAXVoIPLink::mutexIAX = {};
 
 IAXVoIPLink::IAXVoIPLink(IAXAccount& account) :
@@ -61,10 +62,6 @@ IAXVoIPLink::IAXVoIPLink(IAXAccount& account) :
 IAXVoIPLink::~IAXVoIPLink()
 {
     terminate();
-
-    // This is our last account
-    if (Manager::instance().accountCount<IAXAccount>() == 1)
-        clearIaxCallMap();
 }
 
 void
@@ -88,23 +85,27 @@ IAXVoIPLink::terminate()
     if (!initDone_)
         return;
 
-    std::lock_guard<std::mutex> lock(iaxCallMapMutex_);
     handlingEvents_ = false;
 
-    for (auto & item : iaxCallMap_) {
-        auto& call = item.second;
-        if (call) {
-            std::lock_guard<std::mutex> lock(mutexIAX);
-            iax_hangup(call->session, const_cast<char*>("Dumped Call"));
-            call.reset();
-        }
+    for (const auto& call : Manager::instance().callFactory.getAllCalls<IAXCall>()) {
+        std::lock_guard<std::mutex> lock(mutexIAX);
+        iax_hangup(call->session, const_cast<char*>("Dumped Call"));
+        call->removeCall();
     }
 
-    iaxCallMap_.clear();
-
     initDone_ = false;
 }
 
+static std::shared_ptr<IAXCall>
+iaxGetCallFromSession(iax_session* session)
+{
+    for (auto call : Manager::instance().callFactory.getAllCalls<IAXCall>()) {
+        if (call->session == session)
+            return call;
+    }
+    return nullptr;
+}
+
 bool
 IAXVoIPLink::handleEvents()
 {
@@ -125,10 +126,8 @@ IAXVoIPLink::handleEvents()
             continue;
         }
 
-        const std::string id(iaxFindCallIDBySession(event->session));
-
-        if (not id.empty()) {
-            iaxHandleCallEvent(event, id);
+        if (auto raw_call_ptr = iaxGetCallFromSession(event->session)) {
+            iaxHandleCallEvent(event, raw_call_ptr->getCallId());
         } else if (event->session && event->session == account_.getRegSession()) {
             // This is a registration session, deal with it
             iaxHandleRegReply(event);
@@ -153,34 +152,11 @@ IAXVoIPLink::handleEvents()
     return handlingEvents_;
 }
 
-std::vector<std::string>
-IAXVoIPLink::getCallIDs()
-{
-    std::vector<std::string> v;
-    std::lock_guard<std::mutex> lock(iaxCallMapMutex_);
-
-    map_utils::vectorFromMapKeys(iaxCallMap_, v);
-    return v;
-}
-
-std::vector<std::shared_ptr<Call> >
-IAXVoIPLink::getCalls(const std::string &account_id) const
-{
-    std::vector<std::shared_ptr<Call> > calls;
-    for (const auto & item : iaxCallMap_) {
-        if (item.second->getAccountId() == account_id)
-            calls.push_back(item.second);
-    }
-    return calls;
-}
-
 void
 IAXVoIPLink::sendAudioFromMic()
 {
-    for (const auto & item : iaxCallMap_) {
-        auto& currentCall = item.second;
-
-        if (!currentCall or currentCall->getState() != Call::ACTIVE)
+    for (const auto currentCall : Manager::instance().callFactory.getAllCalls<IAXCall>()) {
+        if (currentCall->getState() != Call::ACTIVE)
             continue;
 
         int codecType = currentCall->getAudioCodec();
@@ -231,84 +207,22 @@ IAXVoIPLink::sendAudioFromMic()
     }
 }
 
-std::shared_ptr<IAXCall>
-IAXVoIPLink::getIAXCall(const std::string& id)
-{
-    return getIaxCall(id);
-}
-
-void
-IAXVoIPLink::clearIaxCallMap()
-{
-    std::lock_guard<std::mutex> lock(iaxCallMapMutex_);
-    iaxCallMap_.clear();
-}
-
-void
-IAXVoIPLink::addIaxCall(std::shared_ptr<IAXCall>& call)
-{
-    if (call == nullptr)
-        return;
-
-    std::lock_guard<std::mutex> lock(iaxCallMapMutex_);
-    if (!getIaxCall(call->getCallId()))
-        iaxCallMap_[call->getCallId()] = std::shared_ptr<IAXCall>(call);
-}
-
-void
-IAXVoIPLink::removeIaxCall(const std::string& id)
-{
-    std::lock_guard<std::mutex> lock(iaxCallMapMutex_);
-
-    DEBUG("Removing call %s from list", id.c_str());
-    iaxCallMap_.erase(id);
-}
-
-std::shared_ptr<IAXCall>
-IAXVoIPLink::getIaxCall(const std::string& id)
-{
-    IAXCallMap::iterator iter = iaxCallMap_.find(id);
-    if (iter != iaxCallMap_.end())
-        return iter->second;
-    else
-        return nullptr;
-}
-
-std::string
-IAXVoIPLink::iaxFindCallIDBySession(iax_session* session)
-{
-    std::lock_guard<std::mutex> lock(iaxCallMapMutex_);
-
-    for (const auto & item : iaxCallMap_) {
-        auto& call = item.second;
-
-        if (call and call->session == session)
-            return call->getCallId();
-    }
-
-    return "";
-}
-
 void
 IAXVoIPLink::handleReject(const std::string &id)
 {
-    {
-        std::lock_guard<std::mutex> lock(iaxCallMapMutex_);
-        if (auto call = getIAXCall(id)) {
-            call->setConnectionState(Call::CONNECTED);
-            call->setState(Call::ERROR);
-        }
+    if (auto call = Manager::instance().callFactory.getCall<IAXCall>(id)) {
+        call->setConnectionState(Call::CONNECTED);
+        call->setState(Call::ERROR);
+        Manager::instance().callFailure(id);
+        call->removeCall();
     }
-    Manager::instance().callFailure(id);
-    removeIaxCall(id);
 }
 
 void
 IAXVoIPLink::handleAccept(iax_event* event, const std::string &id)
 {
     if (event->ies.format) {
-        std::lock_guard<std::mutex> lock(iaxCallMapMutex_);
-        if (auto call = getIAXCall(id))
+        if (auto call = Manager::instance().callFactory.getCall<IAXCall>(id))
             call->format = event->ies.format;
     }
 }
@@ -316,18 +230,15 @@ IAXVoIPLink::handleAccept(iax_event* event, const std::string &id)
 void
 IAXVoIPLink::handleAnswerTransfer(iax_event* event, const std::string &id)
 {
-    {
-        std::lock_guard<std::mutex> lock(iaxCallMapMutex_);
-        auto call = getIAXCall(id);
-        if (!call or call->getConnectionState() == Call::CONNECTED)
-            return;
+    auto call = Manager::instance().callFactory.getCall<IAXCall>(id);
+    if (!call or call->getConnectionState() == Call::CONNECTED)
+        return;
 
-        call->setConnectionState(Call::CONNECTED);
-        call->setState(Call::ACTIVE);
+    call->setConnectionState(Call::CONNECTED);
+    call->setState(Call::ACTIVE);
 
-        if (event->ies.format)
-            call->format = event->ies.format;
-    }
+    if (event->ies.format)
+        call->format = event->ies.format;
 
     Manager::instance().addStream(id);
     Manager::instance().peerAnsweredCall(id);
@@ -338,29 +249,27 @@ IAXVoIPLink::handleAnswerTransfer(iax_event* event, const std::string &id)
 void
 IAXVoIPLink::handleBusy(const std::string &id)
 {
-    {
-        std::lock_guard<std::mutex> lock(iaxCallMapMutex_);
-        auto call = getIAXCall(id);
-        if (!call)
-            return;
-        call->setConnectionState(Call::CONNECTED);
-        call->setState(Call::BUSY);
-    }
+    auto call = Manager::instance().callFactory.getCall<IAXCall>(id);
+    if (!call)
+        return;
+
+    call->setConnectionState(Call::CONNECTED);
+    call->setState(Call::BUSY);
+
     Manager::instance().callBusy(id);
-    removeIaxCall(id);
+    call->removeCall();
 }
 
 void
 IAXVoIPLink::handleMessage(iax_event* event, const std::string &id)
 {
     std::string peerNumber;
-    {
-        std::lock_guard<std::mutex> lock(iaxCallMapMutex_);
-        auto call = getIAXCall(id);
-        if (!call)
-            return;
-        peerNumber = call->getPeerNumber();
-    }
+
+    auto call = Manager::instance().callFactory.getCall<IAXCall>(id);
+    if (!call)
+        return;
+
+    peerNumber = call->getPeerNumber();
 
     Manager::instance().incomingMessage(id, peerNumber, std::string((const char*) event->data));
 }
@@ -368,23 +277,31 @@ IAXVoIPLink::handleMessage(iax_event* event, const std::string &id)
 void
 IAXVoIPLink::handleRinging(const std::string &id)
 {
-    {
-        std::lock_guard<std::mutex> lock(iaxCallMapMutex_);
-        auto call = getIAXCall(id);
-        if (!call)
-            return;
-        call->setConnectionState(Call::RINGING);
-    }
+    auto call = Manager::instance().callFactory.getCall<IAXCall>(id);
+    if (!call)
+        return;
+
+    call->setConnectionState(Call::RINGING);
     Manager::instance().peerRingingCall(id);
 }
 
 void
-IAXVoIPLink::iaxHandleCallEvent(iax_event* event, const std::string &id)
+IAXVoIPLink::handleHangup(const std::string &id)
+{
+    auto call = Manager::instance().callFactory.getCall<IAXCall>(id);
+    if (!call)
+        return;
+
+    Manager::instance().peerHungupCall(id);
+    call->removeCall();
+}
+
+void
+IAXVoIPLink::iaxHandleCallEvent(iax_event* event, const std::string& id)
 {
     switch (event->etype) {
         case IAX_EVENT_HANGUP:
-            Manager::instance().peerHungupCall(id);
-            removeIaxCall(id);
+            handleHangup(id);
             break;
 
         case IAX_EVENT_REJECT:
@@ -442,41 +359,38 @@ void IAXVoIPLink::iaxHandleVoiceEvent(iax_event* event, const std::string &id)
 
     AudioBuffer *out;
 
-    {
-        std::lock_guard<std::mutex> lock(iaxCallMapMutex_);
-        auto call = getIAXCall(id);
-        if (!call)
-            throw VoipLinkException("Could not find call");
+    auto call = Manager::instance().callFactory.getCall<IAXCall>(id);
+    if (!call)
+        throw VoipLinkException("Could not find call");
 
-        sfl::AudioCodec *audioCodec = static_cast<sfl::AudioCodec *>(Manager::instance().audioCodecFactory.getCodec(call->getAudioCodec()));
+    sfl::AudioCodec *audioCodec = static_cast<sfl::AudioCodec *>(Manager::instance().audioCodecFactory.getCodec(call->getAudioCodec()));
 
-        if (!audioCodec)
-            return;
+    if (!audioCodec)
+        return;
 
-        Manager::instance().getMainBuffer().setInternalSamplingRate(audioCodec->getClockRate());
-        unsigned int mainBufferSampleRate = Manager::instance().getMainBuffer().getInternalSamplingRate();
+    Manager::instance().getMainBuffer().setInternalSamplingRate(audioCodec->getClockRate());
+    unsigned int mainBufferSampleRate = Manager::instance().getMainBuffer().getInternalSamplingRate();
 
-        if (event->subclass)
-            call->format = event->subclass;
+    if (event->subclass)
+        call->format = event->subclass;
 
-        unsigned char *data = (unsigned char*) event->data;
-        unsigned int size = event->datalen;
+    unsigned char *data = (unsigned char*) event->data;
+    unsigned int size = event->datalen;
 
-        unsigned int max = audioCodec->getClockRate() * 20 / 1000;
+    unsigned int max = audioCodec->getClockRate() * 20 / 1000;
 
-        if (size > max)
-            size = max;
+    if (size > max)
+        size = max;
 
-        audioCodec->decode(rawBuffer_.getData(), data , size);
-        out = &rawBuffer_;
-        unsigned int audioRate = audioCodec->getClockRate();
+    audioCodec->decode(rawBuffer_.getData(), data , size);
+    out = &rawBuffer_;
+    unsigned int audioRate = audioCodec->getClockRate();
 
-        if (audioRate != mainBufferSampleRate) {
-            rawBuffer_.setSampleRate(mainBufferSampleRate);
-            resampledData_.setSampleRate(audioRate);
-            resampler_.resample(rawBuffer_, resampledData_);
-            out = &resampledData_;
-        }
+    if (audioRate != mainBufferSampleRate) {
+        rawBuffer_.setSampleRate(mainBufferSampleRate);
+        resampledData_.setSampleRate(audioRate);
+        resampler_.resample(rawBuffer_, resampledData_);
+        out = &resampledData_;
     }
 
     Manager::instance().getMainBuffer().putData(*out, id);
@@ -509,7 +423,7 @@ void IAXVoIPLink::iaxHandlePrecallEvent(iax_event* event)
         case IAX_EVENT_CONNECT:
             id = Manager::instance().getNewCallID();
 
-            call = std::make_shared<IAXCall>(id, Call::INCOMING, account_, this);
+            call = account_.newIncomingCall<IAXCall>(id);
 
             call->session = event->session;
             call->setConnectionState(Call::PROGRESSING);
@@ -533,17 +447,15 @@ void IAXVoIPLink::iaxHandlePrecallEvent(iax_event* event)
 
             iax_accept(event->session, format);
             iax_ring_announce(event->session);
-            addIaxCall(call);
             call->format = format;
 
             break;
 
         case IAX_EVENT_HANGUP:
-            id = iaxFindCallIDBySession(event->session);
-
-            if (not id.empty()) {
+            if (auto raw_call_ptr = iaxGetCallFromSession(event->session)) {
+                id = raw_call_ptr->getCallId();
                 Manager::instance().peerHungupCall(id);
-                removeIaxCall(id);
+                raw_call_ptr->removeCall();
             }
 
             break;
diff --git a/daemon/src/iax/iaxvoiplink.h b/daemon/src/iax/iaxvoiplink.h
index 215e0aaff615eeb4ea63fbc7a494ef452cc542c1..712b8c35b42937dbd45fdf40240769cf5f0230ee 100644
--- a/daemon/src/iax/iaxvoiplink.h
+++ b/daemon/src/iax/iaxvoiplink.h
@@ -1,8 +1,9 @@
 /*
- *  Copyright (C) 2004-2013 Savoir-Faire Linux Inc.
+ *  Copyright (C) 2004-2014 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>
+ *  Author : Guillaume Roguez <guillaume.roguez@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
@@ -36,7 +37,6 @@
 #include "config.h"
 #endif
 
-#include <mutex>
 #include "account.h"
 #include "voiplink.h"
 #include "audio/audiobuffer.h"
@@ -47,16 +47,13 @@
 
 #include <iax-client.h>
 
+#include <mutex>
 #include <memory>
 
-class IAXCall;
 class IAXAccount;
-
 class AudioCodec;
 class AudioLayer;
 
-typedef std::map<std::string, std::shared_ptr<IAXCall> > IAXCallMap;
-
 /**
  * @file iaxvoiplink.h
  * @brief VoIPLink contains a thread that listen to external events
@@ -75,11 +72,6 @@ class IAXVoIPLink : public VoIPLink {
         bool handleEvents();
 
 
-        /* Returns a list of all callIDs */
-        static std::vector<std::string> getCallIDs();
-
-        std::vector<std::shared_ptr<Call> > getCalls(const std::string &accountId) const;
-
         /**
          * Init the voip link
          */
@@ -96,12 +88,6 @@ class IAXVoIPLink : public VoIPLink {
          */
         virtual void cancel(const std::string& /*id*/) {}
 
-        static void clearIaxCallMap();
-        static void addIaxCall(std::shared_ptr<IAXCall>& call);
-        // must be called while holding iaxCallMapMutex
-        static std::shared_ptr<IAXCall> getIaxCall(const std::string& id);
-        static void removeIaxCall(const std::string &id);
-
         /** Mutex for iax_ calls, since we're the only one dealing with the incorporated
          * iax_stuff inside this class. */
         static std::mutex mutexIAX;
@@ -115,9 +101,7 @@ class IAXVoIPLink : public VoIPLink {
         void handleAnswerTransfer(iax_event* event, const std::string &id);
         void handleBusy(const std::string &id);
         void handleMessage(iax_event* event, const std::string &id);
-
-        static std::mutex iaxCallMapMutex_;
-        static IAXCallMap iaxCallMap_;
+        void handleHangup(const std::string &id);
 
         /*
          * Decode the message count IAX send.
@@ -129,13 +113,6 @@ class IAXVoIPLink : public VoIPLink {
         int processIAXMsgCount(int msgcount);
 
 
-        /**
-         * Get IAX Call from an id
-         * @param id CallId
-         * @return IAXCall pointer or 0
-         */
-        std::shared_ptr<IAXCall> getIAXCall(const std::string& id);
-
         /**
          * Find a iaxcall by iax session number
          * @param session an iax_session valid pointer
diff --git a/daemon/src/manager.cpp b/daemon/src/manager.cpp
index 74c93592cbf50f35358c209047d2634e9ef6c54c..cced0b6d50461549e2d4cbd404c4ed8290138b5d 100644
--- a/daemon/src/manager.cpp
+++ b/daemon/src/manager.cpp
@@ -29,6 +29,7 @@
  */
 
 #include "manager.h"
+#include "logger.h"
 
 ManagerImpl& Manager::instance()
 {
diff --git a/daemon/src/managerimpl.cpp b/daemon/src/managerimpl.cpp
index 1c8b6c3420a4dda3d7254334d053254637d30ec9..14efa79e3b54ba5dadec8b3e31e788e5a44f9e35 100644
--- a/daemon/src/managerimpl.cpp
+++ b/daemon/src/managerimpl.cpp
@@ -48,12 +48,14 @@
 #include "voiplink.h"
 #include "account.h"
 
+#include "call_factory.h"
+
 // FIXME: remove these dependencies
 #include "sip/sipvoiplink.h"
-#include "sip/sipcall.h"
+#include "sip/sip_utils.h"
+
 #if HAVE_IAX
 #include "iax/iaxvoiplink.h"
-#include "iax/iaxcall.h"
 #include "iax/iaxaccount.h"
 #endif
 
@@ -136,7 +138,7 @@ ManagerImpl::ManagerImpl() :
     currentCallId_(), currentCallMutex_(), audiodriver_(nullptr), dtmfKey_(), dtmfBuf_(0, AudioFormat::MONO()),
     toneMutex_(), telephoneTone_(), audiofile_(), audioLayerMutex_(),
     waitingCalls_(), waitingCallsMutex_(), path_(),
-    mainBuffer_(), conferenceMap_(), history_(),
+    mainBuffer_(), callFactory(), conferenceMap_(), history_(),
     finished_(false), accountFactory_()
 
 {
@@ -269,15 +271,20 @@ ManagerImpl::finish()
     finished_ = true;
 
     try {
+        // Forbid call creation
+        callFactory.forbid();
 
-        std::vector<std::string> callList(getCallList());
-        DEBUG("Hangup %zu remaining call(s)", callList.size());
-
-        for (const auto &item : callList)
-            hangupCall(item);
+        // Hangup all remaining active calls
+        DEBUG("Hangup %zu remaining call(s)", callFactory.callCount());
+        for (const auto call : callFactory.getAllCalls())
+            hangupCall(call->getCallId());
+        callFactory.clear();
 
+        // Save accounts config and call's history
         saveConfig();
+        saveHistory();
 
+        // Disconnect accounts, close link stacks and free allocated ressources
         unregisterAccounts();
         accountFactory_.clear();
         SIPVoIPLink::destroy();
@@ -288,8 +295,6 @@ ManagerImpl::finish()
             delete audiodriver_;
             audiodriver_ = nullptr;
         }
-
-        saveHistory();
     } catch (const VoipLinkException &err) {
         ERROR("%s", err.what());
     }
@@ -331,7 +336,7 @@ void ManagerImpl::switchCall(const std::string& id)
 /* Main Thread */
 
 bool
-ManagerImpl::outgoingCall(const std::string& prefered_account_id,
+ManagerImpl::outgoingCall(const std::string& preferred_account_id,
                           const std::string& call_id,
                           const std::string& to,
                           const std::string& conf_id)
@@ -373,7 +378,7 @@ ManagerImpl::outgoingCall(const std::string& prefered_account_id,
          * as the factory may decide to use another account (like IP2IP).
          */
         DEBUG("New outgoing call to %s", to_cleaned.c_str());
-        auto call = Call::newOutgoingCall(call_id, to_cleaned, prefered_account_id);
+        auto call = newOutgoingCall(call_id, to_cleaned, preferred_account_id);
 
         // try to reverse match the peer name using the cache
         if (call->getDisplayName().empty()) {
@@ -963,13 +968,7 @@ ManagerImpl::addMainParticipant(const std::string& conference_id)
 std::shared_ptr<Call>
 ManagerImpl::getCallFromCallID(const std::string& callID)
 {
-    std::shared_ptr<Call> call = SIPVoIPLink::instance().getSipCall(callID);
-#if HAVE_IAX
-    if (!call)
-        call = IAXVoIPLink::getIaxCall(callID);
-#endif
-
-    return call;
+    return callFactory.getCall(callID);
 }
 
 bool
@@ -2594,11 +2593,6 @@ ManagerImpl::loadAccountMap(Conf::YamlParser &parser)
 std::map<std::string, std::string>
 ManagerImpl::getCallDetails(const std::string &callID)
 {
-    // We need here to retrieve the call information attached to the call ID
-    // To achieve that, we need to get the voip link attached to the call
-    // But to achieve that, we need to get the account the call was made with
-
-    // Then the VoIP link this account is linked with (IAX2 or SIP)
     if (auto call = getCallFromCallID(callID)) {
         return call->getDetails();
     } else {
@@ -2617,12 +2611,7 @@ ManagerImpl::getHistory()
 std::vector<std::string>
 ManagerImpl::getCallList() const
 {
-    std::vector<std::string> v(SIPVoIPLink::instance().getCallIDs());
-#if HAVE_IAX
-    const std::vector<std::string> iaxCalls(IAXVoIPLink::getCallIDs());
-    v.insert(v.end(), iaxCalls.begin(), iaxCalls.end());
-#endif
-    return v;
+    return callFactory.getCallIDs();
 }
 
 std::map<std::string, std::string>
@@ -2780,3 +2769,32 @@ ManagerImpl::getVideoManager()
     return client_.getVideoManager();
 }
 #endif
+
+std::shared_ptr<Call>
+ManagerImpl::newOutgoingCall(const std::string& id,
+                             const std::string& toUrl,
+                             const std::string& preferredAccountId)
+{
+    std::shared_ptr<Account> account = Manager::instance().getIP2IPAccount();
+    std::string finalToUrl = toUrl;
+
+    // FIXME: have a generic version to remove sip dependency
+    sip_utils::stripSipUriPrefix(finalToUrl);
+
+    if (!IpAddr::isValid(finalToUrl)) {
+        account = getAccount(preferredAccountId);
+        if (account)
+            finalToUrl = toUrl;
+        else
+            WARN("Preferred account %s doesn't exist, using IP2IP account",
+                 preferredAccountId.c_str());
+    } else
+        WARN("IP Url detected, using IP2IP account");
+
+    if (!account) {
+        ERROR("No suitable account found to create outgoing call");
+        return nullptr;
+    }
+
+    return account->newOutgoingCall(id, finalToUrl);
+}
diff --git a/daemon/src/managerimpl.h b/daemon/src/managerimpl.h
index a7d68ab47fdcf9e1dcb40b3ffbaef74b4e74950b..c313f11a17548e6529c1cc0f80a1507f9d3d81cd 100644
--- a/daemon/src/managerimpl.h
+++ b/daemon/src/managerimpl.h
@@ -50,9 +50,10 @@
 
 #include "config/sfl_config.h"
 
-#include "call.h"
 #include "conference.h"
+
 #include "account_factory.h"
+#include "call_factory.h"
 
 #include "audio/audiolayer.h"
 #include "audio/sound/tone.h"  // for Tone::TONEID declaration
@@ -152,7 +153,7 @@ class ManagerImpl {
         /**
          * Functions which occur with a user's action
          * Place a new call
-         * @param accountId	The account to make tha call with
+         * @param accountId	The account to make the call with
          * @param call_id  The call identifier
          * @param to  The recipient of the call
          * @param conf_id The conference identifier if any
@@ -961,6 +962,21 @@ class ManagerImpl {
         void
         pollEvents();
 
+        /**
+         * Create a new outgoing call
+         * @param id  The ID of the call
+         * @param toUrl The address to call
+         * @param preferredAccountId The IP of preferred account to use.
+         *   This is not necessary the account used.
+         * @return Call*  A shared pointer on a valid call.
+         * @note This function raises VoipLinkException() on errors.
+         */
+        std::shared_ptr<Call> newOutgoingCall(const std::string& id,
+                                              const std::string& toUrl,
+                                              const std::string& preferredAccountId);
+
+        CallFactory callFactory;
+
     private:
         NON_COPYABLE(ManagerImpl);
 
diff --git a/daemon/src/sfl_types.h b/daemon/src/sfl_types.h
index a534c2e1dc3b0d23d4b7347a53ac6751b6aeeb79..855b03a2b597964f0c7fd3393ea4a57ae8d13fc1 100644
--- a/daemon/src/sfl_types.h
+++ b/daemon/src/sfl_types.h
@@ -33,10 +33,18 @@
 
 #include <cstddef> // for size_t
 #include <stdint.h>
+#include <type_traits>
 
 typedef int16_t SFLAudioSample;
 #define SFL_DATA_FORMAT_MAX SHRT_MAX
 
 static const size_t SIZEBUF = 32000; /** About 1s of buffering at 48kHz */
 
+/**
+ * This meta-function is used to enable a template overload
+ * only if given class T is a base of class U
+ */
+template <class T, class U>
+using enable_if_base_of = typename std::enable_if<std::is_base_of<T, U>::value, T>::type;
+
 #endif // SFL_TYPES_H_
diff --git a/daemon/src/sip/sipaccount.cpp b/daemon/src/sip/sipaccount.cpp
index 12319b5dae7179a4594a1cc3e76f1c71ae175bb8..5501ce46e5a693b12bff5af8e6b7f5fc0e03b8b6 100644
--- a/daemon/src/sip/sipaccount.cpp
+++ b/daemon/src/sip/sipaccount.cpp
@@ -1,22 +1,23 @@
 /*
- *  Copyright (C) 2004-2013 Savoir-Faire Linux Inc.
-*
-*  Author: Emmanuel Milou <emmanuel.milou@savoirfairelinux.com>
-*  Author: Pierre-Luc Bacon <pierre-luc.bacon@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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA.
+ *  Copyright (C) 2004-2014 Savoir-Faire Linux Inc.
+ *
+ *  Author: Emmanuel Milou <emmanuel.milou@savoirfairelinux.com>
+ *  Author: Pierre-Luc Bacon <pierre-luc.bacon@savoirfairelinux.com>
+ *  Author : Guillaume Roguez <guillaume.roguez@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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA.
  *
  *  Additional permission under GNU GPL version 3 section 7:
  *
@@ -28,7 +29,7 @@
  *  Corresponding Source for a non-source form of such a combination
  *  shall include the source code for the parts of OpenSSL used as well
  *  as that of the covered work.
-*/
+ */
 
 #include "sipaccount.h"
 
@@ -42,6 +43,8 @@
 #include "sip_utils.h"
 #include "array_size.h"
 
+#include "call_factory.h"
+
 #ifdef SFL_PRESENCE
 #include "sippresence.h"
 #include "client/configurationmanager.h"
@@ -217,9 +220,16 @@ unserializeRange(const Conf::YamlNode &mapNode, const char *minKey, const char *
     updateRange(tmpMin, tmpMax, range);
 }
 
-std::shared_ptr<Call>
-SIPAccount::newOutgoingCall(const std::string& id,
-                            const std::string& toUrl)
+template <>
+std::shared_ptr<SIPCall>
+SIPAccount::newIncomingCall(const std::string& id)
+{
+    return Manager::instance().callFactory.newCall<SIPCall, SIPAccount>(*this, id, Call::INCOMING);
+}
+
+template <>
+std::shared_ptr<SIPCall>
+SIPAccount::newOutgoingCall(const std::string& id, const std::string& toUrl)
 {
     std::string to;
     std::string toUri;
@@ -252,7 +262,7 @@ SIPAccount::newOutgoingCall(const std::string& id,
         DEBUG("UserAgent: New registered account call to %s", toUrl.c_str());
     }
 
-    auto call = std::make_shared<SIPCall>(id, Call::OUTGOING, *this);
+    auto call = Manager::instance().callFactory.newCall<SIPCall, SIPAccount>(*this, id, Call::OUTGOING);
 
     call->setIPToIP(isIP2IP());
     call->setPeerNumber(toUri);
@@ -304,6 +314,12 @@ SIPAccount::newOutgoingCall(const std::string& id,
     return call;
 }
 
+std::shared_ptr<Call>
+SIPAccount::newOutgoingCall(const std::string& id, const std::string& toUrl)
+{
+    return newOutgoingCall<SIPCall>(id, toUrl);
+}
+
 bool
 SIPAccount::SIPStartCall(std::shared_ptr<SIPCall>& call)
 {
@@ -371,7 +387,6 @@ SIPAccount::SIPStartCall(std::shared_ptr<SIPCall>& call)
 
     call->setConnectionState(Call::PROGRESSING);
     call->setState(Call::ACTIVE);
-    link_.addSipCall(call);
 
     return true;
 }
diff --git a/daemon/src/sip/sipaccount.h b/daemon/src/sip/sipaccount.h
index c9642eff6f058ceb7b0ea42926a2ce6d55feb87d..5f043f5e3cade1a0a85f37cca3157d12d56484de 100644
--- a/daemon/src/sip/sipaccount.h
+++ b/daemon/src/sip/sipaccount.h
@@ -43,6 +43,7 @@
 #include "account.h"
 #include "noncopyable.h"
 #include "ip_utils.h"
+#include "sfl_types.h" // enable_if_base_of
 
 #include <pjsip/sip_transport_tls.h>
 #include <pjsip/sip_types.h>
@@ -136,21 +137,13 @@ class SIPAccount : public Account {
          * @param accountID The account identifier
          */
         SIPAccount(const std::string& accountID, bool presenceEnabled);
+
         ~SIPAccount();
 
         const char* getAccountType() const {
             return ACCOUNT_TYPE;
         }
 
-        /**
-         * Create a new outgoing call
-         * @param id  The ID of the call
-         * @param toUrl The address to call
-         * @return Call*  A pointer on the call
-         */
-        std::shared_ptr<Call> newOutgoingCall(const std::string& id,
-                                              const std::string& toUrl);
-
         VoIPLink* getVoIPLink();
 
         pjsip_host_port getHostPortFromSTUN(pj_pool_t *pool);
@@ -614,6 +607,36 @@ class SIPAccount : public Account {
 
         void scheduleReregistration(pjsip_endpoint *endpt);
 
+        /**
+         * Implementation of Account::newOutgoingCall()
+         * Note: keep declaration before newOutgoingCall template.
+         */
+        std::shared_ptr<Call> newOutgoingCall(const std::string& id,
+                                              const std::string& toUrl);
+
+        /**
+         * Create outgoing SIPCall.
+         * @param[in] id The ID of the call
+         * @param[in] toUrl The address to call
+         * @return std::shared_ptr<T> A shared pointer on the created call.
+         *      The type of this instance is given in template argument.
+         *      This type can be any base class of SIPCall class (included).
+         */
+        template <class T=SIPCall>
+        std::shared_ptr<enable_if_base_of<T, SIPCall> >
+        newOutgoingCall(const std::string& id, const std::string& toUrl);
+
+        /**
+         * Create incoming SIPCall.
+         * @param[in] id The ID of the call
+         * @return std::shared_ptr<T> A shared pointer on the created call.
+         *      The type of this instance is given in template argument.
+         *      This type can be any base class of SIPCall class (included).
+         */
+        template <class T=SIPCall>
+        std::shared_ptr<enable_if_base_of<T, SIPCall> >
+        newIncomingCall(const std::string& id);
+
         void onRegister(pjsip_regc_cbparam *param);
 
     private:
diff --git a/daemon/src/sip/sipcall.cpp b/daemon/src/sip/sipcall.cpp
index 794e780802f87f636b43a3d41762b1ef3ef08295..361d19827e9d1431dbb304b0fdd0d3fd1f1f14f9 100644
--- a/daemon/src/sip/sipcall.cpp
+++ b/daemon/src/sip/sipcall.cpp
@@ -1,9 +1,10 @@
 /*
- *  Copyright (C) 2004-2013 Savoir-Faire Linux Inc.
+ *  Copyright (C) 2004-2014 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>
  *  Author : Laurielle Lea <laurielle.lea@savoirfairelinux.com>
+ *  Author : Guillaume Roguez <guillaume.roguez@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
@@ -31,6 +32,7 @@
  *  as that of the covered work.
  */
 
+#include "call_factory.h"
 #include "sipcall.h"
 #include "sip_utils.h"
 #include "logger.h" // for _debug
@@ -63,6 +65,8 @@ static const int INCREMENT_SIZE = INITIAL_SIZE;
  *  Given a SIP call ID (usefull for transaction sucha as transfer)*/
 static std::map<std::string, std::string> transferCallID;
 
+const char* const SIPCall::LINK_TYPE = SIPAccount::ACCOUNT_TYPE;
+
 static void
 dtmfSend(SIPCall &call, char code, const std::string &dtmf)
 {
@@ -92,9 +96,9 @@ dtmfSend(SIPCall &call, char code, const std::string &dtmf)
     call.sendSIPInfo(dtmf_body, "dtmf-relay");
 }
 
-SIPCall::SIPCall(const std::string& id, Call::CallType type,
-                 SIPAccount& account) :
-    Call(id, type, account)
+SIPCall::SIPCall(SIPAccount& account, const std::string& id,
+                 Call::CallType type)
+    : Call(account, id, type)
     , inv(NULL)
     , audiortp_(this)
 #ifdef SFL_VIDEO
@@ -110,6 +114,16 @@ SIPCall::SIPCall(const std::string& id, Call::CallType type,
 
 SIPCall::~SIPCall()
 {
+    const auto mod_ua_id = SIPVoIPLink::instance().getModId();
+
+    // prevent this from getting accessed in callbacks
+    if (inv->mod_data[mod_ua_id]) {
+        WARN("Call was not properly removed from invite callbacks");
+
+        // WARN: this assignation is not thread-safe!
+        inv->mod_data[mod_ua_id] = nullptr;
+    }
+
     // local sdp must be destroyed before pool
     local_sdp_.reset();
     pj_pool_release(pool_);
@@ -333,7 +347,7 @@ SIPCall::hangup(int reason)
     // Stop all RTP streams
     stopRtpIfCurrent();
 
-    siplink.removeSipCall(getCallId());
+    removeCall();
 }
 
 void
@@ -357,7 +371,7 @@ SIPCall::refuse()
     // Make sure the pointer is NULL in callbacks
     inv->mod_data[siplink.getModId()] = NULL;
 
-    siplink.removeSipCall(getCallId());
+    removeCall();
 }
 
 static void
@@ -684,7 +698,7 @@ SIPCall::onServerFailure()
 {
     const std::string id(getCallId());
     Manager::instance().callFailure(id);
-    SIPVoIPLink::instance().removeSipCall(id);
+    removeCall();
 }
 
 void
@@ -692,7 +706,7 @@ SIPCall::onClosed()
 {
     const std::string id(getCallId());
     Manager::instance().peerHungupCall(id);
-    SIPVoIPLink::instance().removeSipCall(id);
+    removeCall();
     Manager::instance().checkAudio();
 }
 
diff --git a/daemon/src/sip/sipcall.h b/daemon/src/sip/sipcall.h
index 5c8079d3372d111c3a8e3c794ae2ba7549b4bcae..34aa380375f12508bd75ec01fcde9a5a7ce699fd 100644
--- a/daemon/src/sip/sipcall.h
+++ b/daemon/src/sip/sipcall.h
@@ -1,8 +1,9 @@
 /*
- *  Copyright (C) 2004-2013 Savoir-Faire Linux Inc.
+ *  Copyright (C) 2004-2014 Savoir-Faire Linux Inc.
  *  Author: Alexandre Bourget <alexandre.bourget@savoirfairelinux.com>
  *  Author: Yan Morin <yan.morin@savoirfairelinux.com>
  *  Author : Laurielle Lea <laurielle.lea@savoirfairelinux.com>
+ *  Author : Guillaume Roguez <guillaume.roguez@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
@@ -29,6 +30,7 @@
  *  shall include the source code for the parts of OpenSSL used as well
  *  as that of the covered work.
  */
+
 #ifndef __SIPCALL_H__
 #define __SIPCALL_H__
 
@@ -60,18 +62,21 @@ class SIPAccount;
  * @file sipcall.h
  * @brief SIPCall are SIP implementation of a normal Call
  */
-class SIPCall : public Call {
+class SIPCall : public Call
+{
     public:
+        static const char* const LINK_TYPE;
 
+    protected:
         /**
-         * Constructor
+         * Constructor (protected)
          * @param id	The call identifier
          * @param type  The type of the call. Could be Incoming
          *						 Outgoing
          */
-        SIPCall(const std::string& id, Call::CallType type,
-                SIPAccount& account);
+        SIPCall(SIPAccount& account, const std::string& id, Call::CallType type);
 
+    public:
         /**
          * Destructor
          */
@@ -166,13 +171,12 @@ class SIPCall : public Call {
         void onClosed();
 
     private:
+        NON_COPYABLE(SIPCall);
 
         // override of Call::createHistoryEntry
         std::map<std::string, std::string>
         createHistoryEntry() const;
 
-        NON_COPYABLE(SIPCall);
-
         void stopRtpIfCurrent();
 
         /**
diff --git a/daemon/src/sip/sipvoiplink.cpp b/daemon/src/sip/sipvoiplink.cpp
index 2510e5dbc1fbe9a91bd84bc4553884beaed955d8..3b621bf9b13238ae978051bd359a5efce9df375e 100644
--- a/daemon/src/sip/sipvoiplink.cpp
+++ b/daemon/src/sip/sipvoiplink.cpp
@@ -1,9 +1,10 @@
 /*
- *  Copyright (C) 2004-2013 Savoir-Faire Linux Inc.
+ *  Copyright (C) 2004-2014 Savoir-Faire Linux Inc.
  *  Author: Emmanuel Milou <emmanuel.milou@savoirfairelinux.com>
  *  Author: Yun Liu <yun.liu@savoirfairelinux.com>
  *  Author: Pierre-Luc Bacon <pierre-luc.bacon@savoirfairelinux.com>
  *  Author: Alexandre Savard <alexandre.savard@savoirfairelinux.com>
+ *  Author : Guillaume Roguez <guillaume.roguez@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
@@ -41,6 +42,8 @@
 #include "sipcall.h"
 #include "sip_utils.h"
 
+#include "call_factory.h"
+
 #include "manager.h"
 #if HAVE_SDES
 #include "sdes_negotiator.h"
@@ -48,7 +51,6 @@
 
 #include "logger.h"
 #include "array_size.h"
-#include "map_utils.h"
 #include "ip_utils.h"
 
 #if HAVE_INSTANT_MESSAGING
@@ -282,8 +284,7 @@ transaction_request_cb(pjsip_rx_data *rdata)
 
     Manager::instance().hookPreference.runHook(rdata->msg_info.msg);
 
-    auto call = std::make_shared<SIPCall>(Manager::instance().getNewCallID(),
-                                          Call::INCOMING, *sipaccount);
+    auto call = sipaccount->newIncomingCall<SIPCall>(Manager::instance().getNewCallID());
 
     // FIXME : for now, use the same address family as the SIP tranport
     auto family = pjsip_transport_type_get_af(sipaccount->getTransportType());
@@ -459,7 +460,6 @@ transaction_request_cb(pjsip_rx_data *rdata)
 
         call->setConnectionState(Call::RINGING);
 
-        SIPVoIPLink::instance().addSipCall(call);
         Manager::instance().incomingCall(*call, account_id);
     }
 
@@ -482,8 +482,8 @@ pj_pool_t* SIPVoIPLink::getPool() const
     return pool_;
 }
 
-SIPVoIPLink::SIPVoIPLink() : sipTransport(),
-    sipCallMapMutex_(), sipCallMap_()
+SIPVoIPLink::SIPVoIPLink()
+    : sipTransport()
 #ifdef SFL_VIDEO
     , keyframeRequestsMutex_()
     , keyframeRequests_()
@@ -587,7 +587,9 @@ SIPVoIPLink::~SIPVoIPLink()
     const pj_time_val tv = {0, 10};
     pjsip_endpt_handle_events(endpt_, &tv);
 
-    clearSipCallMap();
+    if (!Manager::instance().callFactory.empty<SIPCall>())
+        ERROR("%d SIP calls remains!",
+              Manager::instance().callFactory.callCount<SIPCall>());
 
     // destroy SIP transport before endpoint
     sipTransport.reset();
@@ -720,105 +722,6 @@ void SIPVoIPLink::cancelKeepAliveTimer(pj_timer_entry& timer)
     pjsip_endpt_cancel_timer(endpt_, &timer);
 }
 
-void
-SIPVoIPLink::clearSipCallMap()
-{
-    std::lock_guard<std::mutex> lock(sipCallMapMutex_);
-    sipCallMap_.clear();
-}
-
-std::vector<std::string>
-SIPVoIPLink::getCallIDs()
-{
-    std::vector<std::string> v;
-    std::lock_guard<std::mutex> lock(sipCallMapMutex_);
-
-    map_utils::vectorFromMapKeys(sipCallMap_, v);
-    return v;
-}
-
-std::vector<std::shared_ptr<Call> >
-SIPVoIPLink::getCalls(const std::string &account_id) const
-{
-    std::lock_guard<std::mutex> lock(sipCallMapMutex_);
-
-    std::vector<std::shared_ptr<Call> > calls;
-    for (const auto & item : sipCallMap_) {
-        if (item.second->getAccountId() == account_id)
-            calls.push_back(item.second);
-    }
-    return calls;
-}
-
-void SIPVoIPLink::addSipCall(std::shared_ptr<SIPCall>& call)
-{
-    if (!call)
-        return;
-
-    const std::string id(call->getCallId());
-
-    std::lock_guard<std::mutex> lock(sipCallMapMutex_);
-
-    // emplace C++11 method has been implemented in GCC 4.8.0
-    // see https://gcc.gnu.org/bugzilla/show_bug.cgi?id=44436
-#if !defined(__GNUC__) or (__GNUC__ >= 4 && __GNUC_MINOR__ >= 8)
-    if (not sipCallMap_.emplace(id, call).second)
-#else
-    if (sipCallMap_.find(id) == sipCallMap_.end()) {
-        sipCallMap_[id] = call;
-    } else
-#endif
-        ERROR("Call %s is already in the call map", id.c_str());
-
-}
-
-void SIPVoIPLink::removeSipCall(const std::string& id)
-{
-    std::lock_guard<std::mutex> lock(sipCallMapMutex_);
-
-    DEBUG("Removing call %s from list", id.c_str());
-    SipCallMap::iterator iter = sipCallMap_.find(id);
-    if (iter != sipCallMap_.end()) {
-        auto count = iter->second.use_count();
-        if (count > 1)
-            WARN("removing a used SIPCall (by %d holders)", count);
-    }
-    sipCallMap_.erase(id);
-}
-
-std::shared_ptr<SIPCall>
-SIPVoIPLink::getSipCall(const std::string& id)
-{
-    std::lock_guard<std::mutex> lock(sipCallMapMutex_);
-
-    SipCallMap::iterator iter = sipCallMap_.find(id);
-
-    if (iter != sipCallMap_.end())
-        return iter->second;
-    else {
-        DEBUG("No SIP call with ID %s", id.c_str());
-        return nullptr;
-    }
-}
-
-std::shared_ptr<SIPCall>
-SIPVoIPLink::tryGetSIPCall(const std::string& id)
-{
-    std::shared_ptr<SIPCall> call;
-
-    if (sipCallMapMutex_.try_lock()) {
-        SipCallMap::iterator iter = sipCallMap_.find(id);
-
-        if (iter != sipCallMap_.end())
-            call = iter->second;
-
-        sipCallMapMutex_.unlock();
-    } else
-        ERROR("Could not acquire SIPCallMap mutex");
-
-    return call;
-}
-
 #ifdef SFL_VIDEO
 // Called from a video thread
 void
@@ -850,7 +753,7 @@ SIPVoIPLink::requestKeyframe(const std::string &callID)
     const int tries = 10;
 
     for (int i = 0; !call and i < tries; ++i)
-        call = SIPVoIPLink::instance().tryGetSIPCall(callID);
+        call = Manager::instance().callFactory.getCall<SIPCall>(callID); // fixme: need a try version
 
     if (!call)
         return;
@@ -1353,10 +1256,10 @@ onCallTransfered(pjsip_inv_session *inv, pjsip_rx_data *rdata)
     }
 
     try {
-        Call::newOutgoingCall(Manager::instance().getNewCallID(),
-                              std::string(refer_to->hvalue.ptr,
-                                          refer_to->hvalue.slen),
-                              currentCall->getAccountId());
+        Manager::instance().newOutgoingCall(Manager::instance().getNewCallID(),
+                                            std::string(refer_to->hvalue.ptr,
+                                                        refer_to->hvalue.slen),
+                                            currentCall->getAccountId());
         Manager::instance().hangupCall(currentCall->getCallId());
     } catch (const VoipLinkException &e) {
         ERROR("%s", e.what());
diff --git a/daemon/src/sip/sipvoiplink.h b/daemon/src/sip/sipvoiplink.h
index 4f234d9af83283e3148323119a01b1a24bae662e..a6b4d98870a12e8b713f5a5409c6af8fe6214b42 100644
--- a/daemon/src/sip/sipvoiplink.h
+++ b/daemon/src/sip/sipvoiplink.h
@@ -1,10 +1,11 @@
 /*
- *  Copyright (C) 2004-2013 Savoir-Faire Linux Inc.
+ *  Copyright (C) 2004-2014 Savoir-Faire Linux Inc.
  *
  *  Author: Emmanuel Milou <emmanuel.milou@savoirfairelinux.com>
  *  Author: Yun Liu <yun.liu@savoirfairelinux.com>
  *  Author: Pierre-Luc Bacon <pierre-luc.bacon@savoirfairelinux.com>
  *  Author: Alexandre Savard <alexandre.savard@savoirfairelinux.com>
+ *  Author : Guillaume Roguez <guillaume.roguez@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
@@ -104,8 +105,6 @@ class SIPVoIPLink : public VoIPLink {
         /* Returns a list of all callIDs */
         std::vector<std::string> getCallIDs();
 
-        std::vector<std::shared_ptr<Call> > getCalls(const std::string &account_id) const;
-
         /**
          * Register a new keepalive registration timer to this endpoint
          */
@@ -128,23 +127,6 @@ class SIPVoIPLink : public VoIPLink {
          */
         pj_caching_pool *getMemoryPoolFactory();
 
-        void clearSipCallMap();
-        void addSipCall(std::shared_ptr<SIPCall>& call);
-
-        std::shared_ptr<SIPCall> getSipCall(const std::string& id);
-
-        /**
-         * A non-blocking SIPCall accessor
-         *
-         * Will return NULL if the callMapMutex could not be locked
-         *
-         * @param id  The call identifier
-         * @return SIPCall* A pointer to the SIPCall object
-         */
-        std::shared_ptr<SIPCall> tryGetSIPCall(const std::string &id);
-
-        void removeSipCall(const std::string &id);
-
         /**
          * Create the default UDP transport according ot Ip2Ip profile settings
          */
@@ -185,9 +167,6 @@ class SIPVoIPLink : public VoIPLink {
         SIPVoIPLink();
         ~SIPVoIPLink();
 
-        mutable std::mutex sipCallMapMutex_;
-        SipCallMap sipCallMap_;
-
 #ifdef SFL_VIDEO
         void dequeKeyframeRequests();
         void requestKeyframe(const std::string &callID);
diff --git a/daemon/src/video/video_input.cpp b/daemon/src/video/video_input.cpp
index fdcd3a43f78a04ce8f5eefe485e5927dfe250a58..ea08a20c7186e7ea4a6e9653ea4d8d9a7a9dc810 100644
--- a/daemon/src/video/video_input.cpp
+++ b/daemon/src/video/video_input.cpp
@@ -38,6 +38,8 @@
 
 #include <map>
 #include <string>
+#include <cassert>
+#include <unistd.h>
 
 namespace sfl_video {
 
diff --git a/daemon/src/video/video_mixer.cpp b/daemon/src/video/video_mixer.cpp
index 045672b7e11319d71103c535686a230180bc38ad..4aa7d3547109d4a802410d60d0f5817c4466c985 100644
--- a/daemon/src/video/video_mixer.cpp
+++ b/daemon/src/video/video_mixer.cpp
@@ -37,6 +37,7 @@
 #include "logger.h"
 
 #include <cmath>
+#include <unistd.h>
 
 static const double FRAME_DURATION = 1/30.;
 
diff --git a/daemon/src/voiplink.h b/daemon/src/voiplink.h
index fd98442975e23721ad6867203a9946f0f882694c..aa5d61da7f3b06dd25206620c8c3878dbc328578 100644
--- a/daemon/src/voiplink.h
+++ b/daemon/src/voiplink.h
@@ -1,9 +1,10 @@
 /*
- *  Copyright (C) 2004-2013 Savoir-Faire Linux Inc.
+ *  Copyright (C) 2004-2014 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>
+ *  Author : Guillaume Roguez <guillaume.roguez@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
@@ -34,16 +35,8 @@
 #ifndef __VOIP_LINK_H__
 #define __VOIP_LINK_H__
 
-#include "account.h"
-
 #include <stdexcept>
-#include <functional>
 #include <string>
-#include <vector>
-#include <memory>
-
-class Call;
-class Account;
 
 class VoipLinkException : public std::runtime_error {
     public:
@@ -66,12 +59,6 @@ class VoIPLink {
          */
         virtual bool handleEvents() = 0;
 
-        /**
-         * Virtual method
-         * Returns calls involving this account.
-         */
-        virtual std::vector<std::shared_ptr<Call> > getCalls(const std::string &account_id) const = 0;
-
     protected:
         bool handlingEvents_ = false;
 };
diff --git a/daemon/test/siptest.cpp b/daemon/test/siptest.cpp
index 22ed5bbec1b2c6f72654aa4a503c5406bddbb9f0..abe01882c437c7c2e0512c34620d0290d6dc7ffe 100644
--- a/daemon/test/siptest.cpp
+++ b/daemon/test/siptest.cpp
@@ -41,6 +41,7 @@
 #include "manager.h"
 #include "sip/sipvoiplink.h"
 #include "sip/sip_utils.h"
+#include "sip/sipcall.h"
 
 // anonymous namespace
 namespace {
@@ -176,15 +177,12 @@ void SIPTest::testSimpleIncomingIpCall()
     // the incoming invite.
     sleep(2);
 
-    // gtrab call id from sipvoiplink
-    SIPVoIPLink& siplink = SIPVoIPLink::instance();
-
-    CPPUNIT_ASSERT(siplink.sipCallMap_.size() == 1);
-    SipCallMap::iterator iterCallId = siplink.sipCallMap_.begin();
-    std::string testcallid = iterCallId->first;
+    CPPUNIT_ASSERT(Manager::instance().callFactory.callCount<SIPCall>() == 1);
 
     // Answer this call
-    CPPUNIT_ASSERT(Manager::instance().answerCall(testcallid));
+    const auto& calls = Manager::instance().callFactory.getAllCalls<SIPCall>();
+    const auto call = *calls.cbegin();
+    CPPUNIT_ASSERT(Manager::instance().answerCall(call->getCallId()));
 
     sleep(1);
 
@@ -284,15 +282,13 @@ void SIPTest::testTwoIncomingIpCall()
     // the incoming invite.
     sleep(1);
 
-    // gtrab call id from sipvoiplink
-    SIPVoIPLink& sipLink = SIPVoIPLink::instance();
-
-    CPPUNIT_ASSERT(sipLink.sipCallMap_.size() == 1);
-    SipCallMap::iterator iterCallId = sipLink.sipCallMap_.begin();
-    std::string firstCallID = iterCallId->first;
+    CPPUNIT_ASSERT(Manager::instance().callFactory.callCount<SIPCall>() == 1);
 
     // Answer this call
-    CPPUNIT_ASSERT(Manager::instance().answerCall(firstCallID));
+    auto calls = Manager::instance().callFactory.getCallIDs<SIPCall>();
+    auto iterCallId = calls.cbegin();
+    const auto& firstCallId = *iterCallId;
+    CPPUNIT_ASSERT(Manager::instance().answerCall(firstCallId));
 
     sleep(1);
     pthread_t secondCallThread;
@@ -303,13 +299,13 @@ void SIPTest::testTwoIncomingIpCall()
 
     sleep(1);
 
-    CPPUNIT_ASSERT(sipLink.sipCallMap_.size() == 2);
-    iterCallId = sipLink.sipCallMap_.begin();
-
-    if (iterCallId->first == firstCallID)
+    CPPUNIT_ASSERT(Manager::instance().callFactory.callCount<SIPCall>() == 2);
+    calls = Manager::instance().callFactory.getCallIDs<SIPCall>();
+    iterCallId = calls.cbegin();
+    if (*iterCallId == firstCallId)
         ++iterCallId;
 
-    std::string secondCallID(iterCallId->first);
+    std::string secondCallID(*iterCallId);
 
     CPPUNIT_ASSERT(Manager::instance().answerCall(secondCallID));
 
@@ -411,19 +407,16 @@ void SIPTest::testIncomingIpCallSdp()
     // the incoming invite.
     sleep(2);
 
-    // gtrab call id from sipvoiplink
-    SIPVoIPLink& siplink = SIPVoIPLink::instance();
+    CPPUNIT_ASSERT(Manager::instance().callFactory.callCount<SIPCall>() == 1);
 
-    CPPUNIT_ASSERT(siplink.sipCallMap_.size() == 1);
-    SipCallMap::iterator iterCallId = siplink.sipCallMap_.begin();
-    std::string testcallid = iterCallId->first;
+    // Answer this call
+    const auto& calls = Manager::instance().callFactory.getAllCalls<SIPCall>();
 
     // TODO: hmmm, should IP2IP call be stored in call list....
     CPPUNIT_ASSERT(Manager::instance().getCallList().empty());
 
     // Answer this call
-    CPPUNIT_ASSERT(Manager::instance().answerCall(testcallid));
-
+    CPPUNIT_ASSERT(Manager::instance().answerCall((*calls.cbegin())->getCallId()));
 
     sleep(1);